bridge: Make IGMP snooping depend upon BRIDGE.
[safe/jmp/linux-2.6] / net / rose / rose_route.c
index 0dcca42..70a0b3b 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/sockios.h>
@@ -46,7 +45,7 @@ static DEFINE_SPINLOCK(rose_neigh_list_lock);
 static struct rose_route *rose_route_list;
 static DEFINE_SPINLOCK(rose_route_list_lock);
 
-struct rose_neigh rose_loopback_neigh;
+struct rose_neigh *rose_loopback_neigh;
 
 /*
  *     Add a new route to a node, and in the process add the node and the
@@ -78,8 +77,9 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route,
 
        rose_neigh = rose_neigh_list;
        while (rose_neigh != NULL) {
-               if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
-                   && rose_neigh->dev == dev)
+               if (ax25cmp(&rose_route->neighbour,
+                           &rose_neigh->callsign) == 0 &&
+                   rose_neigh->dev == dev)
                        break;
                rose_neigh = rose_neigh->next;
        }
@@ -235,6 +235,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
 
        if ((s = rose_neigh_list) == rose_neigh) {
                rose_neigh_list = rose_neigh->next;
+               if (rose_neigh->ax25)
+                       ax25_cb_put(rose_neigh->ax25);
                kfree(rose_neigh->digipeat);
                kfree(rose_neigh);
                return;
@@ -243,6 +245,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
        while (s != NULL && s->next != NULL) {
                if (s->next == rose_neigh) {
                        s->next = rose_neigh->next;
+                       if (rose_neigh->ax25)
+                               ax25_cb_put(rose_neigh->ax25);
                        kfree(rose_neigh->digipeat);
                        kfree(rose_neigh);
                        return;
@@ -312,8 +316,9 @@ static int rose_del_node(struct rose_route_struct *rose_route,
 
        rose_neigh = rose_neigh_list;
        while (rose_neigh != NULL) {
-               if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
-                   && rose_neigh->dev == dev)
+               if (ax25cmp(&rose_route->neighbour,
+                           &rose_neigh->callsign) == 0 &&
+                   rose_neigh->dev == dev)
                        break;
                rose_neigh = rose_neigh->next;
        }
@@ -363,7 +368,12 @@ out:
  */
 void rose_add_loopback_neigh(void)
 {
-       struct rose_neigh *sn = &rose_loopback_neigh;
+       struct rose_neigh *sn;
+
+       rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_KERNEL);
+       if (!rose_loopback_neigh)
+               return;
+       sn = rose_loopback_neigh;
 
        sn->callsign  = null_ax25_address;
        sn->digipeat  = NULL;
@@ -418,13 +428,13 @@ int rose_add_loopback_node(rose_address *address)
        rose_node->mask         = 10;
        rose_node->count        = 1;
        rose_node->loopback     = 1;
-       rose_node->neighbour[0] = &rose_loopback_neigh;
+       rose_node->neighbour[0] = rose_loopback_neigh;
 
        /* Insert at the head of list. Address is always mask=10 */
        rose_node->next = rose_node_list;
        rose_node_list  = rose_node;
 
-       rose_loopback_neigh.count++;
+       rose_loopback_neigh->count++;
 
 out:
        spin_unlock_bh(&rose_node_list_lock);
@@ -455,7 +465,7 @@ void rose_del_loopback_node(rose_address *address)
 
        rose_remove_node(rose_node);
 
-       rose_loopback_neigh.count--;
+       rose_loopback_neigh->count--;
 
 out:
        spin_unlock_bh(&rose_node_list_lock);
@@ -574,18 +584,18 @@ static int rose_clear_routes(void)
 
 /*
  *     Check that the device given is a valid AX.25 interface that is "up".
+ *     called whith RTNL
  */
-static struct net_device *rose_ax25_dev_get(char *devname)
+static struct net_device *rose_ax25_dev_find(char *devname)
 {
        struct net_device *dev;
 
-       if ((dev = dev_get_by_name(devname)) == NULL)
+       if ((dev = __dev_get_by_name(&init_net, devname)) == NULL)
                return NULL;
 
        if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25)
                return dev;
 
-       dev_put(dev);
        return NULL;
 }
 
@@ -596,13 +606,13 @@ struct net_device *rose_dev_first(void)
 {
        struct net_device *dev, *first = NULL;
 
-       read_lock(&dev_base_lock);
-       for (dev = dev_base; dev != NULL; dev = dev->next) {
+       rcu_read_lock();
+       for_each_netdev_rcu(&init_net, dev) {
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
                        if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
                                first = dev;
        }
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 
        return first;
 }
@@ -614,15 +624,16 @@ struct net_device *rose_dev_get(rose_address *addr)
 {
        struct net_device *dev;
 
-       read_lock(&dev_base_lock);
-       for (dev = dev_base; dev != NULL; dev = dev->next) {
+       rcu_read_lock();
+       for_each_netdev_rcu(&init_net, dev) {
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) {
                        dev_hold(dev);
                        goto out;
                }
        }
+       dev = NULL;
 out:
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
        return dev;
 }
 
@@ -630,13 +641,14 @@ static int rose_dev_exists(rose_address *addr)
 {
        struct net_device *dev;
 
-       read_lock(&dev_base_lock);
-       for (dev = dev_base; dev != NULL; dev = dev->next) {
+       rcu_read_lock();
+       for_each_netdev_rcu(&init_net, dev) {
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
                        goto out;
        }
+       dev = NULL;
 out:
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
        return dev != NULL;
 }
 
@@ -656,27 +668,34 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
 }
 
 /*
- *     Find a neighbour given a ROSE address.
+ *     Find a neighbour or a route given a ROSE address.
  */
 struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
-       unsigned char *diagnostic)
+       unsigned char *diagnostic, int new)
 {
        struct rose_neigh *res = NULL;
        struct rose_node *node;
        int failed = 0;
        int i;
 
-       spin_lock_bh(&rose_node_list_lock);
+       if (!new) spin_lock_bh(&rose_node_list_lock);
        for (node = rose_node_list; node != NULL; node = node->next) {
                if (rosecmpm(addr, &node->address, node->mask) == 0) {
                        for (i = 0; i < node->count; i++) {
-                               if (!rose_ftimer_running(node->neighbour[i])) {
-                                       res = node->neighbour[i];
-                                       goto out;
-                               } else
-                                       failed = 1;
+                               if (new) {
+                                       if (node->neighbour[i]->restarted) {
+                                               res = node->neighbour[i];
+                                               goto out;
+                                       }
+                               }
+                               else {
+                                       if (!rose_ftimer_running(node->neighbour[i])) {
+                                               res = node->neighbour[i];
+                                               goto out;
+                                       } else
+                                               failed = 1;
+                               }
                        }
-                       break;
                }
        }
 
@@ -689,7 +708,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
        }
 
 out:
-       spin_unlock_bh(&rose_node_list_lock);
+       if (!new) spin_unlock_bh(&rose_node_list_lock);
 
        return res;
 }
@@ -707,27 +726,23 @@ int rose_rt_ioctl(unsigned int cmd, void __user *arg)
        case SIOCADDRT:
                if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
                        return -EFAULT;
-               if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
+               if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL)
                        return -EINVAL;
-               if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */
-                       dev_put(dev);
+               if (rose_dev_exists(&rose_route.address)) /* Can't add routes to ourself */
                        return -EINVAL;
-               }
                if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
                        return -EINVAL;
                if (rose_route.ndigis > AX25_MAX_DIGIS)
                        return -EINVAL;
                err = rose_add_node(&rose_route, dev);
-               dev_put(dev);
                return err;
 
        case SIOCDELRT:
                if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
                        return -EFAULT;
-               if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
+               if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL)
                        return -EINVAL;
                err = rose_del_node(&rose_route, dev);
-               dev_put(dev);
                return err;
 
        case SIOCRSCLRRT:
@@ -801,6 +816,7 @@ void rose_link_failed(ax25_cb *ax25, int reason)
 
        if (rose_neigh != NULL) {
                rose_neigh->ax25 = NULL;
+               ax25_cb_put(ax25);
 
                rose_del_route_by_neigh(rose_neigh);
                rose_kill_by_neigh(rose_neigh);
@@ -851,7 +867,6 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        src_addr  = (rose_address *)(skb->data + 9);
        dest_addr = (rose_address *)(skb->data + 4);
 
-       spin_lock_bh(&rose_node_list_lock);
        spin_lock_bh(&rose_neigh_list_lock);
        spin_lock_bh(&rose_route_list_lock);
 
@@ -907,7 +922,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                        }
                }
                else {
-                       skb->h.raw = skb->data;
+                       skb_reset_transport_header(skb);
                        res = rose_process_rx_frame(sk, skb);
                        goto out;
                }
@@ -988,8 +1003,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                goto out;
        }
 
-       len  = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
-       len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
+       len  = (((skb->data[3] >> 4) & 0x0F) + 1) >> 1;
+       len += (((skb->data[3] >> 0) & 0x0F) + 1) >> 1;
 
        memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
 
@@ -1013,7 +1028,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
                rose_route = rose_route->next;
        }
 
-       if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
+       if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic, 1)) == NULL) {
                rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
                goto out;
        }
@@ -1054,7 +1069,6 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
 out:
        spin_unlock_bh(&rose_route_list_lock);
        spin_unlock_bh(&rose_neigh_list_lock);
-       spin_unlock_bh(&rose_node_list_lock);
 
        return res;
 }
@@ -1062,11 +1076,12 @@ out:
 #ifdef CONFIG_PROC_FS
 
 static void *rose_node_start(struct seq_file *seq, loff_t *pos)
+       __acquires(rose_node_list_lock)
 {
        struct rose_node *rose_node;
        int i = 1;
 
-       spin_lock_bh(&rose_neigh_list_lock);
+       spin_lock_bh(&rose_node_list_lock);
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
@@ -1085,12 +1100,14 @@ static void *rose_node_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void rose_node_stop(struct seq_file *seq, void *v)
+       __releases(rose_node_list_lock)
 {
-       spin_unlock_bh(&rose_neigh_list_lock);
+       spin_unlock_bh(&rose_node_list_lock);
 }
 
 static int rose_node_show(struct seq_file *seq, void *v)
 {
+       char rsbuf[11];
        int i;
 
        if (v == SEQ_START_TOKEN)
@@ -1099,13 +1116,13 @@ static int rose_node_show(struct seq_file *seq, void *v)
                const struct rose_node *rose_node = v;
                /* if (rose_node->loopback) {
                        seq_printf(seq, "%-10s %04d 1 loopback\n",
-                               rose2asc(&rose_node->address),
-                               rose_node->mask);
+                                  rose2asc(rsbuf, &rose_node->address),
+                                  rose_node->mask);
                } else { */
                        seq_printf(seq, "%-10s %04d %d",
-                               rose2asc(&rose_node->address),
-                               rose_node->mask,
-                               rose_node->count);
+                                  rose2asc(rsbuf, &rose_node->address),
+                                  rose_node->mask,
+                                  rose_node->count);
 
                        for (i = 0; i < rose_node->count; i++)
                                seq_printf(seq, " %05d",
@@ -1117,7 +1134,7 @@ static int rose_node_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations rose_node_seqops = {
+static const struct seq_operations rose_node_seqops = {
        .start = rose_node_start,
        .next = rose_node_next,
        .stop = rose_node_stop,
@@ -1129,7 +1146,7 @@ static int rose_nodes_open(struct inode *inode, struct file *file)
        return seq_open(file, &rose_node_seqops);
 }
 
-struct file_operations rose_nodes_fops = {
+const struct file_operations rose_nodes_fops = {
        .owner = THIS_MODULE,
        .open = rose_nodes_open,
        .read = seq_read,
@@ -1138,6 +1155,7 @@ struct file_operations rose_nodes_fops = {
 };
 
 static void *rose_neigh_start(struct seq_file *seq, loff_t *pos)
+       __acquires(rose_neigh_list_lock)
 {
        struct rose_neigh *rose_neigh;
        int i = 1;
@@ -1161,6 +1179,7 @@ static void *rose_neigh_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void rose_neigh_stop(struct seq_file *seq, void *v)
+       __releases(rose_neigh_list_lock)
 {
        spin_unlock_bh(&rose_neigh_list_lock);
 }
@@ -1199,7 +1218,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v)
 }
 
 
-static struct seq_operations rose_neigh_seqops = {
+static const struct seq_operations rose_neigh_seqops = {
        .start = rose_neigh_start,
        .next = rose_neigh_next,
        .stop = rose_neigh_stop,
@@ -1211,7 +1230,7 @@ static int rose_neigh_open(struct inode *inode, struct file *file)
        return seq_open(file, &rose_neigh_seqops);
 }
 
-struct file_operations rose_neigh_fops = {
+const struct file_operations rose_neigh_fops = {
        .owner = THIS_MODULE,
        .open = rose_neigh_open,
        .read = seq_read,
@@ -1221,6 +1240,7 @@ struct file_operations rose_neigh_fops = {
 
 
 static void *rose_route_start(struct seq_file *seq, loff_t *pos)
+       __acquires(rose_route_list_lock)
 {
        struct rose_route *rose_route;
        int i = 1;
@@ -1244,13 +1264,14 @@ static void *rose_route_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void rose_route_stop(struct seq_file *seq, void *v)
+       __releases(rose_route_list_lock)
 {
        spin_unlock_bh(&rose_route_list_lock);
 }
 
 static int rose_route_show(struct seq_file *seq, void *v)
 {
-       char buf[11];
+       char buf[11], rsbuf[11];
 
        if (v == SEQ_START_TOKEN)
                seq_puts(seq,
@@ -1262,7 +1283,7 @@ static int rose_route_show(struct seq_file *seq, void *v)
                        seq_printf(seq,
                                   "%3.3X  %-10s  %-9s  %05d      ",
                                   rose_route->lci1,
-                                  rose2asc(&rose_route->src_addr),
+                                  rose2asc(rsbuf, &rose_route->src_addr),
                                   ax2asc(buf, &rose_route->src_call),
                                   rose_route->neigh1->number);
                else
@@ -1272,10 +1293,10 @@ static int rose_route_show(struct seq_file *seq, void *v)
                if (rose_route->neigh2)
                        seq_printf(seq,
                                   "%3.3X  %-10s  %-9s  %05d\n",
-                               rose_route->lci2,
-                               rose2asc(&rose_route->dest_addr),
-                               ax2asc(buf, &rose_route->dest_call),
-                               rose_route->neigh2->number);
+                                  rose_route->lci2,
+                                  rose2asc(rsbuf, &rose_route->dest_addr),
+                                  ax2asc(buf, &rose_route->dest_call),
+                                  rose_route->neigh2->number);
                 else
                         seq_puts(seq,
                                  "000  *           *          00000\n");
@@ -1283,7 +1304,7 @@ static int rose_route_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations rose_route_seqops = {
+static const struct seq_operations rose_route_seqops = {
        .start = rose_route_start,
        .next = rose_route_next,
        .stop = rose_route_stop,
@@ -1295,7 +1316,7 @@ static int rose_route_open(struct inode *inode, struct file *file)
        return seq_open(file, &rose_route_seqops);
 }
 
-struct file_operations rose_routes_fops = {
+const struct file_operations rose_routes_fops = {
        .owner = THIS_MODULE,
        .open = rose_route_open,
        .read = seq_read,