Merge branch 'master' into 83xx
[pandora-kernel.git] / net / rose / af_rose.c
index 55564ef..8c34f1c 100644 (file)
@@ -10,7 +10,6 @@
  * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
  */
 
-#include <linux/config.h>
 #include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -67,6 +66,14 @@ static struct proto_ops rose_proto_ops;
 
 ax25_address rose_callsign;
 
+/*
+ * ROSE network devices are virtual network devices encapsulating ROSE
+ * frames into AX.25 which will be sent through an AX.25 device, so form a
+ * special "super class" of normal net devices; split their locks off into a
+ * separate class since they always nest.
+ */
+static struct lock_class_key rose_netdev_xmit_lock_key;
+
 /*
  *     Convert a ROSE address into text.
  */
@@ -753,7 +760,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
 
                rose_insert_socket(sk);         /* Finish the bind */
        }
-
+rose_try_next_neigh:
        rose->dest_addr   = addr->srose_addr;
        rose->dest_call   = addr->srose_call;
        rose->rand        = ((long)rose & 0xFFFF) + rose->lci;
@@ -811,6 +818,11 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        }
 
        if (sk->sk_state != TCP_ESTABLISHED) {
+       /* Try next neighbour */
+               rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic);
+               if (rose->neighbour)
+                       goto rose_try_next_neigh;
+       /* No more neighbour */
                sock->state = SS_UNCONNECTED;
                return sock_error(sk);  /* Always set at this point */
        }
@@ -1302,7 +1314,8 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                if (copy_from_user(&rose_callsign, argp, sizeof(ax25_address)))
                        return -EFAULT;
                if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
-                       ax25_listen_register(&rose_callsign, NULL);
+                       return ax25_listen_register(&rose_callsign, NULL);
+
                return 0;
 
        case SIOCRSGL2CALL:
@@ -1338,7 +1351,7 @@ static void *rose_info_start(struct seq_file *seq, loff_t *pos)
        spin_lock_bh(&rose_list_lock);
        if (*pos == 0)
                return SEQ_START_TOKEN;
-       
+
        i = 1;
        sk_for_each(s, node, &rose_list) {
                if (i == *pos)
@@ -1352,10 +1365,10 @@ static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        ++*pos;
 
-       return (v == SEQ_START_TOKEN) ? sk_head(&rose_list) 
+       return (v == SEQ_START_TOKEN) ? sk_head(&rose_list)
                : sk_next((struct sock *)v);
 }
-       
+
 static void rose_info_stop(struct seq_file *seq, void *v)
 {
        spin_unlock_bh(&rose_list_lock);
@@ -1366,7 +1379,7 @@ static int rose_info_show(struct seq_file *seq, void *v)
        char buf[11];
 
        if (v == SEQ_START_TOKEN)
-               seq_puts(seq, 
+               seq_puts(seq,
                         "dest_addr  dest_call src_addr   src_call  dev   lci neigh st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");
 
        else {
@@ -1379,7 +1392,7 @@ static int rose_info_show(struct seq_file *seq, void *v)
                        devname = "???";
                else
                        devname = dev->name;
-               
+
                seq_printf(seq, "%-10s %-9s ",
                        rose2asc(&rose->dest_addr),
                        ax2asc(buf, &rose->dest_call));
@@ -1427,7 +1440,7 @@ static int rose_info_open(struct inode *inode, struct file *file)
        return seq_open(file, &rose_info_seqops);
 }
 
-static struct file_operations rose_info_fops = {
+static const struct file_operations rose_info_fops = {
        .owner = THIS_MODULE,
        .open = rose_info_open,
        .read = seq_read,
@@ -1469,6 +1482,15 @@ static struct notifier_block rose_dev_notifier = {
 
 static struct net_device **dev_rose;
 
+static struct ax25_protocol rose_pid = {
+       .pid    = AX25_P_ROSE,
+       .func   = rose_route_frame
+};
+
+static struct ax25_linkfail rose_linkfail_notifier = {
+       .func   = rose_link_failed
+};
+
 static int __init rose_proto_init(void)
 {
        int i;
@@ -1486,20 +1508,19 @@ static int __init rose_proto_init(void)
 
        rose_callsign = null_ax25_address;
 
-       dev_rose = kmalloc(rose_ndevs * sizeof(struct net_device *), GFP_KERNEL);
+       dev_rose = kzalloc(rose_ndevs * sizeof(struct net_device *), GFP_KERNEL);
        if (dev_rose == NULL) {
                printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n");
                rc = -ENOMEM;
                goto out_proto_unregister;
        }
 
-       memset(dev_rose, 0x00, rose_ndevs * sizeof(struct net_device*));
        for (i = 0; i < rose_ndevs; i++) {
                struct net_device *dev;
                char name[IFNAMSIZ];
 
                sprintf(name, "rose%d", i);
-               dev = alloc_netdev(sizeof(struct net_device_stats), 
+               dev = alloc_netdev(sizeof(struct net_device_stats),
                                   name, rose_setup);
                if (!dev) {
                        printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n");
@@ -1512,14 +1533,15 @@ static int __init rose_proto_init(void)
                        free_netdev(dev);
                        goto fail;
                }
+               lockdep_set_class(&dev->_xmit_lock, &rose_netdev_xmit_lock_key);
                dev_rose[i] = dev;
        }
 
        sock_register(&rose_family_ops);
        register_netdevice_notifier(&rose_dev_notifier);
 
-       ax25_protocol_register(AX25_P_ROSE, rose_route_frame);
-       ax25_linkfail_register(rose_link_failed);
+       ax25_register_pid(&rose_pid);
+       ax25_linkfail_register(&rose_linkfail_notifier);
 
 #ifdef CONFIG_SYSCTL
        rose_register_sysctl();
@@ -1567,7 +1589,7 @@ static void __exit rose_exit(void)
        rose_rt_free();
 
        ax25_protocol_release(AX25_P_ROSE);
-       ax25_linkfail_release(rose_link_failed);
+       ax25_linkfail_release(&rose_linkfail_notifier);
 
        if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
                ax25_listen_release(&rose_callsign, NULL);