mac80211: fix modprobe deadlock by not calling wep_init under rtnl_lock
[safe/jmp/linux-2.6] / net / ax25 / ax25_route.c
index c288526..c833ba4 100644 (file)
@@ -11,6 +11,8 @@
  * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
  * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
  */
+
+#include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 static ax25_route *ax25_route_list;
 static DEFINE_RWLOCK(ax25_route_lock);
 
-static ax25_route *ax25_get_route(ax25_address *, struct net_device *);
-
 void ax25_rt_device_down(struct net_device *dev)
 {
        ax25_route *s, *t, *ax25_rt;
 
-       write_lock(&ax25_route_lock);
+       write_lock_bh(&ax25_route_lock);
        ax25_rt = ax25_route_list;
        while (ax25_rt != NULL) {
                s       = ax25_rt;
@@ -54,15 +54,13 @@ void ax25_rt_device_down(struct net_device *dev)
                if (s->dev == dev) {
                        if (ax25_route_list == s) {
                                ax25_route_list = s->next;
-                               if (s->digipeat != NULL)
-                                       kfree(s->digipeat);
+                               kfree(s->digipeat);
                                kfree(s);
                        } else {
                                for (t = ax25_route_list; t != NULL; t = t->next) {
                                        if (t->next == s) {
                                                t->next = s->next;
-                                               if (s->digipeat != NULL)
-                                                       kfree(s->digipeat);
+                                               kfree(s->digipeat);
                                                kfree(s);
                                                break;
                                        }
@@ -70,10 +68,10 @@ void ax25_rt_device_down(struct net_device *dev)
                        }
                }
        }
-       write_unlock(&ax25_route_lock);
+       write_unlock_bh(&ax25_route_lock);
 }
 
-static int ax25_rt_add(struct ax25_routes_struct *route)
+static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
 {
        ax25_route *ax25_rt;
        ax25_dev *ax25_dev;
@@ -84,19 +82,17 @@ static int ax25_rt_add(struct ax25_routes_struct *route)
        if (route->digi_count > AX25_MAX_DIGIS)
                return -EINVAL;
 
-       write_lock(&ax25_route_lock);
+       write_lock_bh(&ax25_route_lock);
 
        ax25_rt = ax25_route_list;
        while (ax25_rt != NULL) {
                if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
-                           ax25_rt->dev == ax25_dev->dev) {
-                       if (ax25_rt->digipeat != NULL) {
-                               kfree(ax25_rt->digipeat);
-                               ax25_rt->digipeat = NULL;
-                       }
+                           ax25_rt->dev == ax25_dev->dev) {
+                       kfree(ax25_rt->digipeat);
+                       ax25_rt->digipeat = NULL;
                        if (route->digi_count != 0) {
                                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
-                                       write_unlock(&ax25_route_lock);
+                                       write_unlock_bh(&ax25_route_lock);
                                        return -ENOMEM;
                                }
                                ax25_rt->digipeat->lastrepeat = -1;
@@ -106,25 +102,25 @@ static int ax25_rt_add(struct ax25_routes_struct *route)
                                        ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
                                }
                        }
-                       write_unlock(&ax25_route_lock);
+                       write_unlock_bh(&ax25_route_lock);
                        return 0;
                }
                ax25_rt = ax25_rt->next;
        }
 
        if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
-               write_unlock(&ax25_route_lock);
+               write_unlock_bh(&ax25_route_lock);
                return -ENOMEM;
        }
 
-       atomic_set(&ax25_rt->ref, 0);
+       atomic_set(&ax25_rt->refcount, 1);
        ax25_rt->callsign     = route->dest_addr;
        ax25_rt->dev          = ax25_dev->dev;
        ax25_rt->digipeat     = NULL;
        ax25_rt->ip_mode      = ' ';
        if (route->digi_count != 0) {
                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
-                       write_unlock(&ax25_route_lock);
+                       write_unlock_bh(&ax25_route_lock);
                        kfree(ax25_rt);
                        return -ENOMEM;
                }
@@ -137,29 +133,15 @@ static int ax25_rt_add(struct ax25_routes_struct *route)
        }
        ax25_rt->next   = ax25_route_list;
        ax25_route_list = ax25_rt;
-       write_unlock(&ax25_route_lock);
+       write_unlock_bh(&ax25_route_lock);
 
        return 0;
 }
 
-static void ax25_rt_destroy(ax25_route *ax25_rt)
+void __ax25_put_route(ax25_route *ax25_rt)
 {
-       if (atomic_read(&ax25_rt->ref) == 0) {
-               if (ax25_rt->digipeat != NULL)
-                       kfree(ax25_rt->digipeat);
-               kfree(ax25_rt);
-               return;
-       }
-
-       /*
-        * Uh...  Route is still in use; we can't yet destroy it.  Retry later.
-        */
-       init_timer(&ax25_rt->timer);
-       ax25_rt->timer.data     = (unsigned long) ax25_rt;
-       ax25_rt->timer.function = (void *) ax25_rt_destroy;
-       ax25_rt->timer.expires  = jiffies + 5 * HZ;
-
-       add_timer(&ax25_rt->timer);
+       kfree(ax25_rt->digipeat);
+       kfree(ax25_rt);
 }
 
 static int ax25_rt_del(struct ax25_routes_struct *route)
@@ -170,7 +152,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route)
        if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
                return -EINVAL;
 
-       write_lock(&ax25_route_lock);
+       write_lock_bh(&ax25_route_lock);
 
        ax25_rt = ax25_route_list;
        while (ax25_rt != NULL) {
@@ -180,19 +162,19 @@ static int ax25_rt_del(struct ax25_routes_struct *route)
                    ax25cmp(&route->dest_addr, &s->callsign) == 0) {
                        if (ax25_route_list == s) {
                                ax25_route_list = s->next;
-                               ax25_rt_destroy(s);
+                               ax25_put_route(s);
                        } else {
                                for (t = ax25_route_list; t != NULL; t = t->next) {
                                        if (t->next == s) {
                                                t->next = s->next;
-                                               ax25_rt_destroy(s);
+                                               ax25_put_route(s);
                                                break;
                                        }
                                }
                        }
                }
        }
-       write_unlock(&ax25_route_lock);
+       write_unlock_bh(&ax25_route_lock);
 
        return 0;
 }
@@ -206,7 +188,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
        if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
                return -EINVAL;
 
-       write_lock(&ax25_route_lock);
+       write_lock_bh(&ax25_route_lock);
 
        ax25_rt = ax25_route_list;
        while (ax25_rt != NULL) {
@@ -234,7 +216,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
        }
 
 out:
-       write_unlock(&ax25_route_lock);
+       write_unlock_bh(&ax25_route_lock);
        return err;
 }
 
@@ -267,11 +249,12 @@ int ax25_rt_ioctl(unsigned int cmd, void __user *arg)
 #ifdef CONFIG_PROC_FS
 
 static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(ax25_route_lock)
 {
        struct ax25_route *ax25_rt;
        int i = 1;
-       read_lock(&ax25_route_lock);
+
+       read_lock(&ax25_route_lock);
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
@@ -287,17 +270,20 @@ static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos)
 static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        ++*pos;
-       return (v == SEQ_START_TOKEN) ? ax25_route_list : 
+       return (v == SEQ_START_TOKEN) ? ax25_route_list :
                ((struct ax25_route *) v)->next;
 }
 
 static void ax25_rt_seq_stop(struct seq_file *seq, void *v)
+       __releases(ax25_route_lock)
 {
        read_unlock(&ax25_route_lock);
 }
 
 static int ax25_rt_seq_show(struct seq_file *seq, void *v)
 {
+       char buf[11];
+
        if (v == SEQ_START_TOKEN)
                seq_puts(seq, "callsign  dev  mode digipeaters\n");
        else {
@@ -308,7 +294,7 @@ static int ax25_rt_seq_show(struct seq_file *seq, void *v)
                if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
                        callsign = "default";
                else
-                       callsign = ax2asc(&ax25_rt->callsign);
+                       callsign = ax2asc(buf, &ax25_rt->callsign);
 
                seq_printf(seq, "%-9s %-4s",
                        callsign,
@@ -328,14 +314,15 @@ static int ax25_rt_seq_show(struct seq_file *seq, void *v)
 
                if (ax25_rt->digipeat != NULL)
                        for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
-                               seq_printf(seq, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
+                               seq_printf(seq, " %s",
+                                    ax2asc(buf, &ax25_rt->digipeat->calls[i]));
 
                seq_puts(seq, "\n");
        }
        return 0;
 }
 
-static struct seq_operations ax25_rt_seqops = {
+static const struct seq_operations ax25_rt_seqops = {
        .start = ax25_rt_seq_start,
        .next = ax25_rt_seq_next,
        .stop = ax25_rt_seq_stop,
@@ -347,7 +334,7 @@ static int ax25_rt_info_open(struct inode *inode, struct file *file)
        return seq_open(file, &ax25_rt_seqops);
 }
 
-struct file_operations ax25_route_fops = {
+const struct file_operations ax25_route_fops = {
        .owner = THIS_MODULE,
        .open = ax25_rt_info_open,
        .read = seq_read,
@@ -360,9 +347,9 @@ struct file_operations ax25_route_fops = {
 /*
  *     Find AX.25 route
  *
- *     Only routes with a refernce rout of zero can be destroyed.
+ *     Only routes with a reference count of zero can be destroyed.
  */
-static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
+ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
 {
        ax25_route *ax25_spe_rt = NULL;
        ax25_route *ax25_def_rt = NULL;
@@ -392,7 +379,7 @@ static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
                ax25_rt = ax25_spe_rt;
 
        if (ax25_rt != NULL)
-               atomic_inc(&ax25_rt->ref);
+               ax25_hold_route(ax25_rt);
 
        read_unlock(&ax25_route_lock);
 
@@ -434,7 +421,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
                goto put;
        }
 
-       user = ax25_findbyuid(current->euid);
+       user = ax25_findbyuid(current_euid());
        if (user) {
                ax25->source_addr = user->call;
                ax25_uid_put(user);
@@ -447,11 +434,12 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
        }
 
        if (ax25_rt->digipeat != NULL) {
-               if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+               ax25->digipeat = kmemdup(ax25_rt->digipeat, sizeof(ax25_digi),
+                                        GFP_ATOMIC);
+               if (ax25->digipeat == NULL) {
                        err = -ENOMEM;
                        goto put;
                }
-               memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi));
                ax25_adjust_path(addr, ax25->digipeat);
        }
 
@@ -467,24 +455,6 @@ put:
        return 0;
 }
 
-ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr,
-       struct net_device *dev)
-{
-       ax25_route *ax25_rt;
-
-       if ((ax25_rt = ax25_get_route(addr, dev)))
-               return ax25_rt;
-
-       route->next     = NULL;
-       atomic_set(&route->ref, 1);
-       route->callsign = *addr;
-       route->dev      = dev;
-       route->digipeat = NULL;
-       route->ip_mode  = ' ';
-
-       return route;
-}
-
 struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
        ax25_address *dest, ax25_digi *digi)
 {
@@ -522,15 +492,13 @@ void __exit ax25_rt_free(void)
 {
        ax25_route *s, *ax25_rt = ax25_route_list;
 
-       write_lock(&ax25_route_lock);
+       write_lock_bh(&ax25_route_lock);
        while (ax25_rt != NULL) {
                s       = ax25_rt;
                ax25_rt = ax25_rt->next;
 
-               if (s->digipeat != NULL)
-                       kfree(s->digipeat);
-
+               kfree(s->digipeat);
                kfree(s);
        }
-       write_unlock(&ax25_route_lock);
+       write_unlock_bh(&ax25_route_lock);
 }