fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / hamradio / bpqether.c
index 803d5a1..5b788d8 100644 (file)
@@ -54,7 +54,6 @@
  *     BPQ   004       Joerg(DL1BKE)           Fixed to not lock up on ifconfig.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 
 static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n";
 
-static unsigned char ax25_bcast[AX25_ADDR_LEN] =
-       {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
-static unsigned char ax25_defaddr[AX25_ADDR_LEN] =
-       {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
-
 static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
 
 static char bpq_eth_addr[6];
 
-static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
+static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 static int bpq_device_event(struct notifier_block *, unsigned long, void *);
 static const char *bpq_print_ethaddr(const unsigned char *);
 
@@ -112,8 +106,6 @@ static struct notifier_block bpq_dev_notifier = {
 };
 
 
-#define MAXBPQDEV 100
-
 struct bpqdev {
        struct list_head bpq_list;      /* list of bpq devices chain */
        struct net_device *ethdev;      /* link to ethernet device */
@@ -125,6 +117,12 @@ struct bpqdev {
 
 static LIST_HEAD(bpq_devices);
 
+/*
+ * bpqether network devices are paired with ethernet devices below them, so
+ * form a special "super class" of normal ethernet devices; split their locks
+ * off into a separate class since they always nest.
+ */
+static struct lock_class_key bpq_netdev_xmit_lock_key;
 
 /* ------------------------------------------------------------------------ */
 
@@ -134,7 +132,7 @@ static LIST_HEAD(bpq_devices);
  */
 static inline struct net_device *bpq_get_ether_dev(struct net_device *dev)
 {
-       struct bpqdev *bpq = (struct bpqdev *) dev->priv;
+       struct bpqdev *bpq = netdev_priv(dev);
 
        return bpq ? bpq->ethdev : NULL;
 }
@@ -146,7 +144,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev)
 {
        struct bpqdev *bpq;
 
-       list_for_each_entry(bpq, &bpq_devices, bpq_list) {
+       list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) {
                if (bpq->ethdev == dev)
                        return bpq->axdev;
        }
@@ -167,7 +165,7 @@ static inline int dev_is_ethdev(struct net_device *dev)
 /*
  *     Receive an AX.25 frame via an ethernet interface.
  */
-static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
+static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
 {
        int len;
        char * ptr;
@@ -191,7 +189,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty
         * we check the source address of the sender.
         */
 
-       bpq = (struct bpqdev *)dev->priv;
+       bpq = netdev_priv(dev);
 
        eth = eth_hdr(skb);
 
@@ -213,11 +211,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty
        ptr = skb_push(skb, 1);
        *ptr = 0;
 
-       skb->dev = dev;
-       skb->protocol = htons(ETH_P_AX25);
-       skb->mac.raw = skb->data;
-       skb->pkt_type = PACKET_HOST;
-
+       skb->protocol = ax25_type_trans(skb, dev);
        netif_rx(skb);
        dev->last_rx = jiffies;
 unlock:
@@ -274,14 +268,12 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
                skb = newskb;
        }
 
-       skb->protocol = htons(ETH_P_AX25);
-
        ptr = skb_push(skb, 2);
 
        *ptr++ = (size + 5) % 256;
        *ptr++ = (size + 5) / 256;
 
-       bpq = (struct bpqdev *)dev->priv;
+       bpq = netdev_priv(dev);
 
        if ((dev = bpq_get_ether_dev(dev)) == NULL) {
                bpq->stats.tx_dropped++;
@@ -289,7 +281,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
                return -ENODEV;
        }
 
-       skb->dev = dev;
+       skb->protocol = ax25_type_trans(skb, dev);
        skb->nh.raw = skb->data;
        dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
        bpq->stats.tx_packets++;
@@ -305,7 +297,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
  */
 static struct net_device_stats *bpq_get_stats(struct net_device *dev)
 {
-       struct bpqdev *bpq = (struct bpqdev *) dev->priv;
+       struct bpqdev *bpq = netdev_priv(dev);
 
        return &bpq->stats;
 }
@@ -332,15 +324,12 @@ static int bpq_set_mac_address(struct net_device *dev, void *addr)
 static int bpq_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct bpq_ethaddr __user *ethaddr = ifr->ifr_data;
-       struct bpqdev *bpq = dev->priv;
+       struct bpqdev *bpq = netdev_priv(dev);
        struct bpq_req req;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       if (bpq == NULL)                /* woops! */
-               return -ENODEV;
-
        switch (cmd) {
                case SIOCSBPQETHOPT:
                        if (copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req)))
@@ -410,7 +399,7 @@ static void *bpq_seq_start(struct seq_file *seq, loff_t *pos)
        if (*pos == 0)
                return SEQ_START_TOKEN;
        
-       list_for_each_entry(bpqdev, &bpq_devices, bpq_list) {
+       list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) {
                if (i == *pos)
                        return bpqdev;
        }
@@ -429,7 +418,7 @@ static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                p = ((struct bpqdev *)v)->bpq_list.next;
 
        return (p == &bpq_devices) ? NULL 
-               : list_entry(p, struct bpqdev, bpq_list);
+               : rcu_dereference(list_entry(p, struct bpqdev, bpq_list));
 }
 
 static void bpq_seq_stop(struct seq_file *seq, void *v)
@@ -493,13 +482,13 @@ static void bpq_setup(struct net_device *dev)
        dev->do_ioctl        = bpq_ioctl;
        dev->destructor      = free_netdev;
 
-       memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
-       memcpy(dev->dev_addr,  ax25_defaddr, AX25_ADDR_LEN);
+       memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+       memcpy(dev->dev_addr,  &ax25_defaddr, AX25_ADDR_LEN);
 
        dev->flags      = 0;
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header     = ax25_encapsulate;
+       dev->hard_header     = ax25_hard_header;
        dev->rebuild_header  = ax25_rebuild_header;
 #endif
 
@@ -525,7 +514,7 @@ static int bpq_new_device(struct net_device *edev)
                return -ENOMEM;
 
                
-       bpq = ndev->priv;
+       bpq = netdev_priv(ndev);
        dev_hold(edev);
        bpq->ethdev = edev;
        bpq->axdev = ndev;
@@ -540,6 +529,7 @@ static int bpq_new_device(struct net_device *edev)
        err = register_netdevice(ndev);
        if (err)
                goto error;
+       lockdep_set_class(&ndev->_xmit_lock, &bpq_netdev_xmit_lock_key);
 
        /* List protected by RTNL */
        list_add_rcu(&bpq->bpq_list, &bpq_devices);
@@ -554,7 +544,7 @@ static int bpq_new_device(struct net_device *edev)
 
 static void bpq_free_device(struct net_device *ndev)
 {
-       struct bpqdev *bpq = ndev->priv;
+       struct bpqdev *bpq = netdev_priv(ndev);
 
        dev_put(bpq->ethdev);
        list_del_rcu(&bpq->bpq_list);
@@ -572,8 +562,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
        if (!dev_is_ethdev(dev))
                return NOTIFY_DONE;
 
-       rcu_read_lock();
-
        switch (event) {
        case NETDEV_UP:         /* new ethernet device -> new BPQ interface */
                if (bpq_get_ax25_dev(dev) == NULL)
@@ -592,7 +580,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
        default:
                break;
        }
-       rcu_read_unlock();
 
        return NOTIFY_DONE;
 }