Commit b333b3d2 authored by Johannes Berg's avatar Johannes Berg Committed by David S. Miller

wireless extensions: make netns aware

This makes wireless extensions netns aware. The
tasklet sending the events is converted to a work
struct so that we can rtnl_lock() in it.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 97fd5bc7
...@@ -79,6 +79,9 @@ struct net { ...@@ -79,6 +79,9 @@ struct net {
#endif #endif
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
struct netns_xfrm xfrm; struct netns_xfrm xfrm;
#endif
#ifdef CONFIG_WIRELESS_EXT
struct sk_buff_head wext_nlevents;
#endif #endif
struct net_generic *gen; struct net_generic *gen;
}; };
......
...@@ -1257,48 +1257,48 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, ...@@ -1257,48 +1257,48 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
} }
#endif #endif
/************************* EVENT PROCESSING *************************/ static int __net_init wext_pernet_init(struct net *net)
/* {
* Process events generated by the wireless layer or the driver. skb_queue_head_init(&net->wext_nlevents);
* Most often, the event will be propagated through rtnetlink return 0;
*/ }
/* ---------------------------------------------------------------- */ static void __net_exit wext_pernet_exit(struct net *net)
/* {
* Locking... skb_queue_purge(&net->wext_nlevents);
* ---------- }
*
* Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
* the locking issue in here and implementing this code !
*
* The issue : wireless_send_event() is often called in interrupt context,
* while the Netlink layer can never be called in interrupt context.
* The fully formed RtNetlink events are queued, and then a tasklet is run
* to feed those to Netlink.
* The skb_queue is interrupt safe, and its lock is not held while calling
* Netlink, so there is no possibility of dealock.
* Jean II
*/
static struct sk_buff_head wireless_nlevent_queue; static struct pernet_operations wext_pernet_ops = {
.init = wext_pernet_init,
.exit = wext_pernet_exit,
};
static int __init wireless_nlevent_init(void) static int __init wireless_nlevent_init(void)
{ {
skb_queue_head_init(&wireless_nlevent_queue); return register_pernet_subsys(&wext_pernet_ops);
return 0; return 0;
} }
subsys_initcall(wireless_nlevent_init); subsys_initcall(wireless_nlevent_init);
static void wireless_nlevent_process(unsigned long data) /* Process events generated by the wireless layer or the driver. */
static void wireless_nlevent_process(struct work_struct *work)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct net *net;
rtnl_lock();
while ((skb = skb_dequeue(&wireless_nlevent_queue))) for_each_net(net) {
rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); while ((skb = skb_dequeue(&net->wext_nlevents)))
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
GFP_KERNEL);
}
rtnl_unlock();
} }
static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
/* /*
...@@ -1348,9 +1348,6 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) ...@@ -1348,9 +1348,6 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
if (!net_eq(dev_net(dev), &init_net))
return;
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!skb) if (!skb)
return; return;
...@@ -1363,8 +1360,8 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) ...@@ -1363,8 +1360,8 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
} }
NETLINK_CB(skb).dst_group = RTNLGRP_LINK; NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
skb_queue_tail(&wireless_nlevent_queue, skb); skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
tasklet_schedule(&wireless_nlevent_tasklet); schedule_work(&wireless_nlevent_work);
} }
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment