]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/net/can/gw.c
skb->sk is used in dev_pick_tx() which is called from dev_queue_xmit(). If
[socketcan-devel.git] / kernel / 2.6 / net / can / gw.c
index 74d51f5cb5e1f88b4700b9984d3a9eb979d51aae..e451b090288e2ba1f8d575ddd605e1b278a791a8 100644 (file)
 #include <socketcan/can/gw.h>
 #include <net/rtnetlink.h>
 #include <net/net_namespace.h>
+#include <net/sock.h>
 
 #include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
-#define CAN_GW_VERSION "20100412"
+#define CAN_GW_VERSION "20101205"
 static __initdata const char banner[] =
        KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n";
 
@@ -72,12 +73,11 @@ MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
 MODULE_ALIAS("can-gw");
 
 HLIST_HEAD(cgw_list);
-static DEFINE_SPINLOCK(cgw_list_lock);
 static struct notifier_block notifier;
 
 static struct kmem_cache *cgw_cache __read_mostly;
 
-#define CGW_SK_MAGIC ((void *)(&notifier))
+static struct sock gw_dummy_sk;
 
 /* structure that contains the (on-the-fly) CAN frame modifications */
 struct cf_mod {
@@ -347,7 +347,7 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
        int modidx = 0;
 
        /* do not handle already routed frames */
-       if (skb->sk == CGW_SK_MAGIC)
+       if (skb->sk == &gw_dummy_sk)
                return;
 
        if (!(gwj->dst.dev->flags & IFF_UP)) {
@@ -372,7 +372,7 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
        }
 
        /* mark routed frames with a 'special' sk value */
-       nskb->sk = CGW_SK_MAGIC;
+       nskb->sk = &gw_dummy_sk;
        nskb->dev = gwj->dst.dev;
 
        /* pointer to modifiable CAN frame */
@@ -435,7 +435,7 @@ static int cgw_notifier(struct notifier_block *nb,
                struct cgw_job *gwj = NULL;
                struct hlist_node *n, *nx;
 
-               spin_lock(&cgw_list_lock);
+               ASSERT_RTNL();
 
                hlist_for_each_entry_safe(gwj, n, nx, &cgw_list, list) {
 
@@ -445,8 +445,6 @@ static int cgw_notifier(struct notifier_block *nb,
                                kfree(gwj);
                        }
                }
-
-               spin_unlock(&cgw_list_lock);
        }
 
        return NOTIFY_DONE;
@@ -829,14 +827,12 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh,
        if (gwj->dst.dev->type != ARPHRD_CAN)
                goto put_src_dst_out;
                
-       spin_lock(&cgw_list_lock);
+       ASSERT_RTNL();
 
        err = cgw_register_filter(gwj);
        if (!err)
                hlist_add_head_rcu(&gwj->list, &cgw_list);
 
-       spin_unlock(&cgw_list_lock);
-       
 put_src_dst_out:
        dev_put(gwj->dst.dev);
 put_src_out:
@@ -853,15 +849,13 @@ static void cgw_remove_all_jobs(void)
        struct cgw_job *gwj = NULL;
        struct hlist_node *n, *nx;
 
-       spin_lock(&cgw_list_lock);
+       ASSERT_RTNL();
 
        hlist_for_each_entry_safe(gwj, n, nx, &cgw_list, list) {
                hlist_del(&gwj->list);
                cgw_unregister_filter(gwj);
                kfree(gwj);
        }
-
-       spin_unlock(&cgw_list_lock);
 }
 
 static int cgw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
@@ -896,7 +890,7 @@ static int cgw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
 
        err = -EINVAL;
 
-       spin_lock(&cgw_list_lock);
+       ASSERT_RTNL();
 
        /* remove only the first matching entry */
        hlist_for_each_entry_safe(gwj, n, nx, &cgw_list, list) {
@@ -918,8 +912,6 @@ static int cgw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
                break;
        }
 
-       spin_unlock(&cgw_list_lock);
-       
        return err;
 }
 
@@ -937,6 +929,11 @@ static __init int cgw_module_init(void)
        notifier.notifier_call = cgw_notifier;
        register_netdevice_notifier(&notifier);
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)
+       /* initialize struct for dev_pick_tx() */
+       sk_tx_queue_clear(&gw_dummy_sk);
+#endif
+
        if (__rtnl_register(PF_CAN, RTM_GETROUTE, NULL, cgw_dump_jobs)) {
                unregister_netdevice_notifier(&notifier);
                kmem_cache_destroy(cgw_cache);
@@ -956,7 +953,9 @@ static __exit void cgw_module_exit(void)
 
        unregister_netdevice_notifier(&notifier);
 
+       rtnl_lock();
        cgw_remove_all_jobs();
+       rtnl_unlock();
 
        rcu_barrier(); /* Wait for completion of call_rcu()'s */