]> git.hungrycats.org Git - linux/commitdiff
[IPV4]: Dynamic allocation for IPGRE net device.
authorStephen Hemminger <shemminger@osdl.org>
Thu, 12 Jun 2003 10:56:01 +0000 (03:56 -0700)
committerDavid S. Miller <davem@nuts.ninka.net>
Thu, 12 Jun 2003 10:56:01 +0000 (03:56 -0700)
net/ipv4/ip_gre.c

index 677c3c8f7f2ea3cbc9d1594849bc4cf2454ab3f2..8d72a478f24489267b26f094ee379495e5a913dc 100644 (file)
  */
 
 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