diff options
Diffstat (limited to 'net/wireless/wext-core.c')
| -rw-r--r-- | net/wireless/wext-core.c | 52 |
1 files changed, 41 insertions, 11 deletions
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index c8717c1d082e..b50ee5d622e1 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c | |||
| @@ -342,6 +342,40 @@ static const int compat_event_type_size[] = { | |||
| 342 | 342 | ||
| 343 | /* IW event code */ | 343 | /* IW event code */ |
| 344 | 344 | ||
| 345 | void wireless_nlevent_flush(void) | ||
| 346 | { | ||
| 347 | struct sk_buff *skb; | ||
| 348 | struct net *net; | ||
| 349 | |||
| 350 | ASSERT_RTNL(); | ||
| 351 | |||
| 352 | for_each_net(net) { | ||
| 353 | while ((skb = skb_dequeue(&net->wext_nlevents))) | ||
| 354 | rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, | ||
| 355 | GFP_KERNEL); | ||
| 356 | } | ||
| 357 | } | ||
| 358 | EXPORT_SYMBOL_GPL(wireless_nlevent_flush); | ||
| 359 | |||
| 360 | static int wext_netdev_notifier_call(struct notifier_block *nb, | ||
| 361 | unsigned long state, void *ptr) | ||
| 362 | { | ||
| 363 | /* | ||
| 364 | * When a netdev changes state in any way, flush all pending messages | ||
| 365 | * to avoid them going out in a strange order, e.g. RTM_NEWLINK after | ||
| 366 | * RTM_DELLINK, or with IFF_UP after without IFF_UP during dev_close() | ||
| 367 | * or similar - all of which could otherwise happen due to delays from | ||
| 368 | * schedule_work(). | ||
| 369 | */ | ||
| 370 | wireless_nlevent_flush(); | ||
| 371 | |||
| 372 | return NOTIFY_OK; | ||
| 373 | } | ||
| 374 | |||
| 375 | static struct notifier_block wext_netdev_notifier = { | ||
| 376 | .notifier_call = wext_netdev_notifier_call, | ||
| 377 | }; | ||
| 378 | |||
| 345 | static int __net_init wext_pernet_init(struct net *net) | 379 | static int __net_init wext_pernet_init(struct net *net) |
| 346 | { | 380 | { |
| 347 | skb_queue_head_init(&net->wext_nlevents); | 381 | skb_queue_head_init(&net->wext_nlevents); |
| @@ -360,7 +394,12 @@ static struct pernet_operations wext_pernet_ops = { | |||
| 360 | 394 | ||
| 361 | static int __init wireless_nlevent_init(void) | 395 | static int __init wireless_nlevent_init(void) |
| 362 | { | 396 | { |
| 363 | return register_pernet_subsys(&wext_pernet_ops); | 397 | int err = register_pernet_subsys(&wext_pernet_ops); |
| 398 | |||
| 399 | if (err) | ||
| 400 | return err; | ||
| 401 | |||
| 402 | return register_netdevice_notifier(&wext_netdev_notifier); | ||
| 364 | } | 403 | } |
| 365 | 404 | ||
| 366 | subsys_initcall(wireless_nlevent_init); | 405 | subsys_initcall(wireless_nlevent_init); |
| @@ -368,17 +407,8 @@ subsys_initcall(wireless_nlevent_init); | |||
| 368 | /* Process events generated by the wireless layer or the driver. */ | 407 | /* Process events generated by the wireless layer or the driver. */ |
| 369 | static void wireless_nlevent_process(struct work_struct *work) | 408 | static void wireless_nlevent_process(struct work_struct *work) |
| 370 | { | 409 | { |
| 371 | struct sk_buff *skb; | ||
| 372 | struct net *net; | ||
| 373 | |||
| 374 | rtnl_lock(); | 410 | rtnl_lock(); |
| 375 | 411 | wireless_nlevent_flush(); | |
| 376 | for_each_net(net) { | ||
| 377 | while ((skb = skb_dequeue(&net->wext_nlevents))) | ||
| 378 | rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, | ||
| 379 | GFP_KERNEL); | ||
| 380 | } | ||
| 381 | |||
| 382 | rtnl_unlock(); | 412 | rtnl_unlock(); |
| 383 | } | 413 | } |
| 384 | 414 | ||
