aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/main.c
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-06-09 06:43:26 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-14 15:42:31 -0400
commit685429623f88d84f98bd5daffc3c427c408740d4 (patch)
treed50f119094dd3fb7668f837dbe50857d11bb4fa3 /net/mac80211/main.c
parent5ea096c0c85e80335889539899af9a4717976e0b (diff)
mac80211: Fix circular locking dependency in ARP filter handling
There is a circular locking dependency when configuring the hardware ARP filters on association, occurring when flushing the mac80211 workqueue. This is what happens: [ 92.026800] ======================================================= [ 92.030507] [ INFO: possible circular locking dependency detected ] [ 92.030507] 2.6.34-04781-g2b2c009 #85 [ 92.030507] ------------------------------------------------------- [ 92.030507] modprobe/5225 is trying to acquire lock: [ 92.030507] ((wiphy_name(local->hw.wiphy))){+.+.+.}, at: [<ffffffff8105b5c0>] flush_workq ueue+0x0/0xb0 [ 92.030507] [ 92.030507] but task is already holding lock: [ 92.030507] (rtnl_mutex){+.+.+.}, at: [<ffffffff812b9ce2>] rtnl_lock+0x12/0x20 [ 92.030507] [ 92.030507] which lock already depends on the new lock. [ 92.030507] [ 92.030507] [ 92.030507] the existing dependency chain (in reverse order) is: [ 92.030507] [ 92.030507] -> #2 (rtnl_mutex){+.+.+.}: [ 92.030507] [<ffffffff810761fb>] lock_acquire+0xdb/0x110 [ 92.030507] [<ffffffff81341754>] mutex_lock_nested+0x44/0x300 [ 92.030507] [<ffffffff812b9ce2>] rtnl_lock+0x12/0x20 [ 92.030507] [<ffffffffa022d47c>] ieee80211_assoc_done+0x6c/0xe0 [mac80211] [ 92.030507] [<ffffffffa022f2ad>] ieee80211_work_work+0x31d/0x1280 [mac80211] [ 92.030507] -> #1 ((&local->work_work)){+.+.+.}: [ 92.030507] [<ffffffff810761fb>] lock_acquire+0xdb/0x110 [ 92.030507] [<ffffffff8105a51a>] worker_thread+0x22a/0x370 [ 92.030507] [<ffffffff8105ecc6>] kthread+0x96/0xb0 [ 92.030507] [<ffffffff81003a94>] kernel_thread_helper+0x4/0x10 [ 92.030507] [ 92.030507] -> #0 ((wiphy_name(local->hw.wiphy))){+.+.+.}: [ 92.030507] [<ffffffff81075fdc>] __lock_acquire+0x1c0c/0x1d50 [ 92.030507] [<ffffffff810761fb>] lock_acquire+0xdb/0x110 [ 92.030507] [<ffffffff8105b60e>] flush_workqueue+0x4e/0xb0 [ 92.030507] [<ffffffffa023ff7b>] ieee80211_stop_device+0x2b/0xb0 [mac80211] [ 92.030507] [<ffffffffa0231635>] ieee80211_stop+0x3e5/0x680 [mac80211] The locking in this case is quite complex. Fix the problem by rewriting the way the hardware ARP filter list is handled - i.e. make a copy of the address list to the bss_conf struct, and provide that list to the hardware driver when needed. The current patch will enable filtering also in promiscuous mode. This may need to be changed in the future. Reported-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r--net/mac80211/main.c54
1 files changed, 34 insertions, 20 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index c2e46e88f3c9..a1bf46c64b93 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -20,6 +20,7 @@
20#include <linux/rtnetlink.h> 20#include <linux/rtnetlink.h>
21#include <linux/bitmap.h> 21#include <linux/bitmap.h>
22#include <linux/pm_qos_params.h> 22#include <linux/pm_qos_params.h>
23#include <linux/inetdevice.h>
23#include <net/net_namespace.h> 24#include <net/net_namespace.h>
24#include <net/cfg80211.h> 25#include <net/cfg80211.h>
25 26
@@ -317,23 +318,6 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
317} 318}
318 319
319#ifdef CONFIG_INET 320#ifdef CONFIG_INET
320int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata)
321{
322 struct in_device *idev;
323 int ret = 0;
324
325 BUG_ON(!sdata);
326 ASSERT_RTNL();
327
328 idev = sdata->dev->ip_ptr;
329 if (!idev)
330 return 0;
331
332 ret = drv_configure_arp_filter(sdata->local, &sdata->vif,
333 idev->ifa_list);
334 return ret;
335}
336
337static int ieee80211_ifa_changed(struct notifier_block *nb, 321static int ieee80211_ifa_changed(struct notifier_block *nb,
338 unsigned long data, void *arg) 322 unsigned long data, void *arg)
339{ 323{
@@ -343,8 +327,11 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
343 ifa_notifier); 327 ifa_notifier);
344 struct net_device *ndev = ifa->ifa_dev->dev; 328 struct net_device *ndev = ifa->ifa_dev->dev;
345 struct wireless_dev *wdev = ndev->ieee80211_ptr; 329 struct wireless_dev *wdev = ndev->ieee80211_ptr;
330 struct in_device *idev;
346 struct ieee80211_sub_if_data *sdata; 331 struct ieee80211_sub_if_data *sdata;
332 struct ieee80211_bss_conf *bss_conf;
347 struct ieee80211_if_managed *ifmgd; 333 struct ieee80211_if_managed *ifmgd;
334 int c = 0;
348 335
349 if (!netif_running(ndev)) 336 if (!netif_running(ndev))
350 return NOTIFY_DONE; 337 return NOTIFY_DONE;
@@ -356,17 +343,44 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
356 if (wdev->wiphy != local->hw.wiphy) 343 if (wdev->wiphy != local->hw.wiphy)
357 return NOTIFY_DONE; 344 return NOTIFY_DONE;
358 345
359 /* We are concerned about IP addresses only when associated */
360 sdata = IEEE80211_DEV_TO_SUB_IF(ndev); 346 sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
347 bss_conf = &sdata->vif.bss_conf;
361 348
362 /* ARP filtering is only supported in managed mode */ 349 /* ARP filtering is only supported in managed mode */
363 if (sdata->vif.type != NL80211_IFTYPE_STATION) 350 if (sdata->vif.type != NL80211_IFTYPE_STATION)
364 return NOTIFY_DONE; 351 return NOTIFY_DONE;
365 352
353 idev = sdata->dev->ip_ptr;
354 if (!idev)
355 return NOTIFY_DONE;
356
366 ifmgd = &sdata->u.mgd; 357 ifmgd = &sdata->u.mgd;
367 mutex_lock(&ifmgd->mtx); 358 mutex_lock(&ifmgd->mtx);
368 if (ifmgd->associated) 359
369 ieee80211_set_arp_filter(sdata); 360 /* Copy the addresses to the bss_conf list */
361 ifa = idev->ifa_list;
362 while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) {
363 bss_conf->arp_addr_list[c] = ifa->ifa_address;
364 ifa = ifa->ifa_next;
365 c++;
366 }
367
368 /* If not all addresses fit the list, disable filtering */
369 if (ifa) {
370 sdata->arp_filter_state = false;
371 c = 0;
372 } else {
373 sdata->arp_filter_state = true;
374 }
375 bss_conf->arp_addr_cnt = c;
376
377 /* Configure driver only if associated */
378 if (ifmgd->associated) {
379 bss_conf->arp_filter_enabled = sdata->arp_filter_state;
380 ieee80211_bss_info_change_notify(sdata,
381 BSS_CHANGED_ARP_FILTER);
382 }
383
370 mutex_unlock(&ifmgd->mtx); 384 mutex_unlock(&ifmgd->mtx);
371 385
372 return NOTIFY_DONE; 386 return NOTIFY_DONE;