* [PATCH 00/27] mac80211 updates
@ 2009-02-10 20:25 Johannes Berg
2009-02-10 20:25 ` [PATCH 01/27] zd1211rw: do not ratelimit no-ops Johannes Berg
` (26 more replies)
0 siblings, 27 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
The whole set, everything was posted before, but I found a few
bugs in some patches, so here's a complete repost.
johannes
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 01/27] zd1211rw: do not ratelimit no-ops
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 02/27] mac80211: disable IBSS beacon before join Johannes Berg
` (25 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
It is rather confusing to see this in the log:
[ 695.606877] __ratelimit: 40 callbacks suppressed
[ 700.726878] __ratelimit: 40 callbacks suppressed
without ever seeing any actual message. This is because
zd1211rw doesn't compile out the net_ratelimit() call
properly if debugging is not enabled.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
drivers/net/wireless/zd1211rw/zd_def.h | 5 +++++
drivers/net/wireless/zd1211rw/zd_mac.c | 7 +++----
2 files changed, 8 insertions(+), 4 deletions(-)
--- wireless-testing.orig/drivers/net/wireless/zd1211rw/zd_def.h 2009-02-06 14:25:41.000000000 +0100
+++ wireless-testing/drivers/net/wireless/zd1211rw/zd_def.h 2009-02-06 14:26:42.000000000 +0100
@@ -33,8 +33,13 @@ typedef u16 __nocast zd_addr_t;
#ifdef DEBUG
# define dev_dbg_f(dev, fmt, args...) \
dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
+# define dev_dbg_f_limit(dev, fmt, args...) do {\
+ if (net_ratelimit())
+ dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
+} while (0)
#else
# define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0)
+# define dev_dbg_f_limit(dev, fmt, args...) do { (void)(dev); } while (0)
#endif /* DEBUG */
#ifdef DEBUG
--- wireless-testing.orig/drivers/net/wireless/zd1211rw/zd_mac.c 2009-02-06 14:25:27.000000000 +0100
+++ wireless-testing/drivers/net/wireless/zd1211rw/zd_mac.c 2009-02-06 14:26:57.000000000 +0100
@@ -793,10 +793,9 @@ static void zd_process_intr(struct work_
struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer+4));
- if (int_status & INT_CFG_NEXT_BCN) {
- if (net_ratelimit())
- dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
- } else
+ if (int_status & INT_CFG_NEXT_BCN)
+ dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
+ else
dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n");
zd_chip_enable_hwint(&mac->chip);
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 02/27] mac80211: disable IBSS beacon before join
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
2009-02-10 20:25 ` [PATCH 01/27] zd1211rw: do not ratelimit no-ops Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 03/27] zd1211rw: honour enable_beacon conf Johannes Berg
` (24 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Before we have a probe response frame (which is used as the
beacon too) there's no need to ask drivers to beacon, they
will not get a beacon anyway.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/main.c | 2 ++
1 file changed, 2 insertions(+)
--- wireless-testing.orig/net/mac80211/main.c 2009-02-10 20:59:28.000000000 +0100
+++ wireless-testing/net/mac80211/main.c 2009-02-10 20:59:29.000000000 +0100
@@ -210,6 +210,8 @@ int ieee80211_if_config(struct ieee80211
!!rcu_dereference(sdata->u.ap.beacon);
break;
case NL80211_IFTYPE_ADHOC:
+ conf.enable_beacon = !!sdata->u.sta.probe_resp;
+ break;
case NL80211_IFTYPE_MESH_POINT:
conf.enable_beacon = true;
break;
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 03/27] zd1211rw: honour enable_beacon conf
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
2009-02-10 20:25 ` [PATCH 01/27] zd1211rw: do not ratelimit no-ops Johannes Berg
2009-02-10 20:25 ` [PATCH 02/27] mac80211: disable IBSS beacon before join Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 04/27] mac80211: properly validate/translate IW_AUTH_MFP values Johannes Berg
` (23 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
This makes zd1211rw honour enable_beacon, as well as fixing
a memory leak: the beacon skb is leaked when configuring it
to the hardware fails.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
drivers/net/wireless/zd1211rw/zd_mac.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
--- wireless-testing.orig/drivers/net/wireless/zd1211rw/zd_mac.c 2009-02-10 20:59:27.000000000 +0100
+++ wireless-testing/drivers/net/wireless/zd1211rw/zd_mac.c 2009-02-10 20:59:29.000000000 +0100
@@ -768,13 +768,23 @@ static int zd_op_config_interface(struct
if (!beacon)
return -ENOMEM;
r = zd_mac_config_beacon(hw, beacon);
+ kfree_skb(beacon);
+
if (r < 0)
return r;
- r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
- hw->conf.beacon_int);
+ }
+
+ if (conf->changed & IEEE80211_IFCC_BEACON_ENABLED) {
+ u32 interval;
+
+ if (conf->enable_beacon)
+ interval = BCN_MODE_IBSS | hw->conf.beacon_int;
+ else
+ interval = 0;
+
+ r = zd_set_beacon_interval(&mac->chip, interval);
if (r < 0)
return r;
- kfree_skb(beacon);
}
} else
associated = is_valid_ether_addr(conf->bssid);
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 04/27] mac80211: properly validate/translate IW_AUTH_MFP values
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (2 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 03/27] zd1211rw: honour enable_beacon conf Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 05/27] mac80211: reject extra IEs for probe request when hw_scan Johannes Berg
` (22 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Make sure nobody passes in bogus values, and translate the values
(although it isn't necessary).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/wext.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
--- wireless-testing.orig/net/mac80211/wext.c 2009-02-10 20:59:27.000000000 +0100
+++ wireless-testing/net/mac80211/wext.c 2009-02-10 20:59:30.000000000 +0100
@@ -982,9 +982,21 @@ static int ieee80211_ioctl_siwauth(struc
break;
}
if (sdata->vif.type == NL80211_IFTYPE_STATION ||
- sdata->vif.type == NL80211_IFTYPE_ADHOC)
- sdata->u.sta.mfp = data->value;
- else
+ sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+ switch (data->value) {
+ case IW_AUTH_MFP_DISABLED:
+ sdata->u.sta.mfp = IEEE80211_MFP_DISABLED;
+ break;
+ case IW_AUTH_MFP_OPTIONAL:
+ sdata->u.sta.mfp = IEEE80211_MFP_OPTIONAL;
+ break;
+ case IW_AUTH_MFP_REQUIRED:
+ sdata->u.sta.mfp = IEEE80211_MFP_REQUIRED;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else
ret = -EOPNOTSUPP;
break;
default:
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 05/27] mac80211: reject extra IEs for probe request when hw_scan
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (3 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 04/27] mac80211: properly validate/translate IW_AUTH_MFP values Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 06/27] mac80211: fix beacon enable more Johannes Berg
` (21 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Jouni Malinen
We cannot currently hand off extra IEs to hw_scan, so reject
configuring extra IEs for probe request frames when hw_scan
is set.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Jouni Malinen <j@w1.fi>
---
net/mac80211/cfg.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
--- wireless-testing.orig/net/mac80211/cfg.c 2009-02-10 20:59:27.000000000 +0100
+++ wireless-testing/net/mac80211/cfg.c 2009-02-10 20:59:30.000000000 +0100
@@ -1176,11 +1176,16 @@ static int ieee80211_set_channel(struct
return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
}
-static int set_mgmt_extra_ie_sta(struct ieee80211_if_sta *ifsta, u8 subtype,
- u8 *ies, size_t ies_len)
+static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata,
+ u8 subtype, u8 *ies, size_t ies_len)
{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
switch (subtype) {
case IEEE80211_STYPE_PROBE_REQ >> 4:
+ if (local->ops->hw_scan)
+ break;
kfree(ifsta->ie_probereq);
ifsta->ie_probereq = ies;
ifsta->ie_probereq_len = ies_len;
@@ -1244,7 +1249,7 @@ static int ieee80211_set_mgmt_extra_ie(s
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
- ret = set_mgmt_extra_ie_sta(&sdata->u.sta, params->subtype,
+ ret = set_mgmt_extra_ie_sta(sdata, params->subtype,
ies, ies_len);
break;
default:
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 06/27] mac80211: fix beacon enable more
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (4 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 05/27] mac80211: reject extra IEs for probe request when hw_scan Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 07/27] mac80211: remove bssid argument from prepare_for_handlers Johannes Berg
` (20 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Hopefully the last required fix ... disable beaconing
only on beaconing interfaces, and thus avoid calling
ieee80211_if_config for purely virtual interfaces
(those driver doesn't know about).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/scan.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
--- wireless-testing.orig/net/mac80211/scan.c 2009-02-10 20:59:27.000000000 +0100
+++ wireless-testing/net/mac80211/scan.c 2009-02-10 20:59:30.000000000 +0100
@@ -500,7 +500,12 @@ void ieee80211_scan_completed(struct iee
} else
netif_tx_wake_all_queues(sdata->dev);
- ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
+ /* re-enable beaconing */
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+ ieee80211_if_config(sdata,
+ IEEE80211_IFCC_BEACON_ENABLED);
}
mutex_unlock(&local->iflist_mtx);
@@ -656,7 +661,12 @@ int ieee80211_start_scan(struct ieee8021
if (!netif_running(sdata->dev))
continue;
- ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED);
+ /* disable beaconing */
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+ ieee80211_if_config(sdata,
+ IEEE80211_IFCC_BEACON_ENABLED);
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 07/27] mac80211: remove bssid argument from prepare_for_handlers
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (5 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 06/27] mac80211: fix beacon enable more Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 08/27] mac80211: remove stray aggregation debugfs definition Johannes Berg
` (19 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
It's a little confusing to get the BSSID outside the function
and pass it in, when it's only needed for this function, so
change that.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/rx.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
--- wireless-testing.orig/net/mac80211/rx.c 2009-02-10 20:59:27.000000000 +0100
+++ wireless-testing/net/mac80211/rx.c 2009-02-10 20:59:31.000000000 +0100
@@ -2030,9 +2030,10 @@ static void ieee80211_invoke_rx_handlers
/* main receive path */
static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
- u8 *bssid, struct ieee80211_rx_data *rx,
+ struct ieee80211_rx_data *rx,
struct ieee80211_hdr *hdr)
{
+ u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type);
int multicast = is_multicast_ether_addr(hdr->addr1);
switch (sdata->vif.type) {
@@ -2135,7 +2136,6 @@ static void __ieee80211_rx_handle_packet
int prepares;
struct ieee80211_sub_if_data *prev = NULL;
struct sk_buff *skb_new;
- u8 *bssid;
hdr = (struct ieee80211_hdr *)skb->data;
memset(&rx, 0, sizeof(rx));
@@ -2174,9 +2174,8 @@ static void __ieee80211_rx_handle_packet
if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
continue;
- bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
rx.flags |= IEEE80211_RX_RA_MATCH;
- prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
+ prepares = prepare_for_handlers(sdata, &rx, hdr);
if (!prepares)
continue;
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 08/27] mac80211: remove stray aggregation debugfs definition
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (6 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 07/27] mac80211: remove bssid argument from prepare_for_handlers Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 09/27] mac80211: fix RX aggregation timeouts Johannes Berg
` (18 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/sta_info.h | 1-
net/mac80211/sta_info.h | 1 -
1 file changed, 1 deletion(-)
--- wireless-testing.orig/net/mac80211/sta_info.h 2009-02-10 20:59:27.000000000 +0100
+++ wireless-testing/net/mac80211/sta_info.h 2009-02-10 20:59:31.000000000 +0100
@@ -65,7 +65,6 @@ enum ieee80211_sta_info_flags {
#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \
HT_ADDBA_DRV_READY_MSK | \
HT_ADDBA_RECEIVED_MSK)
-#define HT_AGG_STATE_DEBUGFS_CTL BIT(7)
/**
* struct tid_ampdu_tx - TID aggregation information (Tx).
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 09/27] mac80211: fix RX aggregation timeouts
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (7 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 08/27] mac80211: remove stray aggregation debugfs definition Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 10/27] mac80211: restructure HT code Johannes Berg
` (17 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
The values are in TUs (1.024ms), not ms.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mesh_hwmp.c | 1 -
net/mac80211/rx.c | 16 ++++++----------
net/mac80211/sta_info.h | 2 +-
4 files changed, 9 insertions(+), 12 deletions(-)
--- wireless-testing.orig/net/mac80211/rx.c 2009-02-10 20:59:31.000000000 +0100
+++ wireless-testing/net/mac80211/rx.c 2009-02-10 20:59:32.000000000 +0100
@@ -1640,11 +1640,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_
start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
/* reset session timer */
- if (tid_agg_rx->timeout) {
- unsigned long expires =
- jiffies + (tid_agg_rx->timeout / 1000) * HZ;
- mod_timer(&tid_agg_rx->session_timer, expires);
- }
+ if (tid_agg_rx->timeout)
+ mod_timer(&tid_agg_rx->session_timer,
+ TU_TO_EXP_TIME(tid_agg_rx->timeout));
/* manage reordering buffer according to requested */
/* sequence number */
@@ -2380,11 +2378,9 @@ static u8 ieee80211_rx_reorder_ampdu(str
/* new un-ordered ampdu frame - process it */
/* reset session timer */
- if (tid_agg_rx->timeout) {
- unsigned long expires =
- jiffies + (tid_agg_rx->timeout / 1000) * HZ;
- mod_timer(&tid_agg_rx->session_timer, expires);
- }
+ if (tid_agg_rx->timeout)
+ mod_timer(&tid_agg_rx->session_timer,
+ TU_TO_EXP_TIME(tid_agg_rx->timeout));
/* if this mpdu is fragmented - terminate rx aggregation session */
sc = le16_to_cpu(hdr->seq_ctrl);
--- wireless-testing.orig/net/mac80211/sta_info.h 2009-02-10 20:59:31.000000000 +0100
+++ wireless-testing/net/mac80211/sta_info.h 2009-02-10 20:59:32.000000000 +0100
@@ -88,7 +88,7 @@ struct tid_ampdu_tx {
* @stored_mpdu_num: number of MPDUs in reordering buffer
* @ssn: Starting Sequence Number expected to be aggregated.
* @buf_size: buffer size for incoming A-MPDUs
- * @timeout: reset timer value.
+ * @timeout: reset timer value (in TUs).
* @dialog_token: dialog token for aggregation session
*/
struct tid_ampdu_rx {
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-02-10 20:59:26.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-02-10 20:59:32.000000000 +0100
@@ -57,6 +57,8 @@ struct ieee80211_local;
*/
#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
+#define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024))
+
struct ieee80211_fragment_entry {
unsigned long first_frag_time;
unsigned int seq;
--- wireless-testing.orig/net/mac80211/mesh_hwmp.c 2009-02-10 20:59:26.000000000 +0100
+++ wireless-testing/net/mac80211/mesh_hwmp.c 2009-02-10 20:59:32.000000000 +0100
@@ -58,7 +58,6 @@ static inline u32 u32_field_get(u8 *preq
#define PERR_IE_DST_ADDR(x) (x + 2)
#define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0);
-#define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000))
#define MSEC_TO_TU(x) (x*1000/1024)
#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0)
#define DSN_LT(x, y) ((long) (x) - (long) (y) < 0)
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 10/27] mac80211: restructure HT code
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (8 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 09/27] mac80211: fix RX aggregation timeouts Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 11/27] mac80211: restrict aggregation to supported interface modes Johannes Berg
` (16 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Create two new files, agg-tx.c and agg-rx.c to make it clearer
which code is common (ht.c) and which is specific (agg-*.c).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/Makefile | 2
net/mac80211/agg-rx.c | 287 ++++++++++++++
net/mac80211/agg-tx.c | 593 ++++++++++++++++++++++++++++++
net/mac80211/ht.c | 867 ---------------------------------------------
net/mac80211/ieee80211_i.h | 3
5 files changed, 895 insertions(+), 857 deletions(-)
--- wireless-testing.orig/net/mac80211/ht.c 2009-02-10 20:59:26.000000000 +0100
+++ wireless-testing/net/mac80211/ht.c 2009-02-10 20:59:32.000000000 +0100
@@ -17,8 +17,6 @@
#include <net/wireless.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
-#include "sta_info.h"
-#include "wme.h"
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
@@ -155,105 +153,23 @@ u32 ieee80211_enable_ht(struct ieee80211
return changed;
}
-static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
- const u8 *da, u16 tid,
- u8 dialog_token, u16 start_seq_num,
- u16 agg_size, u16 timeout)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- u16 capab;
-
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
-
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer "
- "for addba request frame\n", sdata->dev->name);
- return;
- }
- skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
- memset(mgmt, 0, 24);
- memcpy(mgmt->da, da, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == NL80211_IFTYPE_AP)
- memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
- else
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
-
- skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
-
- mgmt->u.action.category = WLAN_CATEGORY_BACK;
- mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
-
- mgmt->u.action.u.addba_req.dialog_token = dialog_token;
- capab = (u16)(1 << 1); /* bit 1 aggregation policy */
- capab |= (u16)(tid << 2); /* bit 5:2 TID number */
- capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
-
- mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
-
- mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
- mgmt->u.action.u.addba_req.start_seq_num =
- cpu_to_le16(start_seq_num << 4);
-
- ieee80211_tx_skb(sdata, skb, 1);
-}
-
-static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
- u8 dialog_token, u16 status, u16 policy,
- u16 buf_size, u16 timeout)
+void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
{
- struct ieee80211_if_sta *ifsta = &sdata->u.sta;
struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_mgmt *mgmt;
- u16 capab;
-
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+ int i;
- if (!skb) {
- printk(KERN_DEBUG "%s: failed to allocate buffer "
- "for addba resp frame\n", sdata->dev->name);
- return;
+ for (i = 0; i < STA_TID_NUM; i++) {
+ ieee80211_stop_tx_ba_session(&local->hw, addr, i,
+ WLAN_BACK_INITIATOR);
+ ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
+ WLAN_BACK_RECIPIENT,
+ WLAN_REASON_QSTA_LEAVE_QBSS);
}
-
- skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
- memset(mgmt, 0, 24);
- memcpy(mgmt->da, da, ETH_ALEN);
- memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == NL80211_IFTYPE_AP)
- memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
- else
- memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_ACTION);
-
- skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
- mgmt->u.action.category = WLAN_CATEGORY_BACK;
- mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
- mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
-
- capab = (u16)(policy << 1); /* bit 1 aggregation policy */
- capab |= (u16)(tid << 2); /* bit 5:2 TID number */
- capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
-
- mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
- mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
- mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
-
- ieee80211_tx_skb(sdata, skb, 1);
}
-static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
- const u8 *da, u16 tid,
- u16 initiator, u16 reason_code)
+void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
+ const u8 *da, u16 tid,
+ u16 initiator, u16 reason_code)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
@@ -294,767 +210,6 @@ static void ieee80211_send_delba(struct
ieee80211_tx_skb(sdata, skb, 1);
}
-void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
-{
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- struct ieee80211_bar *bar;
- u16 bar_control = 0;
-
- skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
- if (!skb) {
- printk(KERN_ERR "%s: failed to allocate buffer for "
- "bar frame\n", sdata->dev->name);
- return;
- }
- skb_reserve(skb, local->hw.extra_tx_headroom);
- bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
- memset(bar, 0, sizeof(*bar));
- bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
- IEEE80211_STYPE_BACK_REQ);
- memcpy(bar->ra, ra, ETH_ALEN);
- memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
- bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
- bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
- bar_control |= (u16)(tid << 12);
- bar->control = cpu_to_le16(bar_control);
- bar->start_seq_num = cpu_to_le16(ssn);
-
- ieee80211_tx_skb(sdata, skb, 0);
-}
-
-void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
- u16 initiator, u16 reason)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_hw *hw = &local->hw;
- struct sta_info *sta;
- int ret, i;
-
- rcu_read_lock();
-
- sta = sta_info_get(local, ra);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
-
- /* check if TID is in operational state */
- spin_lock_bh(&sta->lock);
- if (sta->ampdu_mlme.tid_state_rx[tid]
- != HT_AGG_STATE_OPERATIONAL) {
- spin_unlock_bh(&sta->lock);
- rcu_read_unlock();
- return;
- }
- sta->ampdu_mlme.tid_state_rx[tid] =
- HT_AGG_STATE_REQ_STOP_BA_MSK |
- (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
- spin_unlock_bh(&sta->lock);
-
- /* stop HW Rx aggregation. ampdu_action existence
- * already verified in session init so we add the BUG_ON */
- BUG_ON(!local->ops->ampdu_action);
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
- ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
- &sta->sta, tid, NULL);
- if (ret)
- printk(KERN_DEBUG "HW problem - can not stop rx "
- "aggregation for tid %d\n", tid);
-
- /* shutdown timer has not expired */
- if (initiator != WLAN_BACK_TIMER)
- del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
- /* check if this is a self generated aggregation halt */
- if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
- ieee80211_send_delba(sdata, ra, tid, 0, reason);
-
- /* free the reordering buffer */
- for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
- if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
- /* release the reordered frames */
- dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
- sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
- sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
- }
- }
- /* free resources */
- kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
- kfree(sta->ampdu_mlme.tid_rx[tid]);
- sta->ampdu_mlme.tid_rx[tid] = NULL;
- sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
-
- rcu_read_unlock();
-}
-
-
-/*
- * After sending add Block Ack request we activated a timer until
- * add Block Ack response will arrive from the recipient.
- * If this timer expires sta_addba_resp_timer_expired will be executed.
- */
-static void sta_addba_resp_timer_expired(unsigned long data)
-{
- /* not an elegant detour, but there is no choice as the timer passes
- * only one argument, and both sta_info and TID are needed, so init
- * flow in sta_info_create gives the TID as data, while the timer_to_id
- * array gives the sta through container_of */
- u16 tid = *(u8 *)data;
- struct sta_info *temp_sta = container_of((void *)data,
- struct sta_info, timer_to_tid[tid]);
-
- struct ieee80211_local *local = temp_sta->local;
- struct ieee80211_hw *hw = &local->hw;
- struct sta_info *sta;
- u8 *state;
-
- rcu_read_lock();
-
- sta = sta_info_get(local, temp_sta->sta.addr);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
-
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- /* check if the TID waits for addBA response */
- spin_lock_bh(&sta->lock);
- if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->lock);
- *state = HT_AGG_STATE_IDLE;
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "timer expired on tid %d but we are not "
- "expecting addBA response there", tid);
-#endif
- goto timer_expired_exit;
- }
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
-#endif
-
- /* go through the state check in stop_BA_session */
- *state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
- WLAN_BACK_INITIATOR);
-
-timer_expired_exit:
- rcu_read_unlock();
-}
-
-void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
-{
- struct ieee80211_local *local = sdata->local;
- int i;
-
- for (i = 0; i < STA_TID_NUM; i++) {
- ieee80211_stop_tx_ba_session(&local->hw, addr, i,
- WLAN_BACK_INITIATOR);
- ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
- WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_LEAVE_QBSS);
- }
-}
-
-int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct sta_info *sta;
- struct ieee80211_sub_if_data *sdata;
- u16 start_seq_num;
- u8 *state;
- int ret = 0;
-
- if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
- return -EINVAL;
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
- ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- rcu_read_lock();
-
- sta = sta_info_get(local, ra);
- if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Could not find the station\n");
-#endif
- ret = -ENOENT;
- goto exit;
- }
-
- spin_lock_bh(&sta->lock);
-
- /* we have tried too many times, receiver does not want A-MPDU */
- if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
- ret = -EBUSY;
- goto err_unlock_sta;
- }
-
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- /* check if the TID is not in aggregation flow already */
- if (*state != HT_AGG_STATE_IDLE) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - session is not "
- "idle on tid %u\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- ret = -EAGAIN;
- goto err_unlock_sta;
- }
-
- /* prepare A-MPDU MLME for Tx aggregation */
- sta->ampdu_mlme.tid_tx[tid] =
- kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
- if (!sta->ampdu_mlme.tid_tx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
- tid);
-#endif
- ret = -ENOMEM;
- goto err_unlock_sta;
- }
- /* Tx timer */
- sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
- sta_addba_resp_timer_expired;
- sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
- (unsigned long)&sta->timer_to_tid[tid];
- init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-
- if (hw->ampdu_queues) {
- /* create a new queue for this aggregation */
- ret = ieee80211_ht_agg_queue_add(local, sta, tid);
-
- /* case no queue is available to aggregation
- * don't switch to aggregation */
- if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - "
- "queue unavailable for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto err_unlock_queue;
- }
- }
- sdata = sta->sdata;
-
- /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
- * call back right away, it must see that the flow has begun */
- *state |= HT_ADDBA_REQUESTED_MSK;
-
- /* This is slightly racy because the queue isn't stopped */
- start_seq_num = sta->tid_seq[tid];
-
- if (local->ops->ampdu_action)
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
- &sta->sta, tid, &start_seq_num);
-
- if (ret) {
- /* No need to requeue the packets in the agg queue, since we
- * held the tx lock: no packet could be enqueued to the newly
- * allocated queue */
- if (hw->ampdu_queues)
- ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "BA request denied - HW unavailable for"
- " tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- *state = HT_AGG_STATE_IDLE;
- goto err_unlock_queue;
- }
-
- /* Will put all the packets in the new SW queue */
- if (hw->ampdu_queues)
- ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
- spin_unlock_bh(&sta->lock);
-
- /* send an addBA request */
- sta->ampdu_mlme.dialog_token_allocator++;
- sta->ampdu_mlme.tid_tx[tid]->dialog_token =
- sta->ampdu_mlme.dialog_token_allocator;
- sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
-
-
- ieee80211_send_addba_request(sta->sdata, ra, tid,
- sta->ampdu_mlme.tid_tx[tid]->dialog_token,
- sta->ampdu_mlme.tid_tx[tid]->ssn,
- 0x40, 5000);
- /* activate the timer for the recipient's addBA response */
- sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
- jiffies + ADDBA_RESP_INTERVAL;
- add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-#endif
- goto exit;
-
-err_unlock_queue:
- kfree(sta->ampdu_mlme.tid_tx[tid]);
- sta->ampdu_mlme.tid_tx[tid] = NULL;
- ret = -EBUSY;
-err_unlock_sta:
- spin_unlock_bh(&sta->lock);
-exit:
- rcu_read_unlock();
- return ret;
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
-
-int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
- u8 *ra, u16 tid,
- enum ieee80211_back_parties initiator)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct sta_info *sta;
- u8 *state;
- int ret = 0;
-
- if (tid >= STA_TID_NUM)
- return -EINVAL;
-
- rcu_read_lock();
- sta = sta_info_get(local, ra);
- if (!sta) {
- rcu_read_unlock();
- return -ENOENT;
- }
-
- /* check if the TID is in aggregation */
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->lock);
-
- if (*state != HT_AGG_STATE_OPERATIONAL) {
- ret = -ENOENT;
- goto stop_BA_exit;
- }
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
- ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- if (hw->ampdu_queues)
- ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
-
- *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
- (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
-
- if (local->ops->ampdu_action)
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
- &sta->sta, tid, NULL);
-
- /* case HW denied going back to legacy */
- if (ret) {
- WARN_ON(ret != -EBUSY);
- *state = HT_AGG_STATE_OPERATIONAL;
- if (hw->ampdu_queues)
- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
- goto stop_BA_exit;
- }
-
-stop_BA_exit:
- spin_unlock_bh(&sta->lock);
- rcu_read_unlock();
- return ret;
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
-
-void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct sta_info *sta;
- u8 *state;
-
- if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
- tid, STA_TID_NUM);
-#endif
- return;
- }
-
- rcu_read_lock();
- sta = sta_info_get(local, ra);
- if (!sta) {
- rcu_read_unlock();
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
- return;
- }
-
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->lock);
-
- if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
- *state);
-#endif
- spin_unlock_bh(&sta->lock);
- rcu_read_unlock();
- return;
- }
-
- WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
-
- *state |= HT_ADDBA_DRV_READY_MSK;
-
- if (*state == HT_AGG_STATE_OPERATIONAL) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
-#endif
- if (hw->ampdu_queues)
- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
- }
- spin_unlock_bh(&sta->lock);
- rcu_read_unlock();
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
-
-void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct sta_info *sta;
- u8 *state;
- int agg_queue;
-
- if (tid >= STA_TID_NUM) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
- tid, STA_TID_NUM);
-#endif
- return;
- }
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
- ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- rcu_read_lock();
- sta = sta_info_get(local, ra);
- if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Could not find station: %pM\n", ra);
-#endif
- rcu_read_unlock();
- return;
- }
- state = &sta->ampdu_mlme.tid_state_tx[tid];
-
- /* NOTE: no need to use sta->lock in this state check, as
- * ieee80211_stop_tx_ba_session will let only one stop call to
- * pass through per sta/tid
- */
- if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
-#endif
- rcu_read_unlock();
- return;
- }
-
- if (*state & HT_AGG_STATE_INITIATOR_MSK)
- ieee80211_send_delba(sta->sdata, ra, tid,
- WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
-
- if (hw->ampdu_queues) {
- agg_queue = sta->tid_to_tx_q[tid];
- ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
-
- /* We just requeued the all the frames that were in the
- * removed queue, and since we might miss a softirq we do
- * netif_schedule_queue. ieee80211_wake_queue is not used
- * here as this queue is not necessarily stopped
- */
- netif_schedule_queue(netdev_get_tx_queue(local->mdev,
- agg_queue));
- }
- spin_lock_bh(&sta->lock);
- *state = HT_AGG_STATE_IDLE;
- sta->ampdu_mlme.addba_req_num[tid] = 0;
- kfree(sta->ampdu_mlme.tid_tx[tid]);
- sta->ampdu_mlme.tid_tx[tid] = NULL;
- spin_unlock_bh(&sta->lock);
-
- rcu_read_unlock();
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
-
-void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
- const u8 *ra, u16 tid)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_ra_tid *ra_tid;
- struct sk_buff *skb = dev_alloc_skb(0);
-
- if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping start BA session", skb->dev->name);
-#endif
- return;
- }
- ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
- memcpy(&ra_tid->ra, ra, ETH_ALEN);
- ra_tid->tid = tid;
-
- skb->pkt_type = IEEE80211_ADDBA_MSG;
- skb_queue_tail(&local->skb_queue, skb);
- tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
-
-void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
- const u8 *ra, u16 tid)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_ra_tid *ra_tid;
- struct sk_buff *skb = dev_alloc_skb(0);
-
- if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping stop BA session", skb->dev->name);
-#endif
- return;
- }
- ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
- memcpy(&ra_tid->ra, ra, ETH_ALEN);
- ra_tid->tid = tid;
-
- skb->pkt_type = IEEE80211_DELBA_MSG;
- skb_queue_tail(&local->skb_queue, skb);
- tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
-
-/*
- * After accepting the AddBA Request we activated a timer,
- * resetting it after each frame that arrives from the originator.
- * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
- */
-static void sta_rx_agg_session_timer_expired(unsigned long data)
-{
- /* not an elegant detour, but there is no choice as the timer passes
- * only one argument, and various sta_info are needed here, so init
- * flow in sta_info_create gives the TID as data, while the timer_to_id
- * array gives the sta through container_of */
- u8 *ptid = (u8 *)data;
- u8 *timer_to_id = ptid - *ptid;
- struct sta_info *sta = container_of(timer_to_id, struct sta_info,
- timer_to_tid[0]);
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
-#endif
- ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
- (u16)*ptid, WLAN_BACK_TIMER,
- WLAN_REASON_QSTA_TIMEOUT);
-}
-
-void ieee80211_process_addba_request(struct ieee80211_local *local,
- struct sta_info *sta,
- struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- struct ieee80211_hw *hw = &local->hw;
- struct ieee80211_conf *conf = &hw->conf;
- struct tid_ampdu_rx *tid_agg_rx;
- u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
- u8 dialog_token;
- int ret = -EOPNOTSUPP;
-
- /* extract session parameters from addba request frame */
- dialog_token = mgmt->u.action.u.addba_req.dialog_token;
- timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
- start_seq_num =
- le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
-
- capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
- ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
- tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
- buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
-
- status = WLAN_STATUS_REQUEST_DECLINED;
-
- /* sanity check for incoming parameters:
- * check if configuration can support the BA policy
- * and if buffer size does not exceeds max value */
- /* XXX: check own ht delayed BA capability?? */
- if (((ba_policy != 1)
- && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
- || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
- status = WLAN_STATUS_INVALID_QOS_PARAM;
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "AddBA Req with bad params from "
- "%pM on tid %u. policy %d, buffer size %d\n",
- mgmt->sa, tid, ba_policy,
- buf_size);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto end_no_lock;
- }
- /* determine default buffer size */
- if (buf_size == 0) {
- struct ieee80211_supported_band *sband;
-
- sband = local->hw.wiphy->bands[conf->channel->band];
- buf_size = IEEE80211_MIN_AMPDU_BUF;
- buf_size = buf_size << sband->ht_cap.ampdu_factor;
- }
-
-
- /* examine state machine */
- spin_lock_bh(&sta->lock);
-
- if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "unexpected AddBA Req from "
- "%pM on tid %u\n",
- mgmt->sa, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto end;
- }
-
- /* prepare A-MPDU MLME for Rx aggregation */
- sta->ampdu_mlme.tid_rx[tid] =
- kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
- if (!sta->ampdu_mlme.tid_rx[tid]) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
- tid);
-#endif
- goto end;
- }
- /* rx timer */
- sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
- sta_rx_agg_session_timer_expired;
- sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
- (unsigned long)&sta->timer_to_tid[tid];
- init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
- tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
-
- /* prepare reordering buffer */
- tid_agg_rx->reorder_buf =
- kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
- if (!tid_agg_rx->reorder_buf) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_ERR "can not allocate reordering buffer "
- "to tid %d\n", tid);
-#endif
- kfree(sta->ampdu_mlme.tid_rx[tid]);
- goto end;
- }
-
- if (local->ops->ampdu_action)
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
- &sta->sta, tid, &start_seq_num);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- if (ret) {
- kfree(tid_agg_rx->reorder_buf);
- kfree(tid_agg_rx);
- sta->ampdu_mlme.tid_rx[tid] = NULL;
- goto end;
- }
-
- /* change state and send addba resp */
- sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
- tid_agg_rx->dialog_token = dialog_token;
- tid_agg_rx->ssn = start_seq_num;
- tid_agg_rx->head_seq_num = start_seq_num;
- tid_agg_rx->buf_size = buf_size;
- tid_agg_rx->timeout = timeout;
- tid_agg_rx->stored_mpdu_num = 0;
- status = WLAN_STATUS_SUCCESS;
-end:
- spin_unlock_bh(&sta->lock);
-
-end_no_lock:
- ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
- dialog_token, status, 1, buf_size, timeout);
-}
-
-void ieee80211_process_addba_resp(struct ieee80211_local *local,
- struct sta_info *sta,
- struct ieee80211_mgmt *mgmt,
- size_t len)
-{
- struct ieee80211_hw *hw = &local->hw;
- u16 capab;
- u16 tid, start_seq_num;
- u8 *state;
-
- capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
- tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
-
- state = &sta->ampdu_mlme.tid_state_tx[tid];
-
- spin_lock_bh(&sta->lock);
-
- if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->lock);
- return;
- }
-
- if (mgmt->u.action.u.addba_resp.dialog_token !=
- sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
- spin_unlock_bh(&sta->lock);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- return;
- }
-
- del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
- == WLAN_STATUS_SUCCESS) {
- *state |= HT_ADDBA_RECEIVED_MSK;
- sta->ampdu_mlme.addba_req_num[tid] = 0;
-
- if (*state == HT_AGG_STATE_OPERATIONAL &&
- local->hw.ampdu_queues)
- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
-
- if (local->ops->ampdu_action) {
- (void)local->ops->ampdu_action(hw,
- IEEE80211_AMPDU_TX_RESUME,
- &sta->sta, tid, &start_seq_num);
- }
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- spin_unlock_bh(&sta->lock);
- } else {
- sta->ampdu_mlme.addba_req_num[tid]++;
- /* this will allow the state check in stop_BA_session */
- *state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
- WLAN_BACK_INITIATOR);
- }
-}
-
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_mgmt *mgmt, size_t len)
--- wireless-testing.orig/net/mac80211/Makefile 2009-02-10 20:59:26.000000000 +0100
+++ wireless-testing/net/mac80211/Makefile 2009-02-10 20:59:32.000000000 +0100
@@ -8,7 +8,7 @@ mac80211-y := \
wep.o \
wpa.o \
scan.o \
- ht.o \
+ ht.o agg-tx.o agg-rx.o \
mlme.o \
iface.o \
rate.o \
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-02-10 20:59:32.000000000 +0100
@@ -984,6 +984,9 @@ u32 ieee80211_enable_ht(struct ieee80211
struct ieee80211_ht_info *hti,
u16 ap_ht_cap_flags);
void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
+void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
+ const u8 *da, u16 tid,
+ u16 initiator, u16 reason_code);
void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
u16 tid, u16 initiator, u16 reason);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/net/mac80211/agg-rx.c 2009-02-10 20:59:32.000000000 +0100
@@ -0,0 +1,287 @@
+/*
+ * HT handling
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
+ u16 initiator, u16 reason)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_hw *hw = &local->hw;
+ struct sta_info *sta;
+ int ret, i;
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+
+ /* check if TID is in operational state */
+ spin_lock_bh(&sta->lock);
+ if (sta->ampdu_mlme.tid_state_rx[tid]
+ != HT_AGG_STATE_OPERATIONAL) {
+ spin_unlock_bh(&sta->lock);
+ rcu_read_unlock();
+ return;
+ }
+ sta->ampdu_mlme.tid_state_rx[tid] =
+ HT_AGG_STATE_REQ_STOP_BA_MSK |
+ (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+ spin_unlock_bh(&sta->lock);
+
+ /* stop HW Rx aggregation. ampdu_action existence
+ * already verified in session init so we add the BUG_ON */
+ BUG_ON(!local->ops->ampdu_action);
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
+ ra, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+ ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
+ &sta->sta, tid, NULL);
+ if (ret)
+ printk(KERN_DEBUG "HW problem - can not stop rx "
+ "aggregation for tid %d\n", tid);
+
+ /* shutdown timer has not expired */
+ if (initiator != WLAN_BACK_TIMER)
+ del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
+
+ /* check if this is a self generated aggregation halt */
+ if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
+ ieee80211_send_delba(sdata, ra, tid, 0, reason);
+
+ /* free the reordering buffer */
+ for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
+ if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
+ /* release the reordered frames */
+ dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
+ sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
+ sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
+ }
+ }
+ /* free resources */
+ kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
+ kfree(sta->ampdu_mlme.tid_rx[tid]);
+ sta->ampdu_mlme.tid_rx[tid] = NULL;
+ sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
+
+ rcu_read_unlock();
+}
+
+/*
+ * After accepting the AddBA Request we activated a timer,
+ * resetting it after each frame that arrives from the originator.
+ * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
+ */
+static void sta_rx_agg_session_timer_expired(unsigned long data)
+{
+ /* not an elegant detour, but there is no choice as the timer passes
+ * only one argument, and various sta_info are needed here, so init
+ * flow in sta_info_create gives the TID as data, while the timer_to_id
+ * array gives the sta through container_of */
+ u8 *ptid = (u8 *)data;
+ u8 *timer_to_id = ptid - *ptid;
+ struct sta_info *sta = container_of(timer_to_id, struct sta_info,
+ timer_to_tid[0]);
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
+#endif
+ ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
+ (u16)*ptid, WLAN_BACK_TIMER,
+ WLAN_REASON_QSTA_TIMEOUT);
+}
+
+static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
+ u8 dialog_token, u16 status, u16 policy,
+ u16 buf_size, u16 timeout)
+{
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_local *local = sdata->local;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ u16 capab;
+
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer "
+ "for addba resp frame\n", sdata->dev->name);
+ return;
+ }
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, da, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+ else
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+
+ skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
+ mgmt->u.action.category = WLAN_CATEGORY_BACK;
+ mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
+ mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
+
+ capab = (u16)(policy << 1); /* bit 1 aggregation policy */
+ capab |= (u16)(tid << 2); /* bit 5:2 TID number */
+ capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
+
+ mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
+ mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
+ mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
+
+ ieee80211_tx_skb(sdata, skb, 1);
+}
+
+void ieee80211_process_addba_request(struct ieee80211_local *local,
+ struct sta_info *sta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee80211_hw *hw = &local->hw;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct tid_ampdu_rx *tid_agg_rx;
+ u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
+ u8 dialog_token;
+ int ret = -EOPNOTSUPP;
+
+ /* extract session parameters from addba request frame */
+ dialog_token = mgmt->u.action.u.addba_req.dialog_token;
+ timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+ start_seq_num =
+ le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
+
+ capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+ ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
+ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+ buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+
+ status = WLAN_STATUS_REQUEST_DECLINED;
+
+ /* sanity check for incoming parameters:
+ * check if configuration can support the BA policy
+ * and if buffer size does not exceeds max value */
+ /* XXX: check own ht delayed BA capability?? */
+ if (((ba_policy != 1)
+ && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
+ || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
+ status = WLAN_STATUS_INVALID_QOS_PARAM;
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_DEBUG "AddBA Req with bad params from "
+ "%pM on tid %u. policy %d, buffer size %d\n",
+ mgmt->sa, tid, ba_policy,
+ buf_size);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ goto end_no_lock;
+ }
+ /* determine default buffer size */
+ if (buf_size == 0) {
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[conf->channel->band];
+ buf_size = IEEE80211_MIN_AMPDU_BUF;
+ buf_size = buf_size << sband->ht_cap.ampdu_factor;
+ }
+
+
+ /* examine state machine */
+ spin_lock_bh(&sta->lock);
+
+ if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_DEBUG "unexpected AddBA Req from "
+ "%pM on tid %u\n",
+ mgmt->sa, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ goto end;
+ }
+
+ /* prepare A-MPDU MLME for Rx aggregation */
+ sta->ampdu_mlme.tid_rx[tid] =
+ kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
+ if (!sta->ampdu_mlme.tid_rx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
+ tid);
+#endif
+ goto end;
+ }
+ /* rx timer */
+ sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
+ sta_rx_agg_session_timer_expired;
+ sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
+ (unsigned long)&sta->timer_to_tid[tid];
+ init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
+
+ tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+
+ /* prepare reordering buffer */
+ tid_agg_rx->reorder_buf =
+ kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
+ if (!tid_agg_rx->reorder_buf) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_ERR "can not allocate reordering buffer "
+ "to tid %d\n", tid);
+#endif
+ kfree(sta->ampdu_mlme.tid_rx[tid]);
+ goto end;
+ }
+
+ if (local->ops->ampdu_action)
+ ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
+ &sta->sta, tid, &start_seq_num);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+ if (ret) {
+ kfree(tid_agg_rx->reorder_buf);
+ kfree(tid_agg_rx);
+ sta->ampdu_mlme.tid_rx[tid] = NULL;
+ goto end;
+ }
+
+ /* change state and send addba resp */
+ sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
+ tid_agg_rx->dialog_token = dialog_token;
+ tid_agg_rx->ssn = start_seq_num;
+ tid_agg_rx->head_seq_num = start_seq_num;
+ tid_agg_rx->buf_size = buf_size;
+ tid_agg_rx->timeout = timeout;
+ tid_agg_rx->stored_mpdu_num = 0;
+ status = WLAN_STATUS_SUCCESS;
+end:
+ spin_unlock_bh(&sta->lock);
+
+end_no_lock:
+ ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
+ dialog_token, status, 1, buf_size, timeout);
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/net/mac80211/agg-tx.c 2009-02-10 20:59:32.000000000 +0100
@@ -0,0 +1,593 @@
+/*
+ * HT handling
+ *
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2009, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "wme.h"
+
+static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
+ const u8 *da, u16 tid,
+ u8 dialog_token, u16 start_seq_num,
+ u16 agg_size, u16 timeout)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ u16 capab;
+
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
+ if (!skb) {
+ printk(KERN_ERR "%s: failed to allocate buffer "
+ "for addba request frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, da, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
+ else
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+
+ skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
+
+ mgmt->u.action.category = WLAN_CATEGORY_BACK;
+ mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
+
+ mgmt->u.action.u.addba_req.dialog_token = dialog_token;
+ capab = (u16)(1 << 1); /* bit 1 aggregation policy */
+ capab |= (u16)(tid << 2); /* bit 5:2 TID number */
+ capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
+
+ mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
+
+ mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
+ mgmt->u.action.u.addba_req.start_seq_num =
+ cpu_to_le16(start_seq_num << 4);
+
+ ieee80211_tx_skb(sdata, skb, 1);
+}
+
+void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sk_buff *skb;
+ struct ieee80211_bar *bar;
+ u16 bar_control = 0;
+
+ skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
+ if (!skb) {
+ printk(KERN_ERR "%s: failed to allocate buffer for "
+ "bar frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
+ memset(bar, 0, sizeof(*bar));
+ bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+ IEEE80211_STYPE_BACK_REQ);
+ memcpy(bar->ra, ra, ETH_ALEN);
+ memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
+ bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
+ bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
+ bar_control |= (u16)(tid << 12);
+ bar->control = cpu_to_le16(bar_control);
+ bar->start_seq_num = cpu_to_le16(ssn);
+
+ ieee80211_tx_skb(sdata, skb, 0);
+}
+
+/*
+ * After sending add Block Ack request we activated a timer until
+ * add Block Ack response will arrive from the recipient.
+ * If this timer expires sta_addba_resp_timer_expired will be executed.
+ */
+static void sta_addba_resp_timer_expired(unsigned long data)
+{
+ /* not an elegant detour, but there is no choice as the timer passes
+ * only one argument, and both sta_info and TID are needed, so init
+ * flow in sta_info_create gives the TID as data, while the timer_to_id
+ * array gives the sta through container_of */
+ u16 tid = *(u8 *)data;
+ struct sta_info *temp_sta = container_of((void *)data,
+ struct sta_info, timer_to_tid[tid]);
+
+ struct ieee80211_local *local = temp_sta->local;
+ struct ieee80211_hw *hw = &local->hw;
+ struct sta_info *sta;
+ u8 *state;
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, temp_sta->sta.addr);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+
+ state = &sta->ampdu_mlme.tid_state_tx[tid];
+ /* check if the TID waits for addBA response */
+ spin_lock_bh(&sta->lock);
+ if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+ spin_unlock_bh(&sta->lock);
+ *state = HT_AGG_STATE_IDLE;
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "timer expired on tid %d but we are not "
+ "expecting addBA response there", tid);
+#endif
+ goto timer_expired_exit;
+ }
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+#endif
+
+ /* go through the state check in stop_BA_session */
+ *state = HT_AGG_STATE_OPERATIONAL;
+ spin_unlock_bh(&sta->lock);
+ ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
+ WLAN_BACK_INITIATOR);
+
+timer_expired_exit:
+ rcu_read_unlock();
+}
+
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata;
+ u16 start_seq_num;
+ u8 *state;
+ int ret = 0;
+
+ if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+ return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
+ ra, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Could not find the station\n");
+#endif
+ ret = -ENOENT;
+ goto exit;
+ }
+
+ spin_lock_bh(&sta->lock);
+
+ /* we have tried too many times, receiver does not want A-MPDU */
+ if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
+ ret = -EBUSY;
+ goto err_unlock_sta;
+ }
+
+ state = &sta->ampdu_mlme.tid_state_tx[tid];
+ /* check if the TID is not in aggregation flow already */
+ if (*state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "BA request denied - session is not "
+ "idle on tid %u\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ ret = -EAGAIN;
+ goto err_unlock_sta;
+ }
+
+ /* prepare A-MPDU MLME for Tx aggregation */
+ sta->ampdu_mlme.tid_tx[tid] =
+ kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
+ if (!sta->ampdu_mlme.tid_tx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
+ tid);
+#endif
+ ret = -ENOMEM;
+ goto err_unlock_sta;
+ }
+ /* Tx timer */
+ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
+ sta_addba_resp_timer_expired;
+ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
+ (unsigned long)&sta->timer_to_tid[tid];
+ init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+
+ if (hw->ampdu_queues) {
+ /* create a new queue for this aggregation */
+ ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+
+ /* case no queue is available to aggregation
+ * don't switch to aggregation */
+ if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "BA request denied - "
+ "queue unavailable for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ goto err_unlock_queue;
+ }
+ }
+ sdata = sta->sdata;
+
+ /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
+ * call back right away, it must see that the flow has begun */
+ *state |= HT_ADDBA_REQUESTED_MSK;
+
+ /* This is slightly racy because the queue isn't stopped */
+ start_seq_num = sta->tid_seq[tid];
+
+ if (local->ops->ampdu_action)
+ ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
+ &sta->sta, tid, &start_seq_num);
+
+ if (ret) {
+ /* No need to requeue the packets in the agg queue, since we
+ * held the tx lock: no packet could be enqueued to the newly
+ * allocated queue */
+ if (hw->ampdu_queues)
+ ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "BA request denied - HW unavailable for"
+ " tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ *state = HT_AGG_STATE_IDLE;
+ goto err_unlock_queue;
+ }
+
+ /* Will put all the packets in the new SW queue */
+ if (hw->ampdu_queues)
+ ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+ spin_unlock_bh(&sta->lock);
+
+ /* send an addBA request */
+ sta->ampdu_mlme.dialog_token_allocator++;
+ sta->ampdu_mlme.tid_tx[tid]->dialog_token =
+ sta->ampdu_mlme.dialog_token_allocator;
+ sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+
+
+ ieee80211_send_addba_request(sta->sdata, ra, tid,
+ sta->ampdu_mlme.tid_tx[tid]->dialog_token,
+ sta->ampdu_mlme.tid_tx[tid]->ssn,
+ 0x40, 5000);
+ /* activate the timer for the recipient's addBA response */
+ sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
+ jiffies + ADDBA_RESP_INTERVAL;
+ add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+#endif
+ goto exit;
+
+err_unlock_queue:
+ kfree(sta->ampdu_mlme.tid_tx[tid]);
+ sta->ampdu_mlme.tid_tx[tid] = NULL;
+ ret = -EBUSY;
+err_unlock_sta:
+ spin_unlock_bh(&sta->lock);
+exit:
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
+
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+ u8 *state;
+
+ if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+ tid, STA_TID_NUM);
+#endif
+ return;
+ }
+
+ rcu_read_lock();
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+ rcu_read_unlock();
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Could not find station: %pM\n", ra);
+#endif
+ return;
+ }
+
+ state = &sta->ampdu_mlme.tid_state_tx[tid];
+ spin_lock_bh(&sta->lock);
+
+ if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
+ *state);
+#endif
+ spin_unlock_bh(&sta->lock);
+ rcu_read_unlock();
+ return;
+ }
+
+ WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+
+ *state |= HT_ADDBA_DRV_READY_MSK;
+
+ if (*state == HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+#endif
+ if (hw->ampdu_queues)
+ ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+ }
+ spin_unlock_bh(&sta->lock);
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
+
+
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+ u8 *ra, u16 tid,
+ enum ieee80211_back_parties initiator)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+ u8 *state;
+ int ret = 0;
+
+ if (tid >= STA_TID_NUM)
+ return -EINVAL;
+
+ rcu_read_lock();
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ /* check if the TID is in aggregation */
+ state = &sta->ampdu_mlme.tid_state_tx[tid];
+ spin_lock_bh(&sta->lock);
+
+ if (*state != HT_AGG_STATE_OPERATIONAL) {
+ ret = -ENOENT;
+ goto stop_BA_exit;
+ }
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
+ ra, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+ if (hw->ampdu_queues)
+ ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
+
+ *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
+ (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+
+ if (local->ops->ampdu_action)
+ ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
+ &sta->sta, tid, NULL);
+
+ /* case HW denied going back to legacy */
+ if (ret) {
+ WARN_ON(ret != -EBUSY);
+ *state = HT_AGG_STATE_OPERATIONAL;
+ if (hw->ampdu_queues)
+ ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+ goto stop_BA_exit;
+ }
+
+stop_BA_exit:
+ spin_unlock_bh(&sta->lock);
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
+
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta;
+ u8 *state;
+ int agg_queue;
+
+ if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+ tid, STA_TID_NUM);
+#endif
+ return;
+ }
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
+ ra, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+ rcu_read_lock();
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Could not find station: %pM\n", ra);
+#endif
+ rcu_read_unlock();
+ return;
+ }
+ state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+ /* NOTE: no need to use sta->lock in this state check, as
+ * ieee80211_stop_tx_ba_session will let only one stop call to
+ * pass through per sta/tid
+ */
+ if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
+#endif
+ rcu_read_unlock();
+ return;
+ }
+
+ if (*state & HT_AGG_STATE_INITIATOR_MSK)
+ ieee80211_send_delba(sta->sdata, ra, tid,
+ WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+
+ if (hw->ampdu_queues) {
+ agg_queue = sta->tid_to_tx_q[tid];
+ ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+
+ /* We just requeued the all the frames that were in the
+ * removed queue, and since we might miss a softirq we do
+ * netif_schedule_queue. ieee80211_wake_queue is not used
+ * here as this queue is not necessarily stopped
+ */
+ netif_schedule_queue(netdev_get_tx_queue(local->mdev,
+ agg_queue));
+ }
+ spin_lock_bh(&sta->lock);
+ *state = HT_AGG_STATE_IDLE;
+ sta->ampdu_mlme.addba_req_num[tid] = 0;
+ kfree(sta->ampdu_mlme.tid_tx[tid]);
+ sta->ampdu_mlme.tid_tx[tid] = NULL;
+ spin_unlock_bh(&sta->lock);
+
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
+
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+ const u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_ra_tid *ra_tid;
+ struct sk_buff *skb = dev_alloc_skb(0);
+
+ if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: Not enough memory, "
+ "dropping start BA session", skb->dev->name);
+#endif
+ return;
+ }
+ ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+ memcpy(&ra_tid->ra, ra, ETH_ALEN);
+ ra_tid->tid = tid;
+
+ skb->pkt_type = IEEE80211_ADDBA_MSG;
+ skb_queue_tail(&local->skb_queue, skb);
+ tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+ const u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_ra_tid *ra_tid;
+ struct sk_buff *skb = dev_alloc_skb(0);
+
+ if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: Not enough memory, "
+ "dropping stop BA session", skb->dev->name);
+#endif
+ return;
+ }
+ ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+ memcpy(&ra_tid->ra, ra, ETH_ALEN);
+ ra_tid->tid = tid;
+
+ skb->pkt_type = IEEE80211_DELBA_MSG;
+ skb_queue_tail(&local->skb_queue, skb);
+ tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
+
+void ieee80211_process_addba_resp(struct ieee80211_local *local,
+ struct sta_info *sta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee80211_hw *hw = &local->hw;
+ u16 capab;
+ u16 tid, start_seq_num;
+ u8 *state;
+
+ capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+
+ state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+ spin_lock_bh(&sta->lock);
+
+ if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+ spin_unlock_bh(&sta->lock);
+ return;
+ }
+
+ if (mgmt->u.action.u.addba_resp.dialog_token !=
+ sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
+ spin_unlock_bh(&sta->lock);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ return;
+ }
+
+ del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
+ == WLAN_STATUS_SUCCESS) {
+ *state |= HT_ADDBA_RECEIVED_MSK;
+ sta->ampdu_mlme.addba_req_num[tid] = 0;
+
+ if (*state == HT_AGG_STATE_OPERATIONAL &&
+ local->hw.ampdu_queues)
+ ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+
+ if (local->ops->ampdu_action) {
+ (void)local->ops->ampdu_action(hw,
+ IEEE80211_AMPDU_TX_RESUME,
+ &sta->sta, tid, &start_seq_num);
+ }
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+ spin_unlock_bh(&sta->lock);
+ } else {
+ sta->ampdu_mlme.addba_req_num[tid]++;
+ /* this will allow the state check in stop_BA_session */
+ *state = HT_AGG_STATE_OPERATIONAL;
+ spin_unlock_bh(&sta->lock);
+ ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
+ WLAN_BACK_INITIATOR);
+ }
+}
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 11/27] mac80211: restrict aggregation to supported interface modes
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (9 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 10/27] mac80211: restructure HT code Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 12/27] mac80211: hardware should not deny going back to legacy Johannes Berg
` (15 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
We can only support aggregation on AP/STA right now. HT isn't defined
for IBSS, WDS or MESH. In the WDS/MESH cases it's not clear what to
put into the IBSS field, and we don't handle that in the code at all.
Also fix the code to handle VLAN correctly.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
v2: do not allow IBSS
net/mac80211/agg-rx.c | 3 ++-
net/mac80211/agg-tx.c | 16 +++++++++++++++-
net/mac80211/ht.c | 3 ++-
net/mac80211/rx.c | 11 +++++++++++
4 files changed, 30 insertions(+), 3 deletions(-)
--- wireless-testing.orig/net/mac80211/agg-tx.c 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/agg-tx.c 2009-02-10 20:59:32.000000000 +0100
@@ -41,7 +41,8 @@ static void ieee80211_send_addba_request
memset(mgmt, 0, 24);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == NL80211_IFTYPE_AP)
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
else
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -180,6 +181,19 @@ int ieee80211_start_tx_ba_session(struct
goto exit;
}
+ /*
+ * The aggregation code is not prepared to handle
+ * anything but STA/AP due to the BSSID handling.
+ * IBSS could work in the code but isn't supported
+ * by drivers or the standard.
+ */
+ if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sta->sdata->vif.type != NL80211_IFTYPE_AP) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
spin_lock_bh(&sta->lock);
/* we have tried too many times, receiver does not want A-MPDU */
--- wireless-testing.orig/net/mac80211/rx.c 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/rx.c 2009-02-10 20:59:32.000000000 +0100
@@ -1735,6 +1735,17 @@ ieee80211_rx_h_action(struct ieee80211_r
switch (mgmt->u.action.category) {
case WLAN_CATEGORY_BACK:
+ /*
+ * The aggregation code is not prepared to handle
+ * anything but STA/AP due to the BSSID handling;
+ * IBSS could work in the code but isn't supported
+ * by drivers or the standard.
+ */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP)
+ return RX_DROP_MONITOR;
+
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
--- wireless-testing.orig/net/mac80211/agg-rx.c 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/agg-rx.c 2009-02-10 20:59:32.000000000 +0100
@@ -134,7 +134,8 @@ static void ieee80211_send_addba_resp(st
memset(mgmt, 0, 24);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == NL80211_IFTYPE_AP)
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
else
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
--- wireless-testing.orig/net/mac80211/ht.c 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/ht.c 2009-02-10 20:59:32.000000000 +0100
@@ -190,7 +190,8 @@ void ieee80211_send_delba(struct ieee802
memset(mgmt, 0, 24);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
- if (sdata->vif.type == NL80211_IFTYPE_AP)
+ if (sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
else
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 12/27] mac80211: hardware should not deny going back to legacy
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (10 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 11/27] mac80211: restrict aggregation to supported interface modes Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 13/27] mac80211: document TX aggregation (and small cleanup) Johannes Berg
` (14 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Doing so would be an MLME protocol violation when the peer disabled
the aggregation session. Quick driver review indicates that there are
error codes passed all over the drivers but cannot ever be nonzero
except in error conditions that would indicate mac80211 bugs.
No real changes here, since no drivers currently can return -EBUSY.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/agg-tx.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
--- wireless-testing.orig/net/mac80211/agg-tx.c 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/agg-tx.c 2009-02-10 20:59:33.000000000 +0100
@@ -407,9 +407,8 @@ int ieee80211_stop_tx_ba_session(struct
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
&sta->sta, tid, NULL);
- /* case HW denied going back to legacy */
- if (ret) {
- WARN_ON(ret != -EBUSY);
+ /* HW shall not deny going back to legacy */
+ if (WARN_ON(ret)) {
*state = HT_AGG_STATE_OPERATIONAL;
if (hw->ampdu_queues)
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 13/27] mac80211: document TX aggregation (and small cleanup)
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (11 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 12/27] mac80211: hardware should not deny going back to legacy Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 14/27] mac80211: fix race in TX aggregation Johannes Berg
` (13 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Add documentation and move ieee80211_start_tx_ba_cb_irqsafe to right
after ieee80211_start_tx_ba_cb.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/agg-tx.c | 76 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 51 insertions(+), 25 deletions(-)
--- wireless-testing.orig/net/mac80211/agg-tx.c 2009-02-10 20:59:33.000000000 +0100
+++ wireless-testing/net/mac80211/agg-tx.c 2009-02-10 20:59:33.000000000 +0100
@@ -18,6 +18,31 @@
#include "ieee80211_i.h"
#include "wme.h"
+/**
+ * DOC: TX aggregation
+ *
+ * Aggregation on the TX side requires setting the hardware flag
+ * %IEEE80211_HW_AMPDU_AGGREGATION as well as, if present, the @ampdu_queues
+ * hardware parameter to the number of hardware AMPDU queues. If there are no
+ * hardware queues then the driver will (currently) have to do all frame
+ * buffering.
+ *
+ * When TX aggregation is started by some subsystem (usually the rate control
+ * algorithm would be appropriate) by calling the
+ * ieee80211_start_tx_ba_session() function, the driver will be notified via
+ * its @ampdu_action function, with the %IEEE80211_AMPDU_TX_START action.
+ *
+ * In response to that, the driver is later required to call the
+ * ieee80211_start_tx_ba_cb() (or ieee80211_start_tx_ba_cb_irqsafe())
+ * function, which will start the aggregation session.
+ *
+ * Similarly, when the aggregation session is stopped by
+ * ieee80211_stop_tx_ba_session(), the driver's @ampdu_action function will
+ * be called with the action %IEEE80211_AMPDU_TX_STOP. In this case, the
+ * call must not fail, and the driver must later call ieee80211_stop_tx_ba_cb()
+ * (or ieee80211_stop_tx_ba_cb_irqsafe()).
+ */
+
static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
const u8 *da, u16 tid,
u8 dialog_token, u16 start_seq_num,
@@ -363,6 +388,31 @@ void ieee80211_start_tx_ba_cb(struct iee
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+ const u8 *ra, u16 tid)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_ra_tid *ra_tid;
+ struct sk_buff *skb = dev_alloc_skb(0);
+
+ if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: Not enough memory, "
+ "dropping start BA session", skb->dev->name);
+#endif
+ return;
+ }
+ ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+ memcpy(&ra_tid->ra, ra, ETH_ALEN);
+ ra_tid->tid = tid;
+
+ skb->pkt_type = IEEE80211_ADDBA_MSG;
+ skb_queue_tail(&local->skb_queue, skb);
+ tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
u8 *ra, u16 tid,
@@ -492,31 +542,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
-void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
- const u8 *ra, u16 tid)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_ra_tid *ra_tid;
- struct sk_buff *skb = dev_alloc_skb(0);
-
- if (unlikely(!skb)) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping start BA session", skb->dev->name);
-#endif
- return;
- }
- ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
- memcpy(&ra_tid->ra, ra, ETH_ALEN);
- ra_tid->tid = tid;
-
- skb->pkt_type = IEEE80211_ADDBA_MSG;
- skb_queue_tail(&local->skb_queue, skb);
- tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
-
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
const u8 *ra, u16 tid)
{
@@ -542,6 +567,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(str
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
+
void ieee80211_process_addba_resp(struct ieee80211_local *local,
struct sta_info *sta,
struct ieee80211_mgmt *mgmt,
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 14/27] mac80211: fix race in TX aggregation
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (12 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 13/27] mac80211: document TX aggregation (and small cleanup) Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 15/27] mac80211: fix aggregation timer lockups Johannes Berg
` (12 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
When disabling TX aggregation because it was rejected or from
the timer (it was not accepted), there is a window where we
first set the state to operation, unlock, and then undo the
whole thing. Avoid that by splitting up the stop function.
Also get rid of the pointless sta_info indirection in the timer.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/agg-tx.c | 95 +++++++++++++++++++++++++-------------------------
1 file changed, 48 insertions(+), 47 deletions(-)
--- wireless-testing.orig/net/mac80211/agg-tx.c 2009-02-10 20:59:33.000000000 +0100
+++ wireless-testing/net/mac80211/agg-tx.c 2009-02-10 20:59:34.000000000 +0100
@@ -123,6 +123,34 @@ void ieee80211_send_bar(struct ieee80211
ieee80211_tx_skb(sdata, skb, 0);
}
+static int __ieee80211_stop_tx_ba_session(struct ieee80211_local *local,
+ struct sta_info *sta, u16 tid,
+ enum ieee80211_back_parties initiator)
+{
+ int ret;
+ u8 *state;
+
+ state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+ if (local->hw.ampdu_queues)
+ ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]);
+
+ *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
+ (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+
+ ret = local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_STOP,
+ &sta->sta, tid, NULL);
+
+ /* HW shall not deny going back to legacy */
+ if (WARN_ON(ret)) {
+ *state = HT_AGG_STATE_OPERATIONAL;
+ if (local->hw.ampdu_queues)
+ ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]);
+ }
+
+ return ret;
+}
+
/*
* After sending add Block Ack request we activated a timer until
* add Block Ack response will arrive from the recipient.
@@ -135,23 +163,13 @@ static void sta_addba_resp_timer_expired
* flow in sta_info_create gives the TID as data, while the timer_to_id
* array gives the sta through container_of */
u16 tid = *(u8 *)data;
- struct sta_info *temp_sta = container_of((void *)data,
+ struct sta_info *sta = container_of((void *)data,
struct sta_info, timer_to_tid[tid]);
-
- struct ieee80211_local *local = temp_sta->local;
- struct ieee80211_hw *hw = &local->hw;
- struct sta_info *sta;
+ struct ieee80211_local *local = sta->local;
u8 *state;
- rcu_read_lock();
-
- sta = sta_info_get(local, temp_sta->sta.addr);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
-
state = &sta->ampdu_mlme.tid_state_tx[tid];
+
/* check if the TID waits for addBA response */
spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
@@ -161,21 +179,15 @@ static void sta_addba_resp_timer_expired
printk(KERN_DEBUG "timer expired on tid %d but we are not "
"expecting addBA response there", tid);
#endif
- goto timer_expired_exit;
+ return;
}
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
#endif
- /* go through the state check in stop_BA_session */
- *state = HT_AGG_STATE_OPERATIONAL;
+ __ieee80211_stop_tx_ba_session(local, sta, tid, WLAN_BACK_INITIATOR);
spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
- WLAN_BACK_INITIATOR);
-
-timer_expired_exit:
- rcu_read_unlock();
}
int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
@@ -187,6 +199,9 @@ int ieee80211_start_tx_ba_session(struct
u8 *state;
int ret = 0;
+ if (WARN_ON(!local->ops->ampdu_action))
+ return -EINVAL;
+
if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
return -EINVAL;
@@ -280,9 +295,8 @@ int ieee80211_start_tx_ba_session(struct
/* This is slightly racy because the queue isn't stopped */
start_seq_num = sta->tid_seq[tid];
- if (local->ops->ampdu_action)
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
- &sta->sta, tid, &start_seq_num);
+ ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
+ &sta->sta, tid, &start_seq_num);
if (ret) {
/* No need to requeue the packets in the agg queue, since we
@@ -423,6 +437,9 @@ int ieee80211_stop_tx_ba_session(struct
u8 *state;
int ret = 0;
+ if (WARN_ON(!local->ops->ampdu_action))
+ return -EINVAL;
+
if (tid >= STA_TID_NUM)
return -EINVAL;
@@ -439,7 +456,7 @@ int ieee80211_stop_tx_ba_session(struct
if (*state != HT_AGG_STATE_OPERATIONAL) {
ret = -ENOENT;
- goto stop_BA_exit;
+ goto unlock;
}
#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -447,27 +464,13 @@ int ieee80211_stop_tx_ba_session(struct
ra, tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- if (hw->ampdu_queues)
- ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
-
- *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
- (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+ ret = __ieee80211_stop_tx_ba_session(local, sta, tid, initiator);
- if (local->ops->ampdu_action)
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
- &sta->sta, tid, NULL);
-
- /* HW shall not deny going back to legacy */
- if (WARN_ON(ret)) {
- *state = HT_AGG_STATE_OPERATIONAL;
- if (hw->ampdu_queues)
- ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
- goto stop_BA_exit;
- }
-
-stop_BA_exit:
+ unlock:
spin_unlock_bh(&sta->lock);
+
rcu_read_unlock();
+
return ret;
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
@@ -623,10 +626,8 @@ void ieee80211_process_addba_resp(struct
spin_unlock_bh(&sta->lock);
} else {
sta->ampdu_mlme.addba_req_num[tid]++;
- /* this will allow the state check in stop_BA_session */
- *state = HT_AGG_STATE_OPERATIONAL;
+ __ieee80211_stop_tx_ba_session(local, sta, tid,
+ WLAN_BACK_INITIATOR);
spin_unlock_bh(&sta->lock);
- ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
- WLAN_BACK_INITIATOR);
}
}
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 15/27] mac80211: fix aggregation timer lockups
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (13 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 14/27] mac80211: fix race in TX aggregation Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 16/27] mac80211: clean up BA session teardown Johannes Berg
` (11 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
As far as I can tell, there are possible lockups because both the RX
session_timer and TX addba_resp_timer are del_timer_sync'ed under
the sta spinlock which both timer functions take. Additionally, the
TX agg code seems to leak memory when TX aggregation is not disabled
before the sta_info is freed.
Fix this by making the free code a little smarter in the RX agg case,
and actually make the sta_info_destroy code free the TX agg info in
the TX agg case. We won't notify the peer, but it'll notice something
is wrong anyway, and normally this only happens after we've told it
in some other way we will no longer talk to it.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/agg-rx.c | 11 +++++++++--
net/mac80211/sta_info.c | 37 +++++++++++++++++++++++++++++++++----
net/mac80211/sta_info.h | 1 +
3 files changed, 43 insertions(+), 6 deletions(-)
--- wireless-testing.orig/net/mac80211/agg-rx.c 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/agg-rx.c 2009-02-10 20:59:34.000000000 +0100
@@ -78,11 +78,18 @@ void ieee80211_sta_stop_rx_ba_session(st
sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
}
}
+
+ spin_lock_bh(&sta->lock);
/* free resources */
kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
- kfree(sta->ampdu_mlme.tid_rx[tid]);
- sta->ampdu_mlme.tid_rx[tid] = NULL;
+
+ if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) {
+ kfree(sta->ampdu_mlme.tid_rx[tid]);
+ sta->ampdu_mlme.tid_rx[tid] = NULL;
+ }
+
sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
--- wireless-testing.orig/net/mac80211/sta_info.c 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/net/mac80211/sta_info.c 2009-02-10 20:59:34.000000000 +0100
@@ -194,12 +194,41 @@ void sta_info_destroy(struct sta_info *s
dev_kfree_skb_any(skb);
for (i = 0; i < STA_TID_NUM; i++) {
+ struct tid_ampdu_rx *tid_rx;
+ struct tid_ampdu_tx *tid_tx;
+
spin_lock_bh(&sta->lock);
- if (sta->ampdu_mlme.tid_rx[i])
- del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer);
- if (sta->ampdu_mlme.tid_tx[i])
- del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer);
+ tid_rx = sta->ampdu_mlme.tid_rx[i];
+ /* Make sure timer won't free the tid_rx struct, see below */
+ if (tid_rx)
+ tid_rx->shutdown = true;
spin_unlock_bh(&sta->lock);
+
+ /*
+ * Outside spinlock - shutdown is true now so that the timer
+ * won't free tid_rx, we have to do that now. Can't let the
+ * timer do it because we have to sync the timer outside the
+ * lock that it takes itself.
+ */
+ if (tid_rx) {
+ del_timer_sync(&tid_rx->session_timer);
+ kfree(tid_rx);
+ }
+
+ /*
+ * No need to do such complications for TX agg sessions, the
+ * path leading to freeing the tid_tx struct goes via a call
+ * from the driver, and thus needs to look up the sta struct
+ * again, which cannot be found when we get here. Hence, we
+ * just need to delete the timer and free the aggregation
+ * info; we won't be telling the peer about it then but that
+ * doesn't matter if we're not talking to it again anyway.
+ */
+ tid_tx = sta->ampdu_mlme.tid_tx[i];
+ if (tid_tx) {
+ del_timer_sync(&tid_tx->addba_resp_timer);
+ kfree(tid_tx);
+ }
}
__sta_info_free(local, sta);
--- wireless-testing.orig/net/mac80211/sta_info.h 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/sta_info.h 2009-02-10 20:59:34.000000000 +0100
@@ -100,6 +100,7 @@ struct tid_ampdu_rx {
u16 buf_size;
u16 timeout;
u8 dialog_token;
+ bool shutdown;
};
/**
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 16/27] mac80211: clean up BA session teardown
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (14 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 15/27] mac80211: fix aggregation timer lockups Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 17/27] mac80211: RX aggregation: clean up stop session Johannes Berg
` (10 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
The sta_info pointer can very well be passed to
ieee80211_sta_tear_down_BA_sessions, this will
later allow us to pass it through even further.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/ht.c | 8 ++++----
net/mac80211/ieee80211_i.h | 2 +-
net/mac80211/iface.c | 3 +--
net/mac80211/mlme.c | 2 +-
4 files changed, 7 insertions(+), 8 deletions(-)
--- wireless-testing.orig/net/mac80211/ht.c 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/ht.c 2009-02-10 20:59:34.000000000 +0100
@@ -153,15 +153,15 @@ u32 ieee80211_enable_ht(struct ieee80211
return changed;
}
-void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
{
- struct ieee80211_local *local = sdata->local;
+ struct ieee80211_local *local = sta->local;
int i;
for (i = 0; i < STA_TID_NUM; i++) {
- ieee80211_stop_tx_ba_session(&local->hw, addr, i,
+ ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, i,
WLAN_BACK_INITIATOR);
- ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
+ ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, i,
WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_LEAVE_QBSS);
}
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-02-10 20:59:32.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-02-10 20:59:34.000000000 +0100
@@ -990,7 +990,7 @@ void ieee80211_send_delba(struct ieee802
void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
u16 tid, u16 initiator, u16 reason);
-void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr);
+void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_mgmt *mgmt, size_t len);
--- wireless-testing.orig/net/mac80211/iface.c 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/net/mac80211/iface.c 2009-02-10 20:59:34.000000000 +0100
@@ -362,8 +362,7 @@ static int ieee80211_stop(struct net_dev
list_for_each_entry_rcu(sta, &local->sta_list, list) {
if (sta->sdata == sdata)
- ieee80211_sta_tear_down_BA_sessions(sdata,
- sta->sta.addr);
+ ieee80211_sta_tear_down_BA_sessions(sta);
}
rcu_read_unlock();
--- wireless-testing.orig/net/mac80211/mlme.c 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c 2009-02-10 20:59:34.000000000 +0100
@@ -924,7 +924,7 @@ static void ieee80211_set_disassoc(struc
netif_tx_stop_all_queues(sdata->dev);
netif_carrier_off(sdata->dev);
- ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr);
+ ieee80211_sta_tear_down_BA_sessions(sta);
if (self_disconnected) {
if (deauth)
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 17/27] mac80211: RX aggregation: clean up stop session
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (15 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 16/27] mac80211: clean up BA session teardown Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 18/27] mac80211: further cleanups to stopping BA sessions Johannes Berg
` (9 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Clean up the locking by splitting it into two functions,
this will also enable further cleanups of stopping all
sessions.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/agg-rx.c | 57 ++++++++++++++++++++++++++++----------------------
1 file changed, 32 insertions(+), 25 deletions(-)
--- wireless-testing.orig/net/mac80211/agg-rx.c 2009-02-10 20:59:34.000000000 +0100
+++ wireless-testing/net/mac80211/agg-rx.c 2009-02-10 20:59:35.000000000 +0100
@@ -17,47 +17,32 @@
#include <net/mac80211.h>
#include "ieee80211_i.h"
-void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
- u16 initiator, u16 reason)
+static void __ieee80211_sta_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+ u16 initiator, u16 reason)
{
- struct ieee80211_local *local = sdata->local;
+ struct ieee80211_local *local = sta->local;
struct ieee80211_hw *hw = &local->hw;
- struct sta_info *sta;
- int ret, i;
-
- rcu_read_lock();
-
- sta = sta_info_get(local, ra);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
+ int i;
/* check if TID is in operational state */
spin_lock_bh(&sta->lock);
- if (sta->ampdu_mlme.tid_state_rx[tid]
- != HT_AGG_STATE_OPERATIONAL) {
+ if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) {
spin_unlock_bh(&sta->lock);
- rcu_read_unlock();
return;
}
+
sta->ampdu_mlme.tid_state_rx[tid] =
HT_AGG_STATE_REQ_STOP_BA_MSK |
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
spin_unlock_bh(&sta->lock);
- /* stop HW Rx aggregation. ampdu_action existence
- * already verified in session init so we add the BUG_ON */
- BUG_ON(!local->ops->ampdu_action);
-
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
- ra, tid);
+ sta->sta.addr, tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
- &sta->sta, tid, NULL);
- if (ret)
+ if (local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
+ &sta->sta, tid, NULL))
printk(KERN_DEBUG "HW problem - can not stop rx "
"aggregation for tid %d\n", tid);
@@ -67,7 +52,8 @@ void ieee80211_sta_stop_rx_ba_session(st
/* check if this is a self generated aggregation halt */
if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
- ieee80211_send_delba(sdata, ra, tid, 0, reason);
+ ieee80211_send_delba(sta->sdata, sta->sta.addr,
+ tid, 0, reason);
/* free the reordering buffer */
for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
@@ -90,6 +76,27 @@ void ieee80211_sta_stop_rx_ba_session(st
sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
spin_unlock_bh(&sta->lock);
+}
+
+void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
+ u16 initiator, u16 reason)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ /* stop HW Rx aggregation. ampdu_action existence
+ * already verified in session init so we add the BUG_ON */
+ BUG_ON(!local->ops->ampdu_action);
+
+ rcu_read_lock();
+
+ sta = sta_info_get(local, ra);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+
+ __ieee80211_sta_stop_rx_ba_session(sta, tid, initiator, reason);
rcu_read_unlock();
}
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 18/27] mac80211: further cleanups to stopping BA sessions
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (16 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 17/27] mac80211: RX aggregation: clean up stop session Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 19/27] cfg80211/nl80211: scanning (and mac80211 update to use it) Johannes Berg
` (8 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Essentially consisting of passing the sta_info pointer around,
instead of repeatedly doing hash lookups.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/agg-rx.c | 6 ++--
net/mac80211/agg-tx.c | 63 +++++++++++++++++++++++----------------------
net/mac80211/ht.c | 9 ++----
net/mac80211/ieee80211_i.h | 5 +++
4 files changed, 44 insertions(+), 39 deletions(-)
--- wireless-testing.orig/net/mac80211/agg-rx.c 2009-02-10 20:59:35.000000000 +0100
+++ wireless-testing/net/mac80211/agg-rx.c 2009-02-10 20:59:35.000000000 +0100
@@ -17,8 +17,8 @@
#include <net/mac80211.h>
#include "ieee80211_i.h"
-static void __ieee80211_sta_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- u16 initiator, u16 reason)
+void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+ u16 initiator, u16 reason)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_hw *hw = &local->hw;
@@ -96,7 +96,7 @@ void ieee80211_sta_stop_rx_ba_session(st
return;
}
- __ieee80211_sta_stop_rx_ba_session(sta, tid, initiator, reason);
+ __ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
rcu_read_unlock();
}
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-02-10 20:59:34.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-02-10 20:59:35.000000000 +0100
@@ -990,6 +990,8 @@ void ieee80211_send_delba(struct ieee802
void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
u16 tid, u16 initiator, u16 reason);
+void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+ u16 initiator, u16 reason);
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
@@ -1003,6 +1005,9 @@ void ieee80211_process_addba_request(str
struct ieee80211_mgmt *mgmt,
size_t len);
+int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
+ enum ieee80211_back_parties initiator);
+
/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
--- wireless-testing.orig/net/mac80211/agg-tx.c 2009-02-10 20:59:34.000000000 +0100
+++ wireless-testing/net/mac80211/agg-tx.c 2009-02-10 20:59:35.000000000 +0100
@@ -123,10 +123,10 @@ void ieee80211_send_bar(struct ieee80211
ieee80211_tx_skb(sdata, skb, 0);
}
-static int __ieee80211_stop_tx_ba_session(struct ieee80211_local *local,
- struct sta_info *sta, u16 tid,
- enum ieee80211_back_parties initiator)
+static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
+ enum ieee80211_back_parties initiator)
{
+ struct ieee80211_local *local = sta->local;
int ret;
u8 *state;
@@ -165,7 +165,6 @@ static void sta_addba_resp_timer_expired
u16 tid = *(u8 *)data;
struct sta_info *sta = container_of((void *)data,
struct sta_info, timer_to_tid[tid]);
- struct ieee80211_local *local = sta->local;
u8 *state;
state = &sta->ampdu_mlme.tid_state_tx[tid];
@@ -186,7 +185,7 @@ static void sta_addba_resp_timer_expired
printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
#endif
- __ieee80211_stop_tx_ba_session(local, sta, tid, WLAN_BACK_INITIATOR);
+ ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
spin_unlock_bh(&sta->lock);
}
@@ -427,6 +426,32 @@ void ieee80211_start_tx_ba_cb_irqsafe(st
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
+ enum ieee80211_back_parties initiator)
+{
+ u8 *state;
+ int ret;
+
+ /* check if the TID is in aggregation */
+ state = &sta->ampdu_mlme.tid_state_tx[tid];
+ spin_lock_bh(&sta->lock);
+
+ if (*state != HT_AGG_STATE_OPERATIONAL) {
+ ret = -ENOENT;
+ goto unlock;
+ }
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
+ sta->sta.addr, tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+ ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
+
+ unlock:
+ spin_unlock_bh(&sta->lock);
+ return ret;
+}
int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
u8 *ra, u16 tid,
@@ -434,7 +459,6 @@ int ieee80211_stop_tx_ba_session(struct
{
struct ieee80211_local *local = hw_to_local(hw);
struct sta_info *sta;
- u8 *state;
int ret = 0;
if (WARN_ON(!local->ops->ampdu_action))
@@ -450,27 +474,8 @@ int ieee80211_stop_tx_ba_session(struct
return -ENOENT;
}
- /* check if the TID is in aggregation */
- state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->lock);
-
- if (*state != HT_AGG_STATE_OPERATIONAL) {
- ret = -ENOENT;
- goto unlock;
- }
-
-#ifdef CONFIG_MAC80211_HT_DEBUG
- printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
- ra, tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-
- ret = __ieee80211_stop_tx_ba_session(local, sta, tid, initiator);
-
- unlock:
- spin_unlock_bh(&sta->lock);
-
+ ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator);
rcu_read_unlock();
-
return ret;
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
@@ -623,11 +628,9 @@ void ieee80211_process_addba_resp(struct
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- spin_unlock_bh(&sta->lock);
} else {
sta->ampdu_mlme.addba_req_num[tid]++;
- __ieee80211_stop_tx_ba_session(local, sta, tid,
- WLAN_BACK_INITIATOR);
- spin_unlock_bh(&sta->lock);
+ ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
}
+ spin_unlock_bh(&sta->lock);
}
--- wireless-testing.orig/net/mac80211/ht.c 2009-02-10 20:59:34.000000000 +0100
+++ wireless-testing/net/mac80211/ht.c 2009-02-10 20:59:35.000000000 +0100
@@ -155,15 +155,12 @@ u32 ieee80211_enable_ht(struct ieee80211
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
{
- struct ieee80211_local *local = sta->local;
int i;
for (i = 0; i < STA_TID_NUM; i++) {
- ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, i,
- WLAN_BACK_INITIATOR);
- ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, i,
- WLAN_BACK_RECIPIENT,
- WLAN_REASON_QSTA_LEAVE_QBSS);
+ __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
+ __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
+ WLAN_REASON_QSTA_LEAVE_QBSS);
}
}
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 19/27] cfg80211/nl80211: scanning (and mac80211 update to use it)
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (17 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 18/27] mac80211: further cleanups to stopping BA sessions Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 20/27] mac80211: dont add BSS when creating IBSS Johannes Berg
` (7 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
This patch adds basic scan capability to cfg80211/nl80211 and
changes mac80211 to use it. The BSS list that cfg80211 maintains
is made driver-accessible with a private area in each BSS struct,
but mac80211 doesn't yet use it. That's another large project.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
TODO (later):
* use BSS stuff from cfg80211 in mac80211 (this is fairly involved)
* port a fullmac driver and complete the API
drivers/net/wireless/iwlwifi/iwl-agn.c | 12
drivers/net/wireless/iwlwifi/iwl-core.c | 1
drivers/net/wireless/iwlwifi/iwl-scan.c | 2
drivers/net/wireless/iwlwifi/iwl3945-base.c | 17
include/linux/nl80211.h | 65 ++
include/net/cfg80211.h | 131 ++++
include/net/mac80211.h | 6
include/net/wireless.h | 3
net/mac80211/cfg.c | 20
net/mac80211/ieee80211_i.h | 18
net/mac80211/iface.c | 2
net/mac80211/main.c | 32 +
net/mac80211/mlme.c | 37 -
net/mac80211/scan.c | 356 ++----------
net/mac80211/wext.c | 59 --
net/wireless/Makefile | 2
net/wireless/core.c | 8
net/wireless/core.h | 20
net/wireless/nl80211.c | 323 +++++++++++
net/wireless/nl80211.h | 8
net/wireless/scan.c | 807 ++++++++++++++++++++++++++++
21 files changed, 1546 insertions(+), 383 deletions(-)
--- wireless-testing.orig/include/linux/nl80211.h 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/include/linux/nl80211.h 2009-02-10 20:59:36.000000000 +0100
@@ -143,6 +143,13 @@
* added to all specified management frames generated by
* kernel/firmware/driver.
*
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
+ * NL80211_CMD_GET_SCAN and on the "scan" multicast group)
+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
+ * partial scan results may be available
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -192,6 +199,11 @@ enum nl80211_commands {
NL80211_CMD_GET_REG,
+ NL80211_CMD_GET_SCAN,
+ NL80211_CMD_TRIGGER_SCAN,
+ NL80211_CMD_NEW_SCAN_RESULTS,
+ NL80211_CMD_SCAN_ABORTED,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -305,6 +317,18 @@ enum nl80211_commands {
* @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
* %NL80211_CMD_SET_MGMT_EXTRA_IE).
*
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ * a single scan request, a wiphy attribute.
+ *
+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ * scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the
+ * scan result list changes (BSS expired or added) so that applications
+ * can verify that they got a single, consistent snapshot (when all dump
+ * messages carried the same generation number)
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -372,6 +396,13 @@ enum nl80211_attrs {
NL80211_ATTR_MGMT_SUBTYPE,
NL80211_ATTR_IE,
+ NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+ NL80211_ATTR_SCAN_FREQUENCIES,
+ NL80211_ATTR_SCAN_SSIDS,
+ NL80211_ATTR_SCAN_GENERATION,
+ NL80211_ATTR_BSS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -841,4 +872,38 @@ enum nl80211_channel_type {
NL80211_CHAN_HT40MINUS,
NL80211_CHAN_HT40PLUS
};
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ * raw information elements from the probe response/beacon (bin)
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ * in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ * in unspecified units, scaled to 0..100 (u8)
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+ __NL80211_BSS_INVALID,
+ NL80211_BSS_BSSID,
+ NL80211_BSS_FREQUENCY,
+ NL80211_BSS_TSF,
+ NL80211_BSS_BEACON_INTERVAL,
+ NL80211_BSS_CAPABILITY,
+ NL80211_BSS_INFORMATION_ELEMENTS,
+ NL80211_BSS_SIGNAL_MBM,
+ NL80211_BSS_SIGNAL_UNSPEC,
+
+ /* keep last */
+ __NL80211_BSS_AFTER_LAST,
+ NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
#endif /* __LINUX_NL80211_H */
--- wireless-testing.orig/include/net/cfg80211.h 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h 2009-02-10 20:59:36.000000000 +0100
@@ -4,6 +4,10 @@
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/nl80211.h>
+#include <linux/if_ether.h>
+#include <linux/ieee80211.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
#include <net/genetlink.h>
/* remove once we remove the wext stuff */
#include <net/iw_handler.h>
@@ -505,6 +509,83 @@ struct wiphy;
struct ieee80211_channel;
/**
+ * struct cfg80211_ssid - SSID description
+ * @ssid: the SSID
+ * @ssid_len: length of the ssid
+ */
+struct cfg80211_ssid {
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid_len;
+};
+
+/**
+ * struct cfg80211_scan_request - scan request description
+ *
+ * @ssids: SSIDs to scan for (active scan only)
+ * @n_ssids: number of SSIDs
+ * @channels: channels to scan on.
+ * @n_channels: number of channels for each band
+ * @wiphy: the wiphy this was for
+ * @ifidx: the interface index
+ */
+struct cfg80211_scan_request {
+ struct cfg80211_ssid *ssids;
+ int n_ssids;
+ struct ieee80211_channel **channels;
+ u32 n_channels;
+
+ /* internal */
+ struct wiphy *wiphy;
+ int ifidx;
+};
+
+/**
+ * enum cfg80211_signal_type - signal type
+ *
+ * @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available
+ * @CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm)
+ * @CFG80211_SIGNAL_TYPE_UNSPEC: signal strength, increasing from 0 through 100
+ */
+enum cfg80211_signal_type {
+ CFG80211_SIGNAL_TYPE_NONE,
+ CFG80211_SIGNAL_TYPE_MBM,
+ CFG80211_SIGNAL_TYPE_UNSPEC,
+};
+
+/**
+ * struct cfg80211_bss - BSS description
+ *
+ * This structure describes a BSS (which may also be a mesh network)
+ * for use in scan results and similar.
+ *
+ * @bssid: BSSID of the BSS
+ * @tsf: timestamp of last received update
+ * @beacon_interval: the beacon interval as from the frame
+ * @capability: the capability field in host byte order
+ * @information_elements: the information elements (Note that there
+ * is no guarantee that these are well-formed!)
+ * @len_information_elements: total length of the information elements
+ * @signal: signal strength value
+ * @signal_type: signal type
+ * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
+ */
+struct cfg80211_bss {
+ struct ieee80211_channel *channel;
+
+ u8 bssid[ETH_ALEN];
+ u64 tsf;
+ u16 beacon_interval;
+ u16 capability;
+ u8 *information_elements;
+ size_t len_information_elements;
+
+ s32 signal;
+ enum cfg80211_signal_type signal_type;
+
+ u8 priv[0] __attribute__((__aligned__(sizeof(void *))));
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -571,6 +652,11 @@ struct ieee80211_channel;
* @set_channel: Set channel
*
* @set_mgmt_extra_ie: Set extra IE data for management frames
+ *
+ * @scan: Request to do a scan. If returning zero, the scan request is given
+ * the driver, and will be valid until passed to cfg80211_scan_done().
+ * For scan results, call cfg80211_inform_bss(); you can call this outside
+ * the scan/scan_done bracket too.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy);
@@ -648,6 +734,9 @@ struct cfg80211_ops {
int (*set_mgmt_extra_ie)(struct wiphy *wiphy,
struct net_device *dev,
struct mgmt_extra_ie_params *params);
+
+ int (*scan)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request);
};
/* temporary wext handlers */
@@ -658,5 +747,47 @@ int cfg80211_wext_siwmode(struct net_dev
u32 *mode, char *extra);
int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
u32 *mode, char *extra);
+int cfg80211_wext_siwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+int cfg80211_wext_giwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra);
+
+/**
+ * cfg80211_scan_done - notify that scan finished
+ *
+ * @request: the corresponding scan request
+ * @aborted: set to true if the scan was aborted for any reason,
+ * userspace will be notified of that
+ */
+void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
+
+/**
+ * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ *
+ * @wiphy: the wiphy reporting the BSS
+ * @bss: the found BSS
+ * @gfp: context flags
+ *
+ * This informs cfg80211 that BSS information was found and
+ * the BSS should be updated/added.
+ */
+struct cfg80211_bss*
+cfg80211_inform_bss_frame(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ s32 signal, enum cfg80211_signal_type sigtype,
+ gfp_t gfp);
+
+struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ const u8 *bssid,
+ const u8 *ssid, size_t ssid_len);
+struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ const u8 *meshid, size_t meshidlen,
+ const u8 *meshcfg);
+void cfg80211_put_bss(struct cfg80211_bss *bss);
#endif /* __NET_CFG80211_H */
--- wireless-testing.orig/net/wireless/nl80211.c 2009-02-10 20:59:24.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c 2009-02-10 20:59:36.000000000 +0100
@@ -14,6 +14,7 @@
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
+#include <linux/etherdevice.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
#include "core.h"
@@ -109,6 +110,8 @@ static struct nla_policy nl80211_policy[
[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
[NL80211_ATTR_IE] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
+ [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
};
/* message building helper */
@@ -141,6 +144,8 @@ static int nl80211_send_wiphy(struct sk_
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+ NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+ dev->wiphy.max_scan_ssids);
nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
if (!nl_modes)
@@ -2270,6 +2275,246 @@ static int nl80211_set_mgmt_extra_ie(str
return err;
}
+static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ struct net_device *dev;
+ struct cfg80211_scan_request *request;
+ struct cfg80211_ssid *ssid;
+ struct ieee80211_channel *channel;
+ struct nlattr *attr;
+ struct wiphy *wiphy;
+ int err, tmp, n_ssids = 0, n_channels = 0, i;
+ enum ieee80211_band band;
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ return err;
+
+ wiphy = &drv->wiphy;
+
+ if (!drv->ops->scan) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+
+ if (drv->scan_req) {
+ err = -EBUSY;
+ goto out_unlock;
+ }
+
+ if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp)
+ n_channels++;
+ if (!n_channels) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
+ } else {
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+ if (wiphy->bands[band])
+ n_channels += wiphy->bands[band]->n_channels;
+ }
+
+ if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
+ n_ssids++;
+
+ if (n_ssids > wiphy->max_scan_ssids) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
+
+ request = kzalloc(sizeof(*request)
+ + sizeof(*ssid) * n_ssids
+ + sizeof(channel) * n_channels, GFP_KERNEL);
+ if (!request) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+
+ request->channels = (void *)((char *)request + sizeof(*request));
+ request->n_channels = n_channels;
+ if (n_ssids)
+ request->ssids = (void *)(request->channels + n_channels);
+ request->n_ssids = n_ssids;
+
+ if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ /* user specified, bail out if channel not found */
+ request->n_channels = n_channels;
+ i = 0;
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) {
+ request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr));
+ if (!request->channels[i]) {
+ err = -EINVAL;
+ goto out_free;
+ }
+ i++;
+ }
+ } else {
+ /* all channels */
+ i = 0;
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ int j;
+ if (!wiphy->bands[band])
+ continue;
+ for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+ request->channels[i] = &wiphy->bands[band]->channels[j];
+ i++;
+ }
+ }
+ }
+
+ i = 0;
+ if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
+ if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) {
+ err = -EINVAL;
+ goto out_free;
+ }
+ memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
+ request->ssids[i].ssid_len = nla_len(attr);
+ i++;
+ }
+ }
+
+ request->ifidx = dev->ifindex;
+ request->wiphy = &drv->wiphy;
+
+ drv->scan_req = request;
+ err = drv->ops->scan(&drv->wiphy, dev, request);
+
+ out_free:
+ if (err) {
+ drv->scan_req = NULL;
+ kfree(request);
+ }
+ out_unlock:
+ rtnl_unlock();
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+ struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_bss *res)
+{
+ void *hdr;
+ struct nlattr *bss;
+
+ hdr = nl80211hdr_put(msg, pid, seq, flags,
+ NL80211_CMD_NEW_SCAN_RESULTS);
+ if (!hdr)
+ return -1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION,
+ rdev->bss_generation);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+
+ bss = nla_nest_start(msg, NL80211_ATTR_BSS);
+ if (!bss)
+ goto nla_put_failure;
+ if (!is_zero_ether_addr(res->bssid))
+ NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid);
+ if (res->information_elements && res->len_information_elements)
+ NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS,
+ res->len_information_elements,
+ res->information_elements);
+ if (res->tsf)
+ NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf);
+ if (res->beacon_interval)
+ NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
+ NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
+ NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
+
+ switch (res->signal_type) {
+ case CFG80211_SIGNAL_TYPE_MBM:
+ NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal);
+ break;
+ case CFG80211_SIGNAL_TYPE_UNSPEC:
+ NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal);
+ break;
+ default:
+ break;
+ }
+
+ nla_nest_end(msg, bss);
+
+ return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+static int nl80211_dump_scan(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct cfg80211_registered_device *dev;
+ struct net_device *netdev;
+ struct cfg80211_internal_bss *scan;
+ int ifidx = cb->args[0];
+ int start = cb->args[1], idx = 0;
+ int err;
+
+ if (!ifidx) {
+ err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+ nl80211_fam.attrbuf, nl80211_fam.maxattr,
+ nl80211_policy);
+ if (err)
+ return err;
+
+ if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
+ return -EINVAL;
+
+ ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
+ if (!ifidx)
+ return -EINVAL;
+ cb->args[0] = ifidx;
+ }
+
+ netdev = dev_get_by_index(&init_net, ifidx);
+ if (!netdev)
+ return -ENODEV;
+
+ dev = cfg80211_get_dev_from_ifindex(ifidx);
+ if (IS_ERR(dev)) {
+ err = PTR_ERR(dev);
+ goto out_put_netdev;
+ }
+
+ spin_lock_bh(&dev->bss_lock);
+ cfg80211_bss_expire(dev);
+
+ list_for_each_entry(scan, &dev->bss_list, list) {
+ if (++idx <= start)
+ continue;
+ if (nl80211_send_bss(skb,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ dev, netdev, &scan->pub) < 0) {
+ idx--;
+ goto out;
+ }
+ }
+
+ out:
+ spin_unlock_bh(&dev->bss_lock);
+
+ cb->args[1] = idx;
+ err = skb->len;
+ cfg80211_put_dev(dev);
+ out_put_netdev:
+ dev_put(netdev);
+
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -2443,12 +2688,26 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_TRIGGER_SCAN,
+ .doit = nl80211_trigger_scan,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_GET_SCAN,
+ .policy = nl80211_policy,
+ .dumpit = nl80211_dump_scan,
+ },
};
/* multicast groups */
static struct genl_multicast_group nl80211_config_mcgrp = {
.name = "config",
};
+static struct genl_multicast_group nl80211_scan_mcgrp = {
+ .name = "scan",
+};
/* notification functions */
@@ -2468,6 +2727,66 @@ void nl80211_notify_dev_rename(struct cf
genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
}
+static int nl80211_send_scan_donemsg(struct sk_buff *msg,
+ struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ u32 pid, u32 seq, int flags,
+ u32 cmd)
+{
+ void *hdr;
+
+ hdr = nl80211hdr_put(msg, pid, seq, flags, cmd);
+ if (!hdr)
+ return -1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+
+ /* XXX: we should probably bounce back the request? */
+
+ return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev)
+{
+ struct sk_buff *msg;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
+ NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
+void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev)
+{
+ struct sk_buff *msg;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0,
+ NL80211_CMD_SCAN_ABORTED) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
/* initialisation/exit functions */
int nl80211_init(void)
@@ -2488,6 +2807,10 @@ int nl80211_init(void)
if (err)
goto err_out;
+ err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp);
+ if (err)
+ goto err_out;
+
return 0;
err_out:
genl_unregister_family(&nl80211_fam);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/net/wireless/scan.c 2009-02-10 20:59:36.000000000 +0100
@@ -0,0 +1,807 @@
+/*
+ * cfg80211 scan result handling
+ *
+ * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/nl80211.h>
+#include <linux/etherdevice.h>
+#include <net/arp.h>
+#include <net/cfg80211.h>
+#include <net/iw_handler.h>
+#include "core.h"
+#include "nl80211.h"
+
+#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
+
+void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
+{
+ struct net_device *dev;
+#ifdef CONFIG_WIRELESS_EXT
+ union iwreq_data wrqu;
+#endif
+
+ dev = dev_get_by_index(&init_net, request->ifidx);
+ if (!dev)
+ goto out;
+
+ WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
+ wiphy_to_dev(request->wiphy)->scan_req = NULL;
+
+ if (aborted)
+ nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
+ else
+ nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
+
+#ifdef CONFIG_WIRELESS_EXT
+ if (!aborted) {
+ memset(&wrqu, 0, sizeof(wrqu));
+
+ wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+#endif
+
+ dev_put(dev);
+
+ out:
+ kfree(request);
+}
+EXPORT_SYMBOL(cfg80211_scan_done);
+
+static void bss_release(struct kref *ref)
+{
+ struct cfg80211_internal_bss *bss;
+
+ bss = container_of(ref, struct cfg80211_internal_bss, ref);
+ kfree(bss);
+}
+
+/* must hold dev->bss_lock! */
+void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
+{
+ struct cfg80211_internal_bss *bss, *tmp;
+ bool expired = false;
+
+ list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
+ if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+ continue;
+ list_del(&bss->list);
+ rb_erase(&bss->rbn, &dev->bss_tree);
+ kref_put(&bss->ref, bss_release);
+ expired = true;
+ }
+
+ if (expired)
+ dev->bss_generation++;
+}
+
+static u8 *find_ie(u8 num, u8 *ies, size_t len)
+{
+ while (len > 2 && ies[0] != num) {
+ len -= ies[1] + 2;
+ ies += ies[1] + 2;
+ }
+ if (len < 2)
+ return NULL;
+ if (len < 2 + ies[1])
+ return NULL;
+ return ies;
+}
+
+static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
+{
+ const u8 *ie1 = find_ie(num, ies1, len1);
+ const u8 *ie2 = find_ie(num, ies2, len2);
+ int r;
+
+ if (!ie1 && !ie2)
+ return 0;
+ if (!ie1)
+ return -1;
+
+ r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1]));
+ if (r == 0 && ie1[1] != ie2[1])
+ return ie2[1] - ie1[1];
+ return r;
+}
+
+static bool is_bss(struct cfg80211_bss *a,
+ const u8 *bssid,
+ const u8 *ssid, size_t ssid_len)
+{
+ const u8 *ssidie;
+
+ if (compare_ether_addr(a->bssid, bssid))
+ return false;
+
+ ssidie = find_ie(WLAN_EID_SSID,
+ a->information_elements,
+ a->len_information_elements);
+ if (!ssidie)
+ return false;
+ if (ssidie[1] != ssid_len)
+ return false;
+ return memcmp(ssidie + 2, ssid, ssid_len) == 0;
+}
+
+static bool is_mesh(struct cfg80211_bss *a,
+ const u8 *meshid, size_t meshidlen,
+ const u8 *meshcfg)
+{
+ const u8 *ie;
+
+ if (!is_zero_ether_addr(a->bssid))
+ return false;
+
+ ie = find_ie(WLAN_EID_MESH_ID,
+ a->information_elements,
+ a->len_information_elements);
+ if (!ie)
+ return false;
+ if (ie[1] != meshidlen)
+ return false;
+ if (memcmp(ie + 2, meshid, meshidlen))
+ return false;
+
+ ie = find_ie(WLAN_EID_MESH_CONFIG,
+ a->information_elements,
+ a->len_information_elements);
+ if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
+ return false;
+
+ /*
+ * Ignore mesh capability (last two bytes of the IE) when
+ * comparing since that may differ between stations taking
+ * part in the same mesh.
+ */
+ return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0;
+}
+
+static int cmp_bss(struct cfg80211_bss *a,
+ struct cfg80211_bss *b)
+{
+ int r;
+
+ if (a->channel != b->channel)
+ return b->channel->center_freq - a->channel->center_freq;
+
+ r = memcmp(a->bssid, b->bssid, ETH_ALEN);
+ if (r)
+ return r;
+
+ if (is_zero_ether_addr(a->bssid)) {
+ r = cmp_ies(WLAN_EID_MESH_ID,
+ a->information_elements,
+ a->len_information_elements,
+ b->information_elements,
+ b->len_information_elements);
+ if (r)
+ return r;
+ return cmp_ies(WLAN_EID_MESH_CONFIG,
+ a->information_elements,
+ a->len_information_elements,
+ b->information_elements,
+ b->len_information_elements);
+ }
+
+ return cmp_ies(WLAN_EID_SSID,
+ a->information_elements,
+ a->len_information_elements,
+ b->information_elements,
+ b->len_information_elements);
+}
+
+struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ const u8 *bssid,
+ const u8 *ssid, size_t ssid_len)
+{
+ struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+ struct cfg80211_internal_bss *bss, *res = NULL;
+
+ spin_lock_bh(&dev->bss_lock);
+
+ list_for_each_entry(bss, &dev->bss_list, list) {
+ if (channel && bss->pub.channel != channel)
+ continue;
+ if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
+ res = bss;
+ kref_get(&res->ref);
+ break;
+ }
+ }
+
+ spin_unlock_bh(&dev->bss_lock);
+ if (!res)
+ return NULL;
+ return &res->pub;
+}
+EXPORT_SYMBOL(cfg80211_get_bss);
+
+struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ const u8 *meshid, size_t meshidlen,
+ const u8 *meshcfg)
+{
+ struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+ struct cfg80211_internal_bss *bss, *res = NULL;
+
+ spin_lock_bh(&dev->bss_lock);
+
+ list_for_each_entry(bss, &dev->bss_list, list) {
+ if (channel && bss->pub.channel != channel)
+ continue;
+ if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) {
+ res = bss;
+ kref_get(&res->ref);
+ break;
+ }
+ }
+
+ spin_unlock_bh(&dev->bss_lock);
+ if (!res)
+ return NULL;
+ return &res->pub;
+}
+EXPORT_SYMBOL(cfg80211_get_mesh);
+
+
+static void rb_insert_bss(struct cfg80211_registered_device *dev,
+ struct cfg80211_internal_bss *bss)
+{
+ struct rb_node **p = &dev->bss_tree.rb_node;
+ struct rb_node *parent = NULL;
+ struct cfg80211_internal_bss *tbss;
+ int cmp;
+
+ while (*p) {
+ parent = *p;
+ tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
+
+ cmp = cmp_bss(&bss->pub, &tbss->pub);
+
+ if (WARN_ON(!cmp)) {
+ /* will sort of leak this BSS */
+ return;
+ }
+
+ if (cmp < 0)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ rb_link_node(&bss->rbn, parent, p);
+ rb_insert_color(&bss->rbn, &dev->bss_tree);
+}
+
+static struct cfg80211_internal_bss *
+rb_find_bss(struct cfg80211_registered_device *dev,
+ struct cfg80211_internal_bss *res)
+{
+ struct rb_node *n = dev->bss_tree.rb_node;
+ struct cfg80211_internal_bss *bss;
+ int r;
+
+ while (n) {
+ bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
+ r = cmp_bss(&res->pub, &bss->pub);
+
+ if (r == 0)
+ return bss;
+ else if (r < 0)
+ n = n->rb_left;
+ else
+ n = n->rb_right;
+ }
+
+ return NULL;
+}
+
+static struct cfg80211_internal_bss *
+cfg80211_bss_update(struct cfg80211_registered_device *dev,
+ struct cfg80211_internal_bss *res,
+ bool overwrite)
+{
+ struct cfg80211_internal_bss *found = NULL;
+ const u8 *meshid, *meshcfg;
+
+ /*
+ * The reference to "res" is donated to this function.
+ */
+
+ if (WARN_ON(!res->pub.channel)) {
+ kref_put(&res->ref, bss_release);
+ return NULL;
+ }
+
+ res->ts = jiffies;
+
+ if (is_zero_ether_addr(res->pub.bssid)) {
+ /* must be mesh, verify */
+ meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements,
+ res->pub.len_information_elements);
+ meshcfg = find_ie(WLAN_EID_MESH_CONFIG,
+ res->pub.information_elements,
+ res->pub.len_information_elements);
+ if (!meshid || !meshcfg ||
+ meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) {
+ /* bogus mesh */
+ kref_put(&res->ref, bss_release);
+ return NULL;
+ }
+ }
+
+ spin_lock_bh(&dev->bss_lock);
+
+ found = rb_find_bss(dev, res);
+
+ if (found && overwrite) {
+ list_replace(&found->list, &res->list);
+ rb_replace_node(&found->rbn, &res->rbn,
+ &dev->bss_tree);
+ kref_put(&found->ref, bss_release);
+ found = res;
+ } else if (found) {
+ kref_get(&found->ref);
+ found->pub.beacon_interval = res->pub.beacon_interval;
+ found->pub.tsf = res->pub.tsf;
+ found->pub.signal = res->pub.signal;
+ found->pub.signal_type = res->pub.signal_type;
+ found->pub.capability = res->pub.capability;
+ found->ts = res->ts;
+ kref_put(&res->ref, bss_release);
+ } else {
+ /* this "consumes" the reference */
+ list_add_tail(&res->list, &dev->bss_list);
+ rb_insert_bss(dev, res);
+ found = res;
+ }
+
+ dev->bss_generation++;
+ spin_unlock_bh(&dev->bss_lock);
+
+ kref_get(&found->ref);
+ return found;
+}
+
+struct cfg80211_bss *
+cfg80211_inform_bss_frame(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ s32 signal, enum cfg80211_signal_type sigtype,
+ gfp_t gfp)
+{
+ struct cfg80211_internal_bss *res;
+ size_t ielen = len - offsetof(struct ieee80211_mgmt,
+ u.probe_resp.variable);
+ bool overwrite;
+ size_t privsz = wiphy->bss_priv_size;
+
+ if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC &&
+ (signal < 0 || signal > 100)))
+ return NULL;
+
+ if (WARN_ON(!mgmt || !wiphy ||
+ len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
+ return NULL;
+
+ res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
+ if (!res)
+ return NULL;
+
+ memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
+ res->pub.channel = channel;
+ res->pub.signal_type = sigtype;
+ res->pub.signal = signal;
+ res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
+ res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
+ res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
+ /* point to after the private area */
+ res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
+ memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen);
+ res->pub.len_information_elements = ielen;
+
+ kref_init(&res->ref);
+
+ overwrite = ieee80211_is_probe_resp(mgmt->frame_control);
+
+ res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite);
+ if (!res)
+ return NULL;
+
+ /* cfg80211_bss_update gives us a referenced result */
+ return &res->pub;
+}
+EXPORT_SYMBOL(cfg80211_inform_bss_frame);
+
+void cfg80211_put_bss(struct cfg80211_bss *pub)
+{
+ struct cfg80211_internal_bss *bss;
+
+ if (!pub)
+ return;
+
+ bss = container_of(pub, struct cfg80211_internal_bss, pub);
+ kref_put(&bss->ref, bss_release);
+}
+EXPORT_SYMBOL(cfg80211_put_bss);
+
+#ifdef CONFIG_WIRELESS_EXT
+int cfg80211_wext_siwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct cfg80211_registered_device *rdev;
+ struct wiphy *wiphy;
+ struct iw_scan_req *wreq = NULL;
+ struct cfg80211_scan_request *creq;
+ int i, err, n_channels = 0;
+ enum ieee80211_band band;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ rdev = cfg80211_get_dev_from_ifindex(dev->ifindex);
+
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ if (rdev->scan_req) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ wiphy = &rdev->wiphy;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+ if (wiphy->bands[band])
+ n_channels += wiphy->bands[band]->n_channels;
+
+ creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
+ n_channels * sizeof(void *),
+ GFP_ATOMIC);
+ if (!creq) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ creq->wiphy = wiphy;
+ creq->ifidx = dev->ifindex;
+ creq->ssids = (void *)(creq + 1);
+ creq->channels = (void *)(creq->ssids + 1);
+ creq->n_channels = n_channels;
+ creq->n_ssids = 1;
+
+ /* all channels */
+ i = 0;
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ int j;
+ if (!wiphy->bands[band])
+ continue;
+ for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+ creq->channels[i] = &wiphy->bands[band]->channels[j];
+ i++;
+ }
+ }
+
+ /* translate scan request */
+ if (wrqu->data.length == sizeof(struct iw_scan_req)) {
+ wreq = (struct iw_scan_req *)extra;
+
+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+ memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len);
+ creq->ssids[0].ssid_len = wreq->essid_len;
+ }
+ if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE)
+ creq->n_ssids = 0;
+ }
+
+ rdev->scan_req = creq;
+ err = rdev->ops->scan(wiphy, dev, creq);
+ if (err) {
+ rdev->scan_req = NULL;
+ kfree(creq);
+ }
+ out:
+ cfg80211_put_dev(rdev);
+ return err;
+}
+EXPORT_SYMBOL(cfg80211_wext_siwscan);
+
+static void ieee80211_scan_add_ies(struct iw_request_info *info,
+ struct cfg80211_bss *bss,
+ char **current_ev, char *end_buf)
+{
+ u8 *pos, *end, *next;
+ struct iw_event iwe;
+
+ if (!bss->information_elements ||
+ !bss->len_information_elements)
+ return;
+
+ /*
+ * If needed, fragment the IEs buffer (at IE boundaries) into short
+ * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
+ */
+ pos = bss->information_elements;
+ end = pos + bss->len_information_elements;
+
+ while (end - pos > IW_GENERIC_IE_MAX) {
+ next = pos + 2 + pos[1];
+ while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
+ next = next + 2 + next[1];
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = next - pos;
+ *current_ev = iwe_stream_add_point(info, *current_ev,
+ end_buf, &iwe, pos);
+
+ pos = next;
+ }
+
+ if (end > pos) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = end - pos;
+ *current_ev = iwe_stream_add_point(info, *current_ev,
+ end_buf, &iwe, pos);
+ }
+}
+
+
+static char *
+ieee80211_bss(struct iw_request_info *info,
+ struct cfg80211_internal_bss *bss,
+ char *current_ev, char *end_buf)
+{
+ struct iw_event iwe;
+ u8 *buf, *cfg, *p;
+ u8 *ie = bss->pub.information_elements;
+ int rem = bss->pub.len_information_elements, i;
+ bool ismesh = false;
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+ IW_EV_ADDR_LEN);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
+ iwe.u.freq.e = 0;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = bss->pub.channel->center_freq;
+ iwe.u.freq.e = 6;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+
+ if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
+ IW_QUAL_NOISE_INVALID |
+ IW_QUAL_QUAL_INVALID;
+ switch (bss->pub.signal_type) {
+ case CFG80211_SIGNAL_TYPE_MBM:
+ iwe.u.qual.level = bss->pub.signal / 100;
+ iwe.u.qual.updated |= IW_QUAL_DBM;
+ break;
+ case CFG80211_SIGNAL_TYPE_UNSPEC:
+ iwe.u.qual.level = bss->pub.signal;
+ break;
+ default:
+ /* not reached */
+ break;
+ }
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+ &iwe, IW_EV_QUAL_LEN);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWENCODE;
+ if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, "");
+
+ while (rem >= 2) {
+ /* invalid data */
+ if (ie[1] > rem - 2)
+ break;
+
+ switch (ie[0]) {
+ case WLAN_EID_SSID:
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.length = ie[1];
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, ie + 2);
+ break;
+ case WLAN_EID_MESH_ID:
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.length = ie[1];
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, ie + 2);
+ break;
+ case WLAN_EID_MESH_CONFIG:
+ ismesh = true;
+ if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
+ break;
+ buf = kmalloc(50, GFP_ATOMIC);
+ if (!buf)
+ break;
+ cfg = ie + 2;
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "Mesh network (version %d)", cfg[0]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
+ &iwe, buf);
+ sprintf(buf, "Path Selection Protocol ID: "
+ "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
+ cfg[4]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
+ &iwe, buf);
+ sprintf(buf, "Path Selection Metric ID: "
+ "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
+ cfg[8]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
+ &iwe, buf);
+ sprintf(buf, "Congestion Control Mode ID: "
+ "0x%02X%02X%02X%02X", cfg[9], cfg[10],
+ cfg[11], cfg[12]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
+ &iwe, buf);
+ sprintf(buf, "Channel Precedence: "
+ "0x%02X%02X%02X%02X", cfg[13], cfg[14],
+ cfg[15], cfg[16]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf,
+ &iwe, buf);
+ kfree(buf);
+ break;
+ case WLAN_EID_SUPP_RATES:
+ case WLAN_EID_EXT_SUPP_RATES:
+ /* display all supported rates in readable format */
+ p = current_ev + iwe_stream_lcp_len(info);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+ for (i = 0; i < ie[1]; i++) {
+ iwe.u.bitrate.value =
+ ((ie[i + 2] & 0x7f) * 500000);
+ p = iwe_stream_add_value(info, current_ev, p,
+ end_buf, &iwe, IW_EV_PARAM_LEN);
+ }
+ current_ev = p;
+ break;
+ }
+ rem -= ie[1] + 2;
+ ie += ie[1] + 2;
+ }
+
+ if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
+ || ismesh) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWMODE;
+ if (ismesh)
+ iwe.u.mode = IW_MODE_MESH;
+ else if (bss->pub.capability & WLAN_CAPABILITY_ESS)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+ &iwe, IW_EV_UINT_LEN);
+ }
+
+ buf = kmalloc(30, GFP_ATOMIC);
+ if (buf) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+ &iwe, buf);
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, " Last beacon: %dms ago",
+ jiffies_to_msecs(jiffies - bss->ts));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev,
+ end_buf, &iwe, buf);
+ kfree(buf);
+ }
+
+ ieee80211_scan_add_ies(info, &bss->pub, ¤t_ev, end_buf);
+
+ return current_ev;
+}
+
+
+static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
+ struct iw_request_info *info,
+ char *buf, size_t len)
+{
+ char *current_ev = buf;
+ char *end_buf = buf + len;
+ struct cfg80211_internal_bss *bss;
+
+ spin_lock_bh(&dev->bss_lock);
+ cfg80211_bss_expire(dev);
+
+ list_for_each_entry(bss, &dev->bss_list, list) {
+ if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
+ spin_unlock_bh(&dev->bss_lock);
+ return -E2BIG;
+ }
+ current_ev = ieee80211_bss(info, bss,
+ current_ev, end_buf);
+ }
+ spin_unlock_bh(&dev->bss_lock);
+ return current_ev - buf;
+}
+
+
+int cfg80211_wext_giwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct cfg80211_registered_device *rdev;
+ int res;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ rdev = cfg80211_get_dev_from_ifindex(dev->ifindex);
+
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ if (rdev->scan_req) {
+ res = -EAGAIN;
+ goto out;
+ }
+
+ res = ieee80211_scan_results(rdev, info, extra, data->length);
+ data->length = 0;
+ if (res >= 0) {
+ data->length = res;
+ res = 0;
+ }
+
+ out:
+ cfg80211_put_dev(rdev);
+ return res;
+}
+EXPORT_SYMBOL(cfg80211_wext_giwscan);
+#endif
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-02-10 20:59:35.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-02-10 20:59:36.000000000 +0100
@@ -294,8 +294,6 @@ struct ieee80211_if_sta {
u8 ssid[IEEE80211_MAX_SSID_LEN];
enum ieee80211_sta_mlme_state state;
size_t ssid_len;
- u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
- size_t scan_ssid_len;
u16 aid;
u16 ap_capab, capab;
u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -658,17 +656,18 @@ struct ieee80211_local {
/* Scanning and BSS list */
bool sw_scanning, hw_scanning;
+ struct cfg80211_ssid scan_ssid;
+ struct cfg80211_scan_request int_scan_req;
+ struct cfg80211_scan_request *scan_req;
+ struct ieee80211_channel *scan_channel;
int scan_channel_idx;
- enum ieee80211_band scan_band;
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
unsigned long last_scan_completed;
struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata;
- struct ieee80211_channel *oper_channel, *scan_channel, *csa_channel;
enum nl80211_channel_type oper_channel_type;
- u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
- size_t scan_ssid_len;
+ struct ieee80211_channel *oper_channel, *csa_channel;
struct list_head bss_list;
struct ieee80211_bss *bss_hash[STA_HASH_SIZE];
spinlock_t bss_lock;
@@ -926,7 +925,7 @@ void ieee80211_send_probe_req(struct iee
/* scan/BSS handling */
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
- u8 *ssid, size_t ssid_len);
+ struct cfg80211_scan_request *req);
int ieee80211_scan_results(struct ieee80211_local *local,
struct iw_request_info *info,
char *buf, size_t len);
@@ -941,14 +940,15 @@ int ieee80211_sta_set_extra_ie(struct ie
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
- u8 *ssid, size_t ssid_len);
+ struct cfg80211_scan_request *req);
struct ieee80211_bss *
ieee80211_bss_info_update(struct ieee80211_local *local,
struct ieee80211_rx_status *rx_status,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee802_11_elems *elems,
- int freq, bool beacon);
+ struct ieee80211_channel *channel,
+ bool beacon);
struct ieee80211_bss *
ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len);
--- wireless-testing.orig/net/mac80211/scan.c 2009-02-10 20:59:30.000000000 +0100
+++ wireless-testing/net/mac80211/scan.c 2009-02-10 20:59:36.000000000 +0100
@@ -13,6 +13,9 @@
*/
/* TODO:
+ * figure out how to avoid that the "current BSS" expires
+ * clean up IBSS code (in MLME), see why it adds a BSS to the list
+ * use cfg80211's BSS handling (depends on IBSS TODO above)
* order BSS list by RSSI(?) ("quality of AP")
* scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
* SSID)
@@ -225,10 +228,26 @@ ieee80211_bss_info_update(struct ieee802
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee802_11_elems *elems,
- int freq, bool beacon)
+ struct ieee80211_channel *channel,
+ bool beacon)
{
struct ieee80211_bss *bss;
- int clen;
+ int clen, freq = channel->center_freq;
+ enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE;
+ s32 signal = 0;
+
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+ sigtype = CFG80211_SIGNAL_TYPE_MBM;
+ signal = rx_status->signal * 100;
+ } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
+ sigtype = CFG80211_SIGNAL_TYPE_UNSPEC;
+ signal = (rx_status->signal * 100) / local->hw.max_signal;
+ }
+
+ cfg80211_put_bss(
+ cfg80211_inform_bss_frame(local->hw.wiphy, channel,
+ mgmt, len, signal, sigtype,
+ GFP_ATOMIC));
#ifdef CONFIG_MAC80211_MESH
if (elems->mesh_config)
@@ -401,7 +420,7 @@ ieee80211_scan_rx(struct ieee80211_sub_i
bss = ieee80211_bss_info_update(sdata->local, rx_status,
mgmt, skb->len, &elems,
- freq, beacon);
+ channel, beacon);
if (bss)
ieee80211_rx_bss_put(sdata->local, bss);
@@ -439,26 +458,22 @@ void ieee80211_send_nullfunc(struct ieee
ieee80211_tx_skb(sdata, skb, 0);
}
-void ieee80211_scan_completed(struct ieee80211_hw *hw)
+void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
- union iwreq_data wrqu;
if (WARN_ON(!local->hw_scanning && !local->sw_scanning))
return;
- local->last_scan_completed = jiffies;
- memset(&wrqu, 0, sizeof(wrqu));
+ if (WARN_ON(!local->scan_req))
+ return;
- /*
- * local->scan_sdata could have been NULLed by the interface
- * down code in case we were scanning on an interface that is
- * being taken down.
- */
- sdata = local->scan_sdata;
- if (sdata)
- wireless_send_event(sdata->dev, SIOCGIWSCAN, &wrqu, NULL);
+ if (local->scan_req != &local->int_scan_req)
+ cfg80211_scan_done(local->scan_req, aborted);
+ local->scan_req = NULL;
+
+ local->last_scan_completed = jiffies;
if (local->hw_scanning) {
local->hw_scanning = false;
@@ -520,9 +535,8 @@ void ieee80211_scan_work(struct work_str
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, scan_work.work);
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
- struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
- int skip;
+ int skip, i;
unsigned long next_delay = 0;
/*
@@ -533,33 +547,13 @@ void ieee80211_scan_work(struct work_str
switch (local->scan_state) {
case SCAN_SET_CHANNEL:
- /*
- * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
- * after we successfully scanned the last channel of the last
- * band (and the last band is supported by the hw)
- */
- if (local->scan_band < IEEE80211_NUM_BANDS)
- sband = local->hw.wiphy->bands[local->scan_band];
- else
- sband = NULL;
-
- /*
- * If we are at an unsupported band and have more bands
- * left to scan, advance to the next supported one.
- */
- while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
- local->scan_band++;
- sband = local->hw.wiphy->bands[local->scan_band];
- local->scan_channel_idx = 0;
- }
-
/* if no more bands/channels left, complete scan */
- if (!sband || local->scan_channel_idx >= sband->n_channels) {
- ieee80211_scan_completed(local_to_hw(local));
+ if (local->scan_channel_idx >= local->scan_req->n_channels) {
+ ieee80211_scan_completed(local_to_hw(local), false);
return;
}
skip = 0;
- chan = &sband->channels[local->scan_channel_idx];
+ chan = local->scan_req->channels[local->scan_channel_idx];
if (chan->flags & IEEE80211_CHAN_DISABLED ||
(sdata->vif.type == NL80211_IFTYPE_ADHOC &&
@@ -575,15 +569,6 @@ void ieee80211_scan_work(struct work_str
/* advance state machine to next channel/band */
local->scan_channel_idx++;
- if (local->scan_channel_idx >= sband->n_channels) {
- /*
- * scan_band may end up == IEEE80211_NUM_BANDS, but
- * we'll catch that case above and complete the scan
- * if that is the case.
- */
- local->scan_band++;
- local->scan_channel_idx = 0;
- }
if (skip)
break;
@@ -596,10 +581,14 @@ void ieee80211_scan_work(struct work_str
next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
local->scan_state = SCAN_SET_CHANNEL;
- if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+ if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
+ !local->scan_req->n_ssids)
break;
- ieee80211_send_probe_req(sdata, NULL, local->scan_ssid,
- local->scan_ssid_len);
+ for (i = 0; i < local->scan_req->n_ssids; i++)
+ ieee80211_send_probe_req(
+ sdata, NULL,
+ local->scan_req->ssids[i].ssid,
+ local->scan_req->ssids[i].ssid_len);
next_delay = IEEE80211_CHANNEL_TIME;
break;
}
@@ -610,14 +599,19 @@ void ieee80211_scan_work(struct work_str
int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
- u8 *ssid, size_t ssid_len)
+ struct cfg80211_scan_request *req)
{
struct ieee80211_local *local = scan_sdata->local;
struct ieee80211_sub_if_data *sdata;
- if (ssid_len > IEEE80211_MAX_SSID_LEN)
+ if (!req)
return -EINVAL;
+ if (local->scan_req && local->scan_req != req)
+ return -EBUSY;
+
+ local->scan_req = req;
+
/* MLME-SCAN.request (page 118) page 144 (11.1.3.1)
* BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
* BSSID: MACAddress
@@ -645,7 +639,7 @@ int ieee80211_start_scan(struct ieee8021
int rc;
local->hw_scanning = true;
- rc = local->ops->hw_scan(local_to_hw(local), ssid, ssid_len);
+ rc = local->ops->hw_scan(local_to_hw(local), req);
if (rc) {
local->hw_scanning = false;
return rc;
@@ -678,15 +672,10 @@ int ieee80211_start_scan(struct ieee8021
}
mutex_unlock(&local->iflist_mtx);
- if (ssid) {
- local->scan_ssid_len = ssid_len;
- memcpy(local->scan_ssid, ssid, ssid_len);
- } else
- local->scan_ssid_len = 0;
local->scan_state = SCAN_SET_CHANNEL;
local->scan_channel_idx = 0;
- local->scan_band = IEEE80211_BAND_2GHZ;
local->scan_sdata = scan_sdata;
+ local->scan_req = req;
netif_addr_lock_bh(local->mdev);
local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
@@ -706,13 +695,21 @@ int ieee80211_start_scan(struct ieee8021
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
- u8 *ssid, size_t ssid_len)
+ struct cfg80211_scan_request *req)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_sta *ifsta;
+ if (!req)
+ return -EINVAL;
+
+ if (local->scan_req && local->scan_req != req)
+ return -EBUSY;
+
+ local->scan_req = req;
+
if (sdata->vif.type != NL80211_IFTYPE_STATION)
- return ieee80211_start_scan(sdata, ssid, ssid_len);
+ return ieee80211_start_scan(sdata, req);
/*
* STA has a state machine that might need to defer scanning
@@ -727,241 +724,8 @@ int ieee80211_request_scan(struct ieee80
}
ifsta = &sdata->u.sta;
-
- ifsta->scan_ssid_len = ssid_len;
- if (ssid_len)
- memcpy(ifsta->scan_ssid, ssid, ssid_len);
set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
queue_work(local->hw.workqueue, &ifsta->work);
return 0;
}
-
-
-static void ieee80211_scan_add_ies(struct iw_request_info *info,
- struct ieee80211_bss *bss,
- char **current_ev, char *end_buf)
-{
- u8 *pos, *end, *next;
- struct iw_event iwe;
-
- if (bss == NULL || bss->ies == NULL)
- return;
-
- /*
- * If needed, fragment the IEs buffer (at IE boundaries) into short
- * enough fragments to fit into IW_GENERIC_IE_MAX octet messages.
- */
- pos = bss->ies;
- end = pos + bss->ies_len;
-
- while (end - pos > IW_GENERIC_IE_MAX) {
- next = pos + 2 + pos[1];
- while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX)
- next = next + 2 + next[1];
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = next - pos;
- *current_ev = iwe_stream_add_point(info, *current_ev,
- end_buf, &iwe, pos);
-
- pos = next;
- }
-
- if (end > pos) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = end - pos;
- *current_ev = iwe_stream_add_point(info, *current_ev,
- end_buf, &iwe, pos);
- }
-}
-
-
-static char *
-ieee80211_scan_result(struct ieee80211_local *local,
- struct iw_request_info *info,
- struct ieee80211_bss *bss,
- char *current_ev, char *end_buf)
-{
- struct iw_event iwe;
- char *buf;
-
- if (time_after(jiffies,
- bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
- return current_ev;
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_ADDR_LEN);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWESSID;
- if (bss_mesh_cfg(bss)) {
- iwe.u.data.length = bss_mesh_id_len(bss);
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss_mesh_id(bss));
- } else {
- iwe.u.data.length = bss->ssid_len;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->ssid);
- }
-
- if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
- || bss_mesh_cfg(bss)) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWMODE;
- if (bss_mesh_cfg(bss))
- iwe.u.mode = IW_MODE_MESH;
- else if (bss->capability & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_FREQ_LEN);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = bss->freq;
- iwe.u.freq.e = 6;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_FREQ_LEN);
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = bss->qual;
- iwe.u.qual.level = bss->signal;
- iwe.u.qual.noise = bss->noise;
- iwe.u.qual.updated = local->wstats_flags;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_QUAL_LEN);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWENCODE;
- if (bss->capability & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, "");
-
- ieee80211_scan_add_ies(info, bss, ¤t_ev, end_buf);
-
- if (bss->supp_rates_len > 0) {
- /* display all supported rates in readable format */
- char *p = current_ev + iwe_stream_lcp_len(info);
- int i;
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
- for (i = 0; i < bss->supp_rates_len; i++) {
- iwe.u.bitrate.value = ((bss->supp_rates[i] &
- 0x7f) * 500000);
- p = iwe_stream_add_value(info, current_ev, p,
- end_buf, &iwe, IW_EV_PARAM_LEN);
- }
- current_ev = p;
- }
-
- buf = kmalloc(30, GFP_ATOMIC);
- if (buf) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, buf);
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - bss->last_update));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe, buf);
- kfree(buf);
- }
-
- if (bss_mesh_cfg(bss)) {
- u8 *cfg = bss_mesh_cfg(bss);
- buf = kmalloc(50, GFP_ATOMIC);
- if (buf) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "Mesh network (version %d)", cfg[0]);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
- sprintf(buf, "Path Selection Protocol ID: "
- "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3],
- cfg[4]);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
- sprintf(buf, "Path Selection Metric ID: "
- "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7],
- cfg[8]);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
- sprintf(buf, "Congestion Control Mode ID: "
- "0x%02X%02X%02X%02X", cfg[9], cfg[10],
- cfg[11], cfg[12]);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
- sprintf(buf, "Channel Precedence: "
- "0x%02X%02X%02X%02X", cfg[13], cfg[14],
- cfg[15], cfg[16]);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf,
- &iwe, buf);
- kfree(buf);
- }
- }
-
- return current_ev;
-}
-
-
-int ieee80211_scan_results(struct ieee80211_local *local,
- struct iw_request_info *info,
- char *buf, size_t len)
-{
- char *current_ev = buf;
- char *end_buf = buf + len;
- struct ieee80211_bss *bss;
-
- spin_lock_bh(&local->bss_lock);
- list_for_each_entry(bss, &local->bss_list, list) {
- if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
- spin_unlock_bh(&local->bss_lock);
- return -E2BIG;
- }
- current_ev = ieee80211_scan_result(local, info, bss,
- current_ev, end_buf);
- }
- spin_unlock_bh(&local->bss_lock);
- return current_ev - buf;
-}
--- wireless-testing.orig/net/mac80211/wext.c 2009-02-10 20:59:30.000000000 +0100
+++ wireless-testing/net/mac80211/wext.c 2009-02-10 20:59:36.000000000 +0100
@@ -173,8 +173,9 @@ static int ieee80211_ioctl_giwrange(stru
range->num_encoding_sizes = 2;
range->max_encoding_tokens = NUM_DEFAULT_KEYS;
+ /* cfg80211 requires this, and enforces 0..100 */
if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
- range->max_qual.level = local->hw.max_signal;
+ range->max_qual.level = 100;
else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
range->max_qual.level = -110;
else
@@ -415,58 +416,6 @@ static int ieee80211_ioctl_giwap(struct
}
-static int ieee80211_ioctl_siwscan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct iw_scan_req *req = NULL;
- u8 *ssid = NULL;
- size_t ssid_len = 0;
-
- if (!netif_running(dev))
- return -ENETDOWN;
-
- if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
- return -EOPNOTSUPP;
-
- /* if SSID was specified explicitly then use that */
- if (wrqu->data.length == sizeof(struct iw_scan_req) &&
- wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- req = (struct iw_scan_req *)extra;
- ssid = req->essid;
- ssid_len = req->essid_len;
- }
-
- return ieee80211_request_scan(sdata, ssid, ssid_len);
-}
-
-
-static int ieee80211_ioctl_giwscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- int res;
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- if (local->sw_scanning || local->hw_scanning)
- return -EAGAIN;
-
- res = ieee80211_scan_results(local, info, extra, data->length);
- if (res >= 0) {
- data->length = res;
- return 0;
- }
- data->length = 0;
- return res;
-}
-
-
static int ieee80211_ioctl_siwrate(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rate, char *extra)
@@ -1165,8 +1114,8 @@ static const iw_handler ieee80211_handle
(iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
(iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */
(iw_handler) NULL, /* SIOCGIWAPLIST */
- (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */
- (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */
+ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
+ (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
(iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
(iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
(iw_handler) NULL, /* SIOCSIWNICKN */
--- wireless-testing.orig/net/mac80211/mlme.c 2009-02-10 20:59:34.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c 2009-02-10 20:59:36.000000000 +0100
@@ -1713,7 +1713,7 @@ static void ieee80211_rx_bss_info(struct
}
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
- freq, beacon);
+ channel, beacon);
if (!bss)
return;
@@ -2117,7 +2117,15 @@ static void ieee80211_sta_merge_ibss(str
printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
"IBSS networks with same SSID (merge)\n", sdata->dev->name);
- ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len);
+
+ /* XXX maybe racy? */
+ if (sdata->local->scan_req)
+ return;
+
+ memcpy(sdata->local->int_scan_req.ssids[0].ssid,
+ ifsta->ssid, IEEE80211_MAX_SSID_LEN);
+ sdata->local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
+ ieee80211_request_scan(sdata, &sdata->local->int_scan_req);
}
@@ -2333,8 +2341,15 @@ dont_join:
IEEE80211_SCAN_INTERVAL)) {
printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
"join\n", sdata->dev->name);
- return ieee80211_request_scan(sdata, ifsta->ssid,
- ifsta->ssid_len);
+
+ /* XXX maybe racy? */
+ if (local->scan_req)
+ return -EBUSY;
+
+ memcpy(local->int_scan_req.ssids[0].ssid,
+ ifsta->ssid, IEEE80211_MAX_SSID_LEN);
+ local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
+ return ieee80211_request_scan(sdata, &local->int_scan_req);
} else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) {
int interval = IEEE80211_SCAN_INTERVAL;
@@ -2433,11 +2448,16 @@ static int ieee80211_sta_config_auth(str
} else {
if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
ifsta->assoc_scan_tries++;
+ /* XXX maybe racy? */
+ if (local->scan_req)
+ return -1;
+ memcpy(local->int_scan_req.ssids[0].ssid,
+ ifsta->ssid, IEEE80211_MAX_SSID_LEN);
if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)
- ieee80211_start_scan(sdata, NULL, 0);
+ local->int_scan_req.ssids[0].ssid_len = 0;
else
- ieee80211_start_scan(sdata, ifsta->ssid,
- ifsta->ssid_len);
+ local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
+ ieee80211_start_scan(sdata, &local->int_scan_req);
ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
} else {
@@ -2475,8 +2495,7 @@ static void ieee80211_sta_work(struct wo
ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
- ieee80211_start_scan(sdata, ifsta->scan_ssid,
- ifsta->scan_ssid_len);
+ ieee80211_start_scan(sdata, local->scan_req);
return;
}
--- wireless-testing.orig/net/mac80211/cfg.c 2009-02-10 20:59:30.000000000 +0100
+++ wireless-testing/net/mac80211/cfg.c 2009-02-10 20:59:36.000000000 +0100
@@ -1277,6 +1277,25 @@ static int ieee80211_resume(struct wiphy
#define ieee80211_resume NULL
#endif
+static int ieee80211_scan(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_scan_request *req)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+ return -EOPNOTSUPP;
+
+ return ieee80211_request_scan(sdata, req);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1309,4 +1328,5 @@ struct cfg80211_ops mac80211_config_ops
.set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie,
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
+ .scan = ieee80211_scan,
};
--- wireless-testing.orig/net/wireless/Makefile 2009-02-10 20:59:24.000000000 +0100
+++ wireless-testing/net/wireless/Makefile 2009-02-10 20:59:36.000000000 +0100
@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib8
obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
-cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o
cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
cfg80211-$(CONFIG_NL80211) += nl80211.o
--- wireless-testing.orig/net/mac80211/main.c 2009-02-10 20:59:29.000000000 +0100
+++ wireless-testing/net/mac80211/main.c 2009-02-10 20:59:36.000000000 +0100
@@ -733,6 +733,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(
return NULL;
wiphy->privid = mac80211_wiphy_privid;
+ wiphy->max_scan_ssids = 4;
local = wiphy_priv(wiphy);
local->hw.wiphy = wiphy;
@@ -817,25 +818,33 @@ int ieee80211_register_hw(struct ieee802
enum ieee80211_band band;
struct net_device *mdev;
struct ieee80211_master_priv *mpriv;
+ int channels, i, j;
/*
* generic code guarantees at least one band,
* set this very early because much code assumes
* that hw.conf.channel is assigned
*/
+ channels = 0;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband;
sband = local->hw.wiphy->bands[band];
- if (sband) {
+ if (sband && !local->oper_channel) {
/* init channel we're on */
local->hw.conf.channel =
local->oper_channel =
local->scan_channel = &sband->channels[0];
- break;
}
+ if (sband)
+ channels += sband->n_channels;
}
+ local->int_scan_req.n_channels = channels;
+ local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL);
+ if (!local->int_scan_req.channels)
+ return -ENOMEM;
+
/* if low-level driver supports AP, we also support VLAN */
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
@@ -845,7 +854,7 @@ int ieee80211_register_hw(struct ieee802
result = wiphy_register(local->hw.wiphy);
if (result < 0)
- return result;
+ goto fail_wiphy_register;
/*
* We use the number of queues for feature tests (QoS, HT) internally
@@ -948,6 +957,20 @@ int ieee80211_register_hw(struct ieee802
ieee80211_led_init(local);
+ /* alloc internal scan request */
+ i = 0;
+ local->int_scan_req.ssids = &local->scan_ssid;
+ local->int_scan_req.n_ssids = 1;
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (!hw->wiphy->bands[band])
+ continue;
+ for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
+ local->int_scan_req.channels[i] =
+ &hw->wiphy->bands[band]->channels[j];
+ i++;
+ }
+ }
+
return 0;
fail_wep:
@@ -966,6 +989,8 @@ fail_workqueue:
free_netdev(local->mdev);
fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
+fail_wiphy_register:
+ kfree(local->int_scan_req.channels);
return result;
}
EXPORT_SYMBOL(ieee80211_register_hw);
@@ -1011,6 +1036,7 @@ void ieee80211_unregister_hw(struct ieee
ieee80211_wep_free(local);
ieee80211_led_exit(local);
free_netdev(local->mdev);
+ kfree(local->int_scan_req.channels);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
--- wireless-testing.orig/net/wireless/nl80211.h 2009-02-10 20:59:24.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.h 2009-02-10 20:59:36.000000000 +0100
@@ -7,6 +7,10 @@
extern int nl80211_init(void);
extern void nl80211_exit(void);
extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
+extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev);
+extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev);
#else
static inline int nl80211_init(void)
{
@@ -19,6 +23,10 @@ static inline void nl80211_notify_dev_re
struct cfg80211_registered_device *rdev)
{
}
+static inline void
+nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev)
+{}
#endif /* CONFIG_NL80211 */
#endif /* __NET_WIRELESS_NL80211_H */
--- wireless-testing.orig/net/wireless/core.c 2009-02-10 20:59:24.000000000 +0100
+++ wireless-testing/net/wireless/core.c 2009-02-10 20:59:36.000000000 +0100
@@ -240,6 +240,8 @@ struct wiphy *wiphy_new(struct cfg80211_
mutex_init(&drv->mtx);
mutex_init(&drv->devlist_mtx);
INIT_LIST_HEAD(&drv->netdev_list);
+ spin_lock_init(&drv->bss_lock);
+ INIT_LIST_HEAD(&drv->bss_list);
device_initialize(&drv->wiphy.dev);
drv->wiphy.dev.class = &ieee80211_class;
@@ -259,6 +261,9 @@ int wiphy_register(struct wiphy *wiphy)
int i;
u16 ifmodes = wiphy->interface_modes;
+ if (WARN_ON(wiphy->max_scan_ssids < 1))
+ return -EINVAL;
+
/* sanity check ifmodes */
WARN_ON(!ifmodes);
ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
@@ -367,8 +372,11 @@ EXPORT_SYMBOL(wiphy_unregister);
void cfg80211_dev_free(struct cfg80211_registered_device *drv)
{
+ struct cfg80211_internal_bss *scan, *tmp;
mutex_destroy(&drv->mtx);
mutex_destroy(&drv->devlist_mtx);
+ list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
+ kfree(scan);
kfree(drv);
}
--- wireless-testing.orig/net/wireless/core.h 2009-02-10 20:59:24.000000000 +0100
+++ wireless-testing/net/wireless/core.h 2009-02-10 20:59:36.000000000 +0100
@@ -8,6 +8,8 @@
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/netdevice.h>
+#include <linux/kref.h>
+#include <linux/rbtree.h>
#include <net/genetlink.h>
#include <net/wireless.h>
#include <net/cfg80211.h>
@@ -41,6 +43,13 @@ struct cfg80211_registered_device {
struct mutex devlist_mtx;
struct list_head netdev_list;
+ /* BSSes/scanning */
+ spinlock_t bss_lock;
+ struct list_head bss_list;
+ struct rb_root bss_tree;
+ u32 bss_generation;
+ struct cfg80211_scan_request *scan_req; /* protected by RTNL */
+
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -56,6 +65,15 @@ struct cfg80211_registered_device *wiphy
extern struct mutex cfg80211_drv_mutex;
extern struct list_head cfg80211_drv_list;
+struct cfg80211_internal_bss {
+ struct list_head list;
+ struct rb_node rbn;
+ unsigned long ts;
+ struct kref ref;
+ /* must be last because of priv member */
+ struct cfg80211_bss pub;
+};
+
/*
* This function returns a pointer to the driver
* that the genl_info item that is passed refers to.
@@ -94,4 +112,6 @@ extern int cfg80211_dev_rename(struct cf
void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby);
+void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
+
#endif /* __NET_WIRELESS_CORE_H */
--- wireless-testing.orig/include/net/wireless.h 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/include/net/wireless.h 2009-02-10 20:59:36.000000000 +0100
@@ -213,6 +213,9 @@ struct wiphy {
bool custom_regulatory;
bool strict_regulatory;
+ int bss_priv_size;
+ u8 max_scan_ssids;
+
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered
--- wireless-testing.orig/include/net/mac80211.h 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/include/net/mac80211.h 2009-02-10 20:59:36.000000000 +0100
@@ -1406,7 +1406,8 @@ struct ieee80211_ops {
void (*update_tkip_key)(struct ieee80211_hw *hw,
struct ieee80211_key_conf *conf, const u8 *address,
u32 iv32, u16 *phase1key);
- int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
+ int (*hw_scan)(struct ieee80211_hw *hw,
+ struct cfg80211_scan_request *req);
int (*get_stats)(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
@@ -1844,8 +1845,9 @@ void ieee80211_wake_queues(struct ieee80
* mac80211 that the scan finished.
*
* @hw: the hardware that finished the scan
+ * @aborted: set to true if scan was aborted
*/
-void ieee80211_scan_completed(struct ieee80211_hw *hw);
+void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
/**
* ieee80211_iterate_active_interfaces - iterate active interfaces
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-agn.c 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-agn.c 2009-02-10 20:59:36.000000000 +0100
@@ -2678,11 +2678,19 @@ static void iwl_bss_info_changed(struct
}
-static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw,
+ struct cfg80211_scan_request *req)
{
unsigned long flags;
struct iwl_priv *priv = hw->priv;
int ret;
+ u8 *ssid = NULL;
+ size_t ssid_len = 0;
+
+ if (req->n_ssids) {
+ ssid = req->ssids[0].ssid;
+ ssid_len = req->ssids[0].ssid_len;
+ }
IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -2718,7 +2726,7 @@ static int iwl_mac_hw_scan(struct ieee80
if (ssid_len) {
priv->one_direct_scan = 1;
- priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE);
+ priv->direct_ssid_len = ssid_len;
memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
} else {
priv->one_direct_scan = 0;
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl3945-base.c 2009-02-10 20:59:24.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl3945-base.c 2009-02-10 20:59:36.000000000 +0100
@@ -4442,15 +4442,23 @@ static void iwl3945_bss_info_changed(str
}
-static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw,
+ struct cfg80211_scan_request *req)
{
int rc = 0;
unsigned long flags;
struct iwl_priv *priv = hw->priv;
+ size_t len = 0;
+ u8 *ssid = NULL;
DECLARE_SSID_BUF(ssid_buf);
IWL_DEBUG_MAC80211(priv, "enter\n");
+ if (req->n_ssids) {
+ ssid = req->ssids[0].ssid;
+ len = req->ssids[0].ssid_len;
+ }
+
mutex_lock(&priv->mutex);
spin_lock_irqsave(&priv->lock, flags);
@@ -4478,9 +4486,8 @@ static int iwl3945_mac_hw_scan(struct ie
print_ssid(ssid_buf, ssid, len), len);
priv->one_direct_scan = 1;
- priv->direct_ssid_len = (u8)
- min((u8) len, (u8) IW_ESSID_MAX_SIZE);
- memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+ priv->direct_ssid_len = len;
+ memcpy(priv->direct_ssid, ssid, len);
} else
priv->one_direct_scan = 0;
@@ -5412,6 +5419,8 @@ static int iwl3945_pci_probe(struct pci_
hw->wiphy->custom_regulatory = true;
+ hw->wiphy->max_scan_ssids = 1;
+
/* 4 EDCA QOS priorities */
hw->queues = 4;
--- wireless-testing.orig/net/mac80211/iface.c 2009-02-10 20:59:34.000000000 +0100
+++ wireless-testing/net/mac80211/iface.c 2009-02-10 20:59:36.000000000 +0100
@@ -522,7 +522,7 @@ static int ieee80211_stop(struct net_dev
* scan event to userspace -- the scan is incomplete.
*/
if (local->sw_scanning)
- ieee80211_scan_completed(&local->hw);
+ ieee80211_scan_completed(&local->hw, true);
}
conf.vif = &sdata->vif;
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-scan.c 2009-02-10 20:59:24.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-scan.c 2009-02-10 20:59:36.000000000 +0100
@@ -860,7 +860,7 @@ void iwl_bg_scan_completed(struct work_s
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- ieee80211_scan_completed(priv->hw);
+ ieee80211_scan_completed(priv->hw, false);
/* Since setting the TXPOWER may have been deferred while
* performing the scan, fire one off */
--- wireless-testing.orig/drivers/net/wireless/iwlwifi/iwl-core.c 2009-02-10 20:59:25.000000000 +0100
+++ wireless-testing/drivers/net/wireless/iwlwifi/iwl-core.c 2009-02-10 20:59:36.000000000 +0100
@@ -1271,6 +1271,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->custom_regulatory = true;
+ hw->wiphy->max_scan_ssids = 1;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 20/27] mac80211: dont add BSS when creating IBSS
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (18 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 19/27] cfg80211/nl80211: scanning (and mac80211 update to use it) Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 21/27] cfg80211: free_priv for BSS info Johannes Berg
` (6 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
There's no need to create a BSS struct only to pass it to
ieee80211_sta_join_ibss, so refactor this function into
__ieee80211_sta_join_ibss which takes all the relevant
paramters, and ieee80211_sta_join_ibss which takes a BSS
struct (used when joining an IBSS that already has other
members).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/ieee80211_i.h | 3 -
net/mac80211/mlme.c | 107 ++++++++++++++++++++++++---------------------
net/mac80211/scan.c | 8 ---
3 files changed, 60 insertions(+), 58 deletions(-)
--- wireless-testing.orig/net/mac80211/mlme.c 2009-02-10 20:59:36.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c 2009-02-10 20:59:37.000000000 +0100
@@ -513,14 +513,15 @@ static void ieee80211_send_deauth_disass
/* MLME */
static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_bss *bss)
+ const size_t supp_rates_len,
+ const u8 *supp_rates)
{
struct ieee80211_local *local = sdata->local;
int i, have_higher_than_11mbit = 0;
/* cf. IEEE 802.11 9.2.12 */
- for (i = 0; i < bss->supp_rates_len; i++)
- if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
+ for (i = 0; i < supp_rates_len; i++)
+ if ((supp_rates[i] & 0x7f) * 5 > 110)
have_higher_than_11mbit = 1;
if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
@@ -1516,9 +1517,13 @@ static void ieee80211_rx_mgmt_assoc_resp
}
-static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_if_sta *ifsta,
- struct ieee80211_bss *bss)
+static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_sta *ifsta,
+ const u8 *bssid, const int beacon_int,
+ const int freq,
+ const size_t supp_rates_len,
+ const u8 *supp_rates,
+ const u16 capability)
{
struct ieee80211_local *local = sdata->local;
int res = 0, rates, i, j;
@@ -1534,7 +1539,7 @@ static int ieee80211_sta_join_ibss(struc
}
if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) &&
- memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) == 0)
+ memcmp(ifsta->bssid, bssid, ETH_ALEN) == 0)
return res;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
@@ -1545,28 +1550,28 @@ static int ieee80211_sta_join_ibss(struc
return -ENOMEM;
}
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) {
/* Remove possible STA entries from other IBSS networks. */
sta_info_flush_delayed(sdata);
}
- memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
+ memcpy(ifsta->bssid, bssid, ETH_ALEN);
res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
if (res)
return res;
- local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
+ local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;
- sdata->drop_unencrypted = bss->capability &
+ sdata->drop_unencrypted = capability &
WLAN_CAPABILITY_PRIVACY ? 1 : 0;
- res = ieee80211_set_freq(sdata, bss->freq);
+ res = ieee80211_set_freq(sdata, freq);
if (res)
return res;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
/* Build IBSS probe response */
skb_reserve(skb, local->hw.extra_tx_headroom);
@@ -1575,33 +1580,32 @@ static int ieee80211_sta_join_ibss(struc
skb_put(skb, 24 + sizeof(mgmt->u.beacon));
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_PROBE_RESP);
+ IEEE80211_STYPE_PROBE_RESP);
memset(mgmt->da, 0xff, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
mgmt->u.beacon.beacon_int =
cpu_to_le16(local->hw.conf.beacon_int);
- mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp);
- mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
+ mgmt->u.beacon.capab_info = cpu_to_le16(capability);
pos = skb_put(skb, 2 + ifsta->ssid_len);
*pos++ = WLAN_EID_SSID;
*pos++ = ifsta->ssid_len;
memcpy(pos, ifsta->ssid, ifsta->ssid_len);
- rates = bss->supp_rates_len;
+ rates = supp_rates_len;
if (rates > 8)
rates = 8;
pos = skb_put(skb, 2 + rates);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = rates;
- memcpy(pos, bss->supp_rates, rates);
+ memcpy(pos, supp_rates, rates);
- if (bss->band == IEEE80211_BAND_2GHZ) {
+ if (sband->band == IEEE80211_BAND_2GHZ) {
pos = skb_put(skb, 2 + 1);
*pos++ = WLAN_EID_DS_PARAMS;
*pos++ = 1;
- *pos++ = ieee80211_frequency_to_channel(bss->freq);
+ *pos++ = ieee80211_frequency_to_channel(freq);
}
pos = skb_put(skb, 2 + 2);
@@ -1611,12 +1615,12 @@ static int ieee80211_sta_join_ibss(struc
*pos++ = 0;
*pos++ = 0;
- if (bss->supp_rates_len > 8) {
- rates = bss->supp_rates_len - 8;
+ if (supp_rates_len > 8) {
+ rates = supp_rates_len - 8;
pos = skb_put(skb, 2 + rates);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = rates;
- memcpy(pos, &bss->supp_rates[8], rates);
+ memcpy(pos, &supp_rates[8], rates);
}
add_extra_ies(skb, sdata->u.sta.ie_proberesp,
@@ -1629,16 +1633,15 @@ static int ieee80211_sta_join_ibss(struc
rates = 0;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- for (i = 0; i < bss->supp_rates_len; i++) {
- int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+ for (i = 0; i < supp_rates_len; i++) {
+ int bitrate = (supp_rates[i] & 0x7f) * 5;
for (j = 0; j < sband->n_bitrates; j++)
if (sband->bitrates[j].bitrate == bitrate)
rates |= BIT(j);
}
ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
- ieee80211_sta_def_wmm_params(sdata, bss);
+ ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);
ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED;
@@ -1647,12 +1650,23 @@ static int ieee80211_sta_join_ibss(struc
ieee80211_led_assoc(local, true);
memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
return res;
}
+static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_bss *bss)
+{
+ return __ieee80211_sta_join_ibss(sdata, ifsta,
+ bss->bssid, bss->beacon_int,
+ bss->freq,
+ bss->supp_rates_len, bss->supp_rates,
+ bss->capability);
+}
+
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len,
@@ -2206,11 +2220,12 @@ static int ieee80211_sta_create_ibss(str
struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_bss *bss;
struct ieee80211_supported_band *sband;
- u8 bssid[ETH_ALEN], *pos;
+ u8 *pos;
+ u8 bssid[ETH_ALEN];
+ u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+ u16 capability;
int i;
- int ret;
if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) {
memcpy(bssid, ifsta->bssid, ETH_ALEN);
@@ -2228,36 +2243,29 @@ static int ieee80211_sta_create_ibss(str
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
sdata->dev->name, bssid);
- bss = ieee80211_rx_bss_add(local, bssid,
- local->hw.conf.channel->center_freq,
- sdata->u.sta.ssid, sdata->u.sta.ssid_len);
- if (!bss)
- return -ENOMEM;
-
- bss->band = local->hw.conf.channel->band;
- sband = local->hw.wiphy->bands[bss->band];
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
if (local->hw.conf.beacon_int == 0)
local->hw.conf.beacon_int = 100;
- bss->beacon_int = local->hw.conf.beacon_int;
- bss->last_update = jiffies;
- bss->capability = WLAN_CAPABILITY_IBSS;
+
+ capability = WLAN_CAPABILITY_IBSS;
if (sdata->default_key)
- bss->capability |= WLAN_CAPABILITY_PRIVACY;
+ capability |= WLAN_CAPABILITY_PRIVACY;
else
sdata->drop_unencrypted = 0;
- bss->supp_rates_len = sband->n_bitrates;
- pos = bss->supp_rates;
+ pos = supp_rates;
for (i = 0; i < sband->n_bitrates; i++) {
int rate = sband->bitrates[i].bitrate;
*pos++ = (u8) (rate / 5);
}
- ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);
- ieee80211_rx_bss_put(local, bss);
- return ret;
+ return __ieee80211_sta_join_ibss(sdata, ifsta,
+ bssid, local->hw.conf.beacon_int,
+ local->hw.conf.channel->center_freq,
+ sband->n_bitrates, supp_rates,
+ capability);
}
@@ -2426,7 +2434,8 @@ static int ieee80211_sta_config_auth(str
ieee80211_sta_set_ssid(sdata, selected->ssid,
selected->ssid_len);
ieee80211_sta_set_bssid(sdata, selected->bssid);
- ieee80211_sta_def_wmm_params(sdata, selected);
+ ieee80211_sta_def_wmm_params(sdata, selected->supp_rates_len,
+ selected->supp_rates);
if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED)
sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED;
else
--- wireless-testing.orig/net/mac80211/scan.c 2009-02-10 20:59:36.000000000 +0100
+++ wireless-testing/net/mac80211/scan.c 2009-02-10 20:59:37.000000000 +0100
@@ -14,11 +14,7 @@
/* TODO:
* figure out how to avoid that the "current BSS" expires
- * clean up IBSS code (in MLME), see why it adds a BSS to the list
- * use cfg80211's BSS handling (depends on IBSS TODO above)
- * order BSS list by RSSI(?) ("quality of AP")
- * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
- * SSID)
+ * use cfg80211's BSS handling
*/
#include <linux/wireless.h>
@@ -107,7 +103,7 @@ static void __ieee80211_rx_bss_hash_del(
}
}
-struct ieee80211_bss *
+static struct ieee80211_bss *
ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
{
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-02-10 20:59:36.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-02-10 20:59:37.000000000 +0100
@@ -950,9 +950,6 @@ ieee80211_bss_info_update(struct ieee802
struct ieee80211_channel *channel,
bool beacon);
struct ieee80211_bss *
-ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
- u8 *ssid, u8 ssid_len);
-struct ieee80211_bss *
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len);
void ieee80211_rx_bss_put(struct ieee80211_local *local,
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 21/27] cfg80211: free_priv for BSS info
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (19 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 20/27] mac80211: dont add BSS when creating IBSS Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 22/27] cfg80211: allow users to request removing a BSS Johannes Berg
` (5 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
When cfg80211 users have their own allocated data in the per-BSS
private data, they will need to free this when the BSS struct is
destroyed. Add a free_priv method and fix one place where the BSS
was kfree'd rather than released properly.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/net/cfg80211.h | 2 ++
net/wireless/core.c | 2 +-
net/wireless/scan.c | 2 ++
3 files changed, 5 insertions(+), 1 deletion(-)
--- wireless-testing.orig/include/net/cfg80211.h 2009-02-10 20:59:36.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h 2009-02-10 20:59:37.000000000 +0100
@@ -567,6 +567,7 @@ enum cfg80211_signal_type {
* @len_information_elements: total length of the information elements
* @signal: signal strength value
* @signal_type: signal type
+ * @free_priv: function pointer to free private data
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
*/
struct cfg80211_bss {
@@ -582,6 +583,7 @@ struct cfg80211_bss {
s32 signal;
enum cfg80211_signal_type signal_type;
+ void (*free_priv)(struct cfg80211_bss *bss);
u8 priv[0] __attribute__((__aligned__(sizeof(void *))));
};
--- wireless-testing.orig/net/wireless/scan.c 2009-02-10 20:59:36.000000000 +0100
+++ wireless-testing/net/wireless/scan.c 2009-02-10 20:59:37.000000000 +0100
@@ -56,6 +56,8 @@ static void bss_release(struct kref *ref
struct cfg80211_internal_bss *bss;
bss = container_of(ref, struct cfg80211_internal_bss, ref);
+ if (bss->pub.free_priv)
+ bss->pub.free_priv(&bss->pub);
kfree(bss);
}
--- wireless-testing.orig/net/wireless/core.c 2009-02-10 20:59:36.000000000 +0100
+++ wireless-testing/net/wireless/core.c 2009-02-10 20:59:37.000000000 +0100
@@ -376,7 +376,7 @@ void cfg80211_dev_free(struct cfg80211_r
mutex_destroy(&drv->mtx);
mutex_destroy(&drv->devlist_mtx);
list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
- kfree(scan);
+ cfg80211_put_bss(&scan->pub);
kfree(drv);
}
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 22/27] cfg80211: allow users to request removing a BSS
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (20 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 21/27] cfg80211: free_priv for BSS info Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:25 ` [PATCH 23/27] cfg80211: add more flexible BSS lookup Johannes Berg
` (4 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
This patch introduces cfg80211_unlink_bss, a function to
allow a driver to remove a BSS from the internal list and
make it not show up in scan results any more -- this is
to be used when the driver detects that the BSS is no
longer available.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/net/cfg80211.h | 11 +++++++++++
net/wireless/scan.c | 21 +++++++++++++++++++++
2 files changed, 32 insertions(+)
--- wireless-testing.orig/include/net/cfg80211.h 2009-02-10 20:59:37.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h 2009-02-10 20:59:37.000000000 +0100
@@ -791,5 +791,16 @@ struct cfg80211_bss *cfg80211_get_mesh(s
const u8 *meshid, size_t meshidlen,
const u8 *meshcfg);
void cfg80211_put_bss(struct cfg80211_bss *bss);
+/**
+ * cfg80211_unlink_bss - unlink BSS from internal data structures
+ * @wiphy: the wiphy
+ * @bss: the bss to remove
+ *
+ * This function removes the given BSS from the internal data structures
+ * thereby making it no longer show up in scan results etc. Use this
+ * function when you detect a BSS is gone. Normally BSSes will also time
+ * out, so it is not necessary to use this function at all.
+ */
+void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
#endif /* __NET_CFG80211_H */
--- wireless-testing.orig/net/wireless/scan.c 2009-02-10 20:59:37.000000000 +0100
+++ wireless-testing/net/wireless/scan.c 2009-02-10 20:59:37.000000000 +0100
@@ -432,6 +432,27 @@ void cfg80211_put_bss(struct cfg80211_bs
}
EXPORT_SYMBOL(cfg80211_put_bss);
+void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
+{
+ struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+ struct cfg80211_internal_bss *bss;
+
+ if (WARN_ON(!pub))
+ return;
+
+ bss = container_of(pub, struct cfg80211_internal_bss, pub);
+
+ spin_lock_bh(&dev->bss_lock);
+
+ list_del(&bss->list);
+ rb_erase(&bss->rbn, &dev->bss_tree);
+
+ spin_unlock_bh(&dev->bss_lock);
+
+ kref_put(&bss->ref, bss_release);
+}
+EXPORT_SYMBOL(cfg80211_unlink_bss);
+
#ifdef CONFIG_WIRELESS_EXT
int cfg80211_wext_siwscan(struct net_device *dev,
struct iw_request_info *info,
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 23/27] cfg80211: add more flexible BSS lookup
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (21 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 22/27] cfg80211: allow users to request removing a BSS Johannes Berg
@ 2009-02-10 20:25 ` Johannes Berg
2009-02-10 20:26 ` [PATCH 24/27] mac80211: use cfg80211s BSS infrastructure Johannes Berg
` (3 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:25 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Add a more flexible BSS lookup function so that mac80211 or
other drivers can actually use this for getting the BSS to
connect to.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/net/cfg80211.h | 12 +++++++++++-
net/wireless/scan.c | 10 ++++++++--
2 files changed, 19 insertions(+), 3 deletions(-)
--- wireless-testing.orig/include/net/cfg80211.h 2009-02-10 20:59:37.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h 2009-02-10 20:59:38.000000000 +0100
@@ -785,7 +785,17 @@ cfg80211_inform_bss_frame(struct wiphy *
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *bssid,
- const u8 *ssid, size_t ssid_len);
+ const u8 *ssid, size_t ssid_len,
+ u16 capa_mask, u16 capa_val);
+static inline struct cfg80211_bss *
+cfg80211_get_ibss(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ const u8 *ssid, size_t ssid_len)
+{
+ return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len,
+ WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+}
+
struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *meshid, size_t meshidlen,
--- wireless-testing.orig/net/wireless/scan.c 2009-02-10 20:59:37.000000000 +0100
+++ wireless-testing/net/wireless/scan.c 2009-02-10 20:59:38.000000000 +0100
@@ -116,9 +116,12 @@ static bool is_bss(struct cfg80211_bss *
{
const u8 *ssidie;
- if (compare_ether_addr(a->bssid, bssid))
+ if (bssid && compare_ether_addr(a->bssid, bssid))
return false;
+ if (!ssid)
+ return true;
+
ssidie = find_ie(WLAN_EID_SSID,
a->information_elements,
a->len_information_elements);
@@ -199,7 +202,8 @@ static int cmp_bss(struct cfg80211_bss *
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *bssid,
- const u8 *ssid, size_t ssid_len)
+ const u8 *ssid, size_t ssid_len,
+ u16 capa_mask, u16 capa_val)
{
struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
struct cfg80211_internal_bss *bss, *res = NULL;
@@ -207,6 +211,8 @@ struct cfg80211_bss *cfg80211_get_bss(st
spin_lock_bh(&dev->bss_lock);
list_for_each_entry(bss, &dev->bss_list, list) {
+ if ((bss->pub.capability & capa_mask) != capa_val)
+ continue;
if (channel && bss->pub.channel != channel)
continue;
if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 24/27] mac80211: use cfg80211s BSS infrastructure
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (22 preceding siblings ...)
2009-02-10 20:25 ` [PATCH 23/27] cfg80211: add more flexible BSS lookup Johannes Berg
@ 2009-02-10 20:26 ` Johannes Berg
2009-02-10 20:26 ` [PATCH 25/27] mac80211: calculate wstats_flags on the fly Johannes Berg
` (2 subsequent siblings)
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:26 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Remove all the code from mac80211 to keep track of BSSes
and use the cfg80211-provided code completely.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/ieee80211_i.h | 42 ++-----
net/mac80211/main.c | 6 -
net/mac80211/mesh.c | 10 -
net/mac80211/mesh.h | 1
net/mac80211/mlme.c | 211 ++++++++++++-------------------------
net/mac80211/scan.c | 255 +++------------------------------------------
net/mac80211/spectmgmt.c | 7 -
7 files changed, 114 insertions(+), 418 deletions(-)
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-02-10 20:59:37.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-02-10 20:59:38.000000000 +0100
@@ -72,43 +72,36 @@ struct ieee80211_fragment_entry {
struct ieee80211_bss {
- struct list_head list;
- struct ieee80211_bss *hnext;
- size_t ssid_len;
+ /* Yes, this is a hack */
+ struct cfg80211_bss cbss;
- atomic_t users;
-
- u8 bssid[ETH_ALEN];
+ /* don't want to look up all the time */
+ size_t ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
+
u8 dtim_period;
- u16 capability; /* host byte order */
- enum ieee80211_band band;
- int freq;
- int signal, noise, qual;
- u8 *ies; /* all information elements from the last Beacon or Probe
- * Response frames; note Beacon frame is not allowed to
- * override values from Probe Response */
- size_t ies_len;
+
bool wmm_used;
+
+ unsigned long last_probe_resp;
+
#ifdef CONFIG_MAC80211_MESH
u8 *mesh_id;
size_t mesh_id_len;
u8 *mesh_cfg;
#endif
+
#define IEEE80211_MAX_SUPP_RATES 32
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
- u64 timestamp;
- int beacon_int;
- unsigned long last_probe_resp;
- unsigned long last_update;
-
- /* during assocation, we save an ERP value from a probe response so
+ /*
+ * During assocation, we save an ERP value from a probe response so
* that we can feed ERP info to the driver when handling the
* association completes. these fields probably won't be up-to-date
- * otherwise, you probably don't want to use them. */
- int has_erp_value;
+ * otherwise, you probably don't want to use them.
+ */
+ bool has_erp_value;
u8 erp_value;
};
@@ -668,9 +661,6 @@ struct ieee80211_local {
struct ieee80211_sub_if_data *scan_sdata;
enum nl80211_channel_type oper_channel_type;
struct ieee80211_channel *oper_channel, *csa_channel;
- struct list_head bss_list;
- struct ieee80211_bss *bss_hash[STA_HASH_SIZE];
- spinlock_t bss_lock;
/* SNMP counters */
/* dot11CountersTable */
@@ -933,8 +923,6 @@ ieee80211_rx_result
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_rx_status *rx_status);
-void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
-void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
char *ie, size_t len);
--- wireless-testing.orig/net/mac80211/main.c 2009-02-10 20:59:36.000000000 +0100
+++ wireless-testing/net/mac80211/main.c 2009-02-10 20:59:38.000000000 +0100
@@ -734,6 +734,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(
wiphy->privid = mac80211_wiphy_privid;
wiphy->max_scan_ssids = 4;
+ /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
+ wiphy->bss_priv_size = sizeof(struct ieee80211_bss) -
+ sizeof(struct cfg80211_bss);
local = wiphy_priv(wiphy);
local->hw.wiphy = wiphy;
@@ -877,8 +880,6 @@ int ieee80211_register_hw(struct ieee802
mpriv->local = local;
local->mdev = mdev;
- ieee80211_rx_bss_list_init(local);
-
local->hw.workqueue =
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
if (!local->hw.workqueue) {
@@ -1018,7 +1019,6 @@ void ieee80211_unregister_hw(struct ieee
rtnl_unlock();
- ieee80211_rx_bss_list_deinit(local);
ieee80211_clear_tx_pending(local);
sta_info_stop(local);
rate_control_deinitialize(local);
--- wireless-testing.orig/net/mac80211/scan.c 2009-02-10 20:59:37.000000000 +0100
+++ wireless-testing/net/mac80211/scan.c 2009-02-10 20:59:38.000000000 +0100
@@ -12,10 +12,7 @@
* published by the Free Software Foundation.
*/
-/* TODO:
- * figure out how to avoid that the "current BSS" expires
- * use cfg80211's BSS handling
- */
+/* TODO: figure out how to avoid that the "current BSS" expires */
#include <linux/wireless.h>
#include <linux/if_arp.h>
@@ -30,192 +27,29 @@
#define IEEE80211_CHANNEL_TIME (HZ / 33)
#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
-void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
-{
- spin_lock_init(&local->bss_lock);
- INIT_LIST_HEAD(&local->bss_list);
-}
-
-void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
-{
- struct ieee80211_bss *bss, *tmp;
-
- list_for_each_entry_safe(bss, tmp, &local->bss_list, list)
- ieee80211_rx_bss_put(local, bss);
-}
-
struct ieee80211_bss *
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
{
- struct ieee80211_bss *bss;
-
- spin_lock_bh(&local->bss_lock);
- bss = local->bss_hash[STA_HASH(bssid)];
- while (bss) {
- if (!bss_mesh_cfg(bss) &&
- !memcmp(bss->bssid, bssid, ETH_ALEN) &&
- bss->freq == freq &&
- bss->ssid_len == ssid_len &&
- (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
- atomic_inc(&bss->users);
- break;
- }
- bss = bss->hnext;
- }
- spin_unlock_bh(&local->bss_lock);
- return bss;
-}
-
-/* Caller must hold local->bss_lock */
-static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local,
- struct ieee80211_bss *bss)
-{
- u8 hash_idx;
-
- if (bss_mesh_cfg(bss))
- hash_idx = mesh_id_hash(bss_mesh_id(bss),
- bss_mesh_id_len(bss));
- else
- hash_idx = STA_HASH(bss->bssid);
-
- bss->hnext = local->bss_hash[hash_idx];
- local->bss_hash[hash_idx] = bss;
-}
-
-/* Caller must hold local->bss_lock */
-static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
- struct ieee80211_bss *bss)
-{
- struct ieee80211_bss *b, *prev = NULL;
- b = local->bss_hash[STA_HASH(bss->bssid)];
- while (b) {
- if (b == bss) {
- if (!prev)
- local->bss_hash[STA_HASH(bss->bssid)] =
- bss->hnext;
- else
- prev->hnext = bss->hnext;
- break;
- }
- prev = b;
- b = b->hnext;
- }
-}
-
-static struct ieee80211_bss *
-ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq,
- u8 *ssid, u8 ssid_len)
-{
- struct ieee80211_bss *bss;
-
- bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
- if (!bss)
- return NULL;
- atomic_set(&bss->users, 2);
- memcpy(bss->bssid, bssid, ETH_ALEN);
- bss->freq = freq;
- if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
- memcpy(bss->ssid, ssid, ssid_len);
- bss->ssid_len = ssid_len;
- }
-
- spin_lock_bh(&local->bss_lock);
- /* TODO: order by RSSI? */
- list_add_tail(&bss->list, &local->bss_list);
- __ieee80211_rx_bss_hash_add(local, bss);
- spin_unlock_bh(&local->bss_lock);
- return bss;
-}
-
-#ifdef CONFIG_MAC80211_MESH
-static struct ieee80211_bss *
-ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
- u8 *mesh_cfg, int freq)
-{
- struct ieee80211_bss *bss;
-
- spin_lock_bh(&local->bss_lock);
- bss = local->bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
- while (bss) {
- if (bss_mesh_cfg(bss) &&
- !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
- bss->freq == freq &&
- mesh_id_len == bss->mesh_id_len &&
- (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
- mesh_id_len))) {
- atomic_inc(&bss->users);
- break;
- }
- bss = bss->hnext;
- }
- spin_unlock_bh(&local->bss_lock);
- return bss;
+ return (void *)cfg80211_get_bss(local->hw.wiphy,
+ ieee80211_get_channel(local->hw.wiphy,
+ freq),
+ bssid, ssid, ssid_len,
+ 0, 0);
}
-static struct ieee80211_bss *
-ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len,
- u8 *mesh_cfg, int mesh_config_len, int freq)
+static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
{
- struct ieee80211_bss *bss;
-
- if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN)
- return NULL;
-
- bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
- if (!bss)
- return NULL;
-
- bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC);
- if (!bss->mesh_cfg) {
- kfree(bss);
- return NULL;
- }
-
- if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) {
- bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC);
- if (!bss->mesh_id) {
- kfree(bss->mesh_cfg);
- kfree(bss);
- return NULL;
- }
- memcpy(bss->mesh_id, mesh_id, mesh_id_len);
- }
-
- atomic_set(&bss->users, 2);
- memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN);
- bss->mesh_id_len = mesh_id_len;
- bss->freq = freq;
- spin_lock_bh(&local->bss_lock);
- /* TODO: order by RSSI? */
- list_add_tail(&bss->list, &local->bss_list);
- __ieee80211_rx_bss_hash_add(local, bss);
- spin_unlock_bh(&local->bss_lock);
- return bss;
-}
-#endif
+ struct ieee80211_bss *bss = (void *)cbss;
-static void ieee80211_rx_bss_free(struct ieee80211_bss *bss)
-{
- kfree(bss->ies);
kfree(bss_mesh_id(bss));
kfree(bss_mesh_cfg(bss));
- kfree(bss);
}
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_bss *bss)
{
- local_bh_disable();
- if (!atomic_dec_and_lock(&bss->users, &local->bss_lock)) {
- local_bh_enable();
- return;
- }
-
- __ieee80211_rx_bss_hash_del(local, bss);
- list_del(&bss->list);
- spin_unlock_bh(&local->bss_lock);
- ieee80211_rx_bss_free(bss);
+ cfg80211_put_bss((struct cfg80211_bss *)bss);
}
struct ieee80211_bss *
@@ -228,7 +62,7 @@ ieee80211_bss_info_update(struct ieee802
bool beacon)
{
struct ieee80211_bss *bss;
- int clen, freq = channel->center_freq;
+ int clen;
enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE;
s32 signal = 0;
@@ -240,39 +74,14 @@ ieee80211_bss_info_update(struct ieee802
signal = (rx_status->signal * 100) / local->hw.max_signal;
}
- cfg80211_put_bss(
- cfg80211_inform_bss_frame(local->hw.wiphy, channel,
- mgmt, len, signal, sigtype,
- GFP_ATOMIC));
-
-#ifdef CONFIG_MAC80211_MESH
- if (elems->mesh_config)
- bss = ieee80211_rx_mesh_bss_get(local, elems->mesh_id,
- elems->mesh_id_len, elems->mesh_config, freq);
- else
-#endif
- bss = ieee80211_rx_bss_get(local, mgmt->bssid, freq,
- elems->ssid, elems->ssid_len);
- if (!bss) {
-#ifdef CONFIG_MAC80211_MESH
- if (elems->mesh_config)
- bss = ieee80211_rx_mesh_bss_add(local, elems->mesh_id,
- elems->mesh_id_len, elems->mesh_config,
- elems->mesh_config_len, freq);
- else
-#endif
- bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq,
- elems->ssid, elems->ssid_len);
- if (!bss)
- return NULL;
- } else {
-#if 0
- /* TODO: order by RSSI? */
- spin_lock_bh(&local->bss_lock);
- list_move_tail(&bss->list, &local->bss_list);
- spin_unlock_bh(&local->bss_lock);
-#endif
- }
+ bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
+ mgmt, len, signal, sigtype,
+ GFP_ATOMIC);
+
+ if (!bss)
+ return NULL;
+
+ bss->cbss.free_priv = ieee80211_rx_bss_free;
/* save the ERP value so that it is available at association time */
if (elems->erp_info && elems->erp_info_len >= 1) {
@@ -280,9 +89,6 @@ ieee80211_bss_info_update(struct ieee802
bss->has_erp_value = 1;
}
- bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
- bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
-
if (elems->tim) {
struct ieee80211_tim_ie *tim_ie =
(struct ieee80211_tim_ie *)elems->tim;
@@ -311,34 +117,11 @@ ieee80211_bss_info_update(struct ieee802
bss->supp_rates_len += clen;
}
- bss->band = rx_status->band;
-
- bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
- bss->last_update = jiffies;
- bss->signal = rx_status->signal;
- bss->noise = rx_status->noise;
- bss->qual = rx_status->qual;
bss->wmm_used = elems->wmm_param || elems->wmm_info;
if (!beacon)
bss->last_probe_resp = jiffies;
- /*
- * For probe responses, or if we don't have any information yet,
- * use the IEs from the beacon.
- */
- if (!bss->ies || !beacon) {
- if (bss->ies == NULL || bss->ies_len < elems->total_len) {
- kfree(bss->ies);
- bss->ies = kmalloc(elems->total_len, GFP_ATOMIC);
- }
- if (bss->ies) {
- memcpy(bss->ies, elems->ie_start, elems->total_len);
- bss->ies_len = elems->total_len;
- } else
- bss->ies_len = 0;
- }
-
return bss;
}
@@ -350,7 +133,7 @@ void ieee80211_rx_bss_remove(struct ieee
bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len);
if (bss) {
- atomic_dec(&bss->users);
+ cfg80211_unlink_bss(local->hw.wiphy, (void *)bss);
ieee80211_rx_bss_put(local, bss);
}
}
--- wireless-testing.orig/net/mac80211/mlme.c 2009-02-10 20:59:37.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c 2009-02-10 20:59:38.000000000 +0100
@@ -55,10 +55,10 @@ static u8 *ieee80211_bss_get_ie(struct i
{
u8 *end, *pos;
- pos = bss->ies;
+ pos = bss->cbss.information_elements;
if (pos == NULL)
return NULL;
- end = pos + bss->ies_len;
+ end = pos + bss->cbss.len_information_elements;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
@@ -289,7 +289,7 @@ static void ieee80211_send_assoc(struct
local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
if (bss) {
- if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+ if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;
if (bss->wmm_used)
wmm = 1;
@@ -300,7 +300,7 @@ static void ieee80211_send_assoc(struct
* b-only mode) */
rates_len = ieee80211_compatible_rates(bss, sband, &rates);
- if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+ if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
(local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
@@ -786,12 +786,12 @@ static void ieee80211_set_associated(str
ifsta->ssid, ifsta->ssid_len);
if (bss) {
/* set timing information */
- sdata->vif.bss_conf.beacon_int = bss->beacon_int;
- sdata->vif.bss_conf.timestamp = bss->timestamp;
+ sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
+ sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
sdata->vif.bss_conf.dtim_period = bss->dtim_period;
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
- bss->capability, bss->has_erp_value, bss->erp_value);
+ bss->cbss.capability, bss->has_erp_value, bss->erp_value);
ieee80211_rx_bss_put(local, bss);
}
@@ -1011,7 +1011,7 @@ static int ieee80211_privacy_mismatch(st
if (!bss)
return 0;
- bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY);
+ bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY);
wep_privacy = !!ieee80211_sta_wep_configured(sdata);
privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
@@ -1386,8 +1386,6 @@ static void ieee80211_rx_mgmt_assoc_resp
/* Add STA entry for the AP */
sta = sta_info_get(local, ifsta->bssid);
if (!sta) {
- struct ieee80211_bss *bss;
-
newsta = true;
sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
@@ -1397,15 +1395,6 @@ static void ieee80211_rx_mgmt_assoc_resp
rcu_read_unlock();
return;
}
- bss = ieee80211_rx_bss_get(local, ifsta->bssid,
- local->hw.conf.channel->center_freq,
- ifsta->ssid, ifsta->ssid_len);
- if (bss) {
- sta->last_signal = bss->signal;
- sta->last_qual = bss->qual;
- sta->last_noise = bss->noise;
- ieee80211_rx_bss_put(local, bss);
- }
/* update new sta with its last rx activity */
sta->last_rx = jiffies;
@@ -1661,10 +1650,11 @@ static int ieee80211_sta_join_ibss(struc
struct ieee80211_bss *bss)
{
return __ieee80211_sta_join_ibss(sdata, ifsta,
- bss->bssid, bss->beacon_int,
- bss->freq,
+ bss->cbss.bssid,
+ bss->cbss.beacon_interval,
+ bss->cbss.channel->center_freq,
bss->supp_rates_len, bss->supp_rates,
- bss->capability);
+ bss->cbss.capability);
}
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@@ -1739,7 +1729,7 @@ static void ieee80211_rx_bss_info(struct
}
/* was just updated in ieee80211_bss_info_update */
- beacon_timestamp = bss->timestamp;
+ beacon_timestamp = bss->cbss.tsf;
/*
* In STA mode, the remaining parameters should not be overridden
@@ -1754,8 +1744,8 @@ static void ieee80211_rx_bss_info(struct
/* check if we need to merge IBSS */
if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon &&
(!(sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)) &&
- bss->capability & WLAN_CAPABILITY_IBSS &&
- bss->freq == local->oper_channel->center_freq &&
+ bss->cbss.capability & WLAN_CAPABILITY_IBSS &&
+ bss->cbss.channel == local->oper_channel &&
elems->ssid_len == sdata->u.sta.ssid_len &&
memcmp(elems->ssid, sdata->u.sta.ssid,
sdata->u.sta.ssid_len) == 0) {
@@ -2185,37 +2175,6 @@ static void ieee80211_sta_reset_auth(str
netif_carrier_off(sdata->dev);
}
-
-static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
- const char *ssid, int ssid_len)
-{
- int tmp, hidden_ssid;
-
- if (ssid_len == ifsta->ssid_len &&
- !memcmp(ifsta->ssid, ssid, ssid_len))
- return 1;
-
- if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
- return 0;
-
- hidden_ssid = 1;
- tmp = ssid_len;
- while (tmp--) {
- if (ssid[tmp] != '\0') {
- hidden_ssid = 0;
- break;
- }
- }
-
- if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0))
- return 1;
-
- if (ssid_len == 1 && ssid[0] == ' ')
- return 1;
-
- return 0;
-}
-
static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta)
{
@@ -2274,8 +2233,6 @@ static int ieee80211_sta_find_ibss(struc
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_bss *bss;
- int found = 0;
- u8 bssid[ETH_ALEN];
int active_ibss;
if (ifsta->ssid_len == 0)
@@ -2286,56 +2243,39 @@ static int ieee80211_sta_find_ibss(struc
printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
sdata->dev->name, active_ibss);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- spin_lock_bh(&local->bss_lock);
- list_for_each_entry(bss, &local->bss_list, list) {
- if (ifsta->ssid_len != bss->ssid_len ||
- memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0
- || !(bss->capability & WLAN_CAPABILITY_IBSS))
- continue;
- if ((ifsta->flags & IEEE80211_STA_BSSID_SET) &&
- memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) != 0)
- continue;
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG " bssid=%pM found\n", bss->bssid);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- memcpy(bssid, bss->bssid, ETH_ALEN);
- found = 1;
- if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0)
- break;
- }
- spin_unlock_bh(&local->bss_lock);
+
+ if (active_ibss)
+ return 0;
+
+ if (ifsta->flags & IEEE80211_STA_BSSID_SET)
+ bss = ieee80211_rx_bss_get(local, ifsta->bssid, 0,
+ ifsta->ssid, ifsta->ssid_len);
+ else
+ bss = (void *)cfg80211_get_ibss(local->hw.wiphy,
+ NULL,
+ ifsta->ssid, ifsta->ssid_len);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
if (found)
printk(KERN_DEBUG " sta_find_ibss: selected %pM current "
- "%pM\n", bssid, ifsta->bssid);
+ "%pM\n", bss->cbss.bssid, ifsta->bssid);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- if (found &&
- ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) ||
- memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0)) {
+ if (bss &&
+ (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) ||
+ memcmp(ifsta->bssid, bss->cbss.bssid, ETH_ALEN))) {
int ret;
- int search_freq;
-
- if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
- search_freq = bss->freq;
- else
- search_freq = local->hw.conf.channel->center_freq;
-
- bss = ieee80211_rx_bss_get(local, bssid, search_freq,
- ifsta->ssid, ifsta->ssid_len);
- if (!bss)
- goto dont_join;
printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
" based on configured SSID\n",
- sdata->dev->name, bssid);
+ sdata->dev->name, bss->cbss.bssid);
+
ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);
ieee80211_rx_bss_put(local, bss);
return ret;
- }
+ } else if (bss)
+ ieee80211_rx_bss_put(local, bss);
-dont_join:
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG " did not try to join ibss\n");
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
@@ -2391,51 +2331,44 @@ static int ieee80211_sta_config_auth(str
struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_bss *bss, *selected = NULL;
- int top_rssi = 0, freq;
+ struct ieee80211_bss *bss;
+ u8 *bssid = ifsta->bssid, *ssid = ifsta->ssid;
+ u8 ssid_len = ifsta->ssid_len;
+ u16 capa_mask = WLAN_CAPABILITY_ESS;
+ u16 capa_val = WLAN_CAPABILITY_ESS;
+ struct ieee80211_channel *chan = local->oper_channel;
+
+ if (ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
+ IEEE80211_STA_AUTO_BSSID_SEL |
+ IEEE80211_STA_AUTO_CHANNEL_SEL)) {
+ capa_mask |= WLAN_CAPABILITY_PRIVACY;
+ if (sdata->default_key)
+ capa_val |= WLAN_CAPABILITY_PRIVACY;
+ }
+
+ if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
+ chan = NULL;
- spin_lock_bh(&local->bss_lock);
- freq = local->oper_channel->center_freq;
- list_for_each_entry(bss, &local->bss_list, list) {
- if (!(bss->capability & WLAN_CAPABILITY_ESS))
- continue;
-
- if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
- IEEE80211_STA_AUTO_BSSID_SEL |
- IEEE80211_STA_AUTO_CHANNEL_SEL)) &&
- (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
- !!sdata->default_key))
- continue;
-
- if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) &&
- bss->freq != freq)
- continue;
-
- if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) &&
- memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
- continue;
-
- if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) &&
- !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
- continue;
-
- if (!selected || top_rssi < bss->signal) {
- selected = bss;
- top_rssi = bss->signal;
- }
- }
- if (selected)
- atomic_inc(&selected->users);
- spin_unlock_bh(&local->bss_lock);
+ if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
+ bssid = NULL;
- if (selected) {
- ieee80211_set_freq(sdata, selected->freq);
+ if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) {
+ ssid = NULL;
+ ssid_len = 0;
+ }
+
+ bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan,
+ bssid, ssid, ssid_len,
+ capa_mask, capa_val);
+
+ if (bss) {
+ ieee80211_set_freq(sdata, bss->cbss.channel->center_freq);
if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
- ieee80211_sta_set_ssid(sdata, selected->ssid,
- selected->ssid_len);
- ieee80211_sta_set_bssid(sdata, selected->bssid);
- ieee80211_sta_def_wmm_params(sdata, selected->supp_rates_len,
- selected->supp_rates);
+ ieee80211_sta_set_ssid(sdata, bss->ssid,
+ bss->ssid_len);
+ ieee80211_sta_set_bssid(sdata, bss->cbss.bssid);
+ ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len,
+ bss->supp_rates);
if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED)
sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED;
else
@@ -2444,14 +2377,14 @@ static int ieee80211_sta_config_auth(str
/* Send out direct probe if no probe resp was received or
* the one we have is outdated
*/
- if (!selected->last_probe_resp ||
- time_after(jiffies, selected->last_probe_resp
+ if (!bss->last_probe_resp ||
+ time_after(jiffies, bss->last_probe_resp
+ IEEE80211_SCAN_RESULT_EXPIRE))
ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
else
ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
- ieee80211_rx_bss_put(local, selected);
+ ieee80211_rx_bss_put(local, bss);
ieee80211_sta_reset_auth(sdata, ifsta);
return 0;
} else {
--- wireless-testing.orig/net/mac80211/spectmgmt.c 2009-02-10 17:58:33.000000000 +0100
+++ wireless-testing/net/mac80211/spectmgmt.c 2009-02-10 20:59:38.000000000 +0100
@@ -102,8 +102,9 @@ void ieee80211_chswitch_work(struct work
goto exit;
sdata->local->oper_channel = sdata->local->csa_channel;
+ /* XXX: shouldn't really modify cfg80211-owned data! */
if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
- bss->freq = sdata->local->oper_channel->center_freq;
+ bss->cbss.channel = sdata->local->oper_channel;
ieee80211_rx_bss_put(sdata->local, bss);
exit:
@@ -158,7 +159,9 @@ void ieee80211_process_chanswitch(struct
IEEE80211_QUEUE_STOP_REASON_CSA);
ifsta->flags |= IEEE80211_STA_CSA_RECEIVED;
mod_timer(&ifsta->chswitch_timer,
- jiffies + msecs_to_jiffies(sw_elem->count * bss->beacon_int));
+ jiffies +
+ msecs_to_jiffies(sw_elem->count *
+ bss->cbss.beacon_interval));
}
}
--- wireless-testing.orig/net/mac80211/mesh.c 2009-02-10 17:58:33.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.c 2009-02-10 20:59:38.000000000 +0100
@@ -275,16 +275,6 @@ u32 mesh_table_hash(u8 *addr, struct iee
& tbl->hash_mask;
}
-u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len)
-{
- if (!mesh_id_len)
- return 1;
- else if (mesh_id_len == 1)
- return (u8) mesh_id[0];
- else
- return (u8) (mesh_id[0] + 2 * mesh_id[1]);
-}
-
struct mesh_table *mesh_table_alloc(int size_order)
{
int i;
--- wireless-testing.orig/net/mac80211/mesh.h 2009-02-10 17:58:33.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.h 2009-02-10 20:59:38.000000000 +0100
@@ -196,7 +196,6 @@ struct mesh_rmc {
/* Public interfaces */
/* Various */
-u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len);
int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
struct ieee80211_sub_if_data *sdata);
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 25/27] mac80211: calculate wstats_flags on the fly
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (23 preceding siblings ...)
2009-02-10 20:26 ` [PATCH 24/27] mac80211: use cfg80211s BSS infrastructure Johannes Berg
@ 2009-02-10 20:26 ` Johannes Berg
2009-02-10 20:26 ` [PATCH 26/27] mac80211: fix IBSS auth Johannes Berg
2009-02-10 20:26 ` [PATCH 27/27] mac80211: split managed/ibss code a little more Johannes Berg
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:26 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
Just to make wext.c more self-contained.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/ieee80211_i.h | 1 -
net/mac80211/main.c | 8 --------
net/mac80211/wext.c | 21 ++++++++++++++++++---
3 files changed, 18 insertions(+), 12 deletions(-)
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2009-02-10 20:59:38.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h 2009-02-10 20:59:39.000000000 +0100
@@ -592,7 +592,6 @@ struct ieee80211_local {
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
- u8 wstats_flags;
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
int tx_headroom; /* required headroom for hardware/radiotap */
--- wireless-testing.orig/net/mac80211/main.c 2009-02-10 20:59:38.000000000 +0100
+++ wireless-testing/net/mac80211/main.c 2009-02-10 20:59:39.000000000 +0100
@@ -905,14 +905,6 @@ int ieee80211_register_hw(struct ieee802
local->hw.conf.listen_interval = local->hw.max_listen_interval;
- local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
- IEEE80211_HW_SIGNAL_DBM) ?
- IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
- local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
- IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
- if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
- local->wstats_flags |= IW_QUAL_DBM;
-
result = sta_info_start(local);
if (result < 0)
goto fail_sta_info;
--- wireless-testing.orig/net/mac80211/wext.c 2009-02-10 20:59:36.000000000 +0100
+++ wireless-testing/net/mac80211/wext.c 2009-02-10 20:59:39.000000000 +0100
@@ -145,6 +145,21 @@ static int ieee80211_ioctl_siwgenie(stru
return -EOPNOTSUPP;
}
+static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local)
+{
+ u8 wstats_flags = 0;
+
+ wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+ IEEE80211_HW_SIGNAL_DBM) ?
+ IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
+ wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
+ IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ wstats_flags |= IW_QUAL_DBM;
+
+ return wstats_flags;
+}
+
static int ieee80211_ioctl_giwrange(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
@@ -187,13 +202,13 @@ static int ieee80211_ioctl_giwrange(stru
range->max_qual.noise = 0;
range->max_qual.qual = 100;
- range->max_qual.updated = local->wstats_flags;
+ range->max_qual.updated = ieee80211_get_wstats_flags(local);
range->avg_qual.qual = 50;
/* not always true but better than nothing */
range->avg_qual.level = range->max_qual.level / 2;
range->avg_qual.noise = range->max_qual.noise / 2;
- range->avg_qual.updated = local->wstats_flags;
+ range->avg_qual.updated = ieee80211_get_wstats_flags(local);
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
@@ -979,7 +994,7 @@ static struct iw_statistics *ieee80211_g
wstats->qual.level = sta->last_signal;
wstats->qual.qual = sta->last_qual;
wstats->qual.noise = sta->last_noise;
- wstats->qual.updated = local->wstats_flags;
+ wstats->qual.updated = ieee80211_get_wstats_flags(local);
}
rcu_read_unlock();
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 26/27] mac80211: fix IBSS auth
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (24 preceding siblings ...)
2009-02-10 20:26 ` [PATCH 25/27] mac80211: calculate wstats_flags on the fly Johannes Berg
@ 2009-02-10 20:26 ` Johannes Berg
2009-02-10 20:26 ` [PATCH 27/27] mac80211: split managed/ibss code a little more Johannes Berg
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:26 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Jouni Malinen
The code beyond this point is supposed to be used for
non-IBSS (managed) mode only.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Jouni Malinen <j@w1.fi>
---
net/mac80211/mlme.c | 1 +
1 file changed, 1 insertion(+)
--- wireless-testing.orig/net/mac80211/mlme.c 2009-02-10 20:59:38.000000000 +0100
+++ wireless-testing/net/mac80211/mlme.c 2009-02-10 20:59:39.000000000 +0100
@@ -1175,6 +1175,7 @@ static void ieee80211_rx_mgmt_auth(struc
if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
return;
ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
+ return;
}
if (auth_alg != ifsta->auth_alg ||
--
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 27/27] mac80211: split managed/ibss code a little more
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
` (25 preceding siblings ...)
2009-02-10 20:26 ` [PATCH 26/27] mac80211: fix IBSS auth Johannes Berg
@ 2009-02-10 20:26 ` Johannes Berg
26 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2009-02-10 20:26 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
It appears that you can completely mess up mac80211 in IBSS
mode by sending it a disassoc or deauth: it'll stop queues
and do a lot more but not ever do anything again. Fix this
by not handling all those frames in IBSS mode,=20
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/mlme.c | 254 +++++++++++++++++++++++++++++------------------=
-----
1 file changed, 146 insertions(+), 108 deletions(-)
--- wireless-testing.orig/net/mac80211/mlme.c 2009-02-10 20:59:39.000000000=
+0100
+++ wireless-testing/net/mac80211/mlme.c 2009-02-10 20:59:40.000000000 +010=
0
@@ -778,9 +778,6 @@ static void ieee80211_set_associated(str
bss_info_changed |=3D BSS_CHANGED_ASSOC;
ifsta->flags |=3D IEEE80211_STA_ASSOCIATED;
=20
- if (sdata->vif.type !=3D NL80211_IFTYPE_STATION)
- return;
-
bss =3D ieee80211_rx_bss_get(local, ifsta->bssid,
conf->channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
@@ -1139,6 +1136,30 @@ static void ieee80211_auth_challenge(str
elems.challenge_len + 2, 1);
}
=20
+static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdat=
a,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ u16 auth_alg, auth_transaction, status_code;
+
+ if (len < 24 + 6)
+ return;
+
+ auth_alg =3D le16_to_cpu(mgmt->u.auth.auth_alg);
+ auth_transaction =3D le16_to_cpu(mgmt->u.auth.auth_transaction);
+ status_code =3D le16_to_cpu(mgmt->u.auth.status_code);
+
+ /*
+ * IEEE 802.11 standard does not require authentication in IBSS
+ * networks and most implementations do not seem to use it.
+ * However, try to reply to authentication attempts if someone
+ * has actually implemented this.
+ */
+ if (auth_alg =3D=3D WLAN_AUTH_OPEN && auth_transaction =3D=3D 1)
+ ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
+}
+
static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
@@ -1146,38 +1167,22 @@ static void ieee80211_rx_mgmt_auth(struc
{
u16 auth_alg, auth_transaction, status_code;
=20
- if (ifsta->state !=3D IEEE80211_STA_MLME_AUTHENTICATE &&
- sdata->vif.type !=3D NL80211_IFTYPE_ADHOC)
+ if (ifsta->state !=3D IEEE80211_STA_MLME_AUTHENTICATE)
return;
=20
if (len < 24 + 6)
return;
=20
- if (sdata->vif.type !=3D NL80211_IFTYPE_ADHOC &&
- memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) !=3D 0)
+ if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) !=3D 0)
return;
=20
- if (sdata->vif.type !=3D NL80211_IFTYPE_ADHOC &&
- memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) !=3D 0)
+ if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) !=3D 0)
return;
=20
auth_alg =3D le16_to_cpu(mgmt->u.auth.auth_alg);
auth_transaction =3D le16_to_cpu(mgmt->u.auth.auth_transaction);
status_code =3D le16_to_cpu(mgmt->u.auth.status_code);
=20
- if (sdata->vif.type =3D=3D NL80211_IFTYPE_ADHOC) {
- /*
- * IEEE 802.11 standard does not require authentication in IBSS
- * networks and most implementations do not seem to use it.
- * However, try to reply to authentication attempts if someone
- * has actually implemented this.
- */
- if (auth_alg !=3D WLAN_AUTH_OPEN || auth_transaction !=3D 1)
- return;
- ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
- return;
- }
-
if (auth_alg !=3D ifsta->auth_alg ||
auth_transaction !=3D ifsta->auth_transaction)
return;
@@ -1732,74 +1737,85 @@ static void ieee80211_rx_bss_info(struct
/* was just updated in ieee80211_bss_info_update */
beacon_timestamp =3D bss->cbss.tsf;
=20
- /*
- * In STA mode, the remaining parameters should not be overridden
- * by beacons because they're not necessarily accurate there.
- */
- if (sdata->vif.type !=3D NL80211_IFTYPE_ADHOC &&
- bss->last_probe_resp && beacon) {
- ieee80211_rx_bss_put(local, bss);
- return;
- }
+ if (sdata->vif.type !=3D NL80211_IFTYPE_ADHOC)
+ goto put_bss;
=20
/* check if we need to merge IBSS */
- if (sdata->vif.type =3D=3D NL80211_IFTYPE_ADHOC && beacon &&
- (!(sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)) &&
- bss->cbss.capability & WLAN_CAPABILITY_IBSS &&
- bss->cbss.channel =3D=3D local->oper_channel &&
- elems->ssid_len =3D=3D sdata->u.sta.ssid_len &&
+
+ /* merge only on beacons (???) */
+ if (!beacon)
+ goto put_bss;
+
+ /* we use a fixed BSSID */
+ if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)
+ goto put_bss;
+
+ /* not an IBSS */
+ if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))
+ goto put_bss;
+
+ /* different channel */
+ if (bss->cbss.channel !=3D local->oper_channel)
+ goto put_bss;
+
+ /* different SSID */
+ if (elems->ssid_len !=3D sdata->u.sta.ssid_len ||
memcmp(elems->ssid, sdata->u.sta.ssid,
- sdata->u.sta.ssid_len) =3D=3D 0) {
- if (rx_status->flag & RX_FLAG_TSFT) {
- /* in order for correct IBSS merging we need mactime
- *
- * since mactime is defined as the time the first data
- * symbol of the frame hits the PHY, and the timestamp
- * of the beacon is defined as "the time that the data
- * symbol containing the first bit of the timestamp is
- * transmitted to the PHY plus the transmitting STA=E2=80=99s
- * delays through its local PHY from the MAC-PHY
- * interface to its interface with the WM"
- * (802.11 11.1.2) - equals the time this bit arrives at
- * the receiver - we have to take into account the
- * offset between the two.
- * e.g: at 1 MBit that means mactime is 192 usec earlier
- * (=3D24 bytes * 8 usecs/byte) than the beacon timestamp.
- */
- int rate;
- if (rx_status->flag & RX_FLAG_HT) {
- rate =3D 65; /* TODO: HT rates */
- } else {
- rate =3D local->hw.wiphy->bands[band]->
- bitrates[rx_status->rate_idx].bitrate;
- }
- rx_timestamp =3D rx_status->mactime + (24 * 8 * 10 / rate);
- } else if (local && local->ops && local->ops->get_tsf)
- /* second best option: get current TSF */
- rx_timestamp =3D local->ops->get_tsf(local_to_hw(local));
+ sdata->u.sta.ssid_len))
+ goto put_bss;
+
+ if (rx_status->flag & RX_FLAG_TSFT) {
+ /*
+ * For correct IBSS merging we need mactime; since mactime is
+ * defined as the time the first data symbol of the frame hits
+ * the PHY, and the timestamp of the beacon is defined as "the
+ * time that the data symbol containing the first bit of the
+ * timestamp is transmitted to the PHY plus the transmitting
+ * STA's delays through its local PHY from the MAC-PHY
+ * interface to its interface with the WM" (802.11 11.1.2)
+ * - equals the time this bit arrives at the receiver - we have
+ * to take into account the offset between the two.
+ *
+ * E.g. at 1 MBit that means mactime is 192 usec earlier
+ * (=3D24 bytes * 8 usecs/byte) than the beacon timestamp.
+ */
+ int rate;
+
+ if (rx_status->flag & RX_FLAG_HT)
+ rate =3D 65; /* TODO: HT rates */
else
- /* can't merge without knowing the TSF */
- rx_timestamp =3D -1LLU;
+ rate =3D local->hw.wiphy->bands[band]->
+ bitrates[rx_status->rate_idx].bitrate;
+
+ rx_timestamp =3D rx_status->mactime + (24 * 8 * 10 / rate);
+ } else if (local && local->ops && local->ops->get_tsf)
+ /* second best option: get current TSF */
+ rx_timestamp =3D local->ops->get_tsf(local_to_hw(local));
+ else
+ /* can't merge without knowing the TSF */
+ rx_timestamp =3D -1LLU;
+
#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "RX beacon SA=3D%pM BSSID=3D"
- "%pM TSF=3D0x%llx BCN=3D0x%llx diff=3D%lld @%lu\n",
- mgmt->sa, mgmt->bssid,
- (unsigned long long)rx_timestamp,
- (unsigned long long)beacon_timestamp,
- (unsigned long long)(rx_timestamp - beacon_timestamp),
- jiffies);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- if (beacon_timestamp > rx_timestamp) {
+ printk(KERN_DEBUG "RX beacon SA=3D%pM BSSID=3D"
+ "%pM TSF=3D0x%llx BCN=3D0x%llx diff=3D%lld @%lu\n",
+ mgmt->sa, mgmt->bssid,
+ (unsigned long long)rx_timestamp,
+ (unsigned long long)beacon_timestamp,
+ (unsigned long long)(rx_timestamp - beacon_timestamp),
+ jiffies);
+#endif
+
+ if (beacon_timestamp > rx_timestamp) {
#ifdef CONFIG_MAC80211_IBSS_DEBUG
- printk(KERN_DEBUG "%s: beacon TSF higher than "
- "local TSF - IBSS merge with BSSID %pM\n",
- sdata->dev->name, mgmt->bssid);
+ printk(KERN_DEBUG "%s: beacon TSF higher than "
+ "local TSF - IBSS merge with BSSID %pM\n",
+ sdata->dev->name, mgmt->bssid);
#endif
- ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
- ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
- }
+ ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
+ ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
}
=20
+ put_bss:
ieee80211_rx_bss_put(local, bss);
}
=20
@@ -1948,8 +1964,7 @@ static void ieee80211_rx_mgmt_probe_req(
struct ieee80211_mgmt *resp;
u8 *pos, *end;
=20
- if (sdata->vif.type !=3D NL80211_IFTYPE_ADHOC ||
- ifsta->state !=3D IEEE80211_STA_MLME_IBSS_JOINED ||
+ if (ifsta->state !=3D IEEE80211_STA_MLME_IBSS_JOINED ||
len < 24 + 2 || !ifsta->probe_resp)
return;
=20
@@ -2053,31 +2068,54 @@ static void ieee80211_sta_rx_queued_mgmt
mgmt =3D (struct ieee80211_mgmt *) skb->data;
fc =3D le16_to_cpu(mgmt->frame_control);
=20
- switch (fc & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_PROBE_REQ:
- ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len);
- break;
- case IEEE80211_STYPE_PROBE_RESP:
- ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status);
- break;
- case IEEE80211_STYPE_BEACON:
- ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status);
- break;
- case IEEE80211_STYPE_AUTH:
- ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);
- break;
- case IEEE80211_STYPE_ASSOC_RESP:
- ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0);
- break;
- case IEEE80211_STYPE_REASSOC_RESP:
- ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1);
- break;
- case IEEE80211_STYPE_DEAUTH:
- ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);
- break;
- case IEEE80211_STYPE_DISASSOC:
- ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len);
- break;
+ if (sdata->vif.type =3D=3D NL80211_IFTYPE_ADHOC) {
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_REQ:
+ ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt,
+ skb->len);
+ break;
+ case IEEE80211_STYPE_PROBE_RESP:
+ ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
+ rx_status);
+ break;
+ case IEEE80211_STYPE_BEACON:
+ ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+ rx_status);
+ break;
+ case IEEE80211_STYPE_AUTH:
+ ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt,
+ skb->len);
+ break;
+ }
+ } else { /* NL80211_IFTYPE_STATION */
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
+ rx_status);
+ break;
+ case IEEE80211_STYPE_BEACON:
+ ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+ rx_status);
+ break;
+ case IEEE80211_STYPE_AUTH:
+ ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);
+ break;
+ case IEEE80211_STYPE_ASSOC_RESP:
+ ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,
+ skb->len, 0);
+ break;
+ case IEEE80211_STYPE_REASSOC_RESP:
+ ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,
+ skb->len, 1);
+ break;
+ case IEEE80211_STYPE_DEAUTH:
+ ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);
+ break;
+ case IEEE80211_STYPE_DISASSOC:
+ ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt,
+ skb->len);
+ break;
+ }
}
=20
kfree_skb(skb);
--=20
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2009-02-10 20:44 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-02-10 20:25 [PATCH 00/27] mac80211 updates Johannes Berg
2009-02-10 20:25 ` [PATCH 01/27] zd1211rw: do not ratelimit no-ops Johannes Berg
2009-02-10 20:25 ` [PATCH 02/27] mac80211: disable IBSS beacon before join Johannes Berg
2009-02-10 20:25 ` [PATCH 03/27] zd1211rw: honour enable_beacon conf Johannes Berg
2009-02-10 20:25 ` [PATCH 04/27] mac80211: properly validate/translate IW_AUTH_MFP values Johannes Berg
2009-02-10 20:25 ` [PATCH 05/27] mac80211: reject extra IEs for probe request when hw_scan Johannes Berg
2009-02-10 20:25 ` [PATCH 06/27] mac80211: fix beacon enable more Johannes Berg
2009-02-10 20:25 ` [PATCH 07/27] mac80211: remove bssid argument from prepare_for_handlers Johannes Berg
2009-02-10 20:25 ` [PATCH 08/27] mac80211: remove stray aggregation debugfs definition Johannes Berg
2009-02-10 20:25 ` [PATCH 09/27] mac80211: fix RX aggregation timeouts Johannes Berg
2009-02-10 20:25 ` [PATCH 10/27] mac80211: restructure HT code Johannes Berg
2009-02-10 20:25 ` [PATCH 11/27] mac80211: restrict aggregation to supported interface modes Johannes Berg
2009-02-10 20:25 ` [PATCH 12/27] mac80211: hardware should not deny going back to legacy Johannes Berg
2009-02-10 20:25 ` [PATCH 13/27] mac80211: document TX aggregation (and small cleanup) Johannes Berg
2009-02-10 20:25 ` [PATCH 14/27] mac80211: fix race in TX aggregation Johannes Berg
2009-02-10 20:25 ` [PATCH 15/27] mac80211: fix aggregation timer lockups Johannes Berg
2009-02-10 20:25 ` [PATCH 16/27] mac80211: clean up BA session teardown Johannes Berg
2009-02-10 20:25 ` [PATCH 17/27] mac80211: RX aggregation: clean up stop session Johannes Berg
2009-02-10 20:25 ` [PATCH 18/27] mac80211: further cleanups to stopping BA sessions Johannes Berg
2009-02-10 20:25 ` [PATCH 19/27] cfg80211/nl80211: scanning (and mac80211 update to use it) Johannes Berg
2009-02-10 20:25 ` [PATCH 20/27] mac80211: dont add BSS when creating IBSS Johannes Berg
2009-02-10 20:25 ` [PATCH 21/27] cfg80211: free_priv for BSS info Johannes Berg
2009-02-10 20:25 ` [PATCH 22/27] cfg80211: allow users to request removing a BSS Johannes Berg
2009-02-10 20:25 ` [PATCH 23/27] cfg80211: add more flexible BSS lookup Johannes Berg
2009-02-10 20:26 ` [PATCH 24/27] mac80211: use cfg80211s BSS infrastructure Johannes Berg
2009-02-10 20:26 ` [PATCH 25/27] mac80211: calculate wstats_flags on the fly Johannes Berg
2009-02-10 20:26 ` [PATCH 26/27] mac80211: fix IBSS auth Johannes Berg
2009-02-10 20:26 ` [PATCH 27/27] mac80211: split managed/ibss code a little more Johannes Berg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).