diff options
| author | Stephen Hemminger <shemminger@osdl.org> | 2003-06-12 03:56:01 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2003-06-12 03:56:01 -0700 |
| commit | d2fc0e5d291c16aebcabc85d80d4a3d1e8577652 (patch) | |
| tree | ac757b0e5a5ff1824053adc1cb80008dd04b6bec /net | |
| parent | c5df75610de9c0f4fe273b965b7c108862609ae7 (diff) | |
[IPV4]: Dynamic allocation for IPGRE net device.
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv4/ip_gre.c | 110 |
1 files changed, 52 insertions, 58 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 677c3c8f7f2e..8d72a478f244 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -114,20 +114,13 @@ */ 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 */ static int ipgre_fb_tunnel_init(struct net_device *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" } -}; +static struct net_device *ipgre_fb_tunnel_dev; /* Tunnel hash table */ @@ -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)) 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; } @@ -246,6 +240,7 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int struct net_device *dev; unsigned h = HASH(key); int prio = 0; + char name[IFNAMSIZ]; if (local) prio |= 1; @@ -262,32 +257,28 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int if (!create) return NULL; - dev = kmalloc(sizeof(*dev) + sizeof(*t), GFP_KERNEL); - if (dev == NULL) - return NULL; - - 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) { + if (parms->name[0]) + strlcpy(name, parms->name, IFNAMSIZ); + else { int i; for (i=1; i<100; i++) { - sprintf(dev->name, "gre%d", i); - if (__dev_get_by_name(dev->name) == NULL) + sprintf(name, "gre%d", i); + if (__dev_get_by_name(name) == NULL) break; } if (i==100) 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; + } + + nt = dev->priv; + dev->init = ipgre_tunnel_init; + nt->parms = *parms; dev_hold(dev); ipgre_tunnel_link(nt); @@ -295,16 +286,9 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int return nt; failed: - kfree(dev); 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) { ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv); @@ -916,7 +900,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGETTUNNEL: 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))) { err = -EFAULT; break; @@ -955,8 +939,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = ipgre_tunnel_locate(&p, cmd == SIOCADDTUNNEL); - if (dev != &ipgre_fb_tunnel_dev && cmd == SIOCCHGTUNNEL && - t != &ipgre_fb_tunnel) { + if (dev != ipgre_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { if (t->dev != dev) { err = -EEXIST; @@ -1006,7 +989,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) goto done; - if (dev == &ipgre_fb_tunnel_dev) { + if (dev == ipgre_fb_tunnel_dev) { err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; @@ -1014,7 +997,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if ((t = ipgre_tunnel_locate(&p, 0)) == NULL) goto done; err = -EPERM; - if (t == &ipgre_fb_tunnel) + if (t == ipgre_fb_tunnel_dev->priv) goto done; dev = t->dev; } @@ -1140,12 +1123,11 @@ static int ipgre_close(struct net_device *dev) #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->destructor = ipgre_tunnel_destructor; + dev->destructor = (void (*)(struct net_device *))kfree; dev->hard_start_xmit = ipgre_tunnel_xmit; dev->get_stats = ipgre_tunnel_get_stats; dev->do_ioctl = ipgre_tunnel_ioctl; @@ -1157,8 +1139,6 @@ static void ipgre_tunnel_init_gen(struct net_device *dev) dev->flags = IFF_NOARP; dev->iflink = 0; 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) @@ -1173,7 +1153,9 @@ static int ipgre_tunnel_init(struct net_device *dev) tunnel = (struct ip_tunnel*)dev->priv; 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 */ @@ -1231,18 +1213,15 @@ static int ipgre_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 iphdr *iph; - - ipgre_tunnel_init_gen(dev); + struct iphdr *iph = &tunnel->parms.iph; - iph = &ipgre_fb_tunnel.parms.iph; iph->version = 4; iph->protocol = IPPROTO_GRE; iph->ihl = 5; tunnel->hlen = sizeof(struct iphdr) + 4; dev_hold(dev); - tunnels_wc[0] = &ipgre_fb_tunnel; + tunnels_wc[0] = tunnel; return 0; } @@ -1259,6 +1238,8 @@ static struct inet_protocol ipgre_protocol = { int __init ipgre_init(void) { + int err = -EINVAL; + printk(KERN_INFO "GRE over IPv4 tunneling driver\n"); if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) { @@ -1266,10 +1247,23 @@ int __init ipgre_init(void) return -EAGAIN; } - ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel; - SET_MODULE_OWNER(&ipgre_fb_tunnel_dev); - register_netdev(&ipgre_fb_tunnel_dev); - return 0; + ipgre_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0", + ipgre_tunnel_setup); + if (!ipgre_fb_tunnel_dev) { + 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) @@ -1277,7 +1271,7 @@ void ipgre_fini(void) if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) printk(KERN_INFO "ipgre close: can't remove protocol\n"); - unregister_netdev(&ipgre_fb_tunnel_dev); + unregister_netdev(ipgre_fb_tunnel_dev); } #ifdef MODULE |
