Commit d2fc0e5d authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

[IPV4]: Dynamic allocation for IPGRE net device.

parent c5df7561
...@@ -114,20 +114,13 @@ ...@@ -114,20 +114,13 @@
*/ */
static int ipgre_tunnel_init(struct net_device *dev); static int ipgre_tunnel_init(struct net_device *dev);
static void ipgre_tunnel_setup(struct net_device *dev);
/* Fallback tunnel: no source, no destination, no key, no options */ /* Fallback tunnel: no source, no destination, no key, no options */
static int ipgre_fb_tunnel_init(struct net_device *dev); static int ipgre_fb_tunnel_init(struct net_device *dev);
static struct net_device ipgre_fb_tunnel_dev = { static struct net_device *ipgre_fb_tunnel_dev;
.name = "gre0",
.init = ipgre_fb_tunnel_init
};
static struct ip_tunnel ipgre_fb_tunnel = {
.dev = &ipgre_fb_tunnel_dev,
.parms ={ .name = "gre0" }
};
/* Tunnel hash table */ /* Tunnel hash table */
...@@ -190,8 +183,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key) ...@@ -190,8 +183,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key)
if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) if (t->parms.i_key == key && (t->dev->flags&IFF_UP))
return t; return t;
} }
if (ipgre_fb_tunnel_dev.flags&IFF_UP)
return &ipgre_fb_tunnel; if (ipgre_fb_tunnel_dev->flags&IFF_UP)
return ipgre_fb_tunnel_dev->priv;
return NULL; return NULL;
} }
...@@ -246,6 +240,7 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int ...@@ -246,6 +240,7 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int
struct net_device *dev; struct net_device *dev;
unsigned h = HASH(key); unsigned h = HASH(key);
int prio = 0; int prio = 0;
char name[IFNAMSIZ];
if (local) if (local)
prio |= 1; prio |= 1;
...@@ -262,32 +257,28 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int ...@@ -262,32 +257,28 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int
if (!create) if (!create)
return NULL; return NULL;
dev = kmalloc(sizeof(*dev) + sizeof(*t), GFP_KERNEL); if (parms->name[0])
if (dev == NULL) strlcpy(name, parms->name, IFNAMSIZ);
return NULL; else {
memset(dev, 0, sizeof(*dev) + sizeof(*t));
dev->priv = (void*)(dev+1);
nt = (struct ip_tunnel*)dev->priv;
nt->dev = dev;
dev->init = ipgre_tunnel_init;
memcpy(&nt->parms, parms, sizeof(*parms));
nt->parms.name[IFNAMSIZ-1] = '\0';
strcpy(dev->name, nt->parms.name);
if (dev->name[0] == 0) {
int i; int i;
for (i=1; i<100; i++) { for (i=1; i<100; i++) {
sprintf(dev->name, "gre%d", i); sprintf(name, "gre%d", i);
if (__dev_get_by_name(dev->name) == NULL) if (__dev_get_by_name(name) == NULL)
break; break;
} }
if (i==100) if (i==100)
goto failed; goto failed;
memcpy(nt->parms.name, dev->name, IFNAMSIZ);
} }
SET_MODULE_OWNER(dev);
if (register_netdevice(dev) < 0) dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup);
if (register_netdevice(dev) < 0) {
kfree(dev);
goto failed; goto failed;
}
nt = dev->priv;
dev->init = ipgre_tunnel_init;
nt->parms = *parms;
dev_hold(dev); dev_hold(dev);
ipgre_tunnel_link(nt); ipgre_tunnel_link(nt);
...@@ -295,16 +286,9 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int ...@@ -295,16 +286,9 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int
return nt; return nt;
failed: failed:
kfree(dev);
return NULL; return NULL;
} }
static void ipgre_tunnel_destructor(struct net_device *dev)
{
if (dev != &ipgre_fb_tunnel_dev)
kfree(dev);
}
static void ipgre_tunnel_uninit(struct net_device *dev) static void ipgre_tunnel_uninit(struct net_device *dev)
{ {
ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv); ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv);
...@@ -916,7 +900,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -916,7 +900,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
switch (cmd) { switch (cmd) {
case SIOCGETTUNNEL: case SIOCGETTUNNEL:
t = NULL; t = NULL;
if (dev == &ipgre_fb_tunnel_dev) { if (dev == ipgre_fb_tunnel_dev) {
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
err = -EFAULT; err = -EFAULT;
break; break;
...@@ -955,8 +939,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -955,8 +939,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
t = ipgre_tunnel_locate(&p, cmd == SIOCADDTUNNEL); t = ipgre_tunnel_locate(&p, cmd == SIOCADDTUNNEL);
if (dev != &ipgre_fb_tunnel_dev && cmd == SIOCCHGTUNNEL && if (dev != ipgre_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
t != &ipgre_fb_tunnel) {
if (t != NULL) { if (t != NULL) {
if (t->dev != dev) { if (t->dev != dev) {
err = -EEXIST; err = -EEXIST;
...@@ -1006,7 +989,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1006,7 +989,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
goto done; goto done;
if (dev == &ipgre_fb_tunnel_dev) { if (dev == ipgre_fb_tunnel_dev) {
err = -EFAULT; err = -EFAULT;
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
goto done; goto done;
...@@ -1014,7 +997,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1014,7 +997,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
if ((t = ipgre_tunnel_locate(&p, 0)) == NULL) if ((t = ipgre_tunnel_locate(&p, 0)) == NULL)
goto done; goto done;
err = -EPERM; err = -EPERM;
if (t == &ipgre_fb_tunnel) if (t == ipgre_fb_tunnel_dev->priv)
goto done; goto done;
dev = t->dev; dev = t->dev;
} }
...@@ -1140,12 +1123,11 @@ static int ipgre_close(struct net_device *dev) ...@@ -1140,12 +1123,11 @@ static int ipgre_close(struct net_device *dev)
#endif #endif
static void ipgre_tunnel_init_gen(struct net_device *dev) static void ipgre_tunnel_setup(struct net_device *dev)
{ {
struct ip_tunnel *t = (struct ip_tunnel*)dev->priv; SET_MODULE_OWNER(dev);
dev->uninit = ipgre_tunnel_uninit; dev->uninit = ipgre_tunnel_uninit;
dev->destructor = ipgre_tunnel_destructor; dev->destructor = (void (*)(struct net_device *))kfree;
dev->hard_start_xmit = ipgre_tunnel_xmit; dev->hard_start_xmit = ipgre_tunnel_xmit;
dev->get_stats = ipgre_tunnel_get_stats; dev->get_stats = ipgre_tunnel_get_stats;
dev->do_ioctl = ipgre_tunnel_ioctl; dev->do_ioctl = ipgre_tunnel_ioctl;
...@@ -1157,8 +1139,6 @@ static void ipgre_tunnel_init_gen(struct net_device *dev) ...@@ -1157,8 +1139,6 @@ static void ipgre_tunnel_init_gen(struct net_device *dev)
dev->flags = IFF_NOARP; dev->flags = IFF_NOARP;
dev->iflink = 0; dev->iflink = 0;
dev->addr_len = 4; dev->addr_len = 4;
memcpy(dev->dev_addr, &t->parms.iph.saddr, 4);
memcpy(dev->broadcast, &t->parms.iph.daddr, 4);
} }
static int ipgre_tunnel_init(struct net_device *dev) static int ipgre_tunnel_init(struct net_device *dev)
...@@ -1173,7 +1153,9 @@ static int ipgre_tunnel_init(struct net_device *dev) ...@@ -1173,7 +1153,9 @@ static int ipgre_tunnel_init(struct net_device *dev)
tunnel = (struct ip_tunnel*)dev->priv; tunnel = (struct ip_tunnel*)dev->priv;
iph = &tunnel->parms.iph; iph = &tunnel->parms.iph;
ipgre_tunnel_init_gen(dev); tunnel->dev = dev;
memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
/* Guess output device to choose reasonable mtu and hard_header_len */ /* Guess output device to choose reasonable mtu and hard_header_len */
...@@ -1231,18 +1213,15 @@ static int ipgre_tunnel_init(struct net_device *dev) ...@@ -1231,18 +1213,15 @@ static int ipgre_tunnel_init(struct net_device *dev)
int __init ipgre_fb_tunnel_init(struct net_device *dev) int __init ipgre_fb_tunnel_init(struct net_device *dev)
{ {
struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv; struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv;
struct iphdr *iph; struct iphdr *iph = &tunnel->parms.iph;
ipgre_tunnel_init_gen(dev);
iph = &ipgre_fb_tunnel.parms.iph;
iph->version = 4; iph->version = 4;
iph->protocol = IPPROTO_GRE; iph->protocol = IPPROTO_GRE;
iph->ihl = 5; iph->ihl = 5;
tunnel->hlen = sizeof(struct iphdr) + 4; tunnel->hlen = sizeof(struct iphdr) + 4;
dev_hold(dev); dev_hold(dev);
tunnels_wc[0] = &ipgre_fb_tunnel; tunnels_wc[0] = tunnel;
return 0; return 0;
} }
...@@ -1259,6 +1238,8 @@ static struct inet_protocol ipgre_protocol = { ...@@ -1259,6 +1238,8 @@ static struct inet_protocol ipgre_protocol = {
int __init ipgre_init(void) int __init ipgre_init(void)
{ {
int err = -EINVAL;
printk(KERN_INFO "GRE over IPv4 tunneling driver\n"); printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) { if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) {
...@@ -1266,10 +1247,23 @@ int __init ipgre_init(void) ...@@ -1266,10 +1247,23 @@ int __init ipgre_init(void)
return -EAGAIN; return -EAGAIN;
} }
ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel; ipgre_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
SET_MODULE_OWNER(&ipgre_fb_tunnel_dev); ipgre_tunnel_setup);
register_netdev(&ipgre_fb_tunnel_dev); if (!ipgre_fb_tunnel_dev) {
return 0; err = -ENOMEM;
goto fail;
}
ipgre_fb_tunnel_dev->init = ipgre_fb_tunnel_init;
if ((err = register_netdev(ipgre_fb_tunnel_dev)))
goto fail;
out:
return err;
fail:
inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
kfree(ipgre_fb_tunnel_dev);
goto out;
} }
void ipgre_fini(void) void ipgre_fini(void)
...@@ -1277,7 +1271,7 @@ void ipgre_fini(void) ...@@ -1277,7 +1271,7 @@ void ipgre_fini(void)
if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
printk(KERN_INFO "ipgre close: can't remove protocol\n"); printk(KERN_INFO "ipgre close: can't remove protocol\n");
unregister_netdev(&ipgre_fb_tunnel_dev); unregister_netdev(ipgre_fb_tunnel_dev);
} }
#ifdef MODULE #ifdef MODULE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment