* Re: [PATCH v3 1/3] cfg80211: Add nl80211 antenna configuration
From: Bruno Randolf @ 2010-06-08 1:10 UTC (permalink / raw)
To: Johannes Berg; +Cc: linville, linux-wireless
In-Reply-To: <1275901514.3639.4.camel@jlt3.sipsolutions.net>
On Monday 07 June 2010 18:05:14 you wrote:
> On Mon, 2010-06-07 at 15:58 +0900, Bruno Randolf wrote:
> > + * @NL80211_CMD_GET_ANTENNA: Get antenna configuration from driver.
>
> Since we already have runtime configuration and capability information
> as part of the wiphy information printout, remind me again what was
> wrong with adding antenna information there as well rather than having a
> separate command to retrieve it?
>
> As far as differentiating that information is concerned, you can easily
> implement an iw "get antenna" command by just partially printing the
> wiphy information, for example, no?
i don't particularly care about where the antenna information is printed
exactly, so anything will be fine with me.
but when i look at the wiphy info, it shows mostly capability information,
like the list of supported frequencies, list of bitrates, supported interface
modes, supported commands. the only exception is coverage class, which is the
only runtime configuration as far as i can see. therefore i thought it doesnt
fit there well.
maybe another command for getting runtime configuration like channel(s), fixed
bitrates, essid, bssid, RTS/CTS, fraqmentation, txpower, power management,
antenna settings, etc... would make sense? allthough in this list antenna is
probably the only one which is per phy and not per interface...
i can leave the 'antenna get' command out until this is clarified.
bruno
^ permalink raw reply
* Re: [PATCH v3 1/3] cfg80211: Add nl80211 antenna configuration
From: Bruno Randolf @ 2010-06-08 1:19 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1275901408.3639.2.camel@jlt3.sipsolutions.net>
On Monday 07 June 2010 18:03:28 you wrote:
> On Mon, 2010-06-07 at 15:58 +0900, Bruno Randolf wrote:
> > +static int nl80211_get_antenna(struct sk_buff *skb, struct genl_info
> > *info) +{
> > + struct cfg80211_registered_device *rdev;
> > + struct sk_buff *msg;
> > + void *hdr;
> > + int res;
> > + u8 tx_ant, rx_ant;
>
> You should probably set them both to 0 here,
ok.
> > + res = rdev->ops->get_antenna(&rdev->wiphy, &tx_ant, &rx_ant);
> > + if (res)
> > + goto free_msg;
>
> and complain about the driver if they still are after this.
would that be a WARN_ON?
thanks,
bruno
^ permalink raw reply
* Re: [RFC PATCH] mac80211: Fix circular locking dependency in ARP filter handling
From: Juuso Oikarinen @ 2010-06-08 4:32 UTC (permalink / raw)
To: ext Johannes Berg
Cc: linux-wireless@vger.kernel.org, reinette.chatre@intel.com
In-Reply-To: <1275923383.29978.19.camel@jlt3.sipsolutions.net>
On Mon, 2010-06-07 at 17:09 +0200, ext Johannes Berg wrote:
> On Mon, 2010-06-07 at 16:42 +0300, Juuso Oikarinen wrote:
>
> > > > +#ifdef CONFIG_INET
> > > > + cancel_work_sync(&sdata->u.mgd.arp_config_work);
> > > > +#endif
> > >
> > > No can do, this is under RTNL and thus can't block waiting for a work
> > > that acquires the RTNL ... the work might already be running, waiting
> > > for the RTNL, by the time you get here. This will also get you a lockdep
> > > complaint.
> >
> > The work-func escapes based on ieee80211_sdata_running before acquiring
> > the rtnl - hence here it should never get to the lock. I saw the same
> > being used in those other work funcs too. I was beginning work to try to
> > validate that, so it's not enough?
>
> No, it's not enough. Like I said: "the work might already be running,
> waiting for the RTNL" -- and once it obtains the RTNL, sdata has already
> been freed!
>
> > > This is why
> > >
> > > > @@ -379,7 +379,8 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
> > > > ifmgd = &sdata->u.mgd;
> > > > mutex_lock(&ifmgd->mtx);
> > > > if (ifmgd->associated)
> > > > - ieee80211_set_arp_filter(sdata);
> > > > + ieee80211_queue_work(&sdata->local->hw,
> > > > + &sdata->u.mgd.arp_config_work);
> > > > mutex_unlock(&ifmgd->mtx);
> > >
> > > No need to do change it here since the rtnl is held outside.
> >
> > Yes, I know rtnl is held outside. I changed this for two reasons. First,
> > I think it maybe better if the driver function is always called in the
> > same scope. Secondly, this gets rid of inetdevs intermediate
> > configurations (if you change IP address, it will first remove the
> > previous one, and immediately after add a new one, resulting in two
> > calls to the driver config function.)
>
> Interesting. But that only works if it does that both together under
> rtnl. I don't think the context really matters -- it should be the same
> at least from a locking POV you have both rtnl and mgd->mtx acquired.
>
> > > Also, and this applies to the change in mlme.c too, you must never put
> > > work that acquires the rtnl onto the mac80211 workqueue ... that's what
> > > you were trying to fix to start with!
> >
> > > But because the interface might go away before your work runs, you're in
> > > a stupid situation where you can't really use a per-interface work
> > > either ... I think you probably need to have the work in ieee80211_local
> > > and iterate the interface list.
> >
> > I thought about iterating the interface list. I assume you imply calling
> > the configure function for every interface.
>
> Only if it's associated, I guess.
>
> > Going still back to the current patch: assuming that you overlooked the
> > sdata_running() call in the arp_config_work() function, and we can after
> > all cancel_work_sync in _stop(), would using the kernel's default
> > workqueue solve the rtnl problem, or are the rtnl dependencies there
> > too?
>
> Using the default wq would solve the rtnl from workqueue problem,
> obviously, but wouldn't fix the cancel_work_sync problem.
>
Yeah, I actually did realize this during the night. No, I wasn't
sleepless - my brain still has a tendency to generate realizations for
the joy of the morning.
I'll try to think about alternative solutions. The driver provided list
idea is neat, but I think will scale badly for multiple vif's.
-Juuso
> johannes
>
^ permalink raw reply
* iwlagn fails to assoc with nexus one in ad-hoc mode
From: David Miller @ 2010-06-08 4:46 UTC (permalink / raw)
To: linux-wireless
When I try to associate the wireless activity light blinks like
crazy and I get kernel log dumps like the one at the end of
this email.
The nexus one uses a Broadcom BCM4328 for wireless.
Windows 7 users report the same problem with Intel wireless, and that
upgrading to the Intel wireless windows driver, version 13.1.1.1,
fixes the problem.
For example, see here:
http://code.google.com/p/android-wifi-tether/issues/detail?id=244
Can we make sure whatever got fixed in the windows driver propagates
into our Linux drivers too? :-)
Thanks!
--------------------
iwlagn 0000:03:00.0: Microcode SW error detected. Restarting 0x2000000.
iwlagn 0000:03:00.0: Start IWL Error Log Dump:
iwlagn 0000:03:00.0: Status: 0x000212E4, count: 5
iwlagn 0000:03:00.0: Desc Time data1 data2 line
iwlagn 0000:03:00.0: SYSASSERT (#05) 0010614736 0x00000080 0x00000010 854
iwlagn 0000:03:00.0: blink1 blink2 ilink1 ilink2
iwlagn 0000:03:00.0: 0x03870 0x03870 0x008B2 0x00000
iwlagn 0000:03:00.0: CSR values:
iwlagn 0000:03:00.0: (2nd byte of CSR_INT_COALESCING is CSR_INT_PERIODIC_REG)
iwlagn 0000:03:00.0: CSR_HW_IF_CONFIG_REG: 0X00480302
iwlagn 0000:03:00.0: CSR_INT_COALESCING: 0X00000040
iwlagn 0000:03:00.0: CSR_INT: 0X00000000
iwlagn 0000:03:00.0: CSR_INT_MASK: 0X00000000
iwlagn 0000:03:00.0: CSR_FH_INT_STATUS: 0X00000000
iwlagn 0000:03:00.0: CSR_GPIO_IN: 0X00000000
iwlagn 0000:03:00.0: CSR_RESET: 0X00000000
iwlagn 0000:03:00.0: CSR_GP_CNTRL: 0X080403c5
iwlagn 0000:03:00.0: CSR_HW_REV: 0X00000024
iwlagn 0000:03:00.0: CSR_EEPROM_REG: 0X00000000
iwlagn 0000:03:00.0: CSR_EEPROM_GP: 0X90000004
iwlagn 0000:03:00.0: CSR_OTP_GP_REG: 0X00060000
iwlagn 0000:03:00.0: CSR_GIO_REG: 0X00080046
iwlagn 0000:03:00.0: CSR_GP_UCODE_REG: 0X00000029
iwlagn 0000:03:00.0: CSR_GP_DRIVER_REG: 0X00000000
iwlagn 0000:03:00.0: CSR_UCODE_DRV_GP1: 0X00000000
iwlagn 0000:03:00.0: CSR_UCODE_DRV_GP2: 0X00000000
iwlagn 0000:03:00.0: CSR_LED_REG: 0X00000078
iwlagn 0000:03:00.0: CSR_DRAM_INT_TBL_REG: 0X88034db0
iwlagn 0000:03:00.0: CSR_GIO_CHICKEN_BITS: 0X27800200
iwlagn 0000:03:00.0: CSR_ANA_PLL_CFG: 0X00880300
iwlagn 0000:03:00.0: CSR_HW_REV_WA_REG: 0X0001001a
iwlagn 0000:03:00.0: CSR_DBG_HPET_MEM_REG: 0Xffff0000
iwlagn 0000:03:00.0: FH register values:
iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_STTS_WPTR_REG: 0X034c7900
iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_RBDCB_BASE_REG: 0X0034ccc0
iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_WPTR: 0X00000040
iwlagn 0000:03:00.0: FH_MEM_RCSR_CHNL0_CONFIG_REG: 0X80819104
iwlagn 0000:03:00.0: FH_MEM_RSSR_SHARED_CTRL_REG: 0X000000fc
iwlagn 0000:03:00.0: FH_MEM_RSSR_RX_STATUS_REG: 0X07030000
iwlagn 0000:03:00.0: FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV: 0X00000000
iwlagn 0000:03:00.0: FH_TSSR_TX_STATUS_REG: 0X07ff0001
iwlagn 0000:03:00.0: FH_TSSR_TX_ERROR_REG: 0X00000000
iwlagn 0000:03:00.0: Start IWL Event Log Dump: display last 20 entries
iwlagn 0000:03:00.0: EVT_LOGT:0000054936:0x00000001:0353
iwlagn 0000:03:00.0: EVT_LOGT:0000054953:0x0000010f:0106
iwlagn 0000:03:00.0: EVT_LOGT:0000054955:0x00000000:0301
iwlagn 0000:03:00.0: EVT_LOGT:0000055026:0x0000000d:0353
iwlagn 0000:03:00.0: EVT_LOGT:0000055037:0x00000000:0302
iwlagn 0000:03:00.0: EVT_LOGT:0000055057:0x00000c1d:0352
iwlagn 0000:03:00.0: EVT_LOGT:0000055058:0x00000002:0353
iwlagn 0000:03:00.0: EVT_LOGT:0000055070:0x00000000:0302
iwlagn 0000:03:00.0: EVT_LOGT:0000055094:0x00000d48:0352
iwlagn 0000:03:00.0: EVT_LOGT:0000055095:0x00000003:0353
iwlagn 0000:03:00.0: EVT_LOGT:0000055157:0x0000010f:0106
iwlagn 0000:03:00.0: EVT_LOGT:0000055159:0x00000000:0302
iwlagn 0000:03:00.0: EVT_LOGT:0000055171:0x00002000:0350
iwlagn 0000:03:00.0: EVT_LOGT:0000079297:0x0000010f:0106
iwlagn 0000:03:00.0: EVT_LOGT:0000079299:0x00000000:0301
iwlagn 0000:03:00.0: EVT_LOGT:0000079679:0x00000080:0313
iwlagn 0000:03:00.0: EVT_LOGT:0000079681:0x000005b4:0501
iwlagn 0000:03:00.0: EVT_LOGT:0000081109:0x00000000:0356
iwlagn 0000:03:00.0: EVT_LOGT:0000081141:0x000002ef:0501
iwlagn 0000:03:00.0: EVT_LOGT:0000081150:0x00000000:0125
iwlagn 0000:03:00.0: Unable to find TIM Element in beacon
iwlagn 0000:03:00.0: Unable to find TIM Element in beacon
iwlagn 0000:03:00.0: index 0 already used in uCode key table.
^ permalink raw reply
* [RFC PATCHv2] mac80211: Fix circular locking dependency in ARP filter handling
From: Juuso Oikarinen @ 2010-06-08 6:24 UTC (permalink / raw)
To: linux-wireless; +Cc: reinette.chatre
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.
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
include/net/mac80211.h | 34 ++++++++++++++++++-------------
net/mac80211/driver-ops.h | 17 ---------------
net/mac80211/driver-trace.h | 25 -----------------------
net/mac80211/main.c | 46 +++++++++++++++++++++++++-----------------
net/mac80211/mlme.c | 18 +++++-----------
5 files changed, 53 insertions(+), 87 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e3c1d47..af2f3cc 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -19,7 +19,6 @@
#include <linux/wireless.h>
#include <linux/device.h>
#include <linux/ieee80211.h>
-#include <linux/inetdevice.h>
#include <net/cfg80211.h>
/**
@@ -147,6 +146,7 @@ struct ieee80211_low_level_stats {
* enabled/disabled (beaconing modes)
* @BSS_CHANGED_CQM: Connection quality monitor config changed
* @BSS_CHANGED_IBSS: IBSS join status changed
+ * @BSS_CHANGED_ARP_ADDR_LIST: Hardware ARP filter address list changed
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -161,10 +161,20 @@ enum ieee80211_bss_change {
BSS_CHANGED_BEACON_ENABLED = 1<<9,
BSS_CHANGED_CQM = 1<<10,
BSS_CHANGED_IBSS = 1<<11,
+#ifdef CONFIG_INET
+ BSS_CHANGED_ARP_ADDR_LIST = 1<<12,
+#endif
/* when adding here, make sure to change ieee80211_reconfig */
};
+/*
+ * The maximum number of IPv4 addresses listed for ARP filtering. If the number
+ * of addresses for an interface increase beyond this value, hardware ARP
+ * filtering will be disabled.
+ */
+#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
+
/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
@@ -200,6 +210,11 @@ enum ieee80211_bss_change {
* @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
* implies disabled
* @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
+ * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
+ * may filter ARP queries targeted for other addresses than listed here.
+ * The driver must allow ARP queries targeted for all address listed here
+ * to pass through.
+ * @arp_addr_cnt: Number of addresses currently on the list
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -220,6 +235,10 @@ struct ieee80211_bss_conf {
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
enum nl80211_channel_type channel_type;
+#ifdef CONFIG_INET
+ __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
+ u8 arp_addr_cnt;
+#endifs
};
/**
@@ -1529,16 +1548,6 @@ enum ieee80211_ampdu_mlme_action {
* of the bss parameters has changed when a call is made. The callback
* can sleep.
*
- * @configure_arp_filter: Configuration function for hardware ARP query filter.
- * This function is called with all the IP addresses configured to the
- * interface as argument - all ARP queries targeted to any of these
- * addresses must pass through. If the hardware filter does not support
- * enought addresses, hardware filtering must be disabled. The ifa_list
- * argument may be NULL, indicating that filtering must be disabled.
- * This function is called upon association complete with current
- * address(es), and while associated whenever the IP address(es) change.
- * The callback can sleep.
- *
* @prepare_multicast: Prepare for multicast filter configuration.
* This callback is optional, and its return value is passed
* to configure_filter(). This callback must be atomic.
@@ -1678,9 +1687,6 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u32 changed);
- int (*configure_arp_filter)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct in_ifaddr *ifa_list);
u64 (*prepare_multicast)(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);
void (*configure_filter)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d1139e4..bbea3bc 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -83,23 +83,6 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
trace_drv_bss_info_changed(local, sdata, info, changed);
}
-struct in_ifaddr;
-static inline int drv_configure_arp_filter(struct ieee80211_local *local,
- struct ieee80211_vif *vif,
- struct in_ifaddr *ifa_list)
-{
- int ret = 0;
-
- might_sleep();
-
- if (local->ops->configure_arp_filter)
- ret = local->ops->configure_arp_filter(&local->hw, vif,
- ifa_list);
-
- trace_drv_configure_arp_filter(local, vif_to_sdata(vif), ifa_list, ret);
- return ret;
-}
-
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
struct netdev_hw_addr_list *mc_list)
{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6b90630..1e293df 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -219,31 +219,6 @@ TRACE_EVENT(drv_bss_info_changed,
)
);
-TRACE_EVENT(drv_configure_arp_filter,
- TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct in_ifaddr *ifa_list, int ret),
-
- TP_ARGS(local, sdata, ifa_list, ret),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- VIF_ENTRY
- __field(int, ret)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- VIF_ASSIGN;
- __entry->ret = ret;
- ),
-
- TP_printk(
- VIF_PR_FMT LOCAL_PR_FMT " ret:%d",
- VIF_PR_ARG, LOCAL_PR_ARG, __entry->ret
- )
-);
-
TRACE_EVENT(drv_prepare_multicast,
TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 88b671a..89dc7c1 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -20,6 +20,7 @@
#include <linux/rtnetlink.h>
#include <linux/bitmap.h>
#include <linux/pm_qos_params.h>
+#include <linux/inetdevice.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
@@ -330,23 +331,6 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
}
#ifdef CONFIG_INET
-int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata)
-{
- struct in_device *idev;
- int ret = 0;
-
- BUG_ON(!sdata);
- ASSERT_RTNL();
-
- idev = sdata->dev->ip_ptr;
- if (!idev)
- return 0;
-
- ret = drv_configure_arp_filter(sdata->local, &sdata->vif,
- idev->ifa_list);
- return ret;
-}
-
static int ieee80211_ifa_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
@@ -356,8 +340,11 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
ifa_notifier);
struct net_device *ndev = ifa->ifa_dev->dev;
struct wireless_dev *wdev = ndev->ieee80211_ptr;
+ struct in_device *idev;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_bss_conf *bss_conf;
struct ieee80211_if_managed *ifmgd;
+ int c = 0;
if (!netif_running(ndev))
return NOTIFY_DONE;
@@ -369,17 +356,38 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
if (wdev->wiphy != local->hw.wiphy)
return NOTIFY_DONE;
- /* We are concerned about IP addresses only when associated */
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ bss_conf = &sdata->vif.bss_conf;
/* ARP filtering is only supported in managed mode */
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return NOTIFY_DONE;
+ idev = sdata->dev->ip_ptr;
+ if (!idev)
+ return NOTIFY_DONE;
+
ifmgd = &sdata->u.mgd;
mutex_lock(&ifmgd->mtx);
+
+ /* Copy the addresses to the bss_conf list */
+ ifa = idev->ifa_list;
+ while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) {
+ bss_conf->arp_addr_list[c] = ifa->ifa_address;
+ ifa = ifa->ifa_next;
+ c++;
+ }
+
+ if (c == IEEE80211_BSS_ARP_ADDR_LIST_LEN)
+ c = 0;
+
+ bss_conf->arp_addr_cnt = c;
+
+ /* We are concerned about ARP filterting only when associated */
if (ifmgd->associated)
- ieee80211_set_arp_filter(sdata);
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_ARP_ADDR_LIST);
+
mutex_unlock(&ifmgd->mtx);
return NOTIFY_DONE;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ac68c41..25ceea3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -851,6 +851,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.cqm_rssi_thold)
bss_info_changed |= BSS_CHANGED_CQM;
+#ifdef CONFIG_INET
+ bss_info_changed |= BSS_CHANGED_ARP_ADDR_LIST;
+#endif
+
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
mutex_lock(&local->iflist_mtx);
@@ -2116,19 +2120,9 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
cfg80211_send_assoc_timeout(wk->sdata->dev,
wk->filter_ta);
return WORK_DONE_DESTROY;
-#ifdef CONFIG_INET
- } else {
- mutex_unlock(&wk->sdata->u.mgd.mtx);
-
- /*
- * configure ARP filter IP addresses to the driver,
- * intentionally outside the mgd mutex.
- */
- rtnl_lock();
- ieee80211_set_arp_filter(wk->sdata);
- rtnl_unlock();
-#endif
}
+
+ mutex_unlock(&wk->sdata->u.mgd.mtx);
}
cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH] iwlwifi: add missing rcu_read_lock
From: Johannes Berg @ 2010-06-08 7:25 UTC (permalink / raw)
To: Miles Lane; +Cc: John Linville, Reinette Chatre, Wey-Yi W Guy, linux-wireless
In-Reply-To: <AANLkTin91YUTC8ogoflpFN4V3f21ItLlV_EoFU-uvrzo@mail.gmail.com>
On Mon, 2010-06-07 at 17:31 -0400, Miles Lane wrote:
> > --- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-agn-tx.c 2010-06-07 21:17:56.000000000 +0200
> > +++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-agn-tx.c 2010-06-07 21:18:04.000000000 +0200
> > @@ -1146,6 +1146,7 @@ static void iwlagn_tx_status(struct iwl_
> > struct ieee80211_sta *sta;
> > struct iwl_station_priv *sta_priv;
> >
> > + rcu_read_lock();
> > sta = ieee80211_find_sta(priv->vif, hdr->addr1);
> > if (sta) {
> > sta_priv = (void *)sta->drv_priv;
> > @@ -1154,6 +1155,7 @@ static void iwlagn_tx_status(struct iwl_
> > atomic_dec_return(&sta_priv->pending_frames) == 0)
> > ieee80211_sta_block_awake(priv->hw, sta, false);
> > }
> > + rcu_read_unlock();
> >
> > ieee80211_tx_status_irqsafe(priv->hw, skb);
> > }
> >
> >
> >
>
> Unclean patch application - is this to be expected?
>
> patching file drivers/net/wireless/iwlwifi/iwl-agn-tx.c
> Hunk #1 succeeded at 1125 (offset -21 lines).
> Hunk #2 succeeded at 1134 (offset -21 lines).
Didn't pay much attention what tree I generated it against since I knew
this code hasn't changed in a while ... so the offset looks perfectly
fine. Fuzz I'd have been surprised about :)
johannes
^ permalink raw reply
* Re: [PATCH v3 1/3] cfg80211: Add nl80211 antenna configuration
From: Johannes Berg @ 2010-06-08 7:27 UTC (permalink / raw)
To: Bruno Randolf; +Cc: linux-wireless
In-Reply-To: <201006081019.10217.br1@einfach.org>
On Tue, 2010-06-08 at 10:19 +0900, Bruno Randolf wrote:
> > > + res = rdev->ops->get_antenna(&rdev->wiphy, &tx_ant, &rx_ant);
> > > + if (res)
> > > + goto free_msg;
> >
> > and complain about the driver if they still are after this.
>
> would that be a WARN_ON?
Yeah I suppose so.
johannes
^ permalink raw reply
* Re: [RFC PATCHv2] mac80211: Fix circular locking dependency in ARP filter handling
From: Johannes Berg @ 2010-06-08 8:03 UTC (permalink / raw)
To: Juuso Oikarinen; +Cc: linux-wireless, reinette.chatre
In-Reply-To: <1275978299-18237-1-git-send-email-juuso.oikarinen@nokia.com>
On Tue, 2010-06-08 at 09:24 +0300, Juuso Oikarinen wrote:
> @@ -161,10 +161,20 @@ enum ieee80211_bss_change {
> BSS_CHANGED_BEACON_ENABLED = 1<<9,
> BSS_CHANGED_CQM = 1<<10,
> BSS_CHANGED_IBSS = 1<<11,
> +#ifdef CONFIG_INET
> + BSS_CHANGED_ARP_ADDR_LIST = 1<<12,
> +#endif
Ick, don't do that, all drivers would end up littered with ifdefs.
> @@ -220,6 +235,10 @@ struct ieee80211_bss_conf {
> s32 cqm_rssi_thold;
> u32 cqm_rssi_hyst;
> enum nl80211_channel_type channel_type;
> +#ifdef CONFIG_INET
> + __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
> + u8 arp_addr_cnt;
> +#endifs
same here.
> @@ -851,6 +851,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
> sdata->vif.bss_conf.cqm_rssi_thold)
> bss_info_changed |= BSS_CHANGED_CQM;
>
> +#ifdef CONFIG_INET
> + bss_info_changed |= BSS_CHANGED_ARP_ADDR_LIST;
> +#endif
> +
I don't see why you can't set that unconditionally here either, it'll
just be an empty list always.
Otherwise looks pretty good.
johannes
^ permalink raw reply
* Re: [RFC PATCHv2] mac80211: Fix circular locking dependency in ARP filter handling
From: Juuso Oikarinen @ 2010-06-08 8:46 UTC (permalink / raw)
To: ext Johannes Berg
Cc: linux-wireless@vger.kernel.org, reinette.chatre@intel.com
In-Reply-To: <1275984236.3706.45.camel@jlt3.sipsolutions.net>
On Tue, 2010-06-08 at 10:03 +0200, ext Johannes Berg wrote:
> On Tue, 2010-06-08 at 09:24 +0300, Juuso Oikarinen wrote:
>
> > @@ -161,10 +161,20 @@ enum ieee80211_bss_change {
> > BSS_CHANGED_BEACON_ENABLED = 1<<9,
> > BSS_CHANGED_CQM = 1<<10,
> > BSS_CHANGED_IBSS = 1<<11,
> > +#ifdef CONFIG_INET
> > + BSS_CHANGED_ARP_ADDR_LIST = 1<<12,
> > +#endif
>
> Ick, don't do that, all drivers would end up littered with ifdefs.
>
> > @@ -220,6 +235,10 @@ struct ieee80211_bss_conf {
> > s32 cqm_rssi_thold;
> > u32 cqm_rssi_hyst;
> > enum nl80211_channel_type channel_type;
> > +#ifdef CONFIG_INET
> > + __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
> > + u8 arp_addr_cnt;
> > +#endifs
>
> same here.
>
> > @@ -851,6 +851,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
> > sdata->vif.bss_conf.cqm_rssi_thold)
> > bss_info_changed |= BSS_CHANGED_CQM;
> >
> > +#ifdef CONFIG_INET
> > + bss_info_changed |= BSS_CHANGED_ARP_ADDR_LIST;
> > +#endif
> > +
>
> I don't see why you can't set that unconditionally here either, it'll
> just be an empty list always.
I was about to send the patch without the ifdefs, but was unsure about
the policy here so I decided to add at the at the last minute.
Our testing guy found a bug too - the condition for the max number of
IP's is wrong, it will take at most 3 addresses currently.
> Otherwise looks pretty good.
As you say it looks OK, I'll remove the above #ifdef's, fix that one bug
(and others if/when our tester dude finds more) and resubmit.
-Juuso
> johannes
>
^ permalink raw reply
* Re: [PATCH v3 1/3] cfg80211: Add nl80211 antenna configuration
From: Johannes Berg @ 2010-06-08 9:05 UTC (permalink / raw)
To: Bruno Randolf; +Cc: linville, linux-wireless
In-Reply-To: <201006081010.13314.br1@einfach.org>
On Tue, 2010-06-08 at 10:10 +0900, Bruno Randolf wrote:
> i don't particularly care about where the antenna information is printed
> exactly, so anything will be fine with me.
>
> but when i look at the wiphy info, it shows mostly capability information,
> like the list of supported frequencies, list of bitrates, supported interface
> modes, supported commands. the only exception is coverage class, which is the
> only runtime configuration as far as i can see. therefore i thought it doesnt
> fit there well.
>
> maybe another command for getting runtime configuration like channel(s), fixed
> bitrates, essid, bssid, RTS/CTS, fraqmentation, txpower, power management,
> antenna settings, etc... would make sense? allthough in this list antenna is
> probably the only one which is per phy and not per interface...
Right so there isn't much runtime stuff in the list now. I don't see
anything inherently bad in adding more though, since userspace can
selectively look at the attributes, and it's not like it's a huge amount
of data?
johannes
^ permalink raw reply
* [PATCH] mac80211: Fix circular locking dependency in ARP filter handling
From: Juuso Oikarinen @ 2010-06-08 10:06 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, reinette.chatre
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.
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
include/net/mac80211.h | 30 ++++++++++++++------------
net/mac80211/driver-ops.h | 17 ---------------
net/mac80211/driver-trace.h | 25 ----------------------
net/mac80211/main.c | 47 +++++++++++++++++++++++++-----------------
net/mac80211/mlme.c | 16 +++-----------
5 files changed, 48 insertions(+), 87 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e3c1d47..086f235 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -19,7 +19,6 @@
#include <linux/wireless.h>
#include <linux/device.h>
#include <linux/ieee80211.h>
-#include <linux/inetdevice.h>
#include <net/cfg80211.h>
/**
@@ -147,6 +146,7 @@ struct ieee80211_low_level_stats {
* enabled/disabled (beaconing modes)
* @BSS_CHANGED_CQM: Connection quality monitor config changed
* @BSS_CHANGED_IBSS: IBSS join status changed
+ * @BSS_CHANGED_ARP_ADDR_LIST: Hardware ARP filter address list changed
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -161,10 +161,18 @@ enum ieee80211_bss_change {
BSS_CHANGED_BEACON_ENABLED = 1<<9,
BSS_CHANGED_CQM = 1<<10,
BSS_CHANGED_IBSS = 1<<11,
+ BSS_CHANGED_ARP_ADDR_LIST = 1<<12,
/* when adding here, make sure to change ieee80211_reconfig */
};
+/*
+ * The maximum number of IPv4 addresses listed for ARP filtering. If the number
+ * of addresses for an interface increase beyond this value, hardware ARP
+ * filtering will be disabled.
+ */
+#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
+
/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
@@ -200,6 +208,11 @@ enum ieee80211_bss_change {
* @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
* implies disabled
* @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
+ * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
+ * may filter ARP queries targeted for other addresses than listed here.
+ * The driver must allow ARP queries targeted for all address listed here
+ * to pass through.
+ * @arp_addr_cnt: Number of addresses currently on the list
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -220,6 +233,8 @@ struct ieee80211_bss_conf {
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
enum nl80211_channel_type channel_type;
+ __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
+ u8 arp_addr_cnt;
};
/**
@@ -1529,16 +1544,6 @@ enum ieee80211_ampdu_mlme_action {
* of the bss parameters has changed when a call is made. The callback
* can sleep.
*
- * @configure_arp_filter: Configuration function for hardware ARP query filter.
- * This function is called with all the IP addresses configured to the
- * interface as argument - all ARP queries targeted to any of these
- * addresses must pass through. If the hardware filter does not support
- * enought addresses, hardware filtering must be disabled. The ifa_list
- * argument may be NULL, indicating that filtering must be disabled.
- * This function is called upon association complete with current
- * address(es), and while associated whenever the IP address(es) change.
- * The callback can sleep.
- *
* @prepare_multicast: Prepare for multicast filter configuration.
* This callback is optional, and its return value is passed
* to configure_filter(). This callback must be atomic.
@@ -1678,9 +1683,6 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u32 changed);
- int (*configure_arp_filter)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct in_ifaddr *ifa_list);
u64 (*prepare_multicast)(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);
void (*configure_filter)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d1139e4..bbea3bc 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -83,23 +83,6 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
trace_drv_bss_info_changed(local, sdata, info, changed);
}
-struct in_ifaddr;
-static inline int drv_configure_arp_filter(struct ieee80211_local *local,
- struct ieee80211_vif *vif,
- struct in_ifaddr *ifa_list)
-{
- int ret = 0;
-
- might_sleep();
-
- if (local->ops->configure_arp_filter)
- ret = local->ops->configure_arp_filter(&local->hw, vif,
- ifa_list);
-
- trace_drv_configure_arp_filter(local, vif_to_sdata(vif), ifa_list, ret);
- return ret;
-}
-
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
struct netdev_hw_addr_list *mc_list)
{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6b90630..1e293df 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -219,31 +219,6 @@ TRACE_EVENT(drv_bss_info_changed,
)
);
-TRACE_EVENT(drv_configure_arp_filter,
- TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct in_ifaddr *ifa_list, int ret),
-
- TP_ARGS(local, sdata, ifa_list, ret),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- VIF_ENTRY
- __field(int, ret)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- VIF_ASSIGN;
- __entry->ret = ret;
- ),
-
- TP_printk(
- VIF_PR_FMT LOCAL_PR_FMT " ret:%d",
- VIF_PR_ARG, LOCAL_PR_ARG, __entry->ret
- )
-);
-
TRACE_EVENT(drv_prepare_multicast,
TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 5706156..0a6400b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -20,6 +20,7 @@
#include <linux/rtnetlink.h>
#include <linux/bitmap.h>
#include <linux/pm_qos_params.h>
+#include <linux/inetdevice.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
@@ -330,23 +331,6 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
}
#ifdef CONFIG_INET
-int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata)
-{
- struct in_device *idev;
- int ret = 0;
-
- BUG_ON(!sdata);
- ASSERT_RTNL();
-
- idev = sdata->dev->ip_ptr;
- if (!idev)
- return 0;
-
- ret = drv_configure_arp_filter(sdata->local, &sdata->vif,
- idev->ifa_list);
- return ret;
-}
-
static int ieee80211_ifa_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
@@ -356,8 +340,11 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
ifa_notifier);
struct net_device *ndev = ifa->ifa_dev->dev;
struct wireless_dev *wdev = ndev->ieee80211_ptr;
+ struct in_device *idev;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_bss_conf *bss_conf;
struct ieee80211_if_managed *ifmgd;
+ int c = 0;
/* Make sure it's our interface that got changed */
if (!wdev)
@@ -366,17 +353,39 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
if (wdev->wiphy != local->hw.wiphy)
return NOTIFY_DONE;
- /* We are concerned about IP addresses only when associated */
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ bss_conf = &sdata->vif.bss_conf;
/* ARP filtering is only supported in managed mode */
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return NOTIFY_DONE;
+ idev = sdata->dev->ip_ptr;
+ if (!idev)
+ return NOTIFY_DONE;
+
ifmgd = &sdata->u.mgd;
mutex_lock(&ifmgd->mtx);
+
+ /* Copy the addresses to the bss_conf list */
+ ifa = idev->ifa_list;
+ while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) {
+ bss_conf->arp_addr_list[c] = ifa->ifa_address;
+ ifa = ifa->ifa_next;
+ c++;
+ }
+
+ /* If not all addresses fit the list, disable filtering */
+ if (ifa)
+ c = 0;
+
+ bss_conf->arp_addr_cnt = c;
+
+ /* We are concerned about ARP filterting only when associated */
if (ifmgd->associated)
- ieee80211_set_arp_filter(sdata);
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_ARP_ADDR_LIST);
+
mutex_unlock(&ifmgd->mtx);
return NOTIFY_DONE;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ac68c41..8a39530 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -851,6 +851,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.cqm_rssi_thold)
bss_info_changed |= BSS_CHANGED_CQM;
+ bss_info_changed |= BSS_CHANGED_ARP_ADDR_LIST;
+
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
mutex_lock(&local->iflist_mtx);
@@ -2116,19 +2118,9 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
cfg80211_send_assoc_timeout(wk->sdata->dev,
wk->filter_ta);
return WORK_DONE_DESTROY;
-#ifdef CONFIG_INET
- } else {
- mutex_unlock(&wk->sdata->u.mgd.mtx);
-
- /*
- * configure ARP filter IP addresses to the driver,
- * intentionally outside the mgd mutex.
- */
- rtnl_lock();
- ieee80211_set_arp_filter(wk->sdata);
- rtnl_unlock();
-#endif
}
+
+ mutex_unlock(&wk->sdata->u.mgd.mtx);
}
cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
--
1.6.3.3
^ permalink raw reply related
* [PATCH v2] wl1251: fix ELP_CTRL register reads
From: Grazvydas Ignotas @ 2010-06-08 11:33 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, Grazvydas Ignotas
Reading the ELP_CTRL register with sdio_readb causes problems because
hardware seems to be performing a write using stuff bits in the request
(those bits contain write data in write request). This indicates that it
actually expects RAW (read after write) type of request, so perform that
when reading ELP_CTRL instead. Also cache last written value so we know
what to write when doing RAW request.
Because of the above it was not possible to wake the chip from ELP power
saving mode, PM had to be disabled to have the driver usable in SDIO
mode. After this patch PM is functional.
For backporting to 2.6.34 or earlier, this patch depends on
6c1f716e8154ee9315534782b9b1eedea0559a24, which adds the
required SDIO funcion.
Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>
Acked-by: Kalle Valo <kvalo@adurom.com>
---
This is the same as previous version, just updated the commit message.
drivers/net/wireless/wl12xx/wl1251_sdio.c | 40 ++++++++++++++++++++++++----
1 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c
index c561332..b901b61 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c
@@ -37,11 +37,17 @@
#define SDIO_DEVICE_ID_TI_WL1251 0x9066
#endif
+struct wl1251_sdio {
+ struct sdio_func *func;
+ u32 elp_val;
+};
+
static struct wl12xx_platform_data *wl12xx_board_data;
static struct sdio_func *wl_to_func(struct wl1251 *wl)
{
- return wl->if_priv;
+ struct wl1251_sdio *wl_sdio = wl->if_priv;
+ return wl_sdio->func;
}
static void wl1251_sdio_interrupt(struct sdio_func *func)
@@ -90,10 +96,17 @@ static void wl1251_sdio_write(struct wl1251 *wl, int addr,
static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
{
int ret = 0;
- struct sdio_func *func = wl_to_func(wl);
-
+ struct wl1251_sdio *wl_sdio = wl->if_priv;
+ struct sdio_func *func = wl_sdio->func;
+
+ /*
+ * The hardware only supports RAW (read after write) access for
+ * reading, regular sdio_readb won't work here (it interprets
+ * the unused bits of CMD52 as write data even if we send read
+ * request).
+ */
sdio_claim_host(func);
- *val = sdio_readb(func, addr, &ret);
+ *val = sdio_writeb_readb(func, wl_sdio->elp_val, addr, &ret);
sdio_release_host(func);
if (ret)
@@ -103,7 +116,8 @@ static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
{
int ret = 0;
- struct sdio_func *func = wl_to_func(wl);
+ struct wl1251_sdio *wl_sdio = wl->if_priv;
+ struct sdio_func *func = wl_sdio->func;
sdio_claim_host(func);
sdio_writeb(func, val, addr, &ret);
@@ -111,6 +125,8 @@ static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
if (ret)
wl1251_error("sdio_writeb failed (%d)", ret);
+ else
+ wl_sdio->elp_val = val;
}
static void wl1251_sdio_reset(struct wl1251 *wl)
@@ -197,6 +213,7 @@ static int wl1251_sdio_probe(struct sdio_func *func,
int ret;
struct wl1251 *wl;
struct ieee80211_hw *hw;
+ struct wl1251_sdio *wl_sdio;
hw = wl1251_alloc_hw();
if (IS_ERR(hw))
@@ -204,6 +221,12 @@ static int wl1251_sdio_probe(struct sdio_func *func,
wl = hw->priv;
+ wl_sdio = kzalloc(sizeof(*wl_sdio), GFP_KERNEL);
+ if (wl_sdio == NULL) {
+ ret = -ENOMEM;
+ goto out_free_hw;
+ }
+
sdio_claim_host(func);
ret = sdio_enable_func(func);
if (ret)
@@ -213,7 +236,8 @@ static int wl1251_sdio_probe(struct sdio_func *func,
sdio_release_host(func);
SET_IEEE80211_DEV(hw, &func->dev);
- wl->if_priv = func;
+ wl_sdio->func = func;
+ wl->if_priv = wl_sdio;
wl->if_ops = &wl1251_sdio_ops;
wl->set_power = wl1251_sdio_set_power;
@@ -259,6 +283,8 @@ disable:
sdio_disable_func(func);
release:
sdio_release_host(func);
+ kfree(wl_sdio);
+out_free_hw:
wl1251_free_hw(wl);
return ret;
}
@@ -266,9 +292,11 @@ release:
static void __devexit wl1251_sdio_remove(struct sdio_func *func)
{
struct wl1251 *wl = sdio_get_drvdata(func);
+ struct wl1251_sdio *wl_sdio = wl->if_priv;
if (wl->irq)
free_irq(wl->irq, wl);
+ kfree(wl_sdio);
wl1251_free_hw(wl);
sdio_claim_host(func);
--
1.7.0.2
^ permalink raw reply related
* [RFC 0/3] mac80211: Add support for configuring ibss basic rates
From: Teemu Paasikivi @ 2010-06-08 12:34 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Teemu Paasikivi
This patch set implements support for configuring basic rates for ibss network when joining/creating one. First two patches are basically patch proposed by Johannes Berg on linux-wireless posting list split in two. These implement interface to nl80211 to do actual configuration from user space. Last patch is to fix a problem when leaving and joining back to self created ibss network, without this basic rates would be left unset. That is caused by the fact that the stack holds information for the self created bss and when rejoining it looks like already existing ibss network. This causes little annoyance (bug?) by preventing changing basic rates once ibss is created as long as the stack holds the information.
Teemu Paasikivi (3):
mac80211: Set basic rates while joining ibss network
mac80211: Set changed basic rates flag
mac80211: Store basic rates for bss when joining ibss network
include/net/cfg80211.h | 2 +
net/mac80211/ibss.c | 19 ++++++++++++++++-
net/mac80211/ieee80211_i.h | 2 +
net/wireless/nl80211.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 71 insertions(+), 1 deletions(-)
^ permalink raw reply
* [RFC 1/3] mac80211: Set basic rates while joining ibss network
From: Teemu Paasikivi @ 2010-06-08 12:34 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Teemu Paasikivi
In-Reply-To: <1276000459-1121-1-git-send-email-ext-teemu.3.paasikivi@nokia.com>
This patch adds support to nl80211 and mac80211 to set basic rates when
joining/creating ibss network.
Original patch was posted by Johannes Berg on the linux-wireless posting list.
Signed-off-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
---
include/net/cfg80211.h | 2 +
net/mac80211/ibss.c | 4 ++-
net/mac80211/ieee80211_i.h | 2 +
net/wireless/nl80211.c | 49 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 56 insertions(+), 1 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0c3c214..4ff4e1f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -801,6 +801,7 @@ struct cfg80211_disassoc_request {
* @beacon_interval: beacon interval to use
* @privacy: this is a protected network, keys will be configured
* after joining
+ * @basic_rates: bitmap of basic rates to use when creating the IBSS
*/
struct cfg80211_ibss_params {
u8 *ssid;
@@ -809,6 +810,7 @@ struct cfg80211_ibss_params {
u8 *ie;
u8 ssid_len, ie_len;
u16 beacon_interval;
+ u32 basic_rates;
bool channel_fixed;
bool privacy;
};
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d7a96ce..8be5a96 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -172,6 +172,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
rcu_assign_pointer(ifibss->presp, skb);
sdata->vif.bss_conf.beacon_int = beacon_int;
+ sdata->vif.bss_conf.basic_rates = basic_rates;
bss_change = BSS_CHANGED_BEACON_INT;
bss_change |= ieee80211_reset_erp_info(sdata);
bss_change |= BSS_CHANGED_BSSID;
@@ -529,7 +530,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
sdata->drop_unencrypted = 0;
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
- ifibss->channel, 3, /* first two are basic */
+ ifibss->channel, ifibss->basic_rates,
capability, 0);
}
@@ -910,6 +911,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.fixed_bssid = false;
sdata->u.ibss.privacy = params->privacy;
+ sdata->u.ibss.basic_rates = params->basic_rates;
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4d3883e..fde058b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -393,6 +393,8 @@ struct ieee80211_if_ibss {
unsigned long request;
unsigned long last_scan_completed;
+ u32 basic_rates;
+
bool timer_running;
bool fixed_bssid;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 90ab3c8..324b4a5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3955,6 +3955,55 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
}
}
+ if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
+ u8 *rates =
+ nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+ int n_rates =
+ nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+ struct ieee80211_supported_band *sband =
+ wiphy->bands[ibss.channel->band];
+ int i, j;
+
+ if (n_rates == 0) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < n_rates; i++) {
+ int rate = (rates[i] & 0x7f) * 5;
+ bool found = false;
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].bitrate == rate) {
+ found = true;
+ ibss.basic_rates |= BIT(j);
+ break;
+ }
+ }
+ if (!found) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+ } else {
+ /*
+ * If no rates were explicitly configured,
+ * use the mandatory rate set for 11b or
+ * 11a for maximum compatibility.
+ */
+ struct ieee80211_supported_band *sband =
+ wiphy->bands[ibss.channel->band];
+ int j;
+ u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ?
+ IEEE80211_RATE_MANDATORY_A :
+ IEEE80211_RATE_MANDATORY_B;
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].flags & flag)
+ ibss.basic_rates |= BIT(j);
+ }
+ }
+
err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
out:
--
1.5.6.3
^ permalink raw reply related
* [RFC 2/3] mac80211: Set changed basic rates flag
From: Teemu Paasikivi @ 2010-06-08 12:34 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Teemu Paasikivi
In-Reply-To: <1276000459-1121-2-git-send-email-ext-teemu.3.paasikivi@nokia.com>
Add changed basic rates flag to bss_changed while joinig ibss network.
This patch is split from the patch containing support for setting basic
rates when creating ibss network. Original patch was posted by Johannes
Berg on the linux-wireless posting list.
Signed-off-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
---
net/mac80211/ibss.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 8be5a96..d984ab2 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -179,6 +179,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
bss_change |= BSS_CHANGED_BEACON;
bss_change |= BSS_CHANGED_BEACON_ENABLED;
bss_change |= BSS_CHANGED_IBSS;
+ bss_change |= BSS_CHANGED_BASIC_RATES;
sdata->vif.bss_conf.ibss_joined = true;
ieee80211_bss_info_change_notify(sdata, bss_change);
--
1.5.6.3
^ permalink raw reply related
* [RFC 3/3] mac80211: Store basic rates for bss when joining ibss network
From: Teemu Paasikivi @ 2010-06-08 12:34 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Teemu Paasikivi
In-Reply-To: <1276000459-1121-3-git-send-email-ext-teemu.3.paasikivi@nokia.com>
When joinig a ibss network, basic rates for bss were not stored. When
network was self created, leaving and (re)joining same network has
caused basic rates to be left unset. With this patch stored values are
used.
Signed-off-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
---
net/mac80211/ibss.c | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d984ab2..72407f0 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -77,6 +77,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct cfg80211_bss *bss;
u32 bss_change;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+ struct ieee80211_bss *ibss;
/* Reset own TSF to allow time synchronization work. */
drv_reset_tsf(local);
@@ -191,6 +192,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
mgmt, skb->len, 0, GFP_KERNEL);
+
+ ibss = (struct ieee80211_bss *)(bss->priv);
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ u8 basic = 0x00;
+ if (basic_rates & BIT(i))
+ basic = 0x80;
+
+ ibss->supp_rates[i] = supp_rates[i] | basic;
+ }
+
+ ibss->supp_rates_len = i;
+
cfg80211_put_bss(bss);
cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
}
--
1.5.6.3
^ permalink raw reply related
* [RFC] iw: Configure basic rates when joining ibss network
From: Teemu Paasikivi @ 2010-06-08 12:37 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Teemu Paasikivi
This patch adds configuration option to configure basic rates when
joining ibss network.
Signed-off-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
---
ibss.c | 27 ++++++++++++++++++++++++++-
1 files changed, 26 insertions(+), 1 deletions(-)
diff --git a/ibss.c b/ibss.c
index 4715ac8..edc83fd 100644
--- a/ibss.c
+++ b/ibss.c
@@ -18,6 +18,11 @@ static int join_ibss(struct nl80211_state *state,
{
char *end;
unsigned char abssid[6];
+ unsigned char rates[NL80211_MAX_SUPP_RATES];
+ int n_rates = 0;
+ char *value = NULL, *sptr = NULL;
+ float rate;
+
if (argc < 2)
return 1;
@@ -41,6 +46,24 @@ static int join_ibss(struct nl80211_state *state,
argc--;
}
+ if (argc > 1 && strcmp(argv[0], "basic-rates") == 0) {
+ argv++;
+ argc--;
+
+ value = strtok_r(argv[0], ",", &sptr);
+
+ while (value && n_rates < NL80211_MAX_SUPP_RATES) {
+ rate = atof(value);
+ rates[n_rates++] = rate * 2;
+ value = strtok_r(NULL, ",", &sptr);
+ }
+
+ NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, n_rates, rates);
+
+ argv++;
+ argc--;
+ }
+
if (argc) {
if (mac_addr_a2n(abssid, argv[0]) == 0) {
NLA_PUT(msg, NL80211_ATTR_MAC, 6, abssid);
@@ -73,7 +96,9 @@ static int leave_ibss(struct nl80211_state *state,
COMMAND(ibss, leave, NULL,
NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss,
"Leave the current IBSS cell.");
-COMMAND(ibss, join, "<SSID> <freq in MHz> [fixed-freq] [<fixed bssid>] [key d:0:abcde]",
+COMMAND(ibss, join,
+ "<SSID> <freq in MHz> [fixed-freq] [<fixed bssid>] "
+ "[basic-rates <rate in Mbps,rate2,...>] [key d:0:abcde]",
NL80211_CMD_JOIN_IBSS, 0, CIB_NETDEV, join_ibss,
"Join the IBSS cell with the given SSID, if it doesn't exist create\n"
"it on the given frequency. When fixed frequency is requested, don't\n"
--
1.5.6.3
^ permalink raw reply related
* Re: [RFC 3/3] mac80211: Store basic rates for bss when joining ibss network
From: Johannes Berg @ 2010-06-08 12:48 UTC (permalink / raw)
To: Teemu Paasikivi; +Cc: linville, linux-wireless
In-Reply-To: <1276000459-1121-4-git-send-email-ext-teemu.3.paasikivi@nokia.com>
On Tue, 2010-06-08 at 15:34 +0300, Teemu Paasikivi wrote:
> When joinig a ibss network, basic rates for bss were not stored. When
> network was self created, leaving and (re)joining same network has
> caused basic rates to be left unset. With this patch stored values are
> used.
> bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
> mgmt, skb->len, 0, GFP_KERNEL);
> +
> + ibss = (struct ieee80211_bss *)(bss->priv);
Watch out -- bss can be NULL here if memory allocation fails. It's just
that put_bss(NULL) is valid.
> + for (i = 0; i < sband->n_bitrates; i++) {
> + u8 basic = 0x00;
> + if (basic_rates & BIT(i))
> + basic = 0x80;
> +
> + ibss->supp_rates[i] = supp_rates[i] | basic;
> + }
> +
> + ibss->supp_rates_len = i;
> +
> cfg80211_put_bss(bss);
However this kinda confuses me.
We had a long-standing TODO item on our list at
http://wireless.kernel.org/en/developers/todo-list
"when leaving an IBSS and we were the only member, remove it from
cfg80211's BSS list"
Maybe that would help here too?
However I don't understand the scenario anyway. If you create an IBSS,
you start beaconing and tell cfg80211 about it with a frame that
includes the supported and basic rates. Then you leave, but the BSS
stays around in cfg80211 for 15 seconds. If you re-join within those 15
seconds, the scan results will pick up the old IBSS that no longer
exists, and we "join" it rather than creating it.
However -- joining it will take the basic rates from it. So wouldn't you
get the old basic rates which is fine? What do you mean by "left unset"?
What happens if you join an IBSS that already exists?
johannes
^ permalink raw reply
* [PATCHv2] mac80211: Fix circular locking dependency in ARP filter handling
From: Juuso Oikarinen @ 2010-06-08 13:05 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, reinette.chatre
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.
Additionally, this patch ensures that hardware ARP filtering is not enabled
when promiscuous mode is set.
Reported-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
v2: Do not enable ARP filtering if in promiscuous mode
include/net/mac80211.h | 34 +++++----
net/mac80211/driver-ops.h | 17 -----
net/mac80211/driver-trace.h | 25 -------
net/mac80211/ieee80211_i.h | 2 +
net/mac80211/main.c | 168 +++++++++++++++++++++++++++++--------------
net/mac80211/mlme.c | 39 ++++++----
6 files changed, 159 insertions(+), 126 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e3c1d47..f409d00 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -19,7 +19,6 @@
#include <linux/wireless.h>
#include <linux/device.h>
#include <linux/ieee80211.h>
-#include <linux/inetdevice.h>
#include <net/cfg80211.h>
/**
@@ -147,6 +146,7 @@ struct ieee80211_low_level_stats {
* enabled/disabled (beaconing modes)
* @BSS_CHANGED_CQM: Connection quality monitor config changed
* @BSS_CHANGED_IBSS: IBSS join status changed
+ * @BSS_CHANGED_ARP_FILTER: Hardware ARP filter address list or state changed.
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -161,10 +161,18 @@ enum ieee80211_bss_change {
BSS_CHANGED_BEACON_ENABLED = 1<<9,
BSS_CHANGED_CQM = 1<<10,
BSS_CHANGED_IBSS = 1<<11,
+ BSS_CHANGED_ARP_FILTER = 1<<12,
/* when adding here, make sure to change ieee80211_reconfig */
};
+/*
+ * The maximum number of IPv4 addresses listed for ARP filtering. If the number
+ * of addresses for an interface increase beyond this value, hardware ARP
+ * filtering will be disabled.
+ */
+#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
+
/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
@@ -200,6 +208,14 @@ enum ieee80211_bss_change {
* @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
* implies disabled
* @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
+ * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
+ * may filter ARP queries targeted for other addresses than listed here.
+ * The driver must allow ARP queries targeted for all address listed here
+ * to pass through. An empty list implies no ARP queries need to pass.
+ * @arp_addr_cnt: Number of addresses currently on the list.
+ * @arp_filter_enabled: Enable ARP filtering - if enabled, the hardware may
+ * filter ARP queries based on the @arp_addr_list, if disabled, the
+ * hardware must not perform any ARP filtering.
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -220,6 +236,9 @@ struct ieee80211_bss_conf {
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
enum nl80211_channel_type channel_type;
+ __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
+ u8 arp_addr_cnt;
+ bool arp_filter_enabled;
};
/**
@@ -1529,16 +1548,6 @@ enum ieee80211_ampdu_mlme_action {
* of the bss parameters has changed when a call is made. The callback
* can sleep.
*
- * @configure_arp_filter: Configuration function for hardware ARP query filter.
- * This function is called with all the IP addresses configured to the
- * interface as argument - all ARP queries targeted to any of these
- * addresses must pass through. If the hardware filter does not support
- * enought addresses, hardware filtering must be disabled. The ifa_list
- * argument may be NULL, indicating that filtering must be disabled.
- * This function is called upon association complete with current
- * address(es), and while associated whenever the IP address(es) change.
- * The callback can sleep.
- *
* @prepare_multicast: Prepare for multicast filter configuration.
* This callback is optional, and its return value is passed
* to configure_filter(). This callback must be atomic.
@@ -1678,9 +1687,6 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u32 changed);
- int (*configure_arp_filter)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct in_ifaddr *ifa_list);
u64 (*prepare_multicast)(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);
void (*configure_filter)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d1139e4..bbea3bc 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -83,23 +83,6 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
trace_drv_bss_info_changed(local, sdata, info, changed);
}
-struct in_ifaddr;
-static inline int drv_configure_arp_filter(struct ieee80211_local *local,
- struct ieee80211_vif *vif,
- struct in_ifaddr *ifa_list)
-{
- int ret = 0;
-
- might_sleep();
-
- if (local->ops->configure_arp_filter)
- ret = local->ops->configure_arp_filter(&local->hw, vif,
- ifa_list);
-
- trace_drv_configure_arp_filter(local, vif_to_sdata(vif), ifa_list, ret);
- return ret;
-}
-
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
struct netdev_hw_addr_list *mc_list)
{
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6b90630..1e293df 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -219,31 +219,6 @@ TRACE_EVENT(drv_bss_info_changed,
)
);
-TRACE_EVENT(drv_configure_arp_filter,
- TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct in_ifaddr *ifa_list, int ret),
-
- TP_ARGS(local, sdata, ifa_list, ret),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- VIF_ENTRY
- __field(int, ret)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- VIF_ASSIGN;
- __entry->ret = ret;
- ),
-
- TP_printk(
- VIF_PR_FMT LOCAL_PR_FMT " ret:%d",
- VIF_PR_ARG, LOCAL_PR_ARG, __entry->ret
- )
-);
-
TRACE_EVENT(drv_prepare_multicast,
TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 4d3883e..79e366e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -517,6 +517,8 @@ struct ieee80211_sub_if_data {
u16 sequence_number;
+ bool arp_filter_state;
+
/*
* AP this belongs to: self in AP mode and
* corresponding AP in VLAN mode, NULL for
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 5706156..8398d36 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -20,6 +20,7 @@
#include <linux/rtnetlink.h>
#include <linux/bitmap.h>
#include <linux/pm_qos_params.h>
+#include <linux/inetdevice.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
@@ -84,12 +85,125 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
local->filter_flags = new_flags & ~(1<<31);
}
+#ifdef CONFIG_INET
+static void ieee80211_reconfig_arp_filter(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_managed *ifmgd;
+ struct ieee80211_bss_conf *bss_conf;
+ u32 changed;
+ bool promisc;
+ bool old_state;
+
+ /* Check ARP filtering state for each interface */
+ rtnl_lock();
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ continue;
+
+ ifmgd = &sdata->u.mgd;
+ mutex_lock(&ifmgd->mtx);
+ if (!ifmgd->associated) {
+ mutex_unlock(&ifmgd->mtx);
+ continue;
+ }
+
+ bss_conf = &sdata->vif.bss_conf;
+
+ old_state = !!(bss_conf->arp_filter_enabled);
+
+ promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
+ if (promisc)
+ bss_conf->arp_filter_enabled = 0;
+ else
+ bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+
+ if (old_state != bss_conf->arp_filter_enabled) {
+ changed = BSS_CHANGED_ARP_FILTER;
+ ieee80211_bss_info_change_notify(sdata, changed);
+ }
+
+ mutex_unlock(&ifmgd->mtx);
+ }
+ rtnl_unlock();
+}
+
+static int ieee80211_ifa_changed(struct notifier_block *nb,
+ unsigned long data, void *arg)
+{
+ struct in_ifaddr *ifa = arg;
+ struct ieee80211_local *local =
+ container_of(nb, struct ieee80211_local,
+ ifa_notifier);
+ struct net_device *ndev = ifa->ifa_dev->dev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
+ struct in_device *idev;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_bss_conf *bss_conf;
+ struct ieee80211_if_managed *ifmgd;
+ int c = 0;
+
+ /* Make sure it's our interface that got changed */
+ if (!wdev)
+ return NOTIFY_DONE;
+
+ if (wdev->wiphy != local->hw.wiphy)
+ return NOTIFY_DONE;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ bss_conf = &sdata->vif.bss_conf;
+
+ /* ARP filtering is only supported in managed mode */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return NOTIFY_DONE;
+
+ idev = sdata->dev->ip_ptr;
+ if (!idev)
+ return NOTIFY_DONE;
+
+ ifmgd = &sdata->u.mgd;
+ mutex_lock(&ifmgd->mtx);
+
+ /* Copy the addresses to the bss_conf list */
+ ifa = idev->ifa_list;
+ while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) {
+ bss_conf->arp_addr_list[c] = ifa->ifa_address;
+ ifa = ifa->ifa_next;
+ c++;
+ }
+
+ /* If not all addresses fit the list, disable filtering */
+ if (ifa) {
+ sdata->arp_filter_state = false;
+ c = 0;
+ } else {
+ sdata->arp_filter_state = true;
+ }
+ bss_conf->arp_addr_cnt = c;
+
+ /* Configure driver only if associated and not in promiscuous mode */
+ if (ifmgd->associated && !(sdata->flags & IEEE80211_SDATA_PROMISC)) {
+ bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_ARP_FILTER);
+ }
+
+ mutex_unlock(&ifmgd->mtx);
+
+ return NOTIFY_DONE;
+}
+#endif
+
static void ieee80211_reconfig_filter(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, reconfig_filter);
ieee80211_configure_filter(local);
+
+#ifdef CONFIG_INET
+ ieee80211_reconfig_arp_filter(local);
+#endif
}
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
@@ -329,60 +443,6 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
mutex_unlock(&local->iflist_mtx);
}
-#ifdef CONFIG_INET
-int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata)
-{
- struct in_device *idev;
- int ret = 0;
-
- BUG_ON(!sdata);
- ASSERT_RTNL();
-
- idev = sdata->dev->ip_ptr;
- if (!idev)
- return 0;
-
- ret = drv_configure_arp_filter(sdata->local, &sdata->vif,
- idev->ifa_list);
- return ret;
-}
-
-static int ieee80211_ifa_changed(struct notifier_block *nb,
- unsigned long data, void *arg)
-{
- struct in_ifaddr *ifa = arg;
- struct ieee80211_local *local =
- container_of(nb, struct ieee80211_local,
- ifa_notifier);
- struct net_device *ndev = ifa->ifa_dev->dev;
- struct wireless_dev *wdev = ndev->ieee80211_ptr;
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_if_managed *ifmgd;
-
- /* Make sure it's our interface that got changed */
- if (!wdev)
- return NOTIFY_DONE;
-
- if (wdev->wiphy != local->hw.wiphy)
- return NOTIFY_DONE;
-
- /* We are concerned about IP addresses only when associated */
- sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
-
- /* ARP filtering is only supported in managed mode */
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- return NOTIFY_DONE;
-
- ifmgd = &sdata->u.mgd;
- mutex_lock(&ifmgd->mtx);
- if (ifmgd->associated)
- ieee80211_set_arp_filter(sdata);
- mutex_unlock(&ifmgd->mtx);
-
- return NOTIFY_DONE;
-}
-#endif
-
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ac68c41..d328e9a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -806,11 +806,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_bss *bss = (void *)cbss->priv;
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
bss_info_changed |= BSS_CHANGED_ASSOC;
/* set timing information */
- sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
- sdata->vif.bss_conf.timestamp = cbss->tsf;
+ bss_conf->beacon_int = cbss->beacon_interval;
+ bss_conf->timestamp = cbss->tsf;
bss_info_changed |= BSS_CHANGED_BEACON_INT;
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
@@ -835,7 +836,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_led_assoc(local, 1);
- sdata->vif.bss_conf.assoc = 1;
+ bss_conf->assoc = 1;
/*
* For now just always ask the driver to update the basic rateset
* when we have associated, we aren't checking whether it actually
@@ -848,9 +849,18 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
/* Tell the driver to monitor connection quality (if supported) */
if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) &&
- sdata->vif.bss_conf.cqm_rssi_thold)
+ bss_conf->cqm_rssi_thold)
bss_info_changed |= BSS_CHANGED_CQM;
+#ifdef CONFIG_INET
+ /* Enable ARP filtering unless in promisc mode */
+ if (!(sdata->flags & IEEE80211_SDATA_PROMISC) &&
+ bss_conf->arp_filter_enabled != sdata->arp_filter_state) {
+ bss_conf->arp_filter_enabled = sdata->arp_filter_state;
+ bss_info_changed |= BSS_CHANGED_ARP_FILTER;
+ }
+#endif
+
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
mutex_lock(&local->iflist_mtx);
@@ -932,6 +942,13 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_hw_config(local, config_changed);
+ /* Disable ARP filtering */
+ if (sdata->vif.bss_conf.arp_filter_enabled) {
+ sdata->vif.bss_conf.arp_filter_enabled = false;
+ changed |= BSS_CHANGED_ARP_FILTER;
+ }
+
+
/* The BSSID (not really interesting) and HT changed */
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);
@@ -2116,19 +2133,9 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
cfg80211_send_assoc_timeout(wk->sdata->dev,
wk->filter_ta);
return WORK_DONE_DESTROY;
-#ifdef CONFIG_INET
- } else {
- mutex_unlock(&wk->sdata->u.mgd.mtx);
-
- /*
- * configure ARP filter IP addresses to the driver,
- * intentionally outside the mgd mutex.
- */
- rtnl_lock();
- ieee80211_set_arp_filter(wk->sdata);
- rtnl_unlock();
-#endif
}
+
+ mutex_unlock(&wk->sdata->u.mgd.mtx);
}
cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCHv2] mac80211: Fix circular locking dependency in ARP filter handling
From: Johannes Berg @ 2010-06-08 13:14 UTC (permalink / raw)
To: Juuso Oikarinen; +Cc: linville, linux-wireless, reinette.chatre
In-Reply-To: <1276002335-18600-1-git-send-email-juuso.oikarinen@nokia.com>
On Tue, 2010-06-08 at 16:05 +0300, Juuso Oikarinen wrote:
> + promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
> + if (promisc)
> + bss_conf->arp_filter_enabled = 0;
> + else
> + bss_conf->arp_filter_enabled = sdata->arp_filter_state;
bss_conf->arp_filter_enabled = !promisc && sdata->arp_filter_state;
?
Or if not, use false instead of 0 please.
johannes
^ permalink raw reply
* Re: [PATCH 1/3] Libertas: cfg80211 support
From: John W. Linville @ 2010-06-08 13:30 UTC (permalink / raw)
To: Kiran Divekar
Cc: linux-wireless@vger.kernel.org, libertas-dev@lists.infradead.org,
Amitkumar Karwar
In-Reply-To: <25B60CDC2F704E4E9D88FFD52780CB4C04D6389ABB@SC-VEXCH1.marvell.com>
On Fri, Jun 04, 2010 at 11:20:18PM -0700, Kiran Divekar wrote:
> Holger Schurig's patch (https://patchwork.kernel.org/patch/64286/)
> is rebased to latest wireless-testing tree.
>
> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
> Signed-off-by: Kiran Divekar <dkiran@marvell.com>
> Tested-by: Amitkumar Karwar <akarwar@marvell.com>
I think that your 'latest wireless-testing tree' is not up-to-date.
Please ensure that your local tree has the following commit:
commit 77c2061d10a408d0220c2b0e7faefe52d9c41008
Author: Walter Goldens <goldenstranger@yahoo.com>
Date: Tue May 18 04:44:54 2010 -0700
wireless: fix several minor description typos
Signed-off-by: Walter Goldens <goldenstranger@yahoo.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
I really want your patch, but as presented it fails to apply so
spectacularly that I'm afraid to even start trying to fix it up. :-(
John
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply
* Re: kernel BUG in iwl-agn-rs.c:2076, WAS: iwlagn + some accesspoint == hardlock
From: reinette chatre @ 2010-06-08 17:46 UTC (permalink / raw)
To: Nils Radtke
Cc: linville@tuxdriver.com, linux-kernel@vger.kernel.org,
linux-wireless@vger.kernel.org
In-Reply-To: <20100604165732.GB28003@localhost>
On Fri, 2010-06-04 at 09:57 -0700, Nils Radtke wrote:
> I haven't yet received a comment of yours regarding my many other questions in
> my previous message. I am willing to help investigate more, assist in other ways
> than testing only (always only doing testing isn't a way to keep up fun..)
Your messages contain references to many issues and it is becoming
increasingly hard to keep track of them all in a single email thread.
Since the system crash is clearly the big issue I would like to focus on
that and get that resolved. This is why I proposed that you create bug
reports to help track your various issues better.
Reinette
^ permalink raw reply
* [PATCH] Bug 16111 - hostap_pci: infinite registered netdevice wifi0
From: Tim Gardner @ 2010-06-08 17:58 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless@vger.kernel.org, Colin King
[-- Attachment #1: Type: text/plain, Size: 241 bytes --]
John,
With regard to https://bugzilla.kernel.org/show_bug.cgi?id=16111
This patch is against 2.6.35-rc2. I beleive the patch is suitable for
stable, but it definitely needs to be backported.
rtg
--
Tim Gardner tim.gardner@canonical.com
[-- Attachment #2: 0001-hostap-Protect-against-initialization-interrupt.patch --]
[-- Type: text/x-patch, Size: 4098 bytes --]
>From c8422f9ee8ee77b1d248f3b76d2c0d593fd43282 Mon Sep 17 00:00:00 2001
From: Tim Gardner <tim.gardner@canonical.com>
Date: Tue, 8 Jun 2010 11:33:02 -0600
Subject: [PATCH] hostap: Protect against initialization interrupt
Use an irq spinlock to hold off the IRQ handler until
enough early card init is complete such that the handler
can run without faulting.
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Cc: stable@kernel.org
---
drivers/net/wireless/hostap/hostap_cs.c | 15 +++++++++++++--
drivers/net/wireless/hostap/hostap_hw.c | 10 +++++++---
drivers/net/wireless/hostap/hostap_wlan.h | 2 +-
3 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index db72461..29b31a6 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -594,6 +594,7 @@ static int prism2_config(struct pcmcia_device *link)
local_info_t *local;
int ret = 1;
struct hostap_cs_priv *hw_priv;
+ unsigned long flags;
PDEBUG(DEBUG_FLOW, "prism2_config()\n");
@@ -625,9 +626,15 @@ static int prism2_config(struct pcmcia_device *link)
local->hw_priv = hw_priv;
hw_priv->link = link;
+ /*
+ * Make sure the IRQ handler cannot proceed until at least
+ * dev->base_addr is initialized.
+ */
+ spin_lock_irqsave(&local->irq_init_lock, flags);
+
ret = pcmcia_request_irq(link, prism2_interrupt);
if (ret)
- goto failed;
+ goto failed_unlock;
/*
* This actually configures the PCMCIA socket -- setting up
@@ -636,11 +643,13 @@ static int prism2_config(struct pcmcia_device *link)
*/
ret = pcmcia_request_configuration(link, &link->conf);
if (ret)
- goto failed;
+ goto failed_unlock;
dev->irq = link->irq;
dev->base_addr = link->io.BasePort1;
+ spin_unlock_irqrestore(&local->irq_init_lock, flags);
+
/* Finally, report what we've done */
printk(KERN_INFO "%s: index 0x%02x: ",
dev_info, link->conf.ConfigIndex);
@@ -667,6 +676,8 @@ static int prism2_config(struct pcmcia_device *link)
return ret;
+ failed_unlock:
+ spin_unlock_irqrestore(&local->irq_init_lock, flags);
failed:
kfree(hw_priv);
prism2_release((u_long)link);
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index d707328..2f999fc 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2618,17 +2618,20 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
int events = 0;
u16 ev;
+ iface = netdev_priv(dev);
+ local = iface->local;
+
/* Detect early interrupt before driver is fully configued */
+ spin_lock(&local->irq_init_lock);
if (!dev->base_addr) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
dev->name);
}
+ spin_unlock(&local->irq_init_lock);
return IRQ_HANDLED;
}
-
- iface = netdev_priv(dev);
- local = iface->local;
+ spin_unlock(&local->irq_init_lock);
prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
@@ -3147,6 +3150,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
spin_lock_init(&local->cmdlock);
spin_lock_init(&local->baplock);
spin_lock_init(&local->lock);
+ spin_lock_init(&local->irq_init_lock);
mutex_init(&local->rid_bap_mtx);
if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index 3d23891..1ba33be 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -654,7 +654,7 @@ struct local_info {
rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock
* when removing entries from the list.
* TX and RX paths can use read lock. */
- spinlock_t cmdlock, baplock, lock;
+ spinlock_t cmdlock, baplock, lock, irq_init_lock;
struct mutex rid_bap_mtx;
u16 infofid; /* MAC buffer id for info frame */
/* txfid, intransmitfid, next_txtid, and next_alloc are protected by
--
1.7.0.4
^ permalink raw reply related
* pull request: wireless-2.6 2010-06-08
From: John W. Linville @ 2010-06-08 19:02 UTC (permalink / raw)
To: davem; +Cc: linux-wireless, netdev, linux-kernel
Dave,
Here is a flurry of fixes intended for 2.6.35. Most of them are small
and obvious, but there are a few exceptions...I'll include some text from
the iwlwifi pull request:
We include four fixes. This series includes the overdue 3945 fix to
internal scanning. The system hang issue fixed by this patch is
encountered by many people, see:
http://thread.gmane.org/gmane.linux.kernel/994562
http://thread.gmane.org/gmane.linux.kernel.wireless.general/51343
http://thread.gmane.org/gmane.linux.kernel.wireless.general/51614
http://thread.gmane.org/gmane.linux.kernel/992191/focus=51561
We include a second fix for iwl3945 that enables a workaround to detect
and
recover when the command queue, or a transmit queue, becomes stuck.
Unfortunately users seem to be running into this issue more frequently
now.
The bugs related to this issue is noted in the commit message.
A third fix addresses a lockdep warning.
We also include an update to the MAINTAINERS file that we would like to
include in 2.6.35 since Wey-Yi will be maintainer during this
kernel's stabilization as well as thereafter.
The iwlwifi bits are bigger than I would like to see, but the fixes
seem worthwhile. Also included is a revert of a hostap patch that
introduced failures with some devices, a NULL pointer dereference fix,
a memory leak fix, a fix for an incorrect check of function pointer,
a USB ID for p54, and a fix for an association failure 'corner case'
from Johannes.
Please let me know if there are problems!
Thanks,
John
---
The following changes since commit 035320d54758e21227987e3aae0d46e7a04f4ddc:
Eric Dumazet (1):
ipmr: dont corrupt lists
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git master
Abhijeet Kolekar (1):
iwl3945: fix internal scan
Bob Copeland (1):
ath5k: retain promiscuous setting
Bruno Randolf (1):
ath5k: fix NULL pointer in antenna configuration
Emmanuel Grumbach (1):
iwlwifi: move sysfs_create_group to post request firmware
Grazvydas Ignotas (1):
wl1251: fix a memory leak in probe
Holger Schurig (1):
mac80211: fix function pointer check
Jason Dravet (1):
p54usb: Add device ID for Dell WLA3310 USB
Johannes Berg (3):
mac80211: process station blockack action frames from work
iwlwifi: add missing rcu_read_lock
mac80211: fix deauth before assoc
John W. Linville (1):
Revert "wireless: hostap, fix oops due to early probing interrupt"
Reinette Chatre (1):
iwl3945: enable stuck queue detection on 3945
Tobias Doerffel (1):
ath5k: depend on CONFIG_PM_SLEEP for suspend/resume functions
Wey-Yi Guy (1):
iwlwifi: add name to Maintainers list
Zhu Yi (1):
wireless: remove my name from the maintainer list
MAINTAINERS | 5 +-
drivers/net/wireless/ath/ath5k/base.c | 12 +-
drivers/net/wireless/ath/ath5k/phy.c | 7 +
drivers/net/wireless/hostap/hostap_hw.c | 9 -
drivers/net/wireless/iwlwifi/iwl-3945.c | 1 +
drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 30 +---
drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 2 +
drivers/net/wireless/iwlwifi/iwl-agn.c | 318 +++++++++++++-------------
drivers/net/wireless/iwlwifi/iwl-core.c | 39 ++++
drivers/net/wireless/iwlwifi/iwl-core.h | 2 +
drivers/net/wireless/iwlwifi/iwl3945-base.c | 56 +++++-
drivers/net/wireless/p54/p54usb.c | 1 +
drivers/net/wireless/wl12xx/wl1251_sdio.c | 1 +
net/mac80211/driver-ops.h | 2 +-
net/mac80211/mlme.c | 92 +++++++-
net/mac80211/rx.c | 3 +
16 files changed, 362 insertions(+), 218 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 22a49e6..83be538 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2966,7 +2966,6 @@ F: drivers/net/ixgb/
F: drivers/net/ixgbe/
INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
-M: Zhu Yi <yi.zhu@intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
@@ -2976,7 +2975,6 @@ F: Documentation/networking/README.ipw2100
F: drivers/net/wireless/ipw2x00/ipw2100.*
INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT
-M: Zhu Yi <yi.zhu@intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
@@ -3007,8 +3005,8 @@ F: drivers/net/wimax/i2400m/
F: include/linux/wimax/i2400m.h
INTEL WIRELESS WIFI LINK (iwlwifi)
-M: Zhu Yi <yi.zhu@intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
+M: Wey-Yi Guy <wey-yi.w.guy@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
W: http://intellinuxwireless.org
@@ -3018,7 +3016,6 @@ F: drivers/net/wireless/iwlwifi/
INTEL WIRELESS MULTICOMM 3200 WIFI (iwmc3200wifi)
M: Samuel Ortiz <samuel.ortiz@intel.com>
-M: Zhu Yi <yi.zhu@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
S: Supported
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 2978359..648972d 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -195,7 +195,7 @@ static const struct ieee80211_rate ath5k_rates[] = {
static int __devinit ath5k_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void __devexit ath5k_pci_remove(struct pci_dev *pdev);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ath5k_pci_suspend(struct device *dev);
static int ath5k_pci_resume(struct device *dev);
@@ -203,7 +203,7 @@ static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
#define ATH5K_PM_OPS (&ath5k_pm_ops)
#else
#define ATH5K_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver ath5k_pci_driver = {
.name = KBUILD_MODNAME,
@@ -708,7 +708,7 @@ ath5k_pci_remove(struct pci_dev *pdev)
ieee80211_free_hw(hw);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ath5k_pci_suspend(struct device *dev)
{
struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev));
@@ -734,7 +734,7 @@ static int ath5k_pci_resume(struct device *dev)
ath5k_led_enable(sc);
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
/***********************\
@@ -3140,13 +3140,15 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
if (*new_flags & FIF_PROMISC_IN_BSS) {
- rfilt |= AR5K_RX_FILTER_PROM;
__set_bit(ATH_STAT_PROMISC, sc->status);
} else {
__clear_bit(ATH_STAT_PROMISC, sc->status);
}
}
+ if (test_bit(ATH_STAT_PROMISC, sc->status))
+ rfilt |= AR5K_RX_FILTER_PROM;
+
/* Note, AR5K_RX_FILTER_MCAST is already enabled */
if (*new_flags & FIF_ALLMULTI) {
mfilt[0] = ~0;
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 1b81c47..492cbb1 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1814,6 +1814,13 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
u8 def_ant, tx_ant, ee_mode;
u32 sta_id1 = 0;
+ /* if channel is not initialized yet we can't set the antennas
+ * so just store the mode. it will be set on the next reset */
+ if (channel == NULL) {
+ ah->ah_ant_mode = ant_mode;
+ return;
+ }
+
def_ant = ah->ah_def_ant;
ATH5K_TRACE(ah->ah_sc);
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index d707328..ff9b5c8 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2618,15 +2618,6 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
int events = 0;
u16 ev;
- /* Detect early interrupt before driver is fully configued */
- if (!dev->base_addr) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
- dev->name);
- }
- return IRQ_HANDLED;
- }
-
iface = netdev_priv(dev);
local = iface->local;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 068f7f8..c44a303 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -2852,6 +2852,7 @@ static struct iwl_lib_ops iwl3945_lib = {
.isr = iwl_isr_legacy,
.config_ap = iwl3945_config_ap,
.manage_ibss_station = iwl3945_manage_ibss_station,
+ .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl3945_good_plcp_health,
.debugfs_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 1004cfc..0f292a2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1119,10 +1119,9 @@ static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
struct iwl_scan_channel *scan_ch)
{
const struct ieee80211_supported_band *sband;
- const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
u16 active_dwell = 0;
- int i, added = 0;
+ int added = 0;
u16 channel = 0;
sband = iwl_get_hw_mode(priv, band);
@@ -1137,32 +1136,7 @@ static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
if (passive_dwell <= active_dwell)
passive_dwell = active_dwell + 1;
- /* only scan single channel, good enough to reset the RF */
- /* pick the first valid not in-use channel */
- if (band == IEEE80211_BAND_5GHZ) {
- for (i = 14; i < priv->channel_count; i++) {
- if (priv->channel_info[i].channel !=
- le16_to_cpu(priv->staging_rxon.channel)) {
- channel = priv->channel_info[i].channel;
- ch_info = iwl_get_channel_info(priv,
- band, channel);
- if (is_channel_valid(ch_info))
- break;
- }
- }
- } else {
- for (i = 0; i < 14; i++) {
- if (priv->channel_info[i].channel !=
- le16_to_cpu(priv->staging_rxon.channel)) {
- channel =
- priv->channel_info[i].channel;
- ch_info = iwl_get_channel_info(priv,
- band, channel);
- if (is_channel_valid(ch_info))
- break;
- }
- }
- }
+ channel = iwl_get_single_channel_number(priv, band);
if (channel) {
scan_ch->channel = cpu_to_le16(channel);
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index c402bfc..a732f10 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -1125,6 +1125,7 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
struct ieee80211_sta *sta;
struct iwl_station_priv *sta_priv;
+ rcu_read_lock();
sta = ieee80211_find_sta(priv->vif, hdr->addr1);
if (sta) {
sta_priv = (void *)sta->drv_priv;
@@ -1133,6 +1134,7 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
atomic_dec_return(&sta_priv->pending_frames) == 0)
ieee80211_sta_block_awake(priv->hw, sta, false);
}
+ rcu_read_unlock();
ieee80211_tx_status_irqsafe(priv->hw, skb);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index aef4f71..7726e67 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1484,6 +1484,156 @@ bool iwl_good_ack_health(struct iwl_priv *priv,
}
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ *
+ * The debug_level being managed using sysfs below is a per device debug
+ * level that is used instead of the global debug level if it (the per
+ * device debug level) is set.
+ */
+static ssize_t show_debug_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
+}
+static ssize_t store_debug_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret)
+ IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
+ else {
+ priv->debug_level = val;
+ if (iwl_alloc_traffic_mem(priv))
+ IWL_ERR(priv,
+ "Not enough memory to generate traffic log\n");
+ }
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ show_debug_level, store_debug_level);
+
+
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+
+static ssize_t show_temperature(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", priv->temperature);
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (!iwl_is_ready_rf(priv))
+ return sprintf(buf, "off\n");
+ else
+ return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
+}
+
+static ssize_t store_tx_power(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ IWL_INFO(priv, "%s is not in decimal form.\n", buf);
+ else {
+ ret = iwl_set_tx_power(priv, val, false);
+ if (ret)
+ IWL_ERR(priv, "failed setting tx power (0x%d).\n",
+ ret);
+ else
+ ret = count;
+ }
+ return ret;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_rts_ht_protection(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ return sprintf(buf, "%s\n",
+ priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
+}
+
+static ssize_t store_rts_ht_protection(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ IWL_INFO(priv, "Input is not in decimal form.\n");
+ else {
+ if (!iwl_is_associated(priv))
+ priv->cfg->use_rts_for_ht = val ? true : false;
+ else
+ IWL_ERR(priv, "Sta associated with AP - "
+ "Change protection mechanism is not allowed\n");
+ ret = count;
+ }
+ return ret;
+}
+
+static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
+ show_rts_ht_protection, store_rts_ht_protection);
+
+
+static struct attribute *iwl_sysfs_entries[] = {
+ &dev_attr_temperature.attr,
+ &dev_attr_tx_power.attr,
+ &dev_attr_rts_ht_protection.attr,
+#ifdef CONFIG_IWLWIFI_DEBUG
+ &dev_attr_debug_level.attr,
+#endif
+ NULL
+};
+
+static struct attribute_group iwl_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = iwl_sysfs_entries,
+};
+
/******************************************************************************
*
* uCode download functions
@@ -1965,6 +2115,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
if (err)
IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
+ err = sysfs_create_group(&priv->pci_dev->dev.kobj,
+ &iwl_attribute_group);
+ if (err) {
+ IWL_ERR(priv, "failed to create sysfs device attributes\n");
+ goto out_unbind;
+ }
+
/* We have our copies now, allow OS release its copies */
release_firmware(ucode_raw);
complete(&priv->_agn.firmware_loading_complete);
@@ -3264,141 +3421,6 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
/*****************************************************************************
*
- * sysfs attributes
- *
- *****************************************************************************/
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/*
- * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
- * used for controlling the debug level.
- *
- * See the level definitions in iwl for details.
- *
- * The debug_level being managed using sysfs below is a per device debug
- * level that is used instead of the global debug level if it (the per
- * device debug level) is set.
- */
-static ssize_t show_debug_level(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
-}
-static ssize_t store_debug_level(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret)
- IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
- else {
- priv->debug_level = val;
- if (iwl_alloc_traffic_mem(priv))
- IWL_ERR(priv,
- "Not enough memory to generate traffic log\n");
- }
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
- show_debug_level, store_debug_level);
-
-
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-
-static ssize_t show_temperature(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- if (!iwl_is_alive(priv))
- return -EAGAIN;
-
- return sprintf(buf, "%d\n", priv->temperature);
-}
-
-static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
-
-static ssize_t show_tx_power(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- if (!iwl_is_ready_rf(priv))
- return sprintf(buf, "off\n");
- else
- return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
-}
-
-static ssize_t store_tx_power(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 10, &val);
- if (ret)
- IWL_INFO(priv, "%s is not in decimal form.\n", buf);
- else {
- ret = iwl_set_tx_power(priv, val, false);
- if (ret)
- IWL_ERR(priv, "failed setting tx power (0x%d).\n",
- ret);
- else
- ret = count;
- }
- return ret;
-}
-
-static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
-
-static ssize_t show_rts_ht_protection(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "%s\n",
- priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
-}
-
-static ssize_t store_rts_ht_protection(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 10, &val);
- if (ret)
- IWL_INFO(priv, "Input is not in decimal form.\n");
- else {
- if (!iwl_is_associated(priv))
- priv->cfg->use_rts_for_ht = val ? true : false;
- else
- IWL_ERR(priv, "Sta associated with AP - "
- "Change protection mechanism is not allowed\n");
- ret = count;
- }
- return ret;
-}
-
-static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
- show_rts_ht_protection, store_rts_ht_protection);
-
-
-/*****************************************************************************
- *
* driver setup and teardown
*
*****************************************************************************/
@@ -3550,21 +3572,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
kfree(priv->scan_cmd);
}
-static struct attribute *iwl_sysfs_entries[] = {
- &dev_attr_temperature.attr,
- &dev_attr_tx_power.attr,
- &dev_attr_rts_ht_protection.attr,
-#ifdef CONFIG_IWLWIFI_DEBUG
- &dev_attr_debug_level.attr,
-#endif
- NULL
-};
-
-static struct attribute_group iwl_attribute_group = {
- .name = NULL, /* put in device directory */
- .attrs = iwl_sysfs_entries,
-};
-
static struct ieee80211_ops iwl_hw_ops = {
.tx = iwl_mac_tx,
.start = iwl_mac_start,
@@ -3750,11 +3757,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
goto out_disable_msi;
}
- err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
- if (err) {
- IWL_ERR(priv, "failed to create sysfs device attributes\n");
- goto out_free_irq;
- }
iwl_setup_deferred_work(priv);
iwl_setup_rx_handlers(priv);
@@ -3788,15 +3790,13 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = iwl_request_firmware(priv, true);
if (err)
- goto out_remove_sysfs;
+ goto out_destroy_workqueue;
return 0;
- out_remove_sysfs:
+ out_destroy_workqueue:
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
- sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
- out_free_irq:
free_irq(priv->pci_dev->irq, priv);
iwl_free_isr_ict(priv);
out_disable_msi:
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5a7eca8..426e955 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -854,6 +854,45 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_set_rxon_chain);
+/* Return valid channel */
+u8 iwl_get_single_channel_number(struct iwl_priv *priv,
+ enum ieee80211_band band)
+{
+ const struct iwl_channel_info *ch_info;
+ int i;
+ u8 channel = 0;
+
+ /* only scan single channel, good enough to reset the RF */
+ /* pick the first valid not in-use channel */
+ if (band == IEEE80211_BAND_5GHZ) {
+ for (i = 14; i < priv->channel_count; i++) {
+ if (priv->channel_info[i].channel !=
+ le16_to_cpu(priv->staging_rxon.channel)) {
+ channel = priv->channel_info[i].channel;
+ ch_info = iwl_get_channel_info(priv,
+ band, channel);
+ if (is_channel_valid(ch_info))
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < 14; i++) {
+ if (priv->channel_info[i].channel !=
+ le16_to_cpu(priv->staging_rxon.channel)) {
+ channel =
+ priv->channel_info[i].channel;
+ ch_info = iwl_get_channel_info(priv,
+ band, channel);
+ if (is_channel_valid(ch_info))
+ break;
+ }
+ }
+ }
+
+ return channel;
+}
+EXPORT_SYMBOL(iwl_get_single_channel_number);
+
/**
* iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
* @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 7e5a5ba..31775bd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -343,6 +343,8 @@ int iwl_check_rxon_cmd(struct iwl_priv *priv);
int iwl_full_rxon_required(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
+u8 iwl_get_single_channel_number(struct iwl_priv *priv,
+ enum ieee80211_band band);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *sta_ht_inf);
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 3e5bffb..6c353ca 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -1844,6 +1844,49 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
#endif
}
+static int iwl3945_get_single_channel_for_scan(struct iwl_priv *priv,
+ struct ieee80211_vif *vif,
+ enum ieee80211_band band,
+ struct iwl3945_scan_channel *scan_ch)
+{
+ const struct ieee80211_supported_band *sband;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int added = 0;
+ u8 channel = 0;
+
+ sband = iwl_get_hw_mode(priv, band);
+ if (!sband) {
+ IWL_ERR(priv, "invalid band\n");
+ return added;
+ }
+
+ active_dwell = iwl_get_active_dwell_time(priv, band, 0);
+ passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
+
+ if (passive_dwell <= active_dwell)
+ passive_dwell = active_dwell + 1;
+
+
+ channel = iwl_get_single_channel_number(priv, band);
+
+ if (channel) {
+ scan_ch->channel = channel;
+ scan_ch->type = 0; /* passive */
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+ /* Set txpower levels to defaults */
+ scan_ch->tpc.dsp_atten = 110;
+ if (band == IEEE80211_BAND_5GHZ)
+ scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else
+ scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+ added++;
+ } else
+ IWL_ERR(priv, "no valid channel found\n");
+ return added;
+}
+
static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
enum ieee80211_band band,
u8 is_active, u8 n_probes,
@@ -2992,9 +3035,16 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
/* select Rx antennas */
scan->flags |= iwl3945_get_antenna_flags(priv);
- scan->channel_count =
- iwl3945_get_channels_for_scan(priv, band, is_active, n_probes,
- (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif);
+ if (priv->is_internal_short_scan) {
+ scan->channel_count =
+ iwl3945_get_single_channel_for_scan(priv, vif, band,
+ (void *)&scan->data[le16_to_cpu(
+ scan->tx_cmd.len)]);
+ } else {
+ scan->channel_count =
+ iwl3945_get_channels_for_scan(priv, band, is_active, n_probes,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif);
+ }
if (scan->channel_count == 0) {
IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index d5b197b..7307325 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -80,6 +80,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
{USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
{USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
+ {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
{USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
{USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
{}
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c
index d234285..c561332 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c
@@ -259,6 +259,7 @@ disable:
sdio_disable_func(func);
release:
sdio_release_host(func);
+ wl1251_free_hw(wl);
return ret;
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4f22713..9c1da08 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -349,7 +349,7 @@ static inline int drv_get_survey(struct ieee80211_local *local, int idx,
struct survey_info *survey)
{
int ret = -EOPNOTSUPP;
- if (local->ops->conf_tx)
+ if (local->ops->get_survey)
ret = local->ops->get_survey(&local->hw, idx, survey);
/* trace_drv_get_survey(local, idx, survey, ret); */
return ret;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0839c4e..f803f8b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1692,14 +1692,52 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
break;
case IEEE80211_STYPE_ACTION:
- if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
+ switch (mgmt->u.action.category) {
+ case WLAN_CATEGORY_BACK: {
+ struct ieee80211_local *local = sdata->local;
+ int len = skb->len;
+ struct sta_info *sta;
+
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->sa);
+ if (!sta) {
+ rcu_read_unlock();
+ break;
+ }
+
+ local_bh_disable();
+
+ switch (mgmt->u.action.u.addba_req.action_code) {
+ case WLAN_ACTION_ADDBA_REQ:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.addba_req)))
+ break;
+ ieee80211_process_addba_request(local, sta, mgmt, len);
+ break;
+ case WLAN_ACTION_ADDBA_RESP:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.addba_resp)))
+ break;
+ ieee80211_process_addba_resp(local, sta, mgmt, len);
+ break;
+ case WLAN_ACTION_DELBA:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.delba)))
+ break;
+ ieee80211_process_delba(sdata, sta, mgmt, len);
+ break;
+ }
+ local_bh_enable();
+ rcu_read_unlock();
break;
-
- ieee80211_sta_process_chanswitch(sdata,
- &mgmt->u.action.u.chan_switch.sw_elem,
- (void *)ifmgd->associated->priv,
- rx_status->mactime);
- break;
+ }
+ case WLAN_CATEGORY_SPECTRUM_MGMT:
+ ieee80211_sta_process_chanswitch(sdata,
+ &mgmt->u.action.u.chan_switch.sw_elem,
+ (void *)ifmgd->associated->priv,
+ rx_status->mactime);
+ break;
+ }
}
mutex_unlock(&ifmgd->mtx);
@@ -1722,9 +1760,45 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&ifmgd->mtx);
if (skb->len >= 24 + 2 /* mgmt + deauth reason */ &&
- (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH)
- cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
+ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) {
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_work *wk;
+
+ mutex_lock(&local->work_mtx);
+ list_for_each_entry(wk, &local->work_list, list) {
+ if (wk->sdata != sdata)
+ continue;
+
+ if (wk->type != IEEE80211_WORK_ASSOC)
+ continue;
+
+ if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN))
+ continue;
+ if (memcmp(mgmt->sa, wk->filter_ta, ETH_ALEN))
+ continue;
+ /*
+ * Printing the message only here means we can't
+ * spuriously print it, but it also means that it
+ * won't be printed when the frame comes in before
+ * we even tried to associate or in similar cases.
+ *
+ * Ultimately, I suspect cfg80211 should print the
+ * messages instead.
+ */
+ printk(KERN_DEBUG
+ "%s: deauthenticated from %pM (Reason: %u)\n",
+ sdata->name, mgmt->bssid,
+ le16_to_cpu(mgmt->u.deauth.reason_code));
+
+ list_del_rcu(&wk->list);
+ free_work(wk);
+ break;
+ }
+ mutex_unlock(&local->work_mtx);
+
+ cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len);
+ }
out:
kfree_skb(skb);
}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 5e0b654..be9abc2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1944,6 +1944,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
break;
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ return ieee80211_sta_rx_mgmt(sdata, rx->skb);
+
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply related
* RE: [PATCHv2] mac80211: Fix circular locking dependency in ARP filter handling
From: juuso.oikarinen @ 2010-06-08 21:09 UTC (permalink / raw)
To: johannes; +Cc: linville, linux-wireless, reinette.chatre
In-Reply-To: <1276002863.3706.131.camel@jlt3.sipsolutions.net>
From: ext Johannes Berg [johannes@sipsolutions.net]
>
>On Tue, 2010-06-08 at 16:05 +0300, Juuso Oikarinen wrote:
>
>> + promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
>> + if (promisc)
>> + bss_conf->arp_filter_enabled = 0;
>> + else
>> + bss_conf->arp_filter_enabled = sdata->arp_filter_state;
>
>bss_conf->arp_filter_enabled = !promisc && sdata->arp_filter_state;
>
>?
>
>Or if not, use false instead of 0 please.
>
Yes, sure I can change this.
My home WLAN is giving me a headache, so I can't seem to access my work machine just now, but I began to wonder if I managed to create the same locking problem in this patch I had before. To traverse the interface list we need to acquire a lock - either the mutex for the iflist (which seems not to be an option as we also need the mgd mutex - to be locked after the iflist mutex) or the rtnl lock, which I chose to acquire. I quess the filter reconfig work is in the same mac80211 workqueue as the rest of the stuff, so the rtnl lock problem is there again.
-Juuso
>johannes
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox