#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";
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 *)(¬ifier))
+static struct sock gw_dummy_sk;
/* structure that contains the (on-the-fly) CAN frame modifications */
struct cf_mod {
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)) {
}
/* 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 */
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) {
kfree(gwj);
}
}
-
- spin_unlock(&cgw_list_lock);
}
return NOTIFY_DONE;
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:
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)
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) {
break;
}
- spin_unlock(&cgw_list_lock);
-
return err;
}
notifier.notifier_call = cgw_notifier;
register_netdevice_notifier(¬ifier);
+#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(¬ifier);
kmem_cache_destroy(cgw_cache);
unregister_netdevice_notifier(¬ifier);
+ rtnl_lock();
cgw_remove_all_jobs();
+ rtnl_unlock();
rcu_barrier(); /* Wait for completion of call_rcu()'s */