aboutsummaryrefslogtreecommitdiffstats
path: root/include
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 /include
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 'include')
-rw-r--r--include/net/mac80211.h35
1 files changed, 21 insertions, 14 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index bbae3d9b117..3a47877f496 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -19,7 +19,6 @@
19#include <linux/wireless.h> 19#include <linux/wireless.h>
20#include <linux/device.h> 20#include <linux/device.h>
21#include <linux/ieee80211.h> 21#include <linux/ieee80211.h>
22#include <linux/inetdevice.h>
23#include <net/cfg80211.h> 22#include <net/cfg80211.h>
24 23
25/** 24/**
@@ -147,6 +146,7 @@ struct ieee80211_low_level_stats {
147 * enabled/disabled (beaconing modes) 146 * enabled/disabled (beaconing modes)
148 * @BSS_CHANGED_CQM: Connection quality monitor config changed 147 * @BSS_CHANGED_CQM: Connection quality monitor config changed
149 * @BSS_CHANGED_IBSS: IBSS join status changed 148 * @BSS_CHANGED_IBSS: IBSS join status changed
149 * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed.
150 */ 150 */
151enum ieee80211_bss_change { 151enum ieee80211_bss_change {
152 BSS_CHANGED_ASSOC = 1<<0, 152 BSS_CHANGED_ASSOC = 1<<0,
@@ -161,10 +161,18 @@ enum ieee80211_bss_change {
161 BSS_CHANGED_BEACON_ENABLED = 1<<9, 161 BSS_CHANGED_BEACON_ENABLED = 1<<9,
162 BSS_CHANGED_CQM = 1<<10, 162 BSS_CHANGED_CQM = 1<<10,
163 BSS_CHANGED_IBSS = 1<<11, 163 BSS_CHANGED_IBSS = 1<<11,
164 BSS_CHANGED_ARP_FILTER = 1<<12,
164 165
165 /* when adding here, make sure to change ieee80211_reconfig */ 166 /* when adding here, make sure to change ieee80211_reconfig */
166}; 167};
167 168
169/*
170 * The maximum number of IPv4 addresses listed for ARP filtering. If the number
171 * of addresses for an interface increase beyond this value, hardware ARP
172 * filtering will be disabled.
173 */
174#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
175
168/** 176/**
169 * struct ieee80211_bss_conf - holds the BSS's changing parameters 177 * struct ieee80211_bss_conf - holds the BSS's changing parameters
170 * 178 *
@@ -200,6 +208,15 @@ enum ieee80211_bss_change {
200 * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value 208 * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
201 * implies disabled 209 * implies disabled
202 * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis 210 * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
211 * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
212 * may filter ARP queries targeted for other addresses than listed here.
213 * The driver must allow ARP queries targeted for all address listed here
214 * to pass through. An empty list implies no ARP queries need to pass.
215 * @arp_addr_cnt: Number of addresses currently on the list.
216 * @arp_filter_enabled: Enable ARP filtering - if enabled, the hardware may
217 * filter ARP queries based on the @arp_addr_list, if disabled, the
218 * hardware must not perform any ARP filtering. Note, that the filter will
219 * be enabled also in promiscuous mode.
203 */ 220 */
204struct ieee80211_bss_conf { 221struct ieee80211_bss_conf {
205 const u8 *bssid; 222 const u8 *bssid;
@@ -220,6 +237,9 @@ struct ieee80211_bss_conf {
220 s32 cqm_rssi_thold; 237 s32 cqm_rssi_thold;
221 u32 cqm_rssi_hyst; 238 u32 cqm_rssi_hyst;
222 enum nl80211_channel_type channel_type; 239 enum nl80211_channel_type channel_type;
240 __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
241 u8 arp_addr_cnt;
242 bool arp_filter_enabled;
223}; 243};
224 244
225/** 245/**
@@ -1529,16 +1549,6 @@ enum ieee80211_ampdu_mlme_action {
1529 * of the bss parameters has changed when a call is made. The callback 1549 * of the bss parameters has changed when a call is made. The callback
1530 * can sleep. 1550 * can sleep.
1531 * 1551 *
1532 * @configure_arp_filter: Configuration function for hardware ARP query filter.
1533 * This function is called with all the IP addresses configured to the
1534 * interface as argument - all ARP queries targeted to any of these
1535 * addresses must pass through. If the hardware filter does not support
1536 * enought addresses, hardware filtering must be disabled. The ifa_list
1537 * argument may be NULL, indicating that filtering must be disabled.
1538 * This function is called upon association complete with current
1539 * address(es), and while associated whenever the IP address(es) change.
1540 * The callback can sleep.
1541 *
1542 * @prepare_multicast: Prepare for multicast filter configuration. 1552 * @prepare_multicast: Prepare for multicast filter configuration.
1543 * This callback is optional, and its return value is passed 1553 * This callback is optional, and its return value is passed
1544 * to configure_filter(). This callback must be atomic. 1554 * to configure_filter(). This callback must be atomic.
@@ -1678,9 +1688,6 @@ struct ieee80211_ops {
1678 struct ieee80211_vif *vif, 1688 struct ieee80211_vif *vif,
1679 struct ieee80211_bss_conf *info, 1689 struct ieee80211_bss_conf *info,
1680 u32 changed); 1690 u32 changed);
1681 int (*configure_arp_filter)(struct ieee80211_hw *hw,
1682 struct ieee80211_vif *vif,
1683 struct in_ifaddr *ifa_list);
1684 u64 (*prepare_multicast)(struct ieee80211_hw *hw, 1691 u64 (*prepare_multicast)(struct ieee80211_hw *hw,
1685 struct netdev_hw_addr_list *mc_list); 1692 struct netdev_hw_addr_list *mc_list);
1686 void (*configure_filter)(struct ieee80211_hw *hw, 1693 void (*configure_filter)(struct ieee80211_hw *hw,