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: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
97fd5bc7f2
commit
b333b3d228
@ -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,
|
|||||||
}
|
}
|
||||||
#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;
|
||||||
|
|
||||||
while ((skb = skb_dequeue(&wireless_nlevent_queue)))
|
rtnl_lock();
|
||||||
rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
|
|
||||||
|
for_each_net(net) {
|
||||||
|
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------- */
|
/* ---------------------------------------------------------------- */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user