linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / net / atm / clip.c
index 8db42d4..b10474d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/atmdev.h>
 #include <linux/atmclip.h>
 #include <linux/atmarp.h>
+#include <linux/capability.h>
 #include <linux/ip.h> /* for net/route.h */
 #include <linux/in.h> /* for struct sockaddr_in */
 #include <linux/if.h> /* for IFF_UP */
@@ -58,6 +59,7 @@ static int start_timer = 1;
 
 static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip)
 {
+       struct sock *sk;
        struct atmarp_ctrl *ctrl;
        struct sk_buff *skb;
 
@@ -70,8 +72,10 @@ static int to_atmarpd(enum atmarp_ctrl_type type,int itf,unsigned long ip)
        ctrl->itf_num = itf;
        ctrl->ip = ip;
        atm_force_charge(atmarpd,skb->truesize);
-       skb_queue_tail(&atmarpd->sk->sk_receive_queue, skb);
-       atmarpd->sk->sk_data_ready(atmarpd->sk, skb->len);
+
+       sk = sk_atm(atmarpd);
+       skb_queue_tail(&sk->sk_receive_queue, skb);
+       sk->sk_data_ready(sk, skb->len);
        return 0;
 }
 
@@ -307,7 +311,7 @@ static int clip_constructor(struct neighbour *neigh)
        if (neigh->type != RTN_UNICAST) return -EINVAL;
 
        rcu_read_lock();
-       in_dev = rcu_dereference(__in_dev_get(dev));
+       in_dev = __in_dev_get_rcu(dev);
        if (!in_dev) {
                rcu_read_unlock();
                return -EINVAL;
@@ -434,7 +438,7 @@ static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev)
                memcpy(here,llc_oui,sizeof(llc_oui));
                ((u16 *) here)[3] = skb->protocol;
        }
-       atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc);
+       atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
        ATM_SKB(skb)->atm_options = vcc->atm_options;
        entry->vccs->last_use = jiffies;
        DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev);
@@ -493,7 +497,7 @@ static int clip_mkip(struct atm_vcc *vcc,int timeout)
        vcc->push = clip_push;
        vcc->pop = clip_pop;
        skb_queue_head_init(&copy);
-       skb_migrate(&vcc->sk->sk_receive_queue, &copy);
+       skb_migrate(&sk_atm(vcc)->sk_receive_queue, &copy);
        /* re-process everything received between connection setup and MKIP */
        while ((skb = skb_dequeue(&copy)) != NULL)
                if (!clip_devs) {
@@ -503,9 +507,11 @@ static int clip_mkip(struct atm_vcc *vcc,int timeout)
                else {
                        unsigned int len = skb->len;
 
+                       skb_get(skb);
                        clip_push(vcc,skb);
                        PRIV(skb->dev)->stats.rx_packets--;
                        PRIV(skb->dev)->stats.rx_bytes -= len;
+                       kfree_skb(skb);
                }
        return 0;
 }
@@ -609,12 +615,19 @@ static int clip_create(int number)
 
 
 static int clip_device_event(struct notifier_block *this,unsigned long event,
-    void *dev)
+                            void *arg)
 {
+       struct net_device *dev = arg;
+
+       if (event == NETDEV_UNREGISTER) {
+               neigh_ifdown(&clip_tbl, dev);
+               return NOTIFY_DONE;
+       }
+
        /* ignore non-CLIP devices */
-       if (((struct net_device *) dev)->type != ARPHRD_ATM ||
-           ((struct net_device *) dev)->hard_start_xmit != clip_start_xmit)
+       if (dev->type != ARPHRD_ATM || dev->hard_start_xmit != clip_start_xmit)
                return NOTIFY_DONE;
+
        switch (event) {
                case NETDEV_UP:
                        DPRINTK("clip_device_event NETDEV_UP\n");
@@ -682,14 +695,12 @@ static struct notifier_block clip_inet_notifier = {
 static void atmarpd_close(struct atm_vcc *vcc)
 {
        DPRINTK("atmarpd_close\n");
-       atmarpd = NULL; /* assumed to be atomic */
-       barrier();
-       unregister_inetaddr_notifier(&clip_inet_notifier);
-       unregister_netdevice_notifier(&clip_dev_notifier);
-       if (skb_peek(&vcc->sk->sk_receive_queue))
-               printk(KERN_ERR "atmarpd_close: closing with requests "
-                   "pending\n");
-       skb_queue_purge(&vcc->sk->sk_receive_queue);
+
+       rtnl_lock();
+       atmarpd = NULL;
+       skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
+       rtnl_unlock();
+
        DPRINTK("(done)\n");
        module_put(THIS_MODULE);
 }
@@ -710,7 +721,12 @@ static struct atm_dev atmarpd_dev = {
 
 static int atm_init_atmarp(struct atm_vcc *vcc)
 {
-       if (atmarpd) return -EADDRINUSE;
+       rtnl_lock();
+       if (atmarpd) {
+               rtnl_unlock();
+               return -EADDRINUSE;
+       }
+
        if (start_timer) {
                start_timer = 0;
                init_timer(&idle_timer);
@@ -723,14 +739,11 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
        set_bit(ATM_VF_READY,&vcc->flags);
            /* allow replies and avoid getting closed if signaling dies */
        vcc->dev = &atmarpd_dev;
-       vcc_insert_socket(vcc->sk);
+       vcc_insert_socket(sk_atm(vcc));
        vcc->push = NULL;
        vcc->pop = NULL; /* crash */
        vcc->push_oam = NULL; /* crash */
-       if (register_netdevice_notifier(&clip_dev_notifier))
-               printk(KERN_ERR "register_netdevice_notifier failed\n");
-       if (register_inetaddr_notifier(&clip_inet_notifier))
-               printk(KERN_ERR "register_inetaddr_notifier failed\n");
+       rtnl_unlock();
        return 0;
 }
 
@@ -822,7 +835,7 @@ static void atmarp_info(struct seq_file *seq, struct net_device *dev,
        int svc, llc, off;
 
        svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
-              (clip_vcc->vcc->sk->sk_family == AF_ATMSVC));
+              (sk_atm(clip_vcc->vcc)->sk_family == AF_ATMSVC));
 
        llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
               clip_vcc->encap);
@@ -988,6 +1001,8 @@ static int __init atm_clip_init(void)
 
        clip_tbl_hook = &clip_tbl;
        register_atm_ioctl(&clip_ioctl_ops);
+       register_netdevice_notifier(&clip_dev_notifier);
+       register_inetaddr_notifier(&clip_inet_notifier);
 
 #ifdef CONFIG_PROC_FS
 {
@@ -1008,6 +1023,9 @@ static void __exit atm_clip_exit(void)
 
        remove_proc_entry("arp", atm_proc_root);
 
+       unregister_inetaddr_notifier(&clip_inet_notifier);
+       unregister_netdevice_notifier(&clip_dev_notifier);
+
        deregister_atm_ioctl(&clip_ioctl_ops);
 
        /* First, stop the idle timer, so it stops banging