diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/Makefile | 2 | ||||
-rw-r--r-- | net/mac80211/agg-rx.c | 302 | ||||
-rw-r--r-- | net/mac80211/agg-tx.c | 636 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 31 | ||||
-rw-r--r-- | net/mac80211/ht.c | 869 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 81 | ||||
-rw-r--r-- | net/mac80211/iface.c | 5 | ||||
-rw-r--r-- | net/mac80211/main.c | 48 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 10 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 1 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 1 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 703 | ||||
-rw-r--r-- | net/mac80211/rx.c | 68 | ||||
-rw-r--r-- | net/mac80211/scan.c | 620 | ||||
-rw-r--r-- | net/mac80211/spectmgmt.c | 7 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 37 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 4 | ||||
-rw-r--r-- | net/mac80211/tx.c | 8 | ||||
-rw-r--r-- | net/mac80211/wext.c | 98 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/core.c | 8 | ||||
-rw-r--r-- | net/wireless/core.h | 20 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 323 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 8 | ||||
-rw-r--r-- | net/wireless/scan.c | 836 |
25 files changed, 2855 insertions, 1873 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 58c94bb38e87..3503a3d21318 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -8,7 +8,7 @@ mac80211-y := \ | |||
8 | wep.o \ | 8 | wep.o \ |
9 | wpa.o \ | 9 | wpa.o \ |
10 | scan.o \ | 10 | scan.o \ |
11 | ht.o \ | 11 | ht.o agg-tx.o agg-rx.o \ |
12 | mlme.o \ | 12 | mlme.o \ |
13 | iface.o \ | 13 | iface.o \ |
14 | rate.o \ | 14 | rate.o \ |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c new file mode 100644 index 000000000000..3112bfd441b6 --- /dev/null +++ b/net/mac80211/agg-rx.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * HT handling | ||
3 | * | ||
4 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * Copyright 2002-2005, Instant802 Networks, Inc. | ||
6 | * Copyright 2005-2006, Devicescape Software, Inc. | ||
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
9 | * Copyright 2007-2008, Intel Corporation | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/ieee80211.h> | ||
17 | #include <net/mac80211.h> | ||
18 | #include "ieee80211_i.h" | ||
19 | |||
20 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, | ||
21 | u16 initiator, u16 reason) | ||
22 | { | ||
23 | struct ieee80211_local *local = sta->local; | ||
24 | struct ieee80211_hw *hw = &local->hw; | ||
25 | int i; | ||
26 | |||
27 | /* check if TID is in operational state */ | ||
28 | spin_lock_bh(&sta->lock); | ||
29 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) { | ||
30 | spin_unlock_bh(&sta->lock); | ||
31 | return; | ||
32 | } | ||
33 | |||
34 | sta->ampdu_mlme.tid_state_rx[tid] = | ||
35 | HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
36 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
37 | spin_unlock_bh(&sta->lock); | ||
38 | |||
39 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
40 | printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", | ||
41 | sta->sta.addr, tid); | ||
42 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
43 | |||
44 | if (local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, | ||
45 | &sta->sta, tid, NULL)) | ||
46 | printk(KERN_DEBUG "HW problem - can not stop rx " | ||
47 | "aggregation for tid %d\n", tid); | ||
48 | |||
49 | /* shutdown timer has not expired */ | ||
50 | if (initiator != WLAN_BACK_TIMER) | ||
51 | del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
52 | |||
53 | /* check if this is a self generated aggregation halt */ | ||
54 | if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) | ||
55 | ieee80211_send_delba(sta->sdata, sta->sta.addr, | ||
56 | tid, 0, reason); | ||
57 | |||
58 | /* free the reordering buffer */ | ||
59 | for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { | ||
60 | if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { | ||
61 | /* release the reordered frames */ | ||
62 | dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); | ||
63 | sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; | ||
64 | sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | spin_lock_bh(&sta->lock); | ||
69 | /* free resources */ | ||
70 | kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); | ||
71 | |||
72 | if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) { | ||
73 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
74 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
75 | } | ||
76 | |||
77 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; | ||
78 | spin_unlock_bh(&sta->lock); | ||
79 | } | ||
80 | |||
81 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, | ||
82 | u16 initiator, u16 reason) | ||
83 | { | ||
84 | struct ieee80211_local *local = sdata->local; | ||
85 | struct sta_info *sta; | ||
86 | |||
87 | /* stop HW Rx aggregation. ampdu_action existence | ||
88 | * already verified in session init so we add the BUG_ON */ | ||
89 | BUG_ON(!local->ops->ampdu_action); | ||
90 | |||
91 | rcu_read_lock(); | ||
92 | |||
93 | sta = sta_info_get(local, ra); | ||
94 | if (!sta) { | ||
95 | rcu_read_unlock(); | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | __ieee80211_stop_rx_ba_session(sta, tid, initiator, reason); | ||
100 | |||
101 | rcu_read_unlock(); | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * After accepting the AddBA Request we activated a timer, | ||
106 | * resetting it after each frame that arrives from the originator. | ||
107 | * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. | ||
108 | */ | ||
109 | static void sta_rx_agg_session_timer_expired(unsigned long data) | ||
110 | { | ||
111 | /* not an elegant detour, but there is no choice as the timer passes | ||
112 | * only one argument, and various sta_info are needed here, so init | ||
113 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
114 | * array gives the sta through container_of */ | ||
115 | u8 *ptid = (u8 *)data; | ||
116 | u8 *timer_to_id = ptid - *ptid; | ||
117 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | ||
118 | timer_to_tid[0]); | ||
119 | |||
120 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
121 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | ||
122 | #endif | ||
123 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, | ||
124 | (u16)*ptid, WLAN_BACK_TIMER, | ||
125 | WLAN_REASON_QSTA_TIMEOUT); | ||
126 | } | ||
127 | |||
128 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | ||
129 | u8 dialog_token, u16 status, u16 policy, | ||
130 | u16 buf_size, u16 timeout) | ||
131 | { | ||
132 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
133 | struct ieee80211_local *local = sdata->local; | ||
134 | struct sk_buff *skb; | ||
135 | struct ieee80211_mgmt *mgmt; | ||
136 | u16 capab; | ||
137 | |||
138 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
139 | |||
140 | if (!skb) { | ||
141 | printk(KERN_DEBUG "%s: failed to allocate buffer " | ||
142 | "for addba resp frame\n", sdata->dev->name); | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
147 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
148 | memset(mgmt, 0, 24); | ||
149 | memcpy(mgmt->da, da, ETH_ALEN); | ||
150 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
151 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
152 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
153 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
154 | else | ||
155 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
156 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
157 | IEEE80211_STYPE_ACTION); | ||
158 | |||
159 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); | ||
160 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
161 | mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; | ||
162 | mgmt->u.action.u.addba_resp.dialog_token = dialog_token; | ||
163 | |||
164 | capab = (u16)(policy << 1); /* bit 1 aggregation policy */ | ||
165 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
166 | capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ | ||
167 | |||
168 | mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); | ||
169 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); | ||
170 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); | ||
171 | |||
172 | ieee80211_tx_skb(sdata, skb, 1); | ||
173 | } | ||
174 | |||
175 | void ieee80211_process_addba_request(struct ieee80211_local *local, | ||
176 | struct sta_info *sta, | ||
177 | struct ieee80211_mgmt *mgmt, | ||
178 | size_t len) | ||
179 | { | ||
180 | struct ieee80211_hw *hw = &local->hw; | ||
181 | struct ieee80211_conf *conf = &hw->conf; | ||
182 | struct tid_ampdu_rx *tid_agg_rx; | ||
183 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; | ||
184 | u8 dialog_token; | ||
185 | int ret = -EOPNOTSUPP; | ||
186 | |||
187 | /* extract session parameters from addba request frame */ | ||
188 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | ||
189 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | ||
190 | start_seq_num = | ||
191 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | ||
192 | |||
193 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
194 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | ||
195 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
196 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
197 | |||
198 | status = WLAN_STATUS_REQUEST_DECLINED; | ||
199 | |||
200 | /* sanity check for incoming parameters: | ||
201 | * check if configuration can support the BA policy | ||
202 | * and if buffer size does not exceeds max value */ | ||
203 | /* XXX: check own ht delayed BA capability?? */ | ||
204 | if (((ba_policy != 1) | ||
205 | && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) | ||
206 | || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { | ||
207 | status = WLAN_STATUS_INVALID_QOS_PARAM; | ||
208 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
209 | if (net_ratelimit()) | ||
210 | printk(KERN_DEBUG "AddBA Req with bad params from " | ||
211 | "%pM on tid %u. policy %d, buffer size %d\n", | ||
212 | mgmt->sa, tid, ba_policy, | ||
213 | buf_size); | ||
214 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
215 | goto end_no_lock; | ||
216 | } | ||
217 | /* determine default buffer size */ | ||
218 | if (buf_size == 0) { | ||
219 | struct ieee80211_supported_band *sband; | ||
220 | |||
221 | sband = local->hw.wiphy->bands[conf->channel->band]; | ||
222 | buf_size = IEEE80211_MIN_AMPDU_BUF; | ||
223 | buf_size = buf_size << sband->ht_cap.ampdu_factor; | ||
224 | } | ||
225 | |||
226 | |||
227 | /* examine state machine */ | ||
228 | spin_lock_bh(&sta->lock); | ||
229 | |||
230 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { | ||
231 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
232 | if (net_ratelimit()) | ||
233 | printk(KERN_DEBUG "unexpected AddBA Req from " | ||
234 | "%pM on tid %u\n", | ||
235 | mgmt->sa, tid); | ||
236 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
237 | goto end; | ||
238 | } | ||
239 | |||
240 | /* prepare A-MPDU MLME for Rx aggregation */ | ||
241 | sta->ampdu_mlme.tid_rx[tid] = | ||
242 | kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); | ||
243 | if (!sta->ampdu_mlme.tid_rx[tid]) { | ||
244 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
245 | if (net_ratelimit()) | ||
246 | printk(KERN_ERR "allocate rx mlme to tid %d failed\n", | ||
247 | tid); | ||
248 | #endif | ||
249 | goto end; | ||
250 | } | ||
251 | /* rx timer */ | ||
252 | sta->ampdu_mlme.tid_rx[tid]->session_timer.function = | ||
253 | sta_rx_agg_session_timer_expired; | ||
254 | sta->ampdu_mlme.tid_rx[tid]->session_timer.data = | ||
255 | (unsigned long)&sta->timer_to_tid[tid]; | ||
256 | init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
257 | |||
258 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | ||
259 | |||
260 | /* prepare reordering buffer */ | ||
261 | tid_agg_rx->reorder_buf = | ||
262 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); | ||
263 | if (!tid_agg_rx->reorder_buf) { | ||
264 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
265 | if (net_ratelimit()) | ||
266 | printk(KERN_ERR "can not allocate reordering buffer " | ||
267 | "to tid %d\n", tid); | ||
268 | #endif | ||
269 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
270 | goto end; | ||
271 | } | ||
272 | |||
273 | if (local->ops->ampdu_action) | ||
274 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, | ||
275 | &sta->sta, tid, &start_seq_num); | ||
276 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
277 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); | ||
278 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
279 | |||
280 | if (ret) { | ||
281 | kfree(tid_agg_rx->reorder_buf); | ||
282 | kfree(tid_agg_rx); | ||
283 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
284 | goto end; | ||
285 | } | ||
286 | |||
287 | /* change state and send addba resp */ | ||
288 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; | ||
289 | tid_agg_rx->dialog_token = dialog_token; | ||
290 | tid_agg_rx->ssn = start_seq_num; | ||
291 | tid_agg_rx->head_seq_num = start_seq_num; | ||
292 | tid_agg_rx->buf_size = buf_size; | ||
293 | tid_agg_rx->timeout = timeout; | ||
294 | tid_agg_rx->stored_mpdu_num = 0; | ||
295 | status = WLAN_STATUS_SUCCESS; | ||
296 | end: | ||
297 | spin_unlock_bh(&sta->lock); | ||
298 | |||
299 | end_no_lock: | ||
300 | ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, | ||
301 | dialog_token, status, 1, buf_size, timeout); | ||
302 | } | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c new file mode 100644 index 000000000000..1232d9f01ca9 --- /dev/null +++ b/net/mac80211/agg-tx.c | |||
@@ -0,0 +1,636 @@ | |||
1 | /* | ||
2 | * HT handling | ||
3 | * | ||
4 | * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * Copyright 2002-2005, Instant802 Networks, Inc. | ||
6 | * Copyright 2005-2006, Devicescape Software, Inc. | ||
7 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
8 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
9 | * Copyright 2007-2009, Intel Corporation | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/ieee80211.h> | ||
17 | #include <net/mac80211.h> | ||
18 | #include "ieee80211_i.h" | ||
19 | #include "wme.h" | ||
20 | |||
21 | /** | ||
22 | * DOC: TX aggregation | ||
23 | * | ||
24 | * Aggregation on the TX side requires setting the hardware flag | ||
25 | * %IEEE80211_HW_AMPDU_AGGREGATION as well as, if present, the @ampdu_queues | ||
26 | * hardware parameter to the number of hardware AMPDU queues. If there are no | ||
27 | * hardware queues then the driver will (currently) have to do all frame | ||
28 | * buffering. | ||
29 | * | ||
30 | * When TX aggregation is started by some subsystem (usually the rate control | ||
31 | * algorithm would be appropriate) by calling the | ||
32 | * ieee80211_start_tx_ba_session() function, the driver will be notified via | ||
33 | * its @ampdu_action function, with the %IEEE80211_AMPDU_TX_START action. | ||
34 | * | ||
35 | * In response to that, the driver is later required to call the | ||
36 | * ieee80211_start_tx_ba_cb() (or ieee80211_start_tx_ba_cb_irqsafe()) | ||
37 | * function, which will start the aggregation session. | ||
38 | * | ||
39 | * Similarly, when the aggregation session is stopped by | ||
40 | * ieee80211_stop_tx_ba_session(), the driver's @ampdu_action function will | ||
41 | * be called with the action %IEEE80211_AMPDU_TX_STOP. In this case, the | ||
42 | * call must not fail, and the driver must later call ieee80211_stop_tx_ba_cb() | ||
43 | * (or ieee80211_stop_tx_ba_cb_irqsafe()). | ||
44 | */ | ||
45 | |||
46 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | ||
47 | const u8 *da, u16 tid, | ||
48 | u8 dialog_token, u16 start_seq_num, | ||
49 | u16 agg_size, u16 timeout) | ||
50 | { | ||
51 | struct ieee80211_local *local = sdata->local; | ||
52 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
53 | struct sk_buff *skb; | ||
54 | struct ieee80211_mgmt *mgmt; | ||
55 | u16 capab; | ||
56 | |||
57 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
58 | |||
59 | if (!skb) { | ||
60 | printk(KERN_ERR "%s: failed to allocate buffer " | ||
61 | "for addba request frame\n", sdata->dev->name); | ||
62 | return; | ||
63 | } | ||
64 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
65 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
66 | memset(mgmt, 0, 24); | ||
67 | memcpy(mgmt->da, da, ETH_ALEN); | ||
68 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
69 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
70 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
71 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
72 | else | ||
73 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
74 | |||
75 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
76 | IEEE80211_STYPE_ACTION); | ||
77 | |||
78 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); | ||
79 | |||
80 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
81 | mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; | ||
82 | |||
83 | mgmt->u.action.u.addba_req.dialog_token = dialog_token; | ||
84 | capab = (u16)(1 << 1); /* bit 1 aggregation policy */ | ||
85 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
86 | capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ | ||
87 | |||
88 | mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); | ||
89 | |||
90 | mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); | ||
91 | mgmt->u.action.u.addba_req.start_seq_num = | ||
92 | cpu_to_le16(start_seq_num << 4); | ||
93 | |||
94 | ieee80211_tx_skb(sdata, skb, 1); | ||
95 | } | ||
96 | |||
97 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) | ||
98 | { | ||
99 | struct ieee80211_local *local = sdata->local; | ||
100 | struct sk_buff *skb; | ||
101 | struct ieee80211_bar *bar; | ||
102 | u16 bar_control = 0; | ||
103 | |||
104 | skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); | ||
105 | if (!skb) { | ||
106 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
107 | "bar frame\n", sdata->dev->name); | ||
108 | return; | ||
109 | } | ||
110 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
111 | bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar)); | ||
112 | memset(bar, 0, sizeof(*bar)); | ||
113 | bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
114 | IEEE80211_STYPE_BACK_REQ); | ||
115 | memcpy(bar->ra, ra, ETH_ALEN); | ||
116 | memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); | ||
117 | bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; | ||
118 | bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; | ||
119 | bar_control |= (u16)(tid << 12); | ||
120 | bar->control = cpu_to_le16(bar_control); | ||
121 | bar->start_seq_num = cpu_to_le16(ssn); | ||
122 | |||
123 | ieee80211_tx_skb(sdata, skb, 0); | ||
124 | } | ||
125 | |||
126 | static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | ||
127 | enum ieee80211_back_parties initiator) | ||
128 | { | ||
129 | struct ieee80211_local *local = sta->local; | ||
130 | int ret; | ||
131 | u8 *state; | ||
132 | |||
133 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
134 | |||
135 | if (local->hw.ampdu_queues) | ||
136 | ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]); | ||
137 | |||
138 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
139 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
140 | |||
141 | ret = local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_STOP, | ||
142 | &sta->sta, tid, NULL); | ||
143 | |||
144 | /* HW shall not deny going back to legacy */ | ||
145 | if (WARN_ON(ret)) { | ||
146 | *state = HT_AGG_STATE_OPERATIONAL; | ||
147 | if (local->hw.ampdu_queues) | ||
148 | ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]); | ||
149 | } | ||
150 | |||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * After sending add Block Ack request we activated a timer until | ||
156 | * add Block Ack response will arrive from the recipient. | ||
157 | * If this timer expires sta_addba_resp_timer_expired will be executed. | ||
158 | */ | ||
159 | static void sta_addba_resp_timer_expired(unsigned long data) | ||
160 | { | ||
161 | /* not an elegant detour, but there is no choice as the timer passes | ||
162 | * only one argument, and both sta_info and TID are needed, so init | ||
163 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
164 | * array gives the sta through container_of */ | ||
165 | u16 tid = *(u8 *)data; | ||
166 | struct sta_info *sta = container_of((void *)data, | ||
167 | struct sta_info, timer_to_tid[tid]); | ||
168 | u8 *state; | ||
169 | |||
170 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
171 | |||
172 | /* check if the TID waits for addBA response */ | ||
173 | spin_lock_bh(&sta->lock); | ||
174 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
175 | spin_unlock_bh(&sta->lock); | ||
176 | *state = HT_AGG_STATE_IDLE; | ||
177 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
178 | printk(KERN_DEBUG "timer expired on tid %d but we are not " | ||
179 | "expecting addBA response there", tid); | ||
180 | #endif | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
185 | printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); | ||
186 | #endif | ||
187 | |||
188 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); | ||
189 | spin_unlock_bh(&sta->lock); | ||
190 | } | ||
191 | |||
192 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
193 | { | ||
194 | struct ieee80211_local *local = hw_to_local(hw); | ||
195 | struct sta_info *sta; | ||
196 | struct ieee80211_sub_if_data *sdata; | ||
197 | u16 start_seq_num; | ||
198 | u8 *state; | ||
199 | int ret = 0; | ||
200 | |||
201 | if (WARN_ON(!local->ops->ampdu_action)) | ||
202 | return -EINVAL; | ||
203 | |||
204 | if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | ||
205 | return -EINVAL; | ||
206 | |||
207 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
208 | printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", | ||
209 | ra, tid); | ||
210 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
211 | |||
212 | rcu_read_lock(); | ||
213 | |||
214 | sta = sta_info_get(local, ra); | ||
215 | if (!sta) { | ||
216 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
217 | printk(KERN_DEBUG "Could not find the station\n"); | ||
218 | #endif | ||
219 | ret = -ENOENT; | ||
220 | goto exit; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * The aggregation code is not prepared to handle | ||
225 | * anything but STA/AP due to the BSSID handling. | ||
226 | * IBSS could work in the code but isn't supported | ||
227 | * by drivers or the standard. | ||
228 | */ | ||
229 | if (sta->sdata->vif.type != NL80211_IFTYPE_STATION && | ||
230 | sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
231 | sta->sdata->vif.type != NL80211_IFTYPE_AP) { | ||
232 | ret = -EINVAL; | ||
233 | goto exit; | ||
234 | } | ||
235 | |||
236 | spin_lock_bh(&sta->lock); | ||
237 | |||
238 | /* we have tried too many times, receiver does not want A-MPDU */ | ||
239 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { | ||
240 | ret = -EBUSY; | ||
241 | goto err_unlock_sta; | ||
242 | } | ||
243 | |||
244 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
245 | /* check if the TID is not in aggregation flow already */ | ||
246 | if (*state != HT_AGG_STATE_IDLE) { | ||
247 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
248 | printk(KERN_DEBUG "BA request denied - session is not " | ||
249 | "idle on tid %u\n", tid); | ||
250 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
251 | ret = -EAGAIN; | ||
252 | goto err_unlock_sta; | ||
253 | } | ||
254 | |||
255 | /* prepare A-MPDU MLME for Tx aggregation */ | ||
256 | sta->ampdu_mlme.tid_tx[tid] = | ||
257 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | ||
258 | if (!sta->ampdu_mlme.tid_tx[tid]) { | ||
259 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
260 | if (net_ratelimit()) | ||
261 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", | ||
262 | tid); | ||
263 | #endif | ||
264 | ret = -ENOMEM; | ||
265 | goto err_unlock_sta; | ||
266 | } | ||
267 | /* Tx timer */ | ||
268 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | ||
269 | sta_addba_resp_timer_expired; | ||
270 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = | ||
271 | (unsigned long)&sta->timer_to_tid[tid]; | ||
272 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
273 | |||
274 | if (hw->ampdu_queues) { | ||
275 | /* create a new queue for this aggregation */ | ||
276 | ret = ieee80211_ht_agg_queue_add(local, sta, tid); | ||
277 | |||
278 | /* case no queue is available to aggregation | ||
279 | * don't switch to aggregation */ | ||
280 | if (ret) { | ||
281 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
282 | printk(KERN_DEBUG "BA request denied - " | ||
283 | "queue unavailable for tid %d\n", tid); | ||
284 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
285 | goto err_unlock_queue; | ||
286 | } | ||
287 | } | ||
288 | sdata = sta->sdata; | ||
289 | |||
290 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | ||
291 | * call back right away, it must see that the flow has begun */ | ||
292 | *state |= HT_ADDBA_REQUESTED_MSK; | ||
293 | |||
294 | /* This is slightly racy because the queue isn't stopped */ | ||
295 | start_seq_num = sta->tid_seq[tid]; | ||
296 | |||
297 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, | ||
298 | &sta->sta, tid, &start_seq_num); | ||
299 | |||
300 | if (ret) { | ||
301 | /* No need to requeue the packets in the agg queue, since we | ||
302 | * held the tx lock: no packet could be enqueued to the newly | ||
303 | * allocated queue */ | ||
304 | if (hw->ampdu_queues) | ||
305 | ieee80211_ht_agg_queue_remove(local, sta, tid, 0); | ||
306 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
307 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | ||
308 | " tid %d\n", tid); | ||
309 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
310 | *state = HT_AGG_STATE_IDLE; | ||
311 | goto err_unlock_queue; | ||
312 | } | ||
313 | |||
314 | /* Will put all the packets in the new SW queue */ | ||
315 | if (hw->ampdu_queues) | ||
316 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); | ||
317 | spin_unlock_bh(&sta->lock); | ||
318 | |||
319 | /* send an addBA request */ | ||
320 | sta->ampdu_mlme.dialog_token_allocator++; | ||
321 | sta->ampdu_mlme.tid_tx[tid]->dialog_token = | ||
322 | sta->ampdu_mlme.dialog_token_allocator; | ||
323 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | ||
324 | |||
325 | |||
326 | ieee80211_send_addba_request(sta->sdata, ra, tid, | ||
327 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | ||
328 | sta->ampdu_mlme.tid_tx[tid]->ssn, | ||
329 | 0x40, 5000); | ||
330 | /* activate the timer for the recipient's addBA response */ | ||
331 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = | ||
332 | jiffies + ADDBA_RESP_INTERVAL; | ||
333 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
334 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
335 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | ||
336 | #endif | ||
337 | goto exit; | ||
338 | |||
339 | err_unlock_queue: | ||
340 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
341 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
342 | ret = -EBUSY; | ||
343 | err_unlock_sta: | ||
344 | spin_unlock_bh(&sta->lock); | ||
345 | exit: | ||
346 | rcu_read_unlock(); | ||
347 | return ret; | ||
348 | } | ||
349 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | ||
350 | |||
351 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
352 | { | ||
353 | struct ieee80211_local *local = hw_to_local(hw); | ||
354 | struct sta_info *sta; | ||
355 | u8 *state; | ||
356 | |||
357 | if (tid >= STA_TID_NUM) { | ||
358 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
359 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
360 | tid, STA_TID_NUM); | ||
361 | #endif | ||
362 | return; | ||
363 | } | ||
364 | |||
365 | rcu_read_lock(); | ||
366 | sta = sta_info_get(local, ra); | ||
367 | if (!sta) { | ||
368 | rcu_read_unlock(); | ||
369 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
370 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | ||
371 | #endif | ||
372 | return; | ||
373 | } | ||
374 | |||
375 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
376 | spin_lock_bh(&sta->lock); | ||
377 | |||
378 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
379 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
380 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | ||
381 | *state); | ||
382 | #endif | ||
383 | spin_unlock_bh(&sta->lock); | ||
384 | rcu_read_unlock(); | ||
385 | return; | ||
386 | } | ||
387 | |||
388 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); | ||
389 | |||
390 | *state |= HT_ADDBA_DRV_READY_MSK; | ||
391 | |||
392 | if (*state == HT_AGG_STATE_OPERATIONAL) { | ||
393 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
394 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | ||
395 | #endif | ||
396 | if (hw->ampdu_queues) | ||
397 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
398 | } | ||
399 | spin_unlock_bh(&sta->lock); | ||
400 | rcu_read_unlock(); | ||
401 | } | ||
402 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | ||
403 | |||
404 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
405 | const u8 *ra, u16 tid) | ||
406 | { | ||
407 | struct ieee80211_local *local = hw_to_local(hw); | ||
408 | struct ieee80211_ra_tid *ra_tid; | ||
409 | struct sk_buff *skb = dev_alloc_skb(0); | ||
410 | |||
411 | if (unlikely(!skb)) { | ||
412 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
413 | if (net_ratelimit()) | ||
414 | printk(KERN_WARNING "%s: Not enough memory, " | ||
415 | "dropping start BA session", skb->dev->name); | ||
416 | #endif | ||
417 | return; | ||
418 | } | ||
419 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
420 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
421 | ra_tid->tid = tid; | ||
422 | |||
423 | skb->pkt_type = IEEE80211_ADDBA_MSG; | ||
424 | skb_queue_tail(&local->skb_queue, skb); | ||
425 | tasklet_schedule(&local->tasklet); | ||
426 | } | ||
427 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | ||
428 | |||
429 | int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | ||
430 | enum ieee80211_back_parties initiator) | ||
431 | { | ||
432 | u8 *state; | ||
433 | int ret; | ||
434 | |||
435 | /* check if the TID is in aggregation */ | ||
436 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
437 | spin_lock_bh(&sta->lock); | ||
438 | |||
439 | if (*state != HT_AGG_STATE_OPERATIONAL) { | ||
440 | ret = -ENOENT; | ||
441 | goto unlock; | ||
442 | } | ||
443 | |||
444 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
445 | printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", | ||
446 | sta->sta.addr, tid); | ||
447 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
448 | |||
449 | ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator); | ||
450 | |||
451 | unlock: | ||
452 | spin_unlock_bh(&sta->lock); | ||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | ||
457 | u8 *ra, u16 tid, | ||
458 | enum ieee80211_back_parties initiator) | ||
459 | { | ||
460 | struct ieee80211_local *local = hw_to_local(hw); | ||
461 | struct sta_info *sta; | ||
462 | int ret = 0; | ||
463 | |||
464 | if (WARN_ON(!local->ops->ampdu_action)) | ||
465 | return -EINVAL; | ||
466 | |||
467 | if (tid >= STA_TID_NUM) | ||
468 | return -EINVAL; | ||
469 | |||
470 | rcu_read_lock(); | ||
471 | sta = sta_info_get(local, ra); | ||
472 | if (!sta) { | ||
473 | rcu_read_unlock(); | ||
474 | return -ENOENT; | ||
475 | } | ||
476 | |||
477 | ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator); | ||
478 | rcu_read_unlock(); | ||
479 | return ret; | ||
480 | } | ||
481 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | ||
482 | |||
483 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | ||
484 | { | ||
485 | struct ieee80211_local *local = hw_to_local(hw); | ||
486 | struct sta_info *sta; | ||
487 | u8 *state; | ||
488 | int agg_queue; | ||
489 | |||
490 | if (tid >= STA_TID_NUM) { | ||
491 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
492 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
493 | tid, STA_TID_NUM); | ||
494 | #endif | ||
495 | return; | ||
496 | } | ||
497 | |||
498 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
499 | printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n", | ||
500 | ra, tid); | ||
501 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
502 | |||
503 | rcu_read_lock(); | ||
504 | sta = sta_info_get(local, ra); | ||
505 | if (!sta) { | ||
506 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
507 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | ||
508 | #endif | ||
509 | rcu_read_unlock(); | ||
510 | return; | ||
511 | } | ||
512 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
513 | |||
514 | /* NOTE: no need to use sta->lock in this state check, as | ||
515 | * ieee80211_stop_tx_ba_session will let only one stop call to | ||
516 | * pass through per sta/tid | ||
517 | */ | ||
518 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | ||
519 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
520 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | ||
521 | #endif | ||
522 | rcu_read_unlock(); | ||
523 | return; | ||
524 | } | ||
525 | |||
526 | if (*state & HT_AGG_STATE_INITIATOR_MSK) | ||
527 | ieee80211_send_delba(sta->sdata, ra, tid, | ||
528 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | ||
529 | |||
530 | if (hw->ampdu_queues) { | ||
531 | agg_queue = sta->tid_to_tx_q[tid]; | ||
532 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); | ||
533 | |||
534 | /* We just requeued the all the frames that were in the | ||
535 | * removed queue, and since we might miss a softirq we do | ||
536 | * netif_schedule_queue. ieee80211_wake_queue is not used | ||
537 | * here as this queue is not necessarily stopped | ||
538 | */ | ||
539 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, | ||
540 | agg_queue)); | ||
541 | } | ||
542 | spin_lock_bh(&sta->lock); | ||
543 | *state = HT_AGG_STATE_IDLE; | ||
544 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
545 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
546 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
547 | spin_unlock_bh(&sta->lock); | ||
548 | |||
549 | rcu_read_unlock(); | ||
550 | } | ||
551 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | ||
552 | |||
553 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
554 | const u8 *ra, u16 tid) | ||
555 | { | ||
556 | struct ieee80211_local *local = hw_to_local(hw); | ||
557 | struct ieee80211_ra_tid *ra_tid; | ||
558 | struct sk_buff *skb = dev_alloc_skb(0); | ||
559 | |||
560 | if (unlikely(!skb)) { | ||
561 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
562 | if (net_ratelimit()) | ||
563 | printk(KERN_WARNING "%s: Not enough memory, " | ||
564 | "dropping stop BA session", skb->dev->name); | ||
565 | #endif | ||
566 | return; | ||
567 | } | ||
568 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
569 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
570 | ra_tid->tid = tid; | ||
571 | |||
572 | skb->pkt_type = IEEE80211_DELBA_MSG; | ||
573 | skb_queue_tail(&local->skb_queue, skb); | ||
574 | tasklet_schedule(&local->tasklet); | ||
575 | } | ||
576 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); | ||
577 | |||
578 | |||
579 | void ieee80211_process_addba_resp(struct ieee80211_local *local, | ||
580 | struct sta_info *sta, | ||
581 | struct ieee80211_mgmt *mgmt, | ||
582 | size_t len) | ||
583 | { | ||
584 | struct ieee80211_hw *hw = &local->hw; | ||
585 | u16 capab; | ||
586 | u16 tid, start_seq_num; | ||
587 | u8 *state; | ||
588 | |||
589 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | ||
590 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
591 | |||
592 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
593 | |||
594 | spin_lock_bh(&sta->lock); | ||
595 | |||
596 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
597 | spin_unlock_bh(&sta->lock); | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | if (mgmt->u.action.u.addba_resp.dialog_token != | ||
602 | sta->ampdu_mlme.tid_tx[tid]->dialog_token) { | ||
603 | spin_unlock_bh(&sta->lock); | ||
604 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
605 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); | ||
606 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
607 | return; | ||
608 | } | ||
609 | |||
610 | del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
611 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
612 | printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); | ||
613 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
614 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) | ||
615 | == WLAN_STATUS_SUCCESS) { | ||
616 | *state |= HT_ADDBA_RECEIVED_MSK; | ||
617 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
618 | |||
619 | if (*state == HT_AGG_STATE_OPERATIONAL && | ||
620 | local->hw.ampdu_queues) | ||
621 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
622 | |||
623 | if (local->ops->ampdu_action) { | ||
624 | (void)local->ops->ampdu_action(hw, | ||
625 | IEEE80211_AMPDU_TX_RESUME, | ||
626 | &sta->sta, tid, &start_seq_num); | ||
627 | } | ||
628 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
629 | printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid); | ||
630 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
631 | } else { | ||
632 | sta->ampdu_mlme.addba_req_num[tid]++; | ||
633 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); | ||
634 | } | ||
635 | spin_unlock_bh(&sta->lock); | ||
636 | } | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a1a1344c5c4b..c8d969be440b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1176,11 +1176,16 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1176 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1176 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
1177 | } | 1177 | } |
1178 | 1178 | ||
1179 | static int set_mgmt_extra_ie_sta(struct ieee80211_if_sta *ifsta, u8 subtype, | 1179 | static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata, |
1180 | u8 *ies, size_t ies_len) | 1180 | u8 subtype, u8 *ies, size_t ies_len) |
1181 | { | 1181 | { |
1182 | struct ieee80211_local *local = sdata->local; | ||
1183 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1184 | |||
1182 | switch (subtype) { | 1185 | switch (subtype) { |
1183 | case IEEE80211_STYPE_PROBE_REQ >> 4: | 1186 | case IEEE80211_STYPE_PROBE_REQ >> 4: |
1187 | if (local->ops->hw_scan) | ||
1188 | break; | ||
1184 | kfree(ifsta->ie_probereq); | 1189 | kfree(ifsta->ie_probereq); |
1185 | ifsta->ie_probereq = ies; | 1190 | ifsta->ie_probereq = ies; |
1186 | ifsta->ie_probereq_len = ies_len; | 1191 | ifsta->ie_probereq_len = ies_len; |
@@ -1244,7 +1249,7 @@ static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy, | |||
1244 | switch (sdata->vif.type) { | 1249 | switch (sdata->vif.type) { |
1245 | case NL80211_IFTYPE_STATION: | 1250 | case NL80211_IFTYPE_STATION: |
1246 | case NL80211_IFTYPE_ADHOC: | 1251 | case NL80211_IFTYPE_ADHOC: |
1247 | ret = set_mgmt_extra_ie_sta(&sdata->u.sta, params->subtype, | 1252 | ret = set_mgmt_extra_ie_sta(sdata, params->subtype, |
1248 | ies, ies_len); | 1253 | ies, ies_len); |
1249 | break; | 1254 | break; |
1250 | default: | 1255 | default: |
@@ -1272,6 +1277,25 @@ static int ieee80211_resume(struct wiphy *wiphy) | |||
1272 | #define ieee80211_resume NULL | 1277 | #define ieee80211_resume NULL |
1273 | #endif | 1278 | #endif |
1274 | 1279 | ||
1280 | static int ieee80211_scan(struct wiphy *wiphy, | ||
1281 | struct net_device *dev, | ||
1282 | struct cfg80211_scan_request *req) | ||
1283 | { | ||
1284 | struct ieee80211_sub_if_data *sdata; | ||
1285 | |||
1286 | if (!netif_running(dev)) | ||
1287 | return -ENETDOWN; | ||
1288 | |||
1289 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1290 | |||
1291 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
1292 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | ||
1293 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
1294 | return -EOPNOTSUPP; | ||
1295 | |||
1296 | return ieee80211_request_scan(sdata, req); | ||
1297 | } | ||
1298 | |||
1275 | struct cfg80211_ops mac80211_config_ops = { | 1299 | struct cfg80211_ops mac80211_config_ops = { |
1276 | .add_virtual_intf = ieee80211_add_iface, | 1300 | .add_virtual_intf = ieee80211_add_iface, |
1277 | .del_virtual_intf = ieee80211_del_iface, | 1301 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1304,4 +1328,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1304 | .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie, | 1328 | .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie, |
1305 | .suspend = ieee80211_suspend, | 1329 | .suspend = ieee80211_suspend, |
1306 | .resume = ieee80211_resume, | 1330 | .resume = ieee80211_resume, |
1331 | .scan = ieee80211_scan, | ||
1307 | }; | 1332 | }; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 7a38d2e76ca9..82ea0b63a386 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -17,8 +17,6 @@ | |||
17 | #include <net/wireless.h> | 17 | #include <net/wireless.h> |
18 | #include <net/mac80211.h> | 18 | #include <net/mac80211.h> |
19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
20 | #include "sta_info.h" | ||
21 | #include "wme.h" | ||
22 | 20 | ||
23 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 21 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, |
24 | struct ieee80211_ht_cap *ht_cap_ie, | 22 | struct ieee80211_ht_cap *ht_cap_ie, |
@@ -155,105 +153,20 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
155 | return changed; | 153 | return changed; |
156 | } | 154 | } |
157 | 155 | ||
158 | static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | 156 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta) |
159 | const u8 *da, u16 tid, | ||
160 | u8 dialog_token, u16 start_seq_num, | ||
161 | u16 agg_size, u16 timeout) | ||
162 | { | 157 | { |
163 | struct ieee80211_local *local = sdata->local; | 158 | int i; |
164 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
165 | struct sk_buff *skb; | ||
166 | struct ieee80211_mgmt *mgmt; | ||
167 | u16 capab; | ||
168 | |||
169 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
170 | |||
171 | if (!skb) { | ||
172 | printk(KERN_ERR "%s: failed to allocate buffer " | ||
173 | "for addba request frame\n", sdata->dev->name); | ||
174 | return; | ||
175 | } | ||
176 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
177 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
178 | memset(mgmt, 0, 24); | ||
179 | memcpy(mgmt->da, da, ETH_ALEN); | ||
180 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
181 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
182 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
183 | else | ||
184 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
185 | |||
186 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
187 | IEEE80211_STYPE_ACTION); | ||
188 | |||
189 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); | ||
190 | |||
191 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
192 | mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; | ||
193 | |||
194 | mgmt->u.action.u.addba_req.dialog_token = dialog_token; | ||
195 | capab = (u16)(1 << 1); /* bit 1 aggregation policy */ | ||
196 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
197 | capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ | ||
198 | |||
199 | mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); | ||
200 | |||
201 | mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); | ||
202 | mgmt->u.action.u.addba_req.start_seq_num = | ||
203 | cpu_to_le16(start_seq_num << 4); | ||
204 | |||
205 | ieee80211_tx_skb(sdata, skb, 1); | ||
206 | } | ||
207 | |||
208 | static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, | ||
209 | u8 dialog_token, u16 status, u16 policy, | ||
210 | u16 buf_size, u16 timeout) | ||
211 | { | ||
212 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
213 | struct ieee80211_local *local = sdata->local; | ||
214 | struct sk_buff *skb; | ||
215 | struct ieee80211_mgmt *mgmt; | ||
216 | u16 capab; | ||
217 | |||
218 | skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); | ||
219 | 159 | ||
220 | if (!skb) { | 160 | for (i = 0; i < STA_TID_NUM; i++) { |
221 | printk(KERN_DEBUG "%s: failed to allocate buffer " | 161 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR); |
222 | "for addba resp frame\n", sdata->dev->name); | 162 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, |
223 | return; | 163 | WLAN_REASON_QSTA_LEAVE_QBSS); |
224 | } | 164 | } |
225 | |||
226 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
227 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
228 | memset(mgmt, 0, 24); | ||
229 | memcpy(mgmt->da, da, ETH_ALEN); | ||
230 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
231 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
232 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
233 | else | ||
234 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
235 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
236 | IEEE80211_STYPE_ACTION); | ||
237 | |||
238 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); | ||
239 | mgmt->u.action.category = WLAN_CATEGORY_BACK; | ||
240 | mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; | ||
241 | mgmt->u.action.u.addba_resp.dialog_token = dialog_token; | ||
242 | |||
243 | capab = (u16)(policy << 1); /* bit 1 aggregation policy */ | ||
244 | capab |= (u16)(tid << 2); /* bit 5:2 TID number */ | ||
245 | capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ | ||
246 | |||
247 | mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); | ||
248 | mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); | ||
249 | mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); | ||
250 | |||
251 | ieee80211_tx_skb(sdata, skb, 1); | ||
252 | } | 165 | } |
253 | 166 | ||
254 | static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 167 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
255 | const u8 *da, u16 tid, | 168 | const u8 *da, u16 tid, |
256 | u16 initiator, u16 reason_code) | 169 | u16 initiator, u16 reason_code) |
257 | { | 170 | { |
258 | struct ieee80211_local *local = sdata->local; | 171 | struct ieee80211_local *local = sdata->local; |
259 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 172 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
@@ -274,7 +187,8 @@ static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
274 | memset(mgmt, 0, 24); | 187 | memset(mgmt, 0, 24); |
275 | memcpy(mgmt->da, da, ETH_ALEN); | 188 | memcpy(mgmt->da, da, ETH_ALEN); |
276 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 189 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
277 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 190 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
191 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
278 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 192 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
279 | else | 193 | else |
280 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 194 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
@@ -294,767 +208,6 @@ static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
294 | ieee80211_tx_skb(sdata, skb, 1); | 208 | ieee80211_tx_skb(sdata, skb, 1); |
295 | } | 209 | } |
296 | 210 | ||
297 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn) | ||
298 | { | ||
299 | struct ieee80211_local *local = sdata->local; | ||
300 | struct sk_buff *skb; | ||
301 | struct ieee80211_bar *bar; | ||
302 | u16 bar_control = 0; | ||
303 | |||
304 | skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom); | ||
305 | if (!skb) { | ||
306 | printk(KERN_ERR "%s: failed to allocate buffer for " | ||
307 | "bar frame\n", sdata->dev->name); | ||
308 | return; | ||
309 | } | ||
310 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
311 | bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar)); | ||
312 | memset(bar, 0, sizeof(*bar)); | ||
313 | bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
314 | IEEE80211_STYPE_BACK_REQ); | ||
315 | memcpy(bar->ra, ra, ETH_ALEN); | ||
316 | memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN); | ||
317 | bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL; | ||
318 | bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA; | ||
319 | bar_control |= (u16)(tid << 12); | ||
320 | bar->control = cpu_to_le16(bar_control); | ||
321 | bar->start_seq_num = cpu_to_le16(ssn); | ||
322 | |||
323 | ieee80211_tx_skb(sdata, skb, 0); | ||
324 | } | ||
325 | |||
326 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, | ||
327 | u16 initiator, u16 reason) | ||
328 | { | ||
329 | struct ieee80211_local *local = sdata->local; | ||
330 | struct ieee80211_hw *hw = &local->hw; | ||
331 | struct sta_info *sta; | ||
332 | int ret, i; | ||
333 | |||
334 | rcu_read_lock(); | ||
335 | |||
336 | sta = sta_info_get(local, ra); | ||
337 | if (!sta) { | ||
338 | rcu_read_unlock(); | ||
339 | return; | ||
340 | } | ||
341 | |||
342 | /* check if TID is in operational state */ | ||
343 | spin_lock_bh(&sta->lock); | ||
344 | if (sta->ampdu_mlme.tid_state_rx[tid] | ||
345 | != HT_AGG_STATE_OPERATIONAL) { | ||
346 | spin_unlock_bh(&sta->lock); | ||
347 | rcu_read_unlock(); | ||
348 | return; | ||
349 | } | ||
350 | sta->ampdu_mlme.tid_state_rx[tid] = | ||
351 | HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
352 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
353 | spin_unlock_bh(&sta->lock); | ||
354 | |||
355 | /* stop HW Rx aggregation. ampdu_action existence | ||
356 | * already verified in session init so we add the BUG_ON */ | ||
357 | BUG_ON(!local->ops->ampdu_action); | ||
358 | |||
359 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
360 | printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", | ||
361 | ra, tid); | ||
362 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
363 | |||
364 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, | ||
365 | &sta->sta, tid, NULL); | ||
366 | if (ret) | ||
367 | printk(KERN_DEBUG "HW problem - can not stop rx " | ||
368 | "aggregation for tid %d\n", tid); | ||
369 | |||
370 | /* shutdown timer has not expired */ | ||
371 | if (initiator != WLAN_BACK_TIMER) | ||
372 | del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
373 | |||
374 | /* check if this is a self generated aggregation halt */ | ||
375 | if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) | ||
376 | ieee80211_send_delba(sdata, ra, tid, 0, reason); | ||
377 | |||
378 | /* free the reordering buffer */ | ||
379 | for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { | ||
380 | if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { | ||
381 | /* release the reordered frames */ | ||
382 | dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); | ||
383 | sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; | ||
384 | sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; | ||
385 | } | ||
386 | } | ||
387 | /* free resources */ | ||
388 | kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); | ||
389 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
390 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
391 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; | ||
392 | |||
393 | rcu_read_unlock(); | ||
394 | } | ||
395 | |||
396 | |||
397 | /* | ||
398 | * After sending add Block Ack request we activated a timer until | ||
399 | * add Block Ack response will arrive from the recipient. | ||
400 | * If this timer expires sta_addba_resp_timer_expired will be executed. | ||
401 | */ | ||
402 | static void sta_addba_resp_timer_expired(unsigned long data) | ||
403 | { | ||
404 | /* not an elegant detour, but there is no choice as the timer passes | ||
405 | * only one argument, and both sta_info and TID are needed, so init | ||
406 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
407 | * array gives the sta through container_of */ | ||
408 | u16 tid = *(u8 *)data; | ||
409 | struct sta_info *temp_sta = container_of((void *)data, | ||
410 | struct sta_info, timer_to_tid[tid]); | ||
411 | |||
412 | struct ieee80211_local *local = temp_sta->local; | ||
413 | struct ieee80211_hw *hw = &local->hw; | ||
414 | struct sta_info *sta; | ||
415 | u8 *state; | ||
416 | |||
417 | rcu_read_lock(); | ||
418 | |||
419 | sta = sta_info_get(local, temp_sta->sta.addr); | ||
420 | if (!sta) { | ||
421 | rcu_read_unlock(); | ||
422 | return; | ||
423 | } | ||
424 | |||
425 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
426 | /* check if the TID waits for addBA response */ | ||
427 | spin_lock_bh(&sta->lock); | ||
428 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
429 | spin_unlock_bh(&sta->lock); | ||
430 | *state = HT_AGG_STATE_IDLE; | ||
431 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
432 | printk(KERN_DEBUG "timer expired on tid %d but we are not " | ||
433 | "expecting addBA response there", tid); | ||
434 | #endif | ||
435 | goto timer_expired_exit; | ||
436 | } | ||
437 | |||
438 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
439 | printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); | ||
440 | #endif | ||
441 | |||
442 | /* go through the state check in stop_BA_session */ | ||
443 | *state = HT_AGG_STATE_OPERATIONAL; | ||
444 | spin_unlock_bh(&sta->lock); | ||
445 | ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid, | ||
446 | WLAN_BACK_INITIATOR); | ||
447 | |||
448 | timer_expired_exit: | ||
449 | rcu_read_unlock(); | ||
450 | } | ||
451 | |||
452 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr) | ||
453 | { | ||
454 | struct ieee80211_local *local = sdata->local; | ||
455 | int i; | ||
456 | |||
457 | for (i = 0; i < STA_TID_NUM; i++) { | ||
458 | ieee80211_stop_tx_ba_session(&local->hw, addr, i, | ||
459 | WLAN_BACK_INITIATOR); | ||
460 | ieee80211_sta_stop_rx_ba_session(sdata, addr, i, | ||
461 | WLAN_BACK_RECIPIENT, | ||
462 | WLAN_REASON_QSTA_LEAVE_QBSS); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
467 | { | ||
468 | struct ieee80211_local *local = hw_to_local(hw); | ||
469 | struct sta_info *sta; | ||
470 | struct ieee80211_sub_if_data *sdata; | ||
471 | u16 start_seq_num; | ||
472 | u8 *state; | ||
473 | int ret = 0; | ||
474 | |||
475 | if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | ||
476 | return -EINVAL; | ||
477 | |||
478 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
479 | printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", | ||
480 | ra, tid); | ||
481 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
482 | |||
483 | rcu_read_lock(); | ||
484 | |||
485 | sta = sta_info_get(local, ra); | ||
486 | if (!sta) { | ||
487 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
488 | printk(KERN_DEBUG "Could not find the station\n"); | ||
489 | #endif | ||
490 | ret = -ENOENT; | ||
491 | goto exit; | ||
492 | } | ||
493 | |||
494 | spin_lock_bh(&sta->lock); | ||
495 | |||
496 | /* we have tried too many times, receiver does not want A-MPDU */ | ||
497 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { | ||
498 | ret = -EBUSY; | ||
499 | goto err_unlock_sta; | ||
500 | } | ||
501 | |||
502 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
503 | /* check if the TID is not in aggregation flow already */ | ||
504 | if (*state != HT_AGG_STATE_IDLE) { | ||
505 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
506 | printk(KERN_DEBUG "BA request denied - session is not " | ||
507 | "idle on tid %u\n", tid); | ||
508 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
509 | ret = -EAGAIN; | ||
510 | goto err_unlock_sta; | ||
511 | } | ||
512 | |||
513 | /* prepare A-MPDU MLME for Tx aggregation */ | ||
514 | sta->ampdu_mlme.tid_tx[tid] = | ||
515 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | ||
516 | if (!sta->ampdu_mlme.tid_tx[tid]) { | ||
517 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
518 | if (net_ratelimit()) | ||
519 | printk(KERN_ERR "allocate tx mlme to tid %d failed\n", | ||
520 | tid); | ||
521 | #endif | ||
522 | ret = -ENOMEM; | ||
523 | goto err_unlock_sta; | ||
524 | } | ||
525 | /* Tx timer */ | ||
526 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | ||
527 | sta_addba_resp_timer_expired; | ||
528 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = | ||
529 | (unsigned long)&sta->timer_to_tid[tid]; | ||
530 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
531 | |||
532 | if (hw->ampdu_queues) { | ||
533 | /* create a new queue for this aggregation */ | ||
534 | ret = ieee80211_ht_agg_queue_add(local, sta, tid); | ||
535 | |||
536 | /* case no queue is available to aggregation | ||
537 | * don't switch to aggregation */ | ||
538 | if (ret) { | ||
539 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
540 | printk(KERN_DEBUG "BA request denied - " | ||
541 | "queue unavailable for tid %d\n", tid); | ||
542 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
543 | goto err_unlock_queue; | ||
544 | } | ||
545 | } | ||
546 | sdata = sta->sdata; | ||
547 | |||
548 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | ||
549 | * call back right away, it must see that the flow has begun */ | ||
550 | *state |= HT_ADDBA_REQUESTED_MSK; | ||
551 | |||
552 | /* This is slightly racy because the queue isn't stopped */ | ||
553 | start_seq_num = sta->tid_seq[tid]; | ||
554 | |||
555 | if (local->ops->ampdu_action) | ||
556 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, | ||
557 | &sta->sta, tid, &start_seq_num); | ||
558 | |||
559 | if (ret) { | ||
560 | /* No need to requeue the packets in the agg queue, since we | ||
561 | * held the tx lock: no packet could be enqueued to the newly | ||
562 | * allocated queue */ | ||
563 | if (hw->ampdu_queues) | ||
564 | ieee80211_ht_agg_queue_remove(local, sta, tid, 0); | ||
565 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
566 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | ||
567 | " tid %d\n", tid); | ||
568 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
569 | *state = HT_AGG_STATE_IDLE; | ||
570 | goto err_unlock_queue; | ||
571 | } | ||
572 | |||
573 | /* Will put all the packets in the new SW queue */ | ||
574 | if (hw->ampdu_queues) | ||
575 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); | ||
576 | spin_unlock_bh(&sta->lock); | ||
577 | |||
578 | /* send an addBA request */ | ||
579 | sta->ampdu_mlme.dialog_token_allocator++; | ||
580 | sta->ampdu_mlme.tid_tx[tid]->dialog_token = | ||
581 | sta->ampdu_mlme.dialog_token_allocator; | ||
582 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | ||
583 | |||
584 | |||
585 | ieee80211_send_addba_request(sta->sdata, ra, tid, | ||
586 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | ||
587 | sta->ampdu_mlme.tid_tx[tid]->ssn, | ||
588 | 0x40, 5000); | ||
589 | /* activate the timer for the recipient's addBA response */ | ||
590 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = | ||
591 | jiffies + ADDBA_RESP_INTERVAL; | ||
592 | add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
593 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
594 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | ||
595 | #endif | ||
596 | goto exit; | ||
597 | |||
598 | err_unlock_queue: | ||
599 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
600 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
601 | ret = -EBUSY; | ||
602 | err_unlock_sta: | ||
603 | spin_unlock_bh(&sta->lock); | ||
604 | exit: | ||
605 | rcu_read_unlock(); | ||
606 | return ret; | ||
607 | } | ||
608 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | ||
609 | |||
610 | int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | ||
611 | u8 *ra, u16 tid, | ||
612 | enum ieee80211_back_parties initiator) | ||
613 | { | ||
614 | struct ieee80211_local *local = hw_to_local(hw); | ||
615 | struct sta_info *sta; | ||
616 | u8 *state; | ||
617 | int ret = 0; | ||
618 | |||
619 | if (tid >= STA_TID_NUM) | ||
620 | return -EINVAL; | ||
621 | |||
622 | rcu_read_lock(); | ||
623 | sta = sta_info_get(local, ra); | ||
624 | if (!sta) { | ||
625 | rcu_read_unlock(); | ||
626 | return -ENOENT; | ||
627 | } | ||
628 | |||
629 | /* check if the TID is in aggregation */ | ||
630 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
631 | spin_lock_bh(&sta->lock); | ||
632 | |||
633 | if (*state != HT_AGG_STATE_OPERATIONAL) { | ||
634 | ret = -ENOENT; | ||
635 | goto stop_BA_exit; | ||
636 | } | ||
637 | |||
638 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
639 | printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", | ||
640 | ra, tid); | ||
641 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
642 | |||
643 | if (hw->ampdu_queues) | ||
644 | ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); | ||
645 | |||
646 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | ||
647 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | ||
648 | |||
649 | if (local->ops->ampdu_action) | ||
650 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, | ||
651 | &sta->sta, tid, NULL); | ||
652 | |||
653 | /* case HW denied going back to legacy */ | ||
654 | if (ret) { | ||
655 | WARN_ON(ret != -EBUSY); | ||
656 | *state = HT_AGG_STATE_OPERATIONAL; | ||
657 | if (hw->ampdu_queues) | ||
658 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
659 | goto stop_BA_exit; | ||
660 | } | ||
661 | |||
662 | stop_BA_exit: | ||
663 | spin_unlock_bh(&sta->lock); | ||
664 | rcu_read_unlock(); | ||
665 | return ret; | ||
666 | } | ||
667 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | ||
668 | |||
669 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | ||
670 | { | ||
671 | struct ieee80211_local *local = hw_to_local(hw); | ||
672 | struct sta_info *sta; | ||
673 | u8 *state; | ||
674 | |||
675 | if (tid >= STA_TID_NUM) { | ||
676 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
677 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
678 | tid, STA_TID_NUM); | ||
679 | #endif | ||
680 | return; | ||
681 | } | ||
682 | |||
683 | rcu_read_lock(); | ||
684 | sta = sta_info_get(local, ra); | ||
685 | if (!sta) { | ||
686 | rcu_read_unlock(); | ||
687 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
688 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | ||
689 | #endif | ||
690 | return; | ||
691 | } | ||
692 | |||
693 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
694 | spin_lock_bh(&sta->lock); | ||
695 | |||
696 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
697 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
698 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | ||
699 | *state); | ||
700 | #endif | ||
701 | spin_unlock_bh(&sta->lock); | ||
702 | rcu_read_unlock(); | ||
703 | return; | ||
704 | } | ||
705 | |||
706 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); | ||
707 | |||
708 | *state |= HT_ADDBA_DRV_READY_MSK; | ||
709 | |||
710 | if (*state == HT_AGG_STATE_OPERATIONAL) { | ||
711 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
712 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | ||
713 | #endif | ||
714 | if (hw->ampdu_queues) | ||
715 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
716 | } | ||
717 | spin_unlock_bh(&sta->lock); | ||
718 | rcu_read_unlock(); | ||
719 | } | ||
720 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | ||
721 | |||
722 | void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | ||
723 | { | ||
724 | struct ieee80211_local *local = hw_to_local(hw); | ||
725 | struct sta_info *sta; | ||
726 | u8 *state; | ||
727 | int agg_queue; | ||
728 | |||
729 | if (tid >= STA_TID_NUM) { | ||
730 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
731 | printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", | ||
732 | tid, STA_TID_NUM); | ||
733 | #endif | ||
734 | return; | ||
735 | } | ||
736 | |||
737 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
738 | printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n", | ||
739 | ra, tid); | ||
740 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
741 | |||
742 | rcu_read_lock(); | ||
743 | sta = sta_info_get(local, ra); | ||
744 | if (!sta) { | ||
745 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
746 | printk(KERN_DEBUG "Could not find station: %pM\n", ra); | ||
747 | #endif | ||
748 | rcu_read_unlock(); | ||
749 | return; | ||
750 | } | ||
751 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
752 | |||
753 | /* NOTE: no need to use sta->lock in this state check, as | ||
754 | * ieee80211_stop_tx_ba_session will let only one stop call to | ||
755 | * pass through per sta/tid | ||
756 | */ | ||
757 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | ||
758 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
759 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | ||
760 | #endif | ||
761 | rcu_read_unlock(); | ||
762 | return; | ||
763 | } | ||
764 | |||
765 | if (*state & HT_AGG_STATE_INITIATOR_MSK) | ||
766 | ieee80211_send_delba(sta->sdata, ra, tid, | ||
767 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | ||
768 | |||
769 | if (hw->ampdu_queues) { | ||
770 | agg_queue = sta->tid_to_tx_q[tid]; | ||
771 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); | ||
772 | |||
773 | /* We just requeued the all the frames that were in the | ||
774 | * removed queue, and since we might miss a softirq we do | ||
775 | * netif_schedule_queue. ieee80211_wake_queue is not used | ||
776 | * here as this queue is not necessarily stopped | ||
777 | */ | ||
778 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, | ||
779 | agg_queue)); | ||
780 | } | ||
781 | spin_lock_bh(&sta->lock); | ||
782 | *state = HT_AGG_STATE_IDLE; | ||
783 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
784 | kfree(sta->ampdu_mlme.tid_tx[tid]); | ||
785 | sta->ampdu_mlme.tid_tx[tid] = NULL; | ||
786 | spin_unlock_bh(&sta->lock); | ||
787 | |||
788 | rcu_read_unlock(); | ||
789 | } | ||
790 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | ||
791 | |||
792 | void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
793 | const u8 *ra, u16 tid) | ||
794 | { | ||
795 | struct ieee80211_local *local = hw_to_local(hw); | ||
796 | struct ieee80211_ra_tid *ra_tid; | ||
797 | struct sk_buff *skb = dev_alloc_skb(0); | ||
798 | |||
799 | if (unlikely(!skb)) { | ||
800 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
801 | if (net_ratelimit()) | ||
802 | printk(KERN_WARNING "%s: Not enough memory, " | ||
803 | "dropping start BA session", skb->dev->name); | ||
804 | #endif | ||
805 | return; | ||
806 | } | ||
807 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
808 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
809 | ra_tid->tid = tid; | ||
810 | |||
811 | skb->pkt_type = IEEE80211_ADDBA_MSG; | ||
812 | skb_queue_tail(&local->skb_queue, skb); | ||
813 | tasklet_schedule(&local->tasklet); | ||
814 | } | ||
815 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); | ||
816 | |||
817 | void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, | ||
818 | const u8 *ra, u16 tid) | ||
819 | { | ||
820 | struct ieee80211_local *local = hw_to_local(hw); | ||
821 | struct ieee80211_ra_tid *ra_tid; | ||
822 | struct sk_buff *skb = dev_alloc_skb(0); | ||
823 | |||
824 | if (unlikely(!skb)) { | ||
825 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
826 | if (net_ratelimit()) | ||
827 | printk(KERN_WARNING "%s: Not enough memory, " | ||
828 | "dropping stop BA session", skb->dev->name); | ||
829 | #endif | ||
830 | return; | ||
831 | } | ||
832 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
833 | memcpy(&ra_tid->ra, ra, ETH_ALEN); | ||
834 | ra_tid->tid = tid; | ||
835 | |||
836 | skb->pkt_type = IEEE80211_DELBA_MSG; | ||
837 | skb_queue_tail(&local->skb_queue, skb); | ||
838 | tasklet_schedule(&local->tasklet); | ||
839 | } | ||
840 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); | ||
841 | |||
842 | /* | ||
843 | * After accepting the AddBA Request we activated a timer, | ||
844 | * resetting it after each frame that arrives from the originator. | ||
845 | * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. | ||
846 | */ | ||
847 | static void sta_rx_agg_session_timer_expired(unsigned long data) | ||
848 | { | ||
849 | /* not an elegant detour, but there is no choice as the timer passes | ||
850 | * only one argument, and various sta_info are needed here, so init | ||
851 | * flow in sta_info_create gives the TID as data, while the timer_to_id | ||
852 | * array gives the sta through container_of */ | ||
853 | u8 *ptid = (u8 *)data; | ||
854 | u8 *timer_to_id = ptid - *ptid; | ||
855 | struct sta_info *sta = container_of(timer_to_id, struct sta_info, | ||
856 | timer_to_tid[0]); | ||
857 | |||
858 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
859 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | ||
860 | #endif | ||
861 | ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, | ||
862 | (u16)*ptid, WLAN_BACK_TIMER, | ||
863 | WLAN_REASON_QSTA_TIMEOUT); | ||
864 | } | ||
865 | |||
866 | void ieee80211_process_addba_request(struct ieee80211_local *local, | ||
867 | struct sta_info *sta, | ||
868 | struct ieee80211_mgmt *mgmt, | ||
869 | size_t len) | ||
870 | { | ||
871 | struct ieee80211_hw *hw = &local->hw; | ||
872 | struct ieee80211_conf *conf = &hw->conf; | ||
873 | struct tid_ampdu_rx *tid_agg_rx; | ||
874 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; | ||
875 | u8 dialog_token; | ||
876 | int ret = -EOPNOTSUPP; | ||
877 | |||
878 | /* extract session parameters from addba request frame */ | ||
879 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | ||
880 | timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); | ||
881 | start_seq_num = | ||
882 | le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; | ||
883 | |||
884 | capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); | ||
885 | ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; | ||
886 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
887 | buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||
888 | |||
889 | status = WLAN_STATUS_REQUEST_DECLINED; | ||
890 | |||
891 | /* sanity check for incoming parameters: | ||
892 | * check if configuration can support the BA policy | ||
893 | * and if buffer size does not exceeds max value */ | ||
894 | /* XXX: check own ht delayed BA capability?? */ | ||
895 | if (((ba_policy != 1) | ||
896 | && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) | ||
897 | || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { | ||
898 | status = WLAN_STATUS_INVALID_QOS_PARAM; | ||
899 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
900 | if (net_ratelimit()) | ||
901 | printk(KERN_DEBUG "AddBA Req with bad params from " | ||
902 | "%pM on tid %u. policy %d, buffer size %d\n", | ||
903 | mgmt->sa, tid, ba_policy, | ||
904 | buf_size); | ||
905 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
906 | goto end_no_lock; | ||
907 | } | ||
908 | /* determine default buffer size */ | ||
909 | if (buf_size == 0) { | ||
910 | struct ieee80211_supported_band *sband; | ||
911 | |||
912 | sband = local->hw.wiphy->bands[conf->channel->band]; | ||
913 | buf_size = IEEE80211_MIN_AMPDU_BUF; | ||
914 | buf_size = buf_size << sband->ht_cap.ampdu_factor; | ||
915 | } | ||
916 | |||
917 | |||
918 | /* examine state machine */ | ||
919 | spin_lock_bh(&sta->lock); | ||
920 | |||
921 | if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { | ||
922 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
923 | if (net_ratelimit()) | ||
924 | printk(KERN_DEBUG "unexpected AddBA Req from " | ||
925 | "%pM on tid %u\n", | ||
926 | mgmt->sa, tid); | ||
927 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
928 | goto end; | ||
929 | } | ||
930 | |||
931 | /* prepare A-MPDU MLME for Rx aggregation */ | ||
932 | sta->ampdu_mlme.tid_rx[tid] = | ||
933 | kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); | ||
934 | if (!sta->ampdu_mlme.tid_rx[tid]) { | ||
935 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
936 | if (net_ratelimit()) | ||
937 | printk(KERN_ERR "allocate rx mlme to tid %d failed\n", | ||
938 | tid); | ||
939 | #endif | ||
940 | goto end; | ||
941 | } | ||
942 | /* rx timer */ | ||
943 | sta->ampdu_mlme.tid_rx[tid]->session_timer.function = | ||
944 | sta_rx_agg_session_timer_expired; | ||
945 | sta->ampdu_mlme.tid_rx[tid]->session_timer.data = | ||
946 | (unsigned long)&sta->timer_to_tid[tid]; | ||
947 | init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); | ||
948 | |||
949 | tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; | ||
950 | |||
951 | /* prepare reordering buffer */ | ||
952 | tid_agg_rx->reorder_buf = | ||
953 | kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); | ||
954 | if (!tid_agg_rx->reorder_buf) { | ||
955 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
956 | if (net_ratelimit()) | ||
957 | printk(KERN_ERR "can not allocate reordering buffer " | ||
958 | "to tid %d\n", tid); | ||
959 | #endif | ||
960 | kfree(sta->ampdu_mlme.tid_rx[tid]); | ||
961 | goto end; | ||
962 | } | ||
963 | |||
964 | if (local->ops->ampdu_action) | ||
965 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, | ||
966 | &sta->sta, tid, &start_seq_num); | ||
967 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
968 | printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); | ||
969 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
970 | |||
971 | if (ret) { | ||
972 | kfree(tid_agg_rx->reorder_buf); | ||
973 | kfree(tid_agg_rx); | ||
974 | sta->ampdu_mlme.tid_rx[tid] = NULL; | ||
975 | goto end; | ||
976 | } | ||
977 | |||
978 | /* change state and send addba resp */ | ||
979 | sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; | ||
980 | tid_agg_rx->dialog_token = dialog_token; | ||
981 | tid_agg_rx->ssn = start_seq_num; | ||
982 | tid_agg_rx->head_seq_num = start_seq_num; | ||
983 | tid_agg_rx->buf_size = buf_size; | ||
984 | tid_agg_rx->timeout = timeout; | ||
985 | tid_agg_rx->stored_mpdu_num = 0; | ||
986 | status = WLAN_STATUS_SUCCESS; | ||
987 | end: | ||
988 | spin_unlock_bh(&sta->lock); | ||
989 | |||
990 | end_no_lock: | ||
991 | ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, | ||
992 | dialog_token, status, 1, buf_size, timeout); | ||
993 | } | ||
994 | |||
995 | void ieee80211_process_addba_resp(struct ieee80211_local *local, | ||
996 | struct sta_info *sta, | ||
997 | struct ieee80211_mgmt *mgmt, | ||
998 | size_t len) | ||
999 | { | ||
1000 | struct ieee80211_hw *hw = &local->hw; | ||
1001 | u16 capab; | ||
1002 | u16 tid, start_seq_num; | ||
1003 | u8 *state; | ||
1004 | |||
1005 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | ||
1006 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | ||
1007 | |||
1008 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | ||
1009 | |||
1010 | spin_lock_bh(&sta->lock); | ||
1011 | |||
1012 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | ||
1013 | spin_unlock_bh(&sta->lock); | ||
1014 | return; | ||
1015 | } | ||
1016 | |||
1017 | if (mgmt->u.action.u.addba_resp.dialog_token != | ||
1018 | sta->ampdu_mlme.tid_tx[tid]->dialog_token) { | ||
1019 | spin_unlock_bh(&sta->lock); | ||
1020 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1021 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); | ||
1022 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1023 | return; | ||
1024 | } | ||
1025 | |||
1026 | del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | ||
1027 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1028 | printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); | ||
1029 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1030 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) | ||
1031 | == WLAN_STATUS_SUCCESS) { | ||
1032 | *state |= HT_ADDBA_RECEIVED_MSK; | ||
1033 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
1034 | |||
1035 | if (*state == HT_AGG_STATE_OPERATIONAL && | ||
1036 | local->hw.ampdu_queues) | ||
1037 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | ||
1038 | |||
1039 | if (local->ops->ampdu_action) { | ||
1040 | (void)local->ops->ampdu_action(hw, | ||
1041 | IEEE80211_AMPDU_TX_RESUME, | ||
1042 | &sta->sta, tid, &start_seq_num); | ||
1043 | } | ||
1044 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
1045 | printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid); | ||
1046 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
1047 | spin_unlock_bh(&sta->lock); | ||
1048 | } else { | ||
1049 | sta->ampdu_mlme.addba_req_num[tid]++; | ||
1050 | /* this will allow the state check in stop_BA_session */ | ||
1051 | *state = HT_AGG_STATE_OPERATIONAL; | ||
1052 | spin_unlock_bh(&sta->lock); | ||
1053 | ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid, | ||
1054 | WLAN_BACK_INITIATOR); | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1058 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 211 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
1059 | struct sta_info *sta, | 212 | struct sta_info *sta, |
1060 | struct ieee80211_mgmt *mgmt, size_t len) | 213 | struct ieee80211_mgmt *mgmt, size_t len) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index eaf3603862b7..2cb743ed9f9c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -57,6 +57,8 @@ struct ieee80211_local; | |||
57 | */ | 57 | */ |
58 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) | 58 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) |
59 | 59 | ||
60 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) | ||
61 | |||
60 | struct ieee80211_fragment_entry { | 62 | struct ieee80211_fragment_entry { |
61 | unsigned long first_frag_time; | 63 | unsigned long first_frag_time; |
62 | unsigned int seq; | 64 | unsigned int seq; |
@@ -70,43 +72,36 @@ struct ieee80211_fragment_entry { | |||
70 | 72 | ||
71 | 73 | ||
72 | struct ieee80211_bss { | 74 | struct ieee80211_bss { |
73 | struct list_head list; | 75 | /* Yes, this is a hack */ |
74 | struct ieee80211_bss *hnext; | 76 | struct cfg80211_bss cbss; |
75 | size_t ssid_len; | ||
76 | 77 | ||
77 | atomic_t users; | 78 | /* don't want to look up all the time */ |
78 | 79 | size_t ssid_len; | |
79 | u8 bssid[ETH_ALEN]; | ||
80 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 80 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
81 | |||
81 | u8 dtim_period; | 82 | u8 dtim_period; |
82 | u16 capability; /* host byte order */ | 83 | |
83 | enum ieee80211_band band; | ||
84 | int freq; | ||
85 | int signal, noise, qual; | ||
86 | u8 *ies; /* all information elements from the last Beacon or Probe | ||
87 | * Response frames; note Beacon frame is not allowed to | ||
88 | * override values from Probe Response */ | ||
89 | size_t ies_len; | ||
90 | bool wmm_used; | 84 | bool wmm_used; |
85 | |||
86 | unsigned long last_probe_resp; | ||
87 | |||
91 | #ifdef CONFIG_MAC80211_MESH | 88 | #ifdef CONFIG_MAC80211_MESH |
92 | u8 *mesh_id; | 89 | u8 *mesh_id; |
93 | size_t mesh_id_len; | 90 | size_t mesh_id_len; |
94 | u8 *mesh_cfg; | 91 | u8 *mesh_cfg; |
95 | #endif | 92 | #endif |
93 | |||
96 | #define IEEE80211_MAX_SUPP_RATES 32 | 94 | #define IEEE80211_MAX_SUPP_RATES 32 |
97 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 95 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
98 | size_t supp_rates_len; | 96 | size_t supp_rates_len; |
99 | u64 timestamp; | ||
100 | int beacon_int; | ||
101 | 97 | ||
102 | unsigned long last_probe_resp; | 98 | /* |
103 | unsigned long last_update; | 99 | * During assocation, we save an ERP value from a probe response so |
104 | |||
105 | /* during assocation, we save an ERP value from a probe response so | ||
106 | * that we can feed ERP info to the driver when handling the | 100 | * that we can feed ERP info to the driver when handling the |
107 | * association completes. these fields probably won't be up-to-date | 101 | * association completes. these fields probably won't be up-to-date |
108 | * otherwise, you probably don't want to use them. */ | 102 | * otherwise, you probably don't want to use them. |
109 | int has_erp_value; | 103 | */ |
104 | bool has_erp_value; | ||
110 | u8 erp_value; | 105 | u8 erp_value; |
111 | }; | 106 | }; |
112 | 107 | ||
@@ -292,8 +287,6 @@ struct ieee80211_if_sta { | |||
292 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 287 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
293 | enum ieee80211_sta_mlme_state state; | 288 | enum ieee80211_sta_mlme_state state; |
294 | size_t ssid_len; | 289 | size_t ssid_len; |
295 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | ||
296 | size_t scan_ssid_len; | ||
297 | u16 aid; | 290 | u16 aid; |
298 | u16 ap_capab, capab; | 291 | u16 ap_capab, capab; |
299 | u8 *extra_ie; /* to be added to the end of AssocReq */ | 292 | u8 *extra_ie; /* to be added to the end of AssocReq */ |
@@ -599,7 +592,6 @@ struct ieee80211_local { | |||
599 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; | 592 | int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; |
600 | unsigned int filter_flags; /* FIF_* */ | 593 | unsigned int filter_flags; /* FIF_* */ |
601 | struct iw_statistics wstats; | 594 | struct iw_statistics wstats; |
602 | u8 wstats_flags; | ||
603 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ | 595 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ |
604 | int tx_headroom; /* required headroom for hardware/radiotap */ | 596 | int tx_headroom; /* required headroom for hardware/radiotap */ |
605 | 597 | ||
@@ -656,20 +648,18 @@ struct ieee80211_local { | |||
656 | 648 | ||
657 | /* Scanning and BSS list */ | 649 | /* Scanning and BSS list */ |
658 | bool sw_scanning, hw_scanning; | 650 | bool sw_scanning, hw_scanning; |
651 | struct cfg80211_ssid scan_ssid; | ||
652 | struct cfg80211_scan_request int_scan_req; | ||
653 | struct cfg80211_scan_request *scan_req; | ||
654 | struct ieee80211_channel *scan_channel; | ||
659 | int scan_channel_idx; | 655 | int scan_channel_idx; |
660 | enum ieee80211_band scan_band; | ||
661 | 656 | ||
662 | enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; | 657 | enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; |
663 | unsigned long last_scan_completed; | 658 | unsigned long last_scan_completed; |
664 | struct delayed_work scan_work; | 659 | struct delayed_work scan_work; |
665 | struct ieee80211_sub_if_data *scan_sdata; | 660 | struct ieee80211_sub_if_data *scan_sdata; |
666 | struct ieee80211_channel *oper_channel, *scan_channel, *csa_channel; | ||
667 | enum nl80211_channel_type oper_channel_type; | 661 | enum nl80211_channel_type oper_channel_type; |
668 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 662 | struct ieee80211_channel *oper_channel, *csa_channel; |
669 | size_t scan_ssid_len; | ||
670 | struct list_head bss_list; | ||
671 | struct ieee80211_bss *bss_hash[STA_HASH_SIZE]; | ||
672 | spinlock_t bss_lock; | ||
673 | 663 | ||
674 | /* SNMP counters */ | 664 | /* SNMP counters */ |
675 | /* dot11CountersTable */ | 665 | /* dot11CountersTable */ |
@@ -728,6 +718,7 @@ struct ieee80211_local { | |||
728 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ | 718 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ |
729 | 719 | ||
730 | bool powersave; | 720 | bool powersave; |
721 | bool pspolling; | ||
731 | struct work_struct dynamic_ps_enable_work; | 722 | struct work_struct dynamic_ps_enable_work; |
732 | struct work_struct dynamic_ps_disable_work; | 723 | struct work_struct dynamic_ps_disable_work; |
733 | struct timer_list dynamic_ps_timer; | 724 | struct timer_list dynamic_ps_timer; |
@@ -921,10 +912,12 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
921 | enum ieee80211_band band); | 912 | enum ieee80211_band band); |
922 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 913 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
923 | u8 *ssid, size_t ssid_len); | 914 | u8 *ssid, size_t ssid_len); |
915 | void ieee80211_send_pspoll(struct ieee80211_local *local, | ||
916 | struct ieee80211_sub_if_data *sdata); | ||
924 | 917 | ||
925 | /* scan/BSS handling */ | 918 | /* scan/BSS handling */ |
926 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 919 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
927 | u8 *ssid, size_t ssid_len); | 920 | struct cfg80211_scan_request *req); |
928 | int ieee80211_scan_results(struct ieee80211_local *local, | 921 | int ieee80211_scan_results(struct ieee80211_local *local, |
929 | struct iw_request_info *info, | 922 | struct iw_request_info *info, |
930 | char *buf, size_t len); | 923 | char *buf, size_t len); |
@@ -932,29 +925,27 @@ ieee80211_rx_result | |||
932 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, | 925 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, |
933 | struct sk_buff *skb, | 926 | struct sk_buff *skb, |
934 | struct ieee80211_rx_status *rx_status); | 927 | struct ieee80211_rx_status *rx_status); |
935 | void ieee80211_rx_bss_list_init(struct ieee80211_local *local); | ||
936 | void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local); | ||
937 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | 928 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, |
938 | char *ie, size_t len); | 929 | char *ie, size_t len); |
939 | 930 | ||
940 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | 931 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); |
941 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | 932 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, |
942 | u8 *ssid, size_t ssid_len); | 933 | struct cfg80211_scan_request *req); |
943 | struct ieee80211_bss * | 934 | struct ieee80211_bss * |
944 | ieee80211_bss_info_update(struct ieee80211_local *local, | 935 | ieee80211_bss_info_update(struct ieee80211_local *local, |
945 | struct ieee80211_rx_status *rx_status, | 936 | struct ieee80211_rx_status *rx_status, |
946 | struct ieee80211_mgmt *mgmt, | 937 | struct ieee80211_mgmt *mgmt, |
947 | size_t len, | 938 | size_t len, |
948 | struct ieee802_11_elems *elems, | 939 | struct ieee802_11_elems *elems, |
949 | int freq, bool beacon); | 940 | struct ieee80211_channel *channel, |
950 | struct ieee80211_bss * | 941 | bool beacon); |
951 | ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, | ||
952 | u8 *ssid, u8 ssid_len); | ||
953 | struct ieee80211_bss * | 942 | struct ieee80211_bss * |
954 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | 943 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, |
955 | u8 *ssid, u8 ssid_len); | 944 | u8 *ssid, u8 ssid_len); |
956 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 945 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
957 | struct ieee80211_bss *bss); | 946 | struct ieee80211_bss *bss); |
947 | void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, | ||
948 | int freq, u8 *ssid, u8 ssid_len); | ||
958 | 949 | ||
959 | /* interface handling */ | 950 | /* interface handling */ |
960 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 951 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
@@ -980,10 +971,15 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
980 | struct ieee80211_ht_info *hti, | 971 | struct ieee80211_ht_info *hti, |
981 | u16 ap_ht_cap_flags); | 972 | u16 ap_ht_cap_flags); |
982 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); | 973 | void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); |
974 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | ||
975 | const u8 *da, u16 tid, | ||
976 | u16 initiator, u16 reason_code); | ||
983 | 977 | ||
984 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, | 978 | void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, |
985 | u16 tid, u16 initiator, u16 reason); | 979 | u16 tid, u16 initiator, u16 reason); |
986 | void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr); | 980 | void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, |
981 | u16 initiator, u16 reason); | ||
982 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta); | ||
987 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 983 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
988 | struct sta_info *sta, | 984 | struct sta_info *sta, |
989 | struct ieee80211_mgmt *mgmt, size_t len); | 985 | struct ieee80211_mgmt *mgmt, size_t len); |
@@ -996,6 +992,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
996 | struct ieee80211_mgmt *mgmt, | 992 | struct ieee80211_mgmt *mgmt, |
997 | size_t len); | 993 | size_t len); |
998 | 994 | ||
995 | int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | ||
996 | enum ieee80211_back_parties initiator); | ||
997 | |||
999 | /* Spectrum management */ | 998 | /* Spectrum management */ |
1000 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 999 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
1001 | struct ieee80211_mgmt *mgmt, | 1000 | struct ieee80211_mgmt *mgmt, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 915d04323a32..df94b9365264 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -362,8 +362,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
362 | 362 | ||
363 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | 363 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
364 | if (sta->sdata == sdata) | 364 | if (sta->sdata == sdata) |
365 | ieee80211_sta_tear_down_BA_sessions(sdata, | 365 | ieee80211_sta_tear_down_BA_sessions(sta); |
366 | sta->sta.addr); | ||
367 | } | 366 | } |
368 | 367 | ||
369 | rcu_read_unlock(); | 368 | rcu_read_unlock(); |
@@ -523,7 +522,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
523 | * scan event to userspace -- the scan is incomplete. | 522 | * scan event to userspace -- the scan is incomplete. |
524 | */ | 523 | */ |
525 | if (local->sw_scanning) | 524 | if (local->sw_scanning) |
526 | ieee80211_scan_completed(&local->hw); | 525 | ieee80211_scan_completed(&local->hw, true); |
527 | } | 526 | } |
528 | 527 | ||
529 | conf.vif = &sdata->vif; | 528 | conf.vif = &sdata->vif; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index caf92424c76d..5667f4e8067f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -210,6 +210,8 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
210 | !!rcu_dereference(sdata->u.ap.beacon); | 210 | !!rcu_dereference(sdata->u.ap.beacon); |
211 | break; | 211 | break; |
212 | case NL80211_IFTYPE_ADHOC: | 212 | case NL80211_IFTYPE_ADHOC: |
213 | conf.enable_beacon = !!sdata->u.sta.probe_resp; | ||
214 | break; | ||
213 | case NL80211_IFTYPE_MESH_POINT: | 215 | case NL80211_IFTYPE_MESH_POINT: |
214 | conf.enable_beacon = true; | 216 | conf.enable_beacon = true; |
215 | break; | 217 | break; |
@@ -731,6 +733,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
731 | return NULL; | 733 | return NULL; |
732 | 734 | ||
733 | wiphy->privid = mac80211_wiphy_privid; | 735 | wiphy->privid = mac80211_wiphy_privid; |
736 | wiphy->max_scan_ssids = 4; | ||
737 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | ||
738 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | ||
739 | sizeof(struct cfg80211_bss); | ||
734 | 740 | ||
735 | local = wiphy_priv(wiphy); | 741 | local = wiphy_priv(wiphy); |
736 | local->hw.wiphy = wiphy; | 742 | local->hw.wiphy = wiphy; |
@@ -815,25 +821,33 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
815 | enum ieee80211_band band; | 821 | enum ieee80211_band band; |
816 | struct net_device *mdev; | 822 | struct net_device *mdev; |
817 | struct ieee80211_master_priv *mpriv; | 823 | struct ieee80211_master_priv *mpriv; |
824 | int channels, i, j; | ||
818 | 825 | ||
819 | /* | 826 | /* |
820 | * generic code guarantees at least one band, | 827 | * generic code guarantees at least one band, |
821 | * set this very early because much code assumes | 828 | * set this very early because much code assumes |
822 | * that hw.conf.channel is assigned | 829 | * that hw.conf.channel is assigned |
823 | */ | 830 | */ |
831 | channels = 0; | ||
824 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 832 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
825 | struct ieee80211_supported_band *sband; | 833 | struct ieee80211_supported_band *sband; |
826 | 834 | ||
827 | sband = local->hw.wiphy->bands[band]; | 835 | sband = local->hw.wiphy->bands[band]; |
828 | if (sband) { | 836 | if (sband && !local->oper_channel) { |
829 | /* init channel we're on */ | 837 | /* init channel we're on */ |
830 | local->hw.conf.channel = | 838 | local->hw.conf.channel = |
831 | local->oper_channel = | 839 | local->oper_channel = |
832 | local->scan_channel = &sband->channels[0]; | 840 | local->scan_channel = &sband->channels[0]; |
833 | break; | ||
834 | } | 841 | } |
842 | if (sband) | ||
843 | channels += sband->n_channels; | ||
835 | } | 844 | } |
836 | 845 | ||
846 | local->int_scan_req.n_channels = channels; | ||
847 | local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); | ||
848 | if (!local->int_scan_req.channels) | ||
849 | return -ENOMEM; | ||
850 | |||
837 | /* if low-level driver supports AP, we also support VLAN */ | 851 | /* if low-level driver supports AP, we also support VLAN */ |
838 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) | 852 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) |
839 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); | 853 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); |
@@ -843,7 +857,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
843 | 857 | ||
844 | result = wiphy_register(local->hw.wiphy); | 858 | result = wiphy_register(local->hw.wiphy); |
845 | if (result < 0) | 859 | if (result < 0) |
846 | return result; | 860 | goto fail_wiphy_register; |
847 | 861 | ||
848 | /* | 862 | /* |
849 | * We use the number of queues for feature tests (QoS, HT) internally | 863 | * We use the number of queues for feature tests (QoS, HT) internally |
@@ -866,8 +880,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
866 | mpriv->local = local; | 880 | mpriv->local = local; |
867 | local->mdev = mdev; | 881 | local->mdev = mdev; |
868 | 882 | ||
869 | ieee80211_rx_bss_list_init(local); | ||
870 | |||
871 | local->hw.workqueue = | 883 | local->hw.workqueue = |
872 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); | 884 | create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); |
873 | if (!local->hw.workqueue) { | 885 | if (!local->hw.workqueue) { |
@@ -893,14 +905,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
893 | 905 | ||
894 | local->hw.conf.listen_interval = local->hw.max_listen_interval; | 906 | local->hw.conf.listen_interval = local->hw.max_listen_interval; |
895 | 907 | ||
896 | local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | | ||
897 | IEEE80211_HW_SIGNAL_DBM) ? | ||
898 | IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; | ||
899 | local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? | ||
900 | IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; | ||
901 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
902 | local->wstats_flags |= IW_QUAL_DBM; | ||
903 | |||
904 | result = sta_info_start(local); | 908 | result = sta_info_start(local); |
905 | if (result < 0) | 909 | if (result < 0) |
906 | goto fail_sta_info; | 910 | goto fail_sta_info; |
@@ -946,6 +950,20 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
946 | 950 | ||
947 | ieee80211_led_init(local); | 951 | ieee80211_led_init(local); |
948 | 952 | ||
953 | /* alloc internal scan request */ | ||
954 | i = 0; | ||
955 | local->int_scan_req.ssids = &local->scan_ssid; | ||
956 | local->int_scan_req.n_ssids = 1; | ||
957 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
958 | if (!hw->wiphy->bands[band]) | ||
959 | continue; | ||
960 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { | ||
961 | local->int_scan_req.channels[i] = | ||
962 | &hw->wiphy->bands[band]->channels[j]; | ||
963 | i++; | ||
964 | } | ||
965 | } | ||
966 | |||
949 | return 0; | 967 | return 0; |
950 | 968 | ||
951 | fail_wep: | 969 | fail_wep: |
@@ -964,6 +982,8 @@ fail_workqueue: | |||
964 | free_netdev(local->mdev); | 982 | free_netdev(local->mdev); |
965 | fail_mdev_alloc: | 983 | fail_mdev_alloc: |
966 | wiphy_unregister(local->hw.wiphy); | 984 | wiphy_unregister(local->hw.wiphy); |
985 | fail_wiphy_register: | ||
986 | kfree(local->int_scan_req.channels); | ||
967 | return result; | 987 | return result; |
968 | } | 988 | } |
969 | EXPORT_SYMBOL(ieee80211_register_hw); | 989 | EXPORT_SYMBOL(ieee80211_register_hw); |
@@ -991,7 +1011,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
991 | 1011 | ||
992 | rtnl_unlock(); | 1012 | rtnl_unlock(); |
993 | 1013 | ||
994 | ieee80211_rx_bss_list_deinit(local); | ||
995 | ieee80211_clear_tx_pending(local); | 1014 | ieee80211_clear_tx_pending(local); |
996 | sta_info_stop(local); | 1015 | sta_info_stop(local); |
997 | rate_control_deinitialize(local); | 1016 | rate_control_deinitialize(local); |
@@ -1009,6 +1028,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
1009 | ieee80211_wep_free(local); | 1028 | ieee80211_wep_free(local); |
1010 | ieee80211_led_exit(local); | 1029 | ieee80211_led_exit(local); |
1011 | free_netdev(local->mdev); | 1030 | free_netdev(local->mdev); |
1031 | kfree(local->int_scan_req.channels); | ||
1012 | } | 1032 | } |
1013 | EXPORT_SYMBOL(ieee80211_unregister_hw); | 1033 | EXPORT_SYMBOL(ieee80211_unregister_hw); |
1014 | 1034 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8a1fcaeee4f2..9a3e5de0410a 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -275,16 +275,6 @@ u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_t | |||
275 | & tbl->hash_mask; | 275 | & tbl->hash_mask; |
276 | } | 276 | } |
277 | 277 | ||
278 | u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len) | ||
279 | { | ||
280 | if (!mesh_id_len) | ||
281 | return 1; | ||
282 | else if (mesh_id_len == 1) | ||
283 | return (u8) mesh_id[0]; | ||
284 | else | ||
285 | return (u8) (mesh_id[0] + 2 * mesh_id[1]); | ||
286 | } | ||
287 | |||
288 | struct mesh_table *mesh_table_alloc(int size_order) | 278 | struct mesh_table *mesh_table_alloc(int size_order) |
289 | { | 279 | { |
290 | int i; | 280 | int i; |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 9e064ee98ee0..d891d7ddccd7 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -196,7 +196,6 @@ struct mesh_rmc { | |||
196 | 196 | ||
197 | /* Public interfaces */ | 197 | /* Public interfaces */ |
198 | /* Various */ | 198 | /* Various */ |
199 | u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len); | ||
200 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); | 199 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); |
201 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 200 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
202 | struct ieee80211_sub_if_data *sdata); | 201 | struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 4f862b2a0041..60b35accda91 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -58,7 +58,6 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | |||
58 | #define PERR_IE_DST_ADDR(x) (x + 2) | 58 | #define PERR_IE_DST_ADDR(x) (x + 2) |
59 | #define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); | 59 | #define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); |
60 | 60 | ||
61 | #define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000)) | ||
62 | #define MSEC_TO_TU(x) (x*1000/1024) | 61 | #define MSEC_TO_TU(x) (x*1000/1024) |
63 | #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) | 62 | #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) |
64 | #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) | 63 | #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 57967d32e5fd..fbb766afe599 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -55,10 +55,10 @@ static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie) | |||
55 | { | 55 | { |
56 | u8 *end, *pos; | 56 | u8 *end, *pos; |
57 | 57 | ||
58 | pos = bss->ies; | 58 | pos = bss->cbss.information_elements; |
59 | if (pos == NULL) | 59 | if (pos == NULL) |
60 | return NULL; | 60 | return NULL; |
61 | end = pos + bss->ies_len; | 61 | end = pos + bss->cbss.len_information_elements; |
62 | 62 | ||
63 | while (pos + 1 < end) { | 63 | while (pos + 1 < end) { |
64 | if (pos + 2 + pos[1] > end) | 64 | if (pos + 2 + pos[1] > end) |
@@ -289,7 +289,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
289 | local->hw.conf.channel->center_freq, | 289 | local->hw.conf.channel->center_freq, |
290 | ifsta->ssid, ifsta->ssid_len); | 290 | ifsta->ssid, ifsta->ssid_len); |
291 | if (bss) { | 291 | if (bss) { |
292 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | 292 | if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) |
293 | capab |= WLAN_CAPABILITY_PRIVACY; | 293 | capab |= WLAN_CAPABILITY_PRIVACY; |
294 | if (bss->wmm_used) | 294 | if (bss->wmm_used) |
295 | wmm = 1; | 295 | wmm = 1; |
@@ -300,7 +300,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
300 | * b-only mode) */ | 300 | * b-only mode) */ |
301 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); | 301 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); |
302 | 302 | ||
303 | if ((bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | 303 | if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && |
304 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | 304 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) |
305 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | 305 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; |
306 | 306 | ||
@@ -511,16 +511,50 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
511 | ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED); | 511 | ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED); |
512 | } | 512 | } |
513 | 513 | ||
514 | void ieee80211_send_pspoll(struct ieee80211_local *local, | ||
515 | struct ieee80211_sub_if_data *sdata) | ||
516 | { | ||
517 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
518 | struct ieee80211_pspoll *pspoll; | ||
519 | struct sk_buff *skb; | ||
520 | u16 fc; | ||
521 | |||
522 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); | ||
523 | if (!skb) { | ||
524 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | ||
525 | "pspoll frame\n", sdata->dev->name); | ||
526 | return; | ||
527 | } | ||
528 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
529 | |||
530 | pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); | ||
531 | memset(pspoll, 0, sizeof(*pspoll)); | ||
532 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; | ||
533 | pspoll->frame_control = cpu_to_le16(fc); | ||
534 | pspoll->aid = cpu_to_le16(ifsta->aid); | ||
535 | |||
536 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
537 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | ||
538 | |||
539 | memcpy(pspoll->bssid, ifsta->bssid, ETH_ALEN); | ||
540 | memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); | ||
541 | |||
542 | ieee80211_tx_skb(sdata, skb, 0); | ||
543 | |||
544 | return; | ||
545 | } | ||
546 | |||
514 | /* MLME */ | 547 | /* MLME */ |
515 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 548 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
516 | struct ieee80211_bss *bss) | 549 | const size_t supp_rates_len, |
550 | const u8 *supp_rates) | ||
517 | { | 551 | { |
518 | struct ieee80211_local *local = sdata->local; | 552 | struct ieee80211_local *local = sdata->local; |
519 | int i, have_higher_than_11mbit = 0; | 553 | int i, have_higher_than_11mbit = 0; |
520 | 554 | ||
521 | /* cf. IEEE 802.11 9.2.12 */ | 555 | /* cf. IEEE 802.11 9.2.12 */ |
522 | for (i = 0; i < bss->supp_rates_len; i++) | 556 | for (i = 0; i < supp_rates_len; i++) |
523 | if ((bss->supp_rates[i] & 0x7f) * 5 > 110) | 557 | if ((supp_rates[i] & 0x7f) * 5 > 110) |
524 | have_higher_than_11mbit = 1; | 558 | have_higher_than_11mbit = 1; |
525 | 559 | ||
526 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | 560 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && |
@@ -611,7 +645,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
611 | } | 645 | } |
612 | } | 646 | } |
613 | 647 | ||
614 | static bool check_tim(struct ieee802_11_elems *elems, u16 aid, bool *is_mc) | 648 | static bool ieee80211_check_tim(struct ieee802_11_elems *elems, u16 aid) |
615 | { | 649 | { |
616 | u8 mask; | 650 | u8 mask; |
617 | u8 index, indexn1, indexn2; | 651 | u8 index, indexn1, indexn2; |
@@ -621,9 +655,6 @@ static bool check_tim(struct ieee802_11_elems *elems, u16 aid, bool *is_mc) | |||
621 | index = aid / 8; | 655 | index = aid / 8; |
622 | mask = 1 << (aid & 7); | 656 | mask = 1 << (aid & 7); |
623 | 657 | ||
624 | if (tim->bitmap_ctrl & 0x01) | ||
625 | *is_mc = true; | ||
626 | |||
627 | indexn1 = tim->bitmap_ctrl & 0xfe; | 658 | indexn1 = tim->bitmap_ctrl & 0xfe; |
628 | indexn2 = elems->tim_len + indexn1 - 4; | 659 | indexn2 = elems->tim_len + indexn1 - 4; |
629 | 660 | ||
@@ -777,20 +808,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
777 | bss_info_changed |= BSS_CHANGED_ASSOC; | 808 | bss_info_changed |= BSS_CHANGED_ASSOC; |
778 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; | 809 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; |
779 | 810 | ||
780 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
781 | return; | ||
782 | |||
783 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 811 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, |
784 | conf->channel->center_freq, | 812 | conf->channel->center_freq, |
785 | ifsta->ssid, ifsta->ssid_len); | 813 | ifsta->ssid, ifsta->ssid_len); |
786 | if (bss) { | 814 | if (bss) { |
787 | /* set timing information */ | 815 | /* set timing information */ |
788 | sdata->vif.bss_conf.beacon_int = bss->beacon_int; | 816 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; |
789 | sdata->vif.bss_conf.timestamp = bss->timestamp; | 817 | sdata->vif.bss_conf.timestamp = bss->cbss.tsf; |
790 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | 818 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; |
791 | 819 | ||
792 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 820 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
793 | bss->capability, bss->has_erp_value, bss->erp_value); | 821 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
794 | 822 | ||
795 | ieee80211_rx_bss_put(local, bss); | 823 | ieee80211_rx_bss_put(local, bss); |
796 | } | 824 | } |
@@ -840,6 +868,14 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | |||
840 | sdata->dev->name, ifsta->bssid); | 868 | sdata->dev->name, ifsta->bssid); |
841 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 869 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
842 | ieee80211_sta_send_apinfo(sdata, ifsta); | 870 | ieee80211_sta_send_apinfo(sdata, ifsta); |
871 | |||
872 | /* | ||
873 | * Most likely AP is not in the range so remove the | ||
874 | * bss information associated to the AP | ||
875 | */ | ||
876 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | ||
877 | sdata->local->hw.conf.channel->center_freq, | ||
878 | ifsta->ssid, ifsta->ssid_len); | ||
843 | return; | 879 | return; |
844 | } | 880 | } |
845 | 881 | ||
@@ -871,6 +907,9 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
871 | sdata->dev->name, ifsta->bssid); | 907 | sdata->dev->name, ifsta->bssid); |
872 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 908 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
873 | ieee80211_sta_send_apinfo(sdata, ifsta); | 909 | ieee80211_sta_send_apinfo(sdata, ifsta); |
910 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | ||
911 | sdata->local->hw.conf.channel->center_freq, | ||
912 | ifsta->ssid, ifsta->ssid_len); | ||
874 | return; | 913 | return; |
875 | } | 914 | } |
876 | 915 | ||
@@ -913,7 +952,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
913 | netif_tx_stop_all_queues(sdata->dev); | 952 | netif_tx_stop_all_queues(sdata->dev); |
914 | netif_carrier_off(sdata->dev); | 953 | netif_carrier_off(sdata->dev); |
915 | 954 | ||
916 | ieee80211_sta_tear_down_BA_sessions(sdata, sta->sta.addr); | 955 | ieee80211_sta_tear_down_BA_sessions(sta); |
917 | 956 | ||
918 | if (self_disconnected) { | 957 | if (self_disconnected) { |
919 | if (deauth) | 958 | if (deauth) |
@@ -933,8 +972,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
933 | 972 | ||
934 | ieee80211_sta_send_apinfo(sdata, ifsta); | 973 | ieee80211_sta_send_apinfo(sdata, ifsta); |
935 | 974 | ||
936 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) | 975 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { |
937 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 976 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
977 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | ||
978 | sdata->local->hw.conf.channel->center_freq, | ||
979 | ifsta->ssid, ifsta->ssid_len); | ||
980 | } | ||
938 | 981 | ||
939 | rcu_read_unlock(); | 982 | rcu_read_unlock(); |
940 | 983 | ||
@@ -995,7 +1038,7 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | |||
995 | if (!bss) | 1038 | if (!bss) |
996 | return 0; | 1039 | return 0; |
997 | 1040 | ||
998 | bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY); | 1041 | bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY); |
999 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); | 1042 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); |
1000 | privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); | 1043 | privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); |
1001 | 1044 | ||
@@ -1017,6 +1060,9 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, | |||
1017 | sdata->dev->name, ifsta->bssid); | 1060 | sdata->dev->name, ifsta->bssid); |
1018 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 1061 | ifsta->state = IEEE80211_STA_MLME_DISABLED; |
1019 | ieee80211_sta_send_apinfo(sdata, ifsta); | 1062 | ieee80211_sta_send_apinfo(sdata, ifsta); |
1063 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | ||
1064 | sdata->local->hw.conf.channel->center_freq, | ||
1065 | ifsta->ssid, ifsta->ssid_len); | ||
1020 | return; | 1066 | return; |
1021 | } | 1067 | } |
1022 | 1068 | ||
@@ -1042,7 +1088,6 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1042 | struct ieee80211_local *local = sdata->local; | 1088 | struct ieee80211_local *local = sdata->local; |
1043 | struct sta_info *sta; | 1089 | struct sta_info *sta; |
1044 | int disassoc; | 1090 | int disassoc; |
1045 | bool remove_bss = false; | ||
1046 | 1091 | ||
1047 | /* TODO: start monitoring current AP signal quality and number of | 1092 | /* TODO: start monitoring current AP signal quality and number of |
1048 | * missed beacons. Scan other channels every now and then and search | 1093 | * missed beacons. Scan other channels every now and then and search |
@@ -1068,7 +1113,6 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1068 | "range\n", | 1113 | "range\n", |
1069 | sdata->dev->name, ifsta->bssid); | 1114 | sdata->dev->name, ifsta->bssid); |
1070 | disassoc = 1; | 1115 | disassoc = 1; |
1071 | remove_bss = true; | ||
1072 | } else | 1116 | } else |
1073 | ieee80211_send_probe_req(sdata, ifsta->bssid, | 1117 | ieee80211_send_probe_req(sdata, ifsta->bssid, |
1074 | ifsta->ssid, | 1118 | ifsta->ssid, |
@@ -1088,24 +1132,12 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1088 | 1132 | ||
1089 | rcu_read_unlock(); | 1133 | rcu_read_unlock(); |
1090 | 1134 | ||
1091 | if (disassoc) { | 1135 | if (disassoc) |
1092 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 1136 | ieee80211_set_disassoc(sdata, ifsta, true, true, |
1093 | WLAN_REASON_PREV_AUTH_NOT_VALID); | 1137 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
1094 | if (remove_bss) { | 1138 | else |
1095 | struct ieee80211_bss *bss; | ||
1096 | |||
1097 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | ||
1098 | local->hw.conf.channel->center_freq, | ||
1099 | ifsta->ssid, ifsta->ssid_len); | ||
1100 | if (bss) { | ||
1101 | atomic_dec(&bss->users); | ||
1102 | ieee80211_rx_bss_put(local, bss); | ||
1103 | } | ||
1104 | } | ||
1105 | } else { | ||
1106 | mod_timer(&ifsta->timer, jiffies + | 1139 | mod_timer(&ifsta->timer, jiffies + |
1107 | IEEE80211_MONITORING_INTERVAL); | 1140 | IEEE80211_MONITORING_INTERVAL); |
1108 | } | ||
1109 | } | 1141 | } |
1110 | 1142 | ||
1111 | 1143 | ||
@@ -1134,6 +1166,30 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1134 | elems.challenge_len + 2, 1); | 1166 | elems.challenge_len + 2, 1); |
1135 | } | 1167 | } |
1136 | 1168 | ||
1169 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | ||
1170 | struct ieee80211_if_sta *ifsta, | ||
1171 | struct ieee80211_mgmt *mgmt, | ||
1172 | size_t len) | ||
1173 | { | ||
1174 | u16 auth_alg, auth_transaction, status_code; | ||
1175 | |||
1176 | if (len < 24 + 6) | ||
1177 | return; | ||
1178 | |||
1179 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
1180 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
1181 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
1182 | |||
1183 | /* | ||
1184 | * IEEE 802.11 standard does not require authentication in IBSS | ||
1185 | * networks and most implementations do not seem to use it. | ||
1186 | * However, try to reply to authentication attempts if someone | ||
1187 | * has actually implemented this. | ||
1188 | */ | ||
1189 | if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) | ||
1190 | ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0); | ||
1191 | } | ||
1192 | |||
1137 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 1193 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
1138 | struct ieee80211_if_sta *ifsta, | 1194 | struct ieee80211_if_sta *ifsta, |
1139 | struct ieee80211_mgmt *mgmt, | 1195 | struct ieee80211_mgmt *mgmt, |
@@ -1141,37 +1197,22 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1141 | { | 1197 | { |
1142 | u16 auth_alg, auth_transaction, status_code; | 1198 | u16 auth_alg, auth_transaction, status_code; |
1143 | 1199 | ||
1144 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 1200 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE) |
1145 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
1146 | return; | 1201 | return; |
1147 | 1202 | ||
1148 | if (len < 24 + 6) | 1203 | if (len < 24 + 6) |
1149 | return; | 1204 | return; |
1150 | 1205 | ||
1151 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1206 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) |
1152 | memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | ||
1153 | return; | 1207 | return; |
1154 | 1208 | ||
1155 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1209 | if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1156 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1157 | return; | 1210 | return; |
1158 | 1211 | ||
1159 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 1212 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
1160 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 1213 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
1161 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | 1214 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
1162 | 1215 | ||
1163 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
1164 | /* | ||
1165 | * IEEE 802.11 standard does not require authentication in IBSS | ||
1166 | * networks and most implementations do not seem to use it. | ||
1167 | * However, try to reply to authentication attempts if someone | ||
1168 | * has actually implemented this. | ||
1169 | */ | ||
1170 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | ||
1171 | return; | ||
1172 | ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0); | ||
1173 | } | ||
1174 | |||
1175 | if (auth_alg != ifsta->auth_alg || | 1216 | if (auth_alg != ifsta->auth_alg || |
1176 | auth_transaction != ifsta->auth_transaction) | 1217 | auth_transaction != ifsta->auth_transaction) |
1177 | return; | 1218 | return; |
@@ -1381,8 +1422,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1381 | /* Add STA entry for the AP */ | 1422 | /* Add STA entry for the AP */ |
1382 | sta = sta_info_get(local, ifsta->bssid); | 1423 | sta = sta_info_get(local, ifsta->bssid); |
1383 | if (!sta) { | 1424 | if (!sta) { |
1384 | struct ieee80211_bss *bss; | ||
1385 | |||
1386 | newsta = true; | 1425 | newsta = true; |
1387 | 1426 | ||
1388 | sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); | 1427 | sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); |
@@ -1392,15 +1431,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1392 | rcu_read_unlock(); | 1431 | rcu_read_unlock(); |
1393 | return; | 1432 | return; |
1394 | } | 1433 | } |
1395 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | ||
1396 | local->hw.conf.channel->center_freq, | ||
1397 | ifsta->ssid, ifsta->ssid_len); | ||
1398 | if (bss) { | ||
1399 | sta->last_signal = bss->signal; | ||
1400 | sta->last_qual = bss->qual; | ||
1401 | sta->last_noise = bss->noise; | ||
1402 | ieee80211_rx_bss_put(local, bss); | ||
1403 | } | ||
1404 | 1434 | ||
1405 | /* update new sta with its last rx activity */ | 1435 | /* update new sta with its last rx activity */ |
1406 | sta->last_rx = jiffies; | 1436 | sta->last_rx = jiffies; |
@@ -1512,9 +1542,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1512 | } | 1542 | } |
1513 | 1543 | ||
1514 | 1544 | ||
1515 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 1545 | static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
1516 | struct ieee80211_if_sta *ifsta, | 1546 | struct ieee80211_if_sta *ifsta, |
1517 | struct ieee80211_bss *bss) | 1547 | const u8 *bssid, const int beacon_int, |
1548 | const int freq, | ||
1549 | const size_t supp_rates_len, | ||
1550 | const u8 *supp_rates, | ||
1551 | const u16 capability) | ||
1518 | { | 1552 | { |
1519 | struct ieee80211_local *local = sdata->local; | 1553 | struct ieee80211_local *local = sdata->local; |
1520 | int res = 0, rates, i, j; | 1554 | int res = 0, rates, i, j; |
@@ -1530,7 +1564,7 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1530 | } | 1564 | } |
1531 | 1565 | ||
1532 | if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) && | 1566 | if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) && |
1533 | memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) == 0) | 1567 | memcmp(ifsta->bssid, bssid, ETH_ALEN) == 0) |
1534 | return res; | 1568 | return res; |
1535 | 1569 | ||
1536 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + | 1570 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + |
@@ -1541,28 +1575,28 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1541 | return -ENOMEM; | 1575 | return -ENOMEM; |
1542 | } | 1576 | } |
1543 | 1577 | ||
1544 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1545 | |||
1546 | if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) { | 1578 | if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) { |
1547 | /* Remove possible STA entries from other IBSS networks. */ | 1579 | /* Remove possible STA entries from other IBSS networks. */ |
1548 | sta_info_flush_delayed(sdata); | 1580 | sta_info_flush_delayed(sdata); |
1549 | } | 1581 | } |
1550 | 1582 | ||
1551 | memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); | 1583 | memcpy(ifsta->bssid, bssid, ETH_ALEN); |
1552 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | 1584 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); |
1553 | if (res) | 1585 | if (res) |
1554 | return res; | 1586 | return res; |
1555 | 1587 | ||
1556 | local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; | 1588 | local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; |
1557 | 1589 | ||
1558 | sdata->drop_unencrypted = bss->capability & | 1590 | sdata->drop_unencrypted = capability & |
1559 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | 1591 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; |
1560 | 1592 | ||
1561 | res = ieee80211_set_freq(sdata, bss->freq); | 1593 | res = ieee80211_set_freq(sdata, freq); |
1562 | 1594 | ||
1563 | if (res) | 1595 | if (res) |
1564 | return res; | 1596 | return res; |
1565 | 1597 | ||
1598 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1599 | |||
1566 | /* Build IBSS probe response */ | 1600 | /* Build IBSS probe response */ |
1567 | 1601 | ||
1568 | skb_reserve(skb, local->hw.extra_tx_headroom); | 1602 | skb_reserve(skb, local->hw.extra_tx_headroom); |
@@ -1571,33 +1605,32 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1571 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | 1605 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); |
1572 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | 1606 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); |
1573 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1607 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
1574 | IEEE80211_STYPE_PROBE_RESP); | 1608 | IEEE80211_STYPE_PROBE_RESP); |
1575 | memset(mgmt->da, 0xff, ETH_ALEN); | 1609 | memset(mgmt->da, 0xff, ETH_ALEN); |
1576 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 1610 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
1577 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 1611 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); |
1578 | mgmt->u.beacon.beacon_int = | 1612 | mgmt->u.beacon.beacon_int = |
1579 | cpu_to_le16(local->hw.conf.beacon_int); | 1613 | cpu_to_le16(local->hw.conf.beacon_int); |
1580 | mgmt->u.beacon.timestamp = cpu_to_le64(bss->timestamp); | 1614 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); |
1581 | mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); | ||
1582 | 1615 | ||
1583 | pos = skb_put(skb, 2 + ifsta->ssid_len); | 1616 | pos = skb_put(skb, 2 + ifsta->ssid_len); |
1584 | *pos++ = WLAN_EID_SSID; | 1617 | *pos++ = WLAN_EID_SSID; |
1585 | *pos++ = ifsta->ssid_len; | 1618 | *pos++ = ifsta->ssid_len; |
1586 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | 1619 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); |
1587 | 1620 | ||
1588 | rates = bss->supp_rates_len; | 1621 | rates = supp_rates_len; |
1589 | if (rates > 8) | 1622 | if (rates > 8) |
1590 | rates = 8; | 1623 | rates = 8; |
1591 | pos = skb_put(skb, 2 + rates); | 1624 | pos = skb_put(skb, 2 + rates); |
1592 | *pos++ = WLAN_EID_SUPP_RATES; | 1625 | *pos++ = WLAN_EID_SUPP_RATES; |
1593 | *pos++ = rates; | 1626 | *pos++ = rates; |
1594 | memcpy(pos, bss->supp_rates, rates); | 1627 | memcpy(pos, supp_rates, rates); |
1595 | 1628 | ||
1596 | if (bss->band == IEEE80211_BAND_2GHZ) { | 1629 | if (sband->band == IEEE80211_BAND_2GHZ) { |
1597 | pos = skb_put(skb, 2 + 1); | 1630 | pos = skb_put(skb, 2 + 1); |
1598 | *pos++ = WLAN_EID_DS_PARAMS; | 1631 | *pos++ = WLAN_EID_DS_PARAMS; |
1599 | *pos++ = 1; | 1632 | *pos++ = 1; |
1600 | *pos++ = ieee80211_frequency_to_channel(bss->freq); | 1633 | *pos++ = ieee80211_frequency_to_channel(freq); |
1601 | } | 1634 | } |
1602 | 1635 | ||
1603 | pos = skb_put(skb, 2 + 2); | 1636 | pos = skb_put(skb, 2 + 2); |
@@ -1607,12 +1640,12 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1607 | *pos++ = 0; | 1640 | *pos++ = 0; |
1608 | *pos++ = 0; | 1641 | *pos++ = 0; |
1609 | 1642 | ||
1610 | if (bss->supp_rates_len > 8) { | 1643 | if (supp_rates_len > 8) { |
1611 | rates = bss->supp_rates_len - 8; | 1644 | rates = supp_rates_len - 8; |
1612 | pos = skb_put(skb, 2 + rates); | 1645 | pos = skb_put(skb, 2 + rates); |
1613 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 1646 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
1614 | *pos++ = rates; | 1647 | *pos++ = rates; |
1615 | memcpy(pos, &bss->supp_rates[8], rates); | 1648 | memcpy(pos, &supp_rates[8], rates); |
1616 | } | 1649 | } |
1617 | 1650 | ||
1618 | add_extra_ies(skb, sdata->u.sta.ie_proberesp, | 1651 | add_extra_ies(skb, sdata->u.sta.ie_proberesp, |
@@ -1625,16 +1658,15 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1625 | 1658 | ||
1626 | 1659 | ||
1627 | rates = 0; | 1660 | rates = 0; |
1628 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1661 | for (i = 0; i < supp_rates_len; i++) { |
1629 | for (i = 0; i < bss->supp_rates_len; i++) { | 1662 | int bitrate = (supp_rates[i] & 0x7f) * 5; |
1630 | int bitrate = (bss->supp_rates[i] & 0x7f) * 5; | ||
1631 | for (j = 0; j < sband->n_bitrates; j++) | 1663 | for (j = 0; j < sband->n_bitrates; j++) |
1632 | if (sband->bitrates[j].bitrate == bitrate) | 1664 | if (sband->bitrates[j].bitrate == bitrate) |
1633 | rates |= BIT(j); | 1665 | rates |= BIT(j); |
1634 | } | 1666 | } |
1635 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; | 1667 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; |
1636 | 1668 | ||
1637 | ieee80211_sta_def_wmm_params(sdata, bss); | 1669 | ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); |
1638 | 1670 | ||
1639 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | 1671 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; |
1640 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; | 1672 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; |
@@ -1643,12 +1675,24 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1643 | ieee80211_led_assoc(local, true); | 1675 | ieee80211_led_assoc(local, true); |
1644 | 1676 | ||
1645 | memset(&wrqu, 0, sizeof(wrqu)); | 1677 | memset(&wrqu, 0, sizeof(wrqu)); |
1646 | memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN); | 1678 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
1647 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | 1679 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); |
1648 | 1680 | ||
1649 | return res; | 1681 | return res; |
1650 | } | 1682 | } |
1651 | 1683 | ||
1684 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||
1685 | struct ieee80211_if_sta *ifsta, | ||
1686 | struct ieee80211_bss *bss) | ||
1687 | { | ||
1688 | return __ieee80211_sta_join_ibss(sdata, ifsta, | ||
1689 | bss->cbss.bssid, | ||
1690 | bss->cbss.beacon_interval, | ||
1691 | bss->cbss.channel->center_freq, | ||
1692 | bss->supp_rates_len, bss->supp_rates, | ||
1693 | bss->cbss.capability); | ||
1694 | } | ||
1695 | |||
1652 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 1696 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
1653 | struct ieee80211_mgmt *mgmt, | 1697 | struct ieee80211_mgmt *mgmt, |
1654 | size_t len, | 1698 | size_t len, |
@@ -1709,7 +1753,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1709 | } | 1753 | } |
1710 | 1754 | ||
1711 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 1755 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
1712 | freq, beacon); | 1756 | channel, beacon); |
1713 | if (!bss) | 1757 | if (!bss) |
1714 | return; | 1758 | return; |
1715 | 1759 | ||
@@ -1721,76 +1765,87 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1721 | } | 1765 | } |
1722 | 1766 | ||
1723 | /* was just updated in ieee80211_bss_info_update */ | 1767 | /* was just updated in ieee80211_bss_info_update */ |
1724 | beacon_timestamp = bss->timestamp; | 1768 | beacon_timestamp = bss->cbss.tsf; |
1725 | 1769 | ||
1726 | /* | 1770 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) |
1727 | * In STA mode, the remaining parameters should not be overridden | 1771 | goto put_bss; |
1728 | * by beacons because they're not necessarily accurate there. | ||
1729 | */ | ||
1730 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && | ||
1731 | bss->last_probe_resp && beacon) { | ||
1732 | ieee80211_rx_bss_put(local, bss); | ||
1733 | return; | ||
1734 | } | ||
1735 | 1772 | ||
1736 | /* check if we need to merge IBSS */ | 1773 | /* check if we need to merge IBSS */ |
1737 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && beacon && | 1774 | |
1738 | (!(sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)) && | 1775 | /* merge only on beacons (???) */ |
1739 | bss->capability & WLAN_CAPABILITY_IBSS && | 1776 | if (!beacon) |
1740 | bss->freq == local->oper_channel->center_freq && | 1777 | goto put_bss; |
1741 | elems->ssid_len == sdata->u.sta.ssid_len && | 1778 | |
1779 | /* we use a fixed BSSID */ | ||
1780 | if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) | ||
1781 | goto put_bss; | ||
1782 | |||
1783 | /* not an IBSS */ | ||
1784 | if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) | ||
1785 | goto put_bss; | ||
1786 | |||
1787 | /* different channel */ | ||
1788 | if (bss->cbss.channel != local->oper_channel) | ||
1789 | goto put_bss; | ||
1790 | |||
1791 | /* different SSID */ | ||
1792 | if (elems->ssid_len != sdata->u.sta.ssid_len || | ||
1742 | memcmp(elems->ssid, sdata->u.sta.ssid, | 1793 | memcmp(elems->ssid, sdata->u.sta.ssid, |
1743 | sdata->u.sta.ssid_len) == 0) { | 1794 | sdata->u.sta.ssid_len)) |
1744 | if (rx_status->flag & RX_FLAG_TSFT) { | 1795 | goto put_bss; |
1745 | /* in order for correct IBSS merging we need mactime | 1796 | |
1746 | * | 1797 | if (rx_status->flag & RX_FLAG_TSFT) { |
1747 | * since mactime is defined as the time the first data | 1798 | /* |
1748 | * symbol of the frame hits the PHY, and the timestamp | 1799 | * For correct IBSS merging we need mactime; since mactime is |
1749 | * of the beacon is defined as "the time that the data | 1800 | * defined as the time the first data symbol of the frame hits |
1750 | * symbol containing the first bit of the timestamp is | 1801 | * the PHY, and the timestamp of the beacon is defined as "the |
1751 | * transmitted to the PHY plus the transmitting STA’s | 1802 | * time that the data symbol containing the first bit of the |
1752 | * delays through its local PHY from the MAC-PHY | 1803 | * timestamp is transmitted to the PHY plus the transmitting |
1753 | * interface to its interface with the WM" | 1804 | * STA's delays through its local PHY from the MAC-PHY |
1754 | * (802.11 11.1.2) - equals the time this bit arrives at | 1805 | * interface to its interface with the WM" (802.11 11.1.2) |
1755 | * the receiver - we have to take into account the | 1806 | * - equals the time this bit arrives at the receiver - we have |
1756 | * offset between the two. | 1807 | * to take into account the offset between the two. |
1757 | * e.g: at 1 MBit that means mactime is 192 usec earlier | 1808 | * |
1758 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | 1809 | * E.g. at 1 MBit that means mactime is 192 usec earlier |
1759 | */ | 1810 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. |
1760 | int rate; | 1811 | */ |
1761 | if (rx_status->flag & RX_FLAG_HT) { | 1812 | int rate; |
1762 | rate = 65; /* TODO: HT rates */ | 1813 | |
1763 | } else { | 1814 | if (rx_status->flag & RX_FLAG_HT) |
1764 | rate = local->hw.wiphy->bands[band]-> | 1815 | rate = 65; /* TODO: HT rates */ |
1765 | bitrates[rx_status->rate_idx].bitrate; | ||
1766 | } | ||
1767 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
1768 | } else if (local && local->ops && local->ops->get_tsf) | ||
1769 | /* second best option: get current TSF */ | ||
1770 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | ||
1771 | else | 1816 | else |
1772 | /* can't merge without knowing the TSF */ | 1817 | rate = local->hw.wiphy->bands[band]-> |
1773 | rx_timestamp = -1LLU; | 1818 | bitrates[rx_status->rate_idx].bitrate; |
1819 | |||
1820 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
1821 | } else if (local && local->ops && local->ops->get_tsf) | ||
1822 | /* second best option: get current TSF */ | ||
1823 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | ||
1824 | else | ||
1825 | /* can't merge without knowing the TSF */ | ||
1826 | rx_timestamp = -1LLU; | ||
1827 | |||
1774 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1828 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1775 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | 1829 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" |
1776 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | 1830 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", |
1777 | mgmt->sa, mgmt->bssid, | 1831 | mgmt->sa, mgmt->bssid, |
1778 | (unsigned long long)rx_timestamp, | 1832 | (unsigned long long)rx_timestamp, |
1779 | (unsigned long long)beacon_timestamp, | 1833 | (unsigned long long)beacon_timestamp, |
1780 | (unsigned long long)(rx_timestamp - beacon_timestamp), | 1834 | (unsigned long long)(rx_timestamp - beacon_timestamp), |
1781 | jiffies); | 1835 | jiffies); |
1782 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 1836 | #endif |
1783 | if (beacon_timestamp > rx_timestamp) { | 1837 | |
1838 | if (beacon_timestamp > rx_timestamp) { | ||
1784 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 1839 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
1785 | printk(KERN_DEBUG "%s: beacon TSF higher than " | 1840 | printk(KERN_DEBUG "%s: beacon TSF higher than " |
1786 | "local TSF - IBSS merge with BSSID %pM\n", | 1841 | "local TSF - IBSS merge with BSSID %pM\n", |
1787 | sdata->dev->name, mgmt->bssid); | 1842 | sdata->dev->name, mgmt->bssid); |
1788 | #endif | 1843 | #endif |
1789 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); | 1844 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); |
1790 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 1845 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); |
1791 | } | ||
1792 | } | 1846 | } |
1793 | 1847 | ||
1848 | put_bss: | ||
1794 | ieee80211_rx_bss_put(local, bss); | 1849 | ieee80211_rx_bss_put(local, bss); |
1795 | } | 1850 | } |
1796 | 1851 | ||
@@ -1836,7 +1891,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1836 | struct ieee802_11_elems elems; | 1891 | struct ieee802_11_elems elems; |
1837 | struct ieee80211_local *local = sdata->local; | 1892 | struct ieee80211_local *local = sdata->local; |
1838 | u32 changed = 0; | 1893 | u32 changed = 0; |
1839 | bool erp_valid, directed_tim, is_mc = false; | 1894 | bool erp_valid, directed_tim; |
1840 | u8 erp_value = 0; | 1895 | u8 erp_value = 0; |
1841 | 1896 | ||
1842 | /* Process beacon from the current BSS */ | 1897 | /* Process beacon from the current BSS */ |
@@ -1864,12 +1919,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1864 | 1919 | ||
1865 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && | 1920 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && |
1866 | local->hw.conf.flags & IEEE80211_CONF_PS) { | 1921 | local->hw.conf.flags & IEEE80211_CONF_PS) { |
1867 | directed_tim = check_tim(&elems, ifsta->aid, &is_mc); | 1922 | directed_tim = ieee80211_check_tim(&elems, ifsta->aid); |
1868 | 1923 | ||
1869 | if (directed_tim || is_mc) { | 1924 | if (directed_tim) { |
1870 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | 1925 | if (local->hw.conf.dynamic_ps_timeout > 0) { |
1871 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 1926 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; |
1872 | ieee80211_send_nullfunc(local, sdata, 0); | 1927 | ieee80211_hw_config(local, |
1928 | IEEE80211_CONF_CHANGE_PS); | ||
1929 | ieee80211_send_nullfunc(local, sdata, 0); | ||
1930 | } else { | ||
1931 | local->pspolling = true; | ||
1932 | |||
1933 | /* | ||
1934 | * Here is assumed that the driver will be | ||
1935 | * able to send ps-poll frame and receive a | ||
1936 | * response even though power save mode is | ||
1937 | * enabled, but some drivers might require | ||
1938 | * to disable power save here. This needs | ||
1939 | * to be investigated. | ||
1940 | */ | ||
1941 | ieee80211_send_pspoll(local, sdata); | ||
1942 | } | ||
1873 | } | 1943 | } |
1874 | } | 1944 | } |
1875 | 1945 | ||
@@ -1939,8 +2009,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1939 | struct ieee80211_mgmt *resp; | 2009 | struct ieee80211_mgmt *resp; |
1940 | u8 *pos, *end; | 2010 | u8 *pos, *end; |
1941 | 2011 | ||
1942 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC || | 2012 | if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || |
1943 | ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || | ||
1944 | len < 24 + 2 || !ifsta->probe_resp) | 2013 | len < 24 + 2 || !ifsta->probe_resp) |
1945 | return; | 2014 | return; |
1946 | 2015 | ||
@@ -2044,31 +2113,54 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2044 | mgmt = (struct ieee80211_mgmt *) skb->data; | 2113 | mgmt = (struct ieee80211_mgmt *) skb->data; |
2045 | fc = le16_to_cpu(mgmt->frame_control); | 2114 | fc = le16_to_cpu(mgmt->frame_control); |
2046 | 2115 | ||
2047 | switch (fc & IEEE80211_FCTL_STYPE) { | 2116 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
2048 | case IEEE80211_STYPE_PROBE_REQ: | 2117 | switch (fc & IEEE80211_FCTL_STYPE) { |
2049 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, skb->len); | 2118 | case IEEE80211_STYPE_PROBE_REQ: |
2050 | break; | 2119 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, |
2051 | case IEEE80211_STYPE_PROBE_RESP: | 2120 | skb->len); |
2052 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); | 2121 | break; |
2053 | break; | 2122 | case IEEE80211_STYPE_PROBE_RESP: |
2054 | case IEEE80211_STYPE_BEACON: | 2123 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, |
2055 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); | 2124 | rx_status); |
2056 | break; | 2125 | break; |
2057 | case IEEE80211_STYPE_AUTH: | 2126 | case IEEE80211_STYPE_BEACON: |
2058 | ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len); | 2127 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
2059 | break; | 2128 | rx_status); |
2060 | case IEEE80211_STYPE_ASSOC_RESP: | 2129 | break; |
2061 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0); | 2130 | case IEEE80211_STYPE_AUTH: |
2062 | break; | 2131 | ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt, |
2063 | case IEEE80211_STYPE_REASSOC_RESP: | 2132 | skb->len); |
2064 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1); | 2133 | break; |
2065 | break; | 2134 | } |
2066 | case IEEE80211_STYPE_DEAUTH: | 2135 | } else { /* NL80211_IFTYPE_STATION */ |
2067 | ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len); | 2136 | switch (fc & IEEE80211_FCTL_STYPE) { |
2068 | break; | 2137 | case IEEE80211_STYPE_PROBE_RESP: |
2069 | case IEEE80211_STYPE_DISASSOC: | 2138 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, |
2070 | ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, skb->len); | 2139 | rx_status); |
2071 | break; | 2140 | break; |
2141 | case IEEE80211_STYPE_BEACON: | ||
2142 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | ||
2143 | rx_status); | ||
2144 | break; | ||
2145 | case IEEE80211_STYPE_AUTH: | ||
2146 | ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len); | ||
2147 | break; | ||
2148 | case IEEE80211_STYPE_ASSOC_RESP: | ||
2149 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, | ||
2150 | skb->len, 0); | ||
2151 | break; | ||
2152 | case IEEE80211_STYPE_REASSOC_RESP: | ||
2153 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, | ||
2154 | skb->len, 1); | ||
2155 | break; | ||
2156 | case IEEE80211_STYPE_DEAUTH: | ||
2157 | ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len); | ||
2158 | break; | ||
2159 | case IEEE80211_STYPE_DISASSOC: | ||
2160 | ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, | ||
2161 | skb->len); | ||
2162 | break; | ||
2163 | } | ||
2072 | } | 2164 | } |
2073 | 2165 | ||
2074 | kfree_skb(skb); | 2166 | kfree_skb(skb); |
@@ -2113,7 +2205,15 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata, | |||
2113 | 2205 | ||
2114 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | 2206 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " |
2115 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | 2207 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); |
2116 | ieee80211_request_scan(sdata, ifsta->ssid, ifsta->ssid_len); | 2208 | |
2209 | /* XXX maybe racy? */ | ||
2210 | if (sdata->local->scan_req) | ||
2211 | return; | ||
2212 | |||
2213 | memcpy(sdata->local->int_scan_req.ssids[0].ssid, | ||
2214 | ifsta->ssid, IEEE80211_MAX_SSID_LEN); | ||
2215 | sdata->local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len; | ||
2216 | ieee80211_request_scan(sdata, &sdata->local->int_scan_req); | ||
2117 | } | 2217 | } |
2118 | 2218 | ||
2119 | 2219 | ||
@@ -2159,46 +2259,16 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | |||
2159 | netif_carrier_off(sdata->dev); | 2259 | netif_carrier_off(sdata->dev); |
2160 | } | 2260 | } |
2161 | 2261 | ||
2162 | |||
2163 | static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, | ||
2164 | const char *ssid, int ssid_len) | ||
2165 | { | ||
2166 | int tmp, hidden_ssid; | ||
2167 | |||
2168 | if (ssid_len == ifsta->ssid_len && | ||
2169 | !memcmp(ifsta->ssid, ssid, ssid_len)) | ||
2170 | return 1; | ||
2171 | |||
2172 | if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) | ||
2173 | return 0; | ||
2174 | |||
2175 | hidden_ssid = 1; | ||
2176 | tmp = ssid_len; | ||
2177 | while (tmp--) { | ||
2178 | if (ssid[tmp] != '\0') { | ||
2179 | hidden_ssid = 0; | ||
2180 | break; | ||
2181 | } | ||
2182 | } | ||
2183 | |||
2184 | if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0)) | ||
2185 | return 1; | ||
2186 | |||
2187 | if (ssid_len == 1 && ssid[0] == ' ') | ||
2188 | return 1; | ||
2189 | |||
2190 | return 0; | ||
2191 | } | ||
2192 | |||
2193 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | 2262 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, |
2194 | struct ieee80211_if_sta *ifsta) | 2263 | struct ieee80211_if_sta *ifsta) |
2195 | { | 2264 | { |
2196 | struct ieee80211_local *local = sdata->local; | 2265 | struct ieee80211_local *local = sdata->local; |
2197 | struct ieee80211_bss *bss; | ||
2198 | struct ieee80211_supported_band *sband; | 2266 | struct ieee80211_supported_band *sband; |
2199 | u8 bssid[ETH_ALEN], *pos; | 2267 | u8 *pos; |
2268 | u8 bssid[ETH_ALEN]; | ||
2269 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
2270 | u16 capability; | ||
2200 | int i; | 2271 | int i; |
2201 | int ret; | ||
2202 | 2272 | ||
2203 | if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) { | 2273 | if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) { |
2204 | memcpy(bssid, ifsta->bssid, ETH_ALEN); | 2274 | memcpy(bssid, ifsta->bssid, ETH_ALEN); |
@@ -2216,36 +2286,29 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | |||
2216 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | 2286 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", |
2217 | sdata->dev->name, bssid); | 2287 | sdata->dev->name, bssid); |
2218 | 2288 | ||
2219 | bss = ieee80211_rx_bss_add(local, bssid, | 2289 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
2220 | local->hw.conf.channel->center_freq, | ||
2221 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); | ||
2222 | if (!bss) | ||
2223 | return -ENOMEM; | ||
2224 | |||
2225 | bss->band = local->hw.conf.channel->band; | ||
2226 | sband = local->hw.wiphy->bands[bss->band]; | ||
2227 | 2290 | ||
2228 | if (local->hw.conf.beacon_int == 0) | 2291 | if (local->hw.conf.beacon_int == 0) |
2229 | local->hw.conf.beacon_int = 100; | 2292 | local->hw.conf.beacon_int = 100; |
2230 | bss->beacon_int = local->hw.conf.beacon_int; | 2293 | |
2231 | bss->last_update = jiffies; | 2294 | capability = WLAN_CAPABILITY_IBSS; |
2232 | bss->capability = WLAN_CAPABILITY_IBSS; | ||
2233 | 2295 | ||
2234 | if (sdata->default_key) | 2296 | if (sdata->default_key) |
2235 | bss->capability |= WLAN_CAPABILITY_PRIVACY; | 2297 | capability |= WLAN_CAPABILITY_PRIVACY; |
2236 | else | 2298 | else |
2237 | sdata->drop_unencrypted = 0; | 2299 | sdata->drop_unencrypted = 0; |
2238 | 2300 | ||
2239 | bss->supp_rates_len = sband->n_bitrates; | 2301 | pos = supp_rates; |
2240 | pos = bss->supp_rates; | ||
2241 | for (i = 0; i < sband->n_bitrates; i++) { | 2302 | for (i = 0; i < sband->n_bitrates; i++) { |
2242 | int rate = sband->bitrates[i].bitrate; | 2303 | int rate = sband->bitrates[i].bitrate; |
2243 | *pos++ = (u8) (rate / 5); | 2304 | *pos++ = (u8) (rate / 5); |
2244 | } | 2305 | } |
2245 | 2306 | ||
2246 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); | 2307 | return __ieee80211_sta_join_ibss(sdata, ifsta, |
2247 | ieee80211_rx_bss_put(local, bss); | 2308 | bssid, local->hw.conf.beacon_int, |
2248 | return ret; | 2309 | local->hw.conf.channel->center_freq, |
2310 | sband->n_bitrates, supp_rates, | ||
2311 | capability); | ||
2249 | } | 2312 | } |
2250 | 2313 | ||
2251 | 2314 | ||
@@ -2254,8 +2317,6 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | |||
2254 | { | 2317 | { |
2255 | struct ieee80211_local *local = sdata->local; | 2318 | struct ieee80211_local *local = sdata->local; |
2256 | struct ieee80211_bss *bss; | 2319 | struct ieee80211_bss *bss; |
2257 | int found = 0; | ||
2258 | u8 bssid[ETH_ALEN]; | ||
2259 | int active_ibss; | 2320 | int active_ibss; |
2260 | 2321 | ||
2261 | if (ifsta->ssid_len == 0) | 2322 | if (ifsta->ssid_len == 0) |
@@ -2266,56 +2327,39 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | |||
2266 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | 2327 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", |
2267 | sdata->dev->name, active_ibss); | 2328 | sdata->dev->name, active_ibss); |
2268 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2329 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2269 | spin_lock_bh(&local->bss_lock); | 2330 | |
2270 | list_for_each_entry(bss, &local->bss_list, list) { | 2331 | if (active_ibss) |
2271 | if (ifsta->ssid_len != bss->ssid_len || | 2332 | return 0; |
2272 | memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0 | 2333 | |
2273 | || !(bss->capability & WLAN_CAPABILITY_IBSS)) | 2334 | if (ifsta->flags & IEEE80211_STA_BSSID_SET) |
2274 | continue; | 2335 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, 0, |
2275 | if ((ifsta->flags & IEEE80211_STA_BSSID_SET) && | 2336 | ifsta->ssid, ifsta->ssid_len); |
2276 | memcmp(ifsta->bssid, bss->bssid, ETH_ALEN) != 0) | 2337 | else |
2277 | continue; | 2338 | bss = (void *)cfg80211_get_ibss(local->hw.wiphy, |
2278 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 2339 | NULL, |
2279 | printk(KERN_DEBUG " bssid=%pM found\n", bss->bssid); | 2340 | ifsta->ssid, ifsta->ssid_len); |
2280 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2281 | memcpy(bssid, bss->bssid, ETH_ALEN); | ||
2282 | found = 1; | ||
2283 | if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0) | ||
2284 | break; | ||
2285 | } | ||
2286 | spin_unlock_bh(&local->bss_lock); | ||
2287 | 2341 | ||
2288 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 2342 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
2289 | if (found) | 2343 | if (bss) |
2290 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " | 2344 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " |
2291 | "%pM\n", bssid, ifsta->bssid); | 2345 | "%pM\n", bss->cbss.bssid, ifsta->bssid); |
2292 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2346 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2293 | 2347 | ||
2294 | if (found && | 2348 | if (bss && |
2295 | ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) || | 2349 | (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) || |
2296 | memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0)) { | 2350 | memcmp(ifsta->bssid, bss->cbss.bssid, ETH_ALEN))) { |
2297 | int ret; | 2351 | int ret; |
2298 | int search_freq; | ||
2299 | |||
2300 | if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) | ||
2301 | search_freq = bss->freq; | ||
2302 | else | ||
2303 | search_freq = local->hw.conf.channel->center_freq; | ||
2304 | |||
2305 | bss = ieee80211_rx_bss_get(local, bssid, search_freq, | ||
2306 | ifsta->ssid, ifsta->ssid_len); | ||
2307 | if (!bss) | ||
2308 | goto dont_join; | ||
2309 | 2352 | ||
2310 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | 2353 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" |
2311 | " based on configured SSID\n", | 2354 | " based on configured SSID\n", |
2312 | sdata->dev->name, bssid); | 2355 | sdata->dev->name, bss->cbss.bssid); |
2356 | |||
2313 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); | 2357 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); |
2314 | ieee80211_rx_bss_put(local, bss); | 2358 | ieee80211_rx_bss_put(local, bss); |
2315 | return ret; | 2359 | return ret; |
2316 | } | 2360 | } else if (bss) |
2361 | ieee80211_rx_bss_put(local, bss); | ||
2317 | 2362 | ||
2318 | dont_join: | ||
2319 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 2363 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
2320 | printk(KERN_DEBUG " did not try to join ibss\n"); | 2364 | printk(KERN_DEBUG " did not try to join ibss\n"); |
2321 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2365 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
@@ -2329,8 +2373,15 @@ dont_join: | |||
2329 | IEEE80211_SCAN_INTERVAL)) { | 2373 | IEEE80211_SCAN_INTERVAL)) { |
2330 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | 2374 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " |
2331 | "join\n", sdata->dev->name); | 2375 | "join\n", sdata->dev->name); |
2332 | return ieee80211_request_scan(sdata, ifsta->ssid, | 2376 | |
2333 | ifsta->ssid_len); | 2377 | /* XXX maybe racy? */ |
2378 | if (local->scan_req) | ||
2379 | return -EBUSY; | ||
2380 | |||
2381 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
2382 | ifsta->ssid, IEEE80211_MAX_SSID_LEN); | ||
2383 | local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len; | ||
2384 | return ieee80211_request_scan(sdata, &local->int_scan_req); | ||
2334 | } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) { | 2385 | } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) { |
2335 | int interval = IEEE80211_SCAN_INTERVAL; | 2386 | int interval = IEEE80211_SCAN_INTERVAL; |
2336 | 2387 | ||
@@ -2364,50 +2415,44 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2364 | struct ieee80211_if_sta *ifsta) | 2415 | struct ieee80211_if_sta *ifsta) |
2365 | { | 2416 | { |
2366 | struct ieee80211_local *local = sdata->local; | 2417 | struct ieee80211_local *local = sdata->local; |
2367 | struct ieee80211_bss *bss, *selected = NULL; | 2418 | struct ieee80211_bss *bss; |
2368 | int top_rssi = 0, freq; | 2419 | u8 *bssid = ifsta->bssid, *ssid = ifsta->ssid; |
2369 | 2420 | u8 ssid_len = ifsta->ssid_len; | |
2370 | spin_lock_bh(&local->bss_lock); | 2421 | u16 capa_mask = WLAN_CAPABILITY_ESS; |
2371 | freq = local->oper_channel->center_freq; | 2422 | u16 capa_val = WLAN_CAPABILITY_ESS; |
2372 | list_for_each_entry(bss, &local->bss_list, list) { | 2423 | struct ieee80211_channel *chan = local->oper_channel; |
2373 | if (!(bss->capability & WLAN_CAPABILITY_ESS)) | 2424 | |
2374 | continue; | 2425 | if (ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | |
2375 | 2426 | IEEE80211_STA_AUTO_BSSID_SEL | | |
2376 | if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | 2427 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { |
2377 | IEEE80211_STA_AUTO_BSSID_SEL | | 2428 | capa_mask |= WLAN_CAPABILITY_PRIVACY; |
2378 | IEEE80211_STA_AUTO_CHANNEL_SEL)) && | 2429 | if (sdata->default_key) |
2379 | (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ | 2430 | capa_val |= WLAN_CAPABILITY_PRIVACY; |
2380 | !!sdata->default_key)) | 2431 | } |
2381 | continue; | 2432 | |
2382 | 2433 | if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) | |
2383 | if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && | 2434 | chan = NULL; |
2384 | bss->freq != freq) | 2435 | |
2385 | continue; | 2436 | if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) |
2386 | 2437 | bssid = NULL; | |
2387 | if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && | 2438 | |
2388 | memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) | 2439 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) { |
2389 | continue; | 2440 | ssid = NULL; |
2390 | 2441 | ssid_len = 0; | |
2391 | if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && | ||
2392 | !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) | ||
2393 | continue; | ||
2394 | |||
2395 | if (!selected || top_rssi < bss->signal) { | ||
2396 | selected = bss; | ||
2397 | top_rssi = bss->signal; | ||
2398 | } | ||
2399 | } | 2442 | } |
2400 | if (selected) | ||
2401 | atomic_inc(&selected->users); | ||
2402 | spin_unlock_bh(&local->bss_lock); | ||
2403 | 2443 | ||
2404 | if (selected) { | 2444 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, |
2405 | ieee80211_set_freq(sdata, selected->freq); | 2445 | bssid, ssid, ssid_len, |
2446 | capa_mask, capa_val); | ||
2447 | |||
2448 | if (bss) { | ||
2449 | ieee80211_set_freq(sdata, bss->cbss.channel->center_freq); | ||
2406 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | 2450 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) |
2407 | ieee80211_sta_set_ssid(sdata, selected->ssid, | 2451 | ieee80211_sta_set_ssid(sdata, bss->ssid, |
2408 | selected->ssid_len); | 2452 | bss->ssid_len); |
2409 | ieee80211_sta_set_bssid(sdata, selected->bssid); | 2453 | ieee80211_sta_set_bssid(sdata, bss->cbss.bssid); |
2410 | ieee80211_sta_def_wmm_params(sdata, selected); | 2454 | ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, |
2455 | bss->supp_rates); | ||
2411 | if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED) | 2456 | if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED) |
2412 | sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED; | 2457 | sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED; |
2413 | else | 2458 | else |
@@ -2416,24 +2461,29 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2416 | /* Send out direct probe if no probe resp was received or | 2461 | /* Send out direct probe if no probe resp was received or |
2417 | * the one we have is outdated | 2462 | * the one we have is outdated |
2418 | */ | 2463 | */ |
2419 | if (!selected->last_probe_resp || | 2464 | if (!bss->last_probe_resp || |
2420 | time_after(jiffies, selected->last_probe_resp | 2465 | time_after(jiffies, bss->last_probe_resp |
2421 | + IEEE80211_SCAN_RESULT_EXPIRE)) | 2466 | + IEEE80211_SCAN_RESULT_EXPIRE)) |
2422 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 2467 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
2423 | else | 2468 | else |
2424 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 2469 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2425 | 2470 | ||
2426 | ieee80211_rx_bss_put(local, selected); | 2471 | ieee80211_rx_bss_put(local, bss); |
2427 | ieee80211_sta_reset_auth(sdata, ifsta); | 2472 | ieee80211_sta_reset_auth(sdata, ifsta); |
2428 | return 0; | 2473 | return 0; |
2429 | } else { | 2474 | } else { |
2430 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | 2475 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { |
2431 | ifsta->assoc_scan_tries++; | 2476 | ifsta->assoc_scan_tries++; |
2477 | /* XXX maybe racy? */ | ||
2478 | if (local->scan_req) | ||
2479 | return -1; | ||
2480 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
2481 | ifsta->ssid, IEEE80211_MAX_SSID_LEN); | ||
2432 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | 2482 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) |
2433 | ieee80211_start_scan(sdata, NULL, 0); | 2483 | local->int_scan_req.ssids[0].ssid_len = 0; |
2434 | else | 2484 | else |
2435 | ieee80211_start_scan(sdata, ifsta->ssid, | 2485 | local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len; |
2436 | ifsta->ssid_len); | 2486 | ieee80211_start_scan(sdata, &local->int_scan_req); |
2437 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 2487 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2438 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 2488 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); |
2439 | } else { | 2489 | } else { |
@@ -2471,8 +2521,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2471 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 2521 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && |
2472 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | 2522 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && |
2473 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | 2523 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { |
2474 | ieee80211_start_scan(sdata, ifsta->scan_ssid, | 2524 | ieee80211_start_scan(sdata, local->scan_req); |
2475 | ifsta->scan_ssid_len); | ||
2476 | return; | 2525 | return; |
2477 | } | 2526 | } |
2478 | 2527 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8e8ddbfcd236..1327d424bf31 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -731,6 +731,39 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
731 | return result; | 731 | return result; |
732 | } | 732 | } |
733 | 733 | ||
734 | static ieee80211_rx_result debug_noinline | ||
735 | ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx) | ||
736 | { | ||
737 | struct ieee80211_local *local; | ||
738 | struct ieee80211_hdr *hdr; | ||
739 | struct sk_buff *skb; | ||
740 | |||
741 | local = rx->local; | ||
742 | skb = rx->skb; | ||
743 | hdr = (struct ieee80211_hdr *) skb->data; | ||
744 | |||
745 | if (!local->pspolling) | ||
746 | return RX_CONTINUE; | ||
747 | |||
748 | if (!ieee80211_has_fromds(hdr->frame_control)) | ||
749 | /* this is not from AP */ | ||
750 | return RX_CONTINUE; | ||
751 | |||
752 | if (!ieee80211_is_data(hdr->frame_control)) | ||
753 | return RX_CONTINUE; | ||
754 | |||
755 | if (!ieee80211_has_moredata(hdr->frame_control)) { | ||
756 | /* AP has no more frames buffered for us */ | ||
757 | local->pspolling = false; | ||
758 | return RX_CONTINUE; | ||
759 | } | ||
760 | |||
761 | /* more data bit is set, let's request a new frame from the AP */ | ||
762 | ieee80211_send_pspoll(local, rx->sdata); | ||
763 | |||
764 | return RX_CONTINUE; | ||
765 | } | ||
766 | |||
734 | static void ap_sta_ps_start(struct sta_info *sta) | 767 | static void ap_sta_ps_start(struct sta_info *sta) |
735 | { | 768 | { |
736 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 769 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -1640,11 +1673,9 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) | |||
1640 | start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; | 1673 | start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; |
1641 | 1674 | ||
1642 | /* reset session timer */ | 1675 | /* reset session timer */ |
1643 | if (tid_agg_rx->timeout) { | 1676 | if (tid_agg_rx->timeout) |
1644 | unsigned long expires = | 1677 | mod_timer(&tid_agg_rx->session_timer, |
1645 | jiffies + (tid_agg_rx->timeout / 1000) * HZ; | 1678 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); |
1646 | mod_timer(&tid_agg_rx->session_timer, expires); | ||
1647 | } | ||
1648 | 1679 | ||
1649 | /* manage reordering buffer according to requested */ | 1680 | /* manage reordering buffer according to requested */ |
1650 | /* sequence number */ | 1681 | /* sequence number */ |
@@ -1737,6 +1768,17 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1737 | 1768 | ||
1738 | switch (mgmt->u.action.category) { | 1769 | switch (mgmt->u.action.category) { |
1739 | case WLAN_CATEGORY_BACK: | 1770 | case WLAN_CATEGORY_BACK: |
1771 | /* | ||
1772 | * The aggregation code is not prepared to handle | ||
1773 | * anything but STA/AP due to the BSSID handling; | ||
1774 | * IBSS could work in the code but isn't supported | ||
1775 | * by drivers or the standard. | ||
1776 | */ | ||
1777 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
1778 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
1779 | sdata->vif.type != NL80211_IFTYPE_AP) | ||
1780 | return RX_DROP_MONITOR; | ||
1781 | |||
1740 | switch (mgmt->u.action.u.addba_req.action_code) { | 1782 | switch (mgmt->u.action.u.addba_req.action_code) { |
1741 | case WLAN_ACTION_ADDBA_REQ: | 1783 | case WLAN_ACTION_ADDBA_REQ: |
1742 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1784 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
@@ -1987,6 +2029,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
1987 | CALL_RXH(ieee80211_rx_h_passive_scan) | 2029 | CALL_RXH(ieee80211_rx_h_passive_scan) |
1988 | CALL_RXH(ieee80211_rx_h_check) | 2030 | CALL_RXH(ieee80211_rx_h_check) |
1989 | CALL_RXH(ieee80211_rx_h_decrypt) | 2031 | CALL_RXH(ieee80211_rx_h_decrypt) |
2032 | CALL_RXH(ieee80211_rx_h_check_more_data) | ||
1990 | CALL_RXH(ieee80211_rx_h_sta_process) | 2033 | CALL_RXH(ieee80211_rx_h_sta_process) |
1991 | CALL_RXH(ieee80211_rx_h_defragment) | 2034 | CALL_RXH(ieee80211_rx_h_defragment) |
1992 | CALL_RXH(ieee80211_rx_h_ps_poll) | 2035 | CALL_RXH(ieee80211_rx_h_ps_poll) |
@@ -2030,9 +2073,10 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, | |||
2030 | /* main receive path */ | 2073 | /* main receive path */ |
2031 | 2074 | ||
2032 | static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | 2075 | static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, |
2033 | u8 *bssid, struct ieee80211_rx_data *rx, | 2076 | struct ieee80211_rx_data *rx, |
2034 | struct ieee80211_hdr *hdr) | 2077 | struct ieee80211_hdr *hdr) |
2035 | { | 2078 | { |
2079 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type); | ||
2036 | int multicast = is_multicast_ether_addr(hdr->addr1); | 2080 | int multicast = is_multicast_ether_addr(hdr->addr1); |
2037 | 2081 | ||
2038 | switch (sdata->vif.type) { | 2082 | switch (sdata->vif.type) { |
@@ -2135,7 +2179,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2135 | int prepares; | 2179 | int prepares; |
2136 | struct ieee80211_sub_if_data *prev = NULL; | 2180 | struct ieee80211_sub_if_data *prev = NULL; |
2137 | struct sk_buff *skb_new; | 2181 | struct sk_buff *skb_new; |
2138 | u8 *bssid; | ||
2139 | 2182 | ||
2140 | hdr = (struct ieee80211_hdr *)skb->data; | 2183 | hdr = (struct ieee80211_hdr *)skb->data; |
2141 | memset(&rx, 0, sizeof(rx)); | 2184 | memset(&rx, 0, sizeof(rx)); |
@@ -2174,9 +2217,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2174 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) | 2217 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) |
2175 | continue; | 2218 | continue; |
2176 | 2219 | ||
2177 | bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); | ||
2178 | rx.flags |= IEEE80211_RX_RA_MATCH; | 2220 | rx.flags |= IEEE80211_RX_RA_MATCH; |
2179 | prepares = prepare_for_handlers(sdata, bssid, &rx, hdr); | 2221 | prepares = prepare_for_handlers(sdata, &rx, hdr); |
2180 | 2222 | ||
2181 | if (!prepares) | 2223 | if (!prepares) |
2182 | continue; | 2224 | continue; |
@@ -2381,11 +2423,9 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2381 | /* new un-ordered ampdu frame - process it */ | 2423 | /* new un-ordered ampdu frame - process it */ |
2382 | 2424 | ||
2383 | /* reset session timer */ | 2425 | /* reset session timer */ |
2384 | if (tid_agg_rx->timeout) { | 2426 | if (tid_agg_rx->timeout) |
2385 | unsigned long expires = | 2427 | mod_timer(&tid_agg_rx->session_timer, |
2386 | jiffies + (tid_agg_rx->timeout / 1000) * HZ; | 2428 | TU_TO_EXP_TIME(tid_agg_rx->timeout)); |
2387 | mod_timer(&tid_agg_rx->session_timer, expires); | ||
2388 | } | ||
2389 | 2429 | ||
2390 | /* if this mpdu is fragmented - terminate rx aggregation session */ | 2430 | /* if this mpdu is fragmented - terminate rx aggregation session */ |
2391 | sc = le16_to_cpu(hdr->seq_ctrl); | 2431 | sc = le16_to_cpu(hdr->seq_ctrl); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 282e6a0dec01..f883ab9f1e6e 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -12,11 +12,7 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | /* TODO: | 15 | /* TODO: figure out how to avoid that the "current BSS" expires */ |
16 | * order BSS list by RSSI(?) ("quality of AP") | ||
17 | * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, | ||
18 | * SSID) | ||
19 | */ | ||
20 | 16 | ||
21 | #include <linux/wireless.h> | 17 | #include <linux/wireless.h> |
22 | #include <linux/if_arp.h> | 18 | #include <linux/if_arp.h> |
@@ -31,192 +27,29 @@ | |||
31 | #define IEEE80211_CHANNEL_TIME (HZ / 33) | 27 | #define IEEE80211_CHANNEL_TIME (HZ / 33) |
32 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) | 28 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) |
33 | 29 | ||
34 | void ieee80211_rx_bss_list_init(struct ieee80211_local *local) | ||
35 | { | ||
36 | spin_lock_init(&local->bss_lock); | ||
37 | INIT_LIST_HEAD(&local->bss_list); | ||
38 | } | ||
39 | |||
40 | void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local) | ||
41 | { | ||
42 | struct ieee80211_bss *bss, *tmp; | ||
43 | |||
44 | list_for_each_entry_safe(bss, tmp, &local->bss_list, list) | ||
45 | ieee80211_rx_bss_put(local, bss); | ||
46 | } | ||
47 | |||
48 | struct ieee80211_bss * | 30 | struct ieee80211_bss * |
49 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | 31 | ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, |
50 | u8 *ssid, u8 ssid_len) | 32 | u8 *ssid, u8 ssid_len) |
51 | { | 33 | { |
52 | struct ieee80211_bss *bss; | 34 | return (void *)cfg80211_get_bss(local->hw.wiphy, |
53 | 35 | ieee80211_get_channel(local->hw.wiphy, | |
54 | spin_lock_bh(&local->bss_lock); | 36 | freq), |
55 | bss = local->bss_hash[STA_HASH(bssid)]; | 37 | bssid, ssid, ssid_len, |
56 | while (bss) { | 38 | 0, 0); |
57 | if (!bss_mesh_cfg(bss) && | ||
58 | !memcmp(bss->bssid, bssid, ETH_ALEN) && | ||
59 | bss->freq == freq && | ||
60 | bss->ssid_len == ssid_len && | ||
61 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { | ||
62 | atomic_inc(&bss->users); | ||
63 | break; | ||
64 | } | ||
65 | bss = bss->hnext; | ||
66 | } | ||
67 | spin_unlock_bh(&local->bss_lock); | ||
68 | return bss; | ||
69 | } | ||
70 | |||
71 | /* Caller must hold local->bss_lock */ | ||
72 | static void __ieee80211_rx_bss_hash_add(struct ieee80211_local *local, | ||
73 | struct ieee80211_bss *bss) | ||
74 | { | ||
75 | u8 hash_idx; | ||
76 | |||
77 | if (bss_mesh_cfg(bss)) | ||
78 | hash_idx = mesh_id_hash(bss_mesh_id(bss), | ||
79 | bss_mesh_id_len(bss)); | ||
80 | else | ||
81 | hash_idx = STA_HASH(bss->bssid); | ||
82 | |||
83 | bss->hnext = local->bss_hash[hash_idx]; | ||
84 | local->bss_hash[hash_idx] = bss; | ||
85 | } | ||
86 | |||
87 | /* Caller must hold local->bss_lock */ | ||
88 | static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local, | ||
89 | struct ieee80211_bss *bss) | ||
90 | { | ||
91 | struct ieee80211_bss *b, *prev = NULL; | ||
92 | b = local->bss_hash[STA_HASH(bss->bssid)]; | ||
93 | while (b) { | ||
94 | if (b == bss) { | ||
95 | if (!prev) | ||
96 | local->bss_hash[STA_HASH(bss->bssid)] = | ||
97 | bss->hnext; | ||
98 | else | ||
99 | prev->hnext = bss->hnext; | ||
100 | break; | ||
101 | } | ||
102 | prev = b; | ||
103 | b = b->hnext; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | struct ieee80211_bss * | ||
108 | ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, | ||
109 | u8 *ssid, u8 ssid_len) | ||
110 | { | ||
111 | struct ieee80211_bss *bss; | ||
112 | |||
113 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
114 | if (!bss) | ||
115 | return NULL; | ||
116 | atomic_set(&bss->users, 2); | ||
117 | memcpy(bss->bssid, bssid, ETH_ALEN); | ||
118 | bss->freq = freq; | ||
119 | if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { | ||
120 | memcpy(bss->ssid, ssid, ssid_len); | ||
121 | bss->ssid_len = ssid_len; | ||
122 | } | ||
123 | |||
124 | spin_lock_bh(&local->bss_lock); | ||
125 | /* TODO: order by RSSI? */ | ||
126 | list_add_tail(&bss->list, &local->bss_list); | ||
127 | __ieee80211_rx_bss_hash_add(local, bss); | ||
128 | spin_unlock_bh(&local->bss_lock); | ||
129 | return bss; | ||
130 | } | ||
131 | |||
132 | #ifdef CONFIG_MAC80211_MESH | ||
133 | static struct ieee80211_bss * | ||
134 | ieee80211_rx_mesh_bss_get(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
135 | u8 *mesh_cfg, int freq) | ||
136 | { | ||
137 | struct ieee80211_bss *bss; | ||
138 | |||
139 | spin_lock_bh(&local->bss_lock); | ||
140 | bss = local->bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; | ||
141 | while (bss) { | ||
142 | if (bss_mesh_cfg(bss) && | ||
143 | !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && | ||
144 | bss->freq == freq && | ||
145 | mesh_id_len == bss->mesh_id_len && | ||
146 | (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, | ||
147 | mesh_id_len))) { | ||
148 | atomic_inc(&bss->users); | ||
149 | break; | ||
150 | } | ||
151 | bss = bss->hnext; | ||
152 | } | ||
153 | spin_unlock_bh(&local->bss_lock); | ||
154 | return bss; | ||
155 | } | 39 | } |
156 | 40 | ||
157 | static struct ieee80211_bss * | 41 | static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) |
158 | ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_id_len, | ||
159 | u8 *mesh_cfg, int mesh_config_len, int freq) | ||
160 | { | 42 | { |
161 | struct ieee80211_bss *bss; | 43 | struct ieee80211_bss *bss = (void *)cbss; |
162 | 44 | ||
163 | if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN) | ||
164 | return NULL; | ||
165 | |||
166 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
167 | if (!bss) | ||
168 | return NULL; | ||
169 | |||
170 | bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); | ||
171 | if (!bss->mesh_cfg) { | ||
172 | kfree(bss); | ||
173 | return NULL; | ||
174 | } | ||
175 | |||
176 | if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { | ||
177 | bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); | ||
178 | if (!bss->mesh_id) { | ||
179 | kfree(bss->mesh_cfg); | ||
180 | kfree(bss); | ||
181 | return NULL; | ||
182 | } | ||
183 | memcpy(bss->mesh_id, mesh_id, mesh_id_len); | ||
184 | } | ||
185 | |||
186 | atomic_set(&bss->users, 2); | ||
187 | memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); | ||
188 | bss->mesh_id_len = mesh_id_len; | ||
189 | bss->freq = freq; | ||
190 | spin_lock_bh(&local->bss_lock); | ||
191 | /* TODO: order by RSSI? */ | ||
192 | list_add_tail(&bss->list, &local->bss_list); | ||
193 | __ieee80211_rx_bss_hash_add(local, bss); | ||
194 | spin_unlock_bh(&local->bss_lock); | ||
195 | return bss; | ||
196 | } | ||
197 | #endif | ||
198 | |||
199 | static void ieee80211_rx_bss_free(struct ieee80211_bss *bss) | ||
200 | { | ||
201 | kfree(bss->ies); | ||
202 | kfree(bss_mesh_id(bss)); | 45 | kfree(bss_mesh_id(bss)); |
203 | kfree(bss_mesh_cfg(bss)); | 46 | kfree(bss_mesh_cfg(bss)); |
204 | kfree(bss); | ||
205 | } | 47 | } |
206 | 48 | ||
207 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 49 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
208 | struct ieee80211_bss *bss) | 50 | struct ieee80211_bss *bss) |
209 | { | 51 | { |
210 | local_bh_disable(); | 52 | cfg80211_put_bss((struct cfg80211_bss *)bss); |
211 | if (!atomic_dec_and_lock(&bss->users, &local->bss_lock)) { | ||
212 | local_bh_enable(); | ||
213 | return; | ||
214 | } | ||
215 | |||
216 | __ieee80211_rx_bss_hash_del(local, bss); | ||
217 | list_del(&bss->list); | ||
218 | spin_unlock_bh(&local->bss_lock); | ||
219 | ieee80211_rx_bss_free(bss); | ||
220 | } | 53 | } |
221 | 54 | ||
222 | struct ieee80211_bss * | 55 | struct ieee80211_bss * |
@@ -225,49 +58,37 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
225 | struct ieee80211_mgmt *mgmt, | 58 | struct ieee80211_mgmt *mgmt, |
226 | size_t len, | 59 | size_t len, |
227 | struct ieee802_11_elems *elems, | 60 | struct ieee802_11_elems *elems, |
228 | int freq, bool beacon) | 61 | struct ieee80211_channel *channel, |
62 | bool beacon) | ||
229 | { | 63 | { |
230 | struct ieee80211_bss *bss; | 64 | struct ieee80211_bss *bss; |
231 | int clen; | 65 | int clen; |
232 | 66 | enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE; | |
233 | #ifdef CONFIG_MAC80211_MESH | 67 | s32 signal = 0; |
234 | if (elems->mesh_config) | 68 | |
235 | bss = ieee80211_rx_mesh_bss_get(local, elems->mesh_id, | 69 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { |
236 | elems->mesh_id_len, elems->mesh_config, freq); | 70 | sigtype = CFG80211_SIGNAL_TYPE_MBM; |
237 | else | 71 | signal = rx_status->signal * 100; |
238 | #endif | 72 | } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) { |
239 | bss = ieee80211_rx_bss_get(local, mgmt->bssid, freq, | 73 | sigtype = CFG80211_SIGNAL_TYPE_UNSPEC; |
240 | elems->ssid, elems->ssid_len); | 74 | signal = (rx_status->signal * 100) / local->hw.max_signal; |
241 | if (!bss) { | ||
242 | #ifdef CONFIG_MAC80211_MESH | ||
243 | if (elems->mesh_config) | ||
244 | bss = ieee80211_rx_mesh_bss_add(local, elems->mesh_id, | ||
245 | elems->mesh_id_len, elems->mesh_config, | ||
246 | elems->mesh_config_len, freq); | ||
247 | else | ||
248 | #endif | ||
249 | bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq, | ||
250 | elems->ssid, elems->ssid_len); | ||
251 | if (!bss) | ||
252 | return NULL; | ||
253 | } else { | ||
254 | #if 0 | ||
255 | /* TODO: order by RSSI? */ | ||
256 | spin_lock_bh(&local->bss_lock); | ||
257 | list_move_tail(&bss->list, &local->bss_list); | ||
258 | spin_unlock_bh(&local->bss_lock); | ||
259 | #endif | ||
260 | } | 75 | } |
261 | 76 | ||
77 | bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, | ||
78 | mgmt, len, signal, sigtype, | ||
79 | GFP_ATOMIC); | ||
80 | |||
81 | if (!bss) | ||
82 | return NULL; | ||
83 | |||
84 | bss->cbss.free_priv = ieee80211_rx_bss_free; | ||
85 | |||
262 | /* save the ERP value so that it is available at association time */ | 86 | /* save the ERP value so that it is available at association time */ |
263 | if (elems->erp_info && elems->erp_info_len >= 1) { | 87 | if (elems->erp_info && elems->erp_info_len >= 1) { |
264 | bss->erp_value = elems->erp_info[0]; | 88 | bss->erp_value = elems->erp_info[0]; |
265 | bss->has_erp_value = 1; | 89 | bss->has_erp_value = 1; |
266 | } | 90 | } |
267 | 91 | ||
268 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); | ||
269 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); | ||
270 | |||
271 | if (elems->tim) { | 92 | if (elems->tim) { |
272 | struct ieee80211_tim_ie *tim_ie = | 93 | struct ieee80211_tim_ie *tim_ie = |
273 | (struct ieee80211_tim_ie *)elems->tim; | 94 | (struct ieee80211_tim_ie *)elems->tim; |
@@ -296,37 +117,27 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
296 | bss->supp_rates_len += clen; | 117 | bss->supp_rates_len += clen; |
297 | } | 118 | } |
298 | 119 | ||
299 | bss->band = rx_status->band; | ||
300 | |||
301 | bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); | ||
302 | bss->last_update = jiffies; | ||
303 | bss->signal = rx_status->signal; | ||
304 | bss->noise = rx_status->noise; | ||
305 | bss->qual = rx_status->qual; | ||
306 | bss->wmm_used = elems->wmm_param || elems->wmm_info; | 120 | bss->wmm_used = elems->wmm_param || elems->wmm_info; |
307 | 121 | ||
308 | if (!beacon) | 122 | if (!beacon) |
309 | bss->last_probe_resp = jiffies; | 123 | bss->last_probe_resp = jiffies; |
310 | 124 | ||
311 | /* | ||
312 | * For probe responses, or if we don't have any information yet, | ||
313 | * use the IEs from the beacon. | ||
314 | */ | ||
315 | if (!bss->ies || !beacon) { | ||
316 | if (bss->ies == NULL || bss->ies_len < elems->total_len) { | ||
317 | kfree(bss->ies); | ||
318 | bss->ies = kmalloc(elems->total_len, GFP_ATOMIC); | ||
319 | } | ||
320 | if (bss->ies) { | ||
321 | memcpy(bss->ies, elems->ie_start, elems->total_len); | ||
322 | bss->ies_len = elems->total_len; | ||
323 | } else | ||
324 | bss->ies_len = 0; | ||
325 | } | ||
326 | |||
327 | return bss; | 125 | return bss; |
328 | } | 126 | } |
329 | 127 | ||
128 | void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, | ||
129 | int freq, u8 *ssid, u8 ssid_len) | ||
130 | { | ||
131 | struct ieee80211_bss *bss; | ||
132 | struct ieee80211_local *local = sdata->local; | ||
133 | |||
134 | bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len); | ||
135 | if (bss) { | ||
136 | cfg80211_unlink_bss(local->hw.wiphy, (void *)bss); | ||
137 | ieee80211_rx_bss_put(local, bss); | ||
138 | } | ||
139 | } | ||
140 | |||
330 | ieee80211_rx_result | 141 | ieee80211_rx_result |
331 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 142 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
332 | struct ieee80211_rx_status *rx_status) | 143 | struct ieee80211_rx_status *rx_status) |
@@ -388,7 +199,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
388 | 199 | ||
389 | bss = ieee80211_bss_info_update(sdata->local, rx_status, | 200 | bss = ieee80211_bss_info_update(sdata->local, rx_status, |
390 | mgmt, skb->len, &elems, | 201 | mgmt, skb->len, &elems, |
391 | freq, beacon); | 202 | channel, beacon); |
392 | if (bss) | 203 | if (bss) |
393 | ieee80211_rx_bss_put(sdata->local, bss); | 204 | ieee80211_rx_bss_put(sdata->local, bss); |
394 | 205 | ||
@@ -426,26 +237,22 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
426 | ieee80211_tx_skb(sdata, skb, 0); | 237 | ieee80211_tx_skb(sdata, skb, 0); |
427 | } | 238 | } |
428 | 239 | ||
429 | void ieee80211_scan_completed(struct ieee80211_hw *hw) | 240 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
430 | { | 241 | { |
431 | struct ieee80211_local *local = hw_to_local(hw); | 242 | struct ieee80211_local *local = hw_to_local(hw); |
432 | struct ieee80211_sub_if_data *sdata; | 243 | struct ieee80211_sub_if_data *sdata; |
433 | union iwreq_data wrqu; | ||
434 | 244 | ||
435 | if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) | 245 | if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) |
436 | return; | 246 | return; |
437 | 247 | ||
438 | local->last_scan_completed = jiffies; | 248 | if (WARN_ON(!local->scan_req)) |
439 | memset(&wrqu, 0, sizeof(wrqu)); | 249 | return; |
440 | 250 | ||
441 | /* | 251 | if (local->scan_req != &local->int_scan_req) |
442 | * local->scan_sdata could have been NULLed by the interface | 252 | cfg80211_scan_done(local->scan_req, aborted); |
443 | * down code in case we were scanning on an interface that is | 253 | local->scan_req = NULL; |
444 | * being taken down. | 254 | |
445 | */ | 255 | local->last_scan_completed = jiffies; |
446 | sdata = local->scan_sdata; | ||
447 | if (sdata) | ||
448 | wireless_send_event(sdata->dev, SIOCGIWSCAN, &wrqu, NULL); | ||
449 | 256 | ||
450 | if (local->hw_scanning) { | 257 | if (local->hw_scanning) { |
451 | local->hw_scanning = false; | 258 | local->hw_scanning = false; |
@@ -487,7 +294,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
487 | } else | 294 | } else |
488 | netif_tx_wake_all_queues(sdata->dev); | 295 | netif_tx_wake_all_queues(sdata->dev); |
489 | 296 | ||
490 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); | 297 | /* re-enable beaconing */ |
298 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
299 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||
300 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||
301 | ieee80211_if_config(sdata, | ||
302 | IEEE80211_IFCC_BEACON_ENABLED); | ||
491 | } | 303 | } |
492 | mutex_unlock(&local->iflist_mtx); | 304 | mutex_unlock(&local->iflist_mtx); |
493 | 305 | ||
@@ -502,9 +314,8 @@ void ieee80211_scan_work(struct work_struct *work) | |||
502 | struct ieee80211_local *local = | 314 | struct ieee80211_local *local = |
503 | container_of(work, struct ieee80211_local, scan_work.work); | 315 | container_of(work, struct ieee80211_local, scan_work.work); |
504 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 316 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
505 | struct ieee80211_supported_band *sband; | ||
506 | struct ieee80211_channel *chan; | 317 | struct ieee80211_channel *chan; |
507 | int skip; | 318 | int skip, i; |
508 | unsigned long next_delay = 0; | 319 | unsigned long next_delay = 0; |
509 | 320 | ||
510 | /* | 321 | /* |
@@ -515,33 +326,13 @@ void ieee80211_scan_work(struct work_struct *work) | |||
515 | 326 | ||
516 | switch (local->scan_state) { | 327 | switch (local->scan_state) { |
517 | case SCAN_SET_CHANNEL: | 328 | case SCAN_SET_CHANNEL: |
518 | /* | ||
519 | * Get current scan band. scan_band may be IEEE80211_NUM_BANDS | ||
520 | * after we successfully scanned the last channel of the last | ||
521 | * band (and the last band is supported by the hw) | ||
522 | */ | ||
523 | if (local->scan_band < IEEE80211_NUM_BANDS) | ||
524 | sband = local->hw.wiphy->bands[local->scan_band]; | ||
525 | else | ||
526 | sband = NULL; | ||
527 | |||
528 | /* | ||
529 | * If we are at an unsupported band and have more bands | ||
530 | * left to scan, advance to the next supported one. | ||
531 | */ | ||
532 | while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { | ||
533 | local->scan_band++; | ||
534 | sband = local->hw.wiphy->bands[local->scan_band]; | ||
535 | local->scan_channel_idx = 0; | ||
536 | } | ||
537 | |||
538 | /* if no more bands/channels left, complete scan */ | 329 | /* if no more bands/channels left, complete scan */ |
539 | if (!sband || local->scan_channel_idx >= sband->n_channels) { | 330 | if (local->scan_channel_idx >= local->scan_req->n_channels) { |
540 | ieee80211_scan_completed(local_to_hw(local)); | 331 | ieee80211_scan_completed(local_to_hw(local), false); |
541 | return; | 332 | return; |
542 | } | 333 | } |
543 | skip = 0; | 334 | skip = 0; |
544 | chan = &sband->channels[local->scan_channel_idx]; | 335 | chan = local->scan_req->channels[local->scan_channel_idx]; |
545 | 336 | ||
546 | if (chan->flags & IEEE80211_CHAN_DISABLED || | 337 | if (chan->flags & IEEE80211_CHAN_DISABLED || |
547 | (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 338 | (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
@@ -557,15 +348,6 @@ void ieee80211_scan_work(struct work_struct *work) | |||
557 | 348 | ||
558 | /* advance state machine to next channel/band */ | 349 | /* advance state machine to next channel/band */ |
559 | local->scan_channel_idx++; | 350 | local->scan_channel_idx++; |
560 | if (local->scan_channel_idx >= sband->n_channels) { | ||
561 | /* | ||
562 | * scan_band may end up == IEEE80211_NUM_BANDS, but | ||
563 | * we'll catch that case above and complete the scan | ||
564 | * if that is the case. | ||
565 | */ | ||
566 | local->scan_band++; | ||
567 | local->scan_channel_idx = 0; | ||
568 | } | ||
569 | 351 | ||
570 | if (skip) | 352 | if (skip) |
571 | break; | 353 | break; |
@@ -578,10 +360,14 @@ void ieee80211_scan_work(struct work_struct *work) | |||
578 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 360 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
579 | local->scan_state = SCAN_SET_CHANNEL; | 361 | local->scan_state = SCAN_SET_CHANNEL; |
580 | 362 | ||
581 | if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 363 | if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN || |
364 | !local->scan_req->n_ssids) | ||
582 | break; | 365 | break; |
583 | ieee80211_send_probe_req(sdata, NULL, local->scan_ssid, | 366 | for (i = 0; i < local->scan_req->n_ssids; i++) |
584 | local->scan_ssid_len); | 367 | ieee80211_send_probe_req( |
368 | sdata, NULL, | ||
369 | local->scan_req->ssids[i].ssid, | ||
370 | local->scan_req->ssids[i].ssid_len); | ||
585 | next_delay = IEEE80211_CHANNEL_TIME; | 371 | next_delay = IEEE80211_CHANNEL_TIME; |
586 | break; | 372 | break; |
587 | } | 373 | } |
@@ -592,14 +378,19 @@ void ieee80211_scan_work(struct work_struct *work) | |||
592 | 378 | ||
593 | 379 | ||
594 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | 380 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, |
595 | u8 *ssid, size_t ssid_len) | 381 | struct cfg80211_scan_request *req) |
596 | { | 382 | { |
597 | struct ieee80211_local *local = scan_sdata->local; | 383 | struct ieee80211_local *local = scan_sdata->local; |
598 | struct ieee80211_sub_if_data *sdata; | 384 | struct ieee80211_sub_if_data *sdata; |
599 | 385 | ||
600 | if (ssid_len > IEEE80211_MAX_SSID_LEN) | 386 | if (!req) |
601 | return -EINVAL; | 387 | return -EINVAL; |
602 | 388 | ||
389 | if (local->scan_req && local->scan_req != req) | ||
390 | return -EBUSY; | ||
391 | |||
392 | local->scan_req = req; | ||
393 | |||
603 | /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) | 394 | /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) |
604 | * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS | 395 | * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS |
605 | * BSSID: MACAddress | 396 | * BSSID: MACAddress |
@@ -627,7 +418,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
627 | int rc; | 418 | int rc; |
628 | 419 | ||
629 | local->hw_scanning = true; | 420 | local->hw_scanning = true; |
630 | rc = local->ops->hw_scan(local_to_hw(local), ssid, ssid_len); | 421 | rc = local->ops->hw_scan(local_to_hw(local), req); |
631 | if (rc) { | 422 | if (rc) { |
632 | local->hw_scanning = false; | 423 | local->hw_scanning = false; |
633 | return rc; | 424 | return rc; |
@@ -643,7 +434,12 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
643 | if (!netif_running(sdata->dev)) | 434 | if (!netif_running(sdata->dev)) |
644 | continue; | 435 | continue; |
645 | 436 | ||
646 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON_ENABLED); | 437 | /* disable beaconing */ |
438 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
439 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||
440 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||
441 | ieee80211_if_config(sdata, | ||
442 | IEEE80211_IFCC_BEACON_ENABLED); | ||
647 | 443 | ||
648 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 444 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
649 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 445 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { |
@@ -655,15 +451,10 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
655 | } | 451 | } |
656 | mutex_unlock(&local->iflist_mtx); | 452 | mutex_unlock(&local->iflist_mtx); |
657 | 453 | ||
658 | if (ssid) { | ||
659 | local->scan_ssid_len = ssid_len; | ||
660 | memcpy(local->scan_ssid, ssid, ssid_len); | ||
661 | } else | ||
662 | local->scan_ssid_len = 0; | ||
663 | local->scan_state = SCAN_SET_CHANNEL; | 454 | local->scan_state = SCAN_SET_CHANNEL; |
664 | local->scan_channel_idx = 0; | 455 | local->scan_channel_idx = 0; |
665 | local->scan_band = IEEE80211_BAND_2GHZ; | ||
666 | local->scan_sdata = scan_sdata; | 456 | local->scan_sdata = scan_sdata; |
457 | local->scan_req = req; | ||
667 | 458 | ||
668 | netif_addr_lock_bh(local->mdev); | 459 | netif_addr_lock_bh(local->mdev); |
669 | local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; | 460 | local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; |
@@ -683,13 +474,21 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
683 | 474 | ||
684 | 475 | ||
685 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 476 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
686 | u8 *ssid, size_t ssid_len) | 477 | struct cfg80211_scan_request *req) |
687 | { | 478 | { |
688 | struct ieee80211_local *local = sdata->local; | 479 | struct ieee80211_local *local = sdata->local; |
689 | struct ieee80211_if_sta *ifsta; | 480 | struct ieee80211_if_sta *ifsta; |
690 | 481 | ||
482 | if (!req) | ||
483 | return -EINVAL; | ||
484 | |||
485 | if (local->scan_req && local->scan_req != req) | ||
486 | return -EBUSY; | ||
487 | |||
488 | local->scan_req = req; | ||
489 | |||
691 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 490 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
692 | return ieee80211_start_scan(sdata, ssid, ssid_len); | 491 | return ieee80211_start_scan(sdata, req); |
693 | 492 | ||
694 | /* | 493 | /* |
695 | * STA has a state machine that might need to defer scanning | 494 | * STA has a state machine that might need to defer scanning |
@@ -704,241 +503,8 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
704 | } | 503 | } |
705 | 504 | ||
706 | ifsta = &sdata->u.sta; | 505 | ifsta = &sdata->u.sta; |
707 | |||
708 | ifsta->scan_ssid_len = ssid_len; | ||
709 | if (ssid_len) | ||
710 | memcpy(ifsta->scan_ssid, ssid, ssid_len); | ||
711 | set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); | 506 | set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); |
712 | queue_work(local->hw.workqueue, &ifsta->work); | 507 | queue_work(local->hw.workqueue, &ifsta->work); |
713 | 508 | ||
714 | return 0; | 509 | return 0; |
715 | } | 510 | } |
716 | |||
717 | |||
718 | static void ieee80211_scan_add_ies(struct iw_request_info *info, | ||
719 | struct ieee80211_bss *bss, | ||
720 | char **current_ev, char *end_buf) | ||
721 | { | ||
722 | u8 *pos, *end, *next; | ||
723 | struct iw_event iwe; | ||
724 | |||
725 | if (bss == NULL || bss->ies == NULL) | ||
726 | return; | ||
727 | |||
728 | /* | ||
729 | * If needed, fragment the IEs buffer (at IE boundaries) into short | ||
730 | * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. | ||
731 | */ | ||
732 | pos = bss->ies; | ||
733 | end = pos + bss->ies_len; | ||
734 | |||
735 | while (end - pos > IW_GENERIC_IE_MAX) { | ||
736 | next = pos + 2 + pos[1]; | ||
737 | while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) | ||
738 | next = next + 2 + next[1]; | ||
739 | |||
740 | memset(&iwe, 0, sizeof(iwe)); | ||
741 | iwe.cmd = IWEVGENIE; | ||
742 | iwe.u.data.length = next - pos; | ||
743 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
744 | end_buf, &iwe, pos); | ||
745 | |||
746 | pos = next; | ||
747 | } | ||
748 | |||
749 | if (end > pos) { | ||
750 | memset(&iwe, 0, sizeof(iwe)); | ||
751 | iwe.cmd = IWEVGENIE; | ||
752 | iwe.u.data.length = end - pos; | ||
753 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
754 | end_buf, &iwe, pos); | ||
755 | } | ||
756 | } | ||
757 | |||
758 | |||
759 | static char * | ||
760 | ieee80211_scan_result(struct ieee80211_local *local, | ||
761 | struct iw_request_info *info, | ||
762 | struct ieee80211_bss *bss, | ||
763 | char *current_ev, char *end_buf) | ||
764 | { | ||
765 | struct iw_event iwe; | ||
766 | char *buf; | ||
767 | |||
768 | if (time_after(jiffies, | ||
769 | bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
770 | return current_ev; | ||
771 | |||
772 | memset(&iwe, 0, sizeof(iwe)); | ||
773 | iwe.cmd = SIOCGIWAP; | ||
774 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
775 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); | ||
776 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
777 | IW_EV_ADDR_LEN); | ||
778 | |||
779 | memset(&iwe, 0, sizeof(iwe)); | ||
780 | iwe.cmd = SIOCGIWESSID; | ||
781 | if (bss_mesh_cfg(bss)) { | ||
782 | iwe.u.data.length = bss_mesh_id_len(bss); | ||
783 | iwe.u.data.flags = 1; | ||
784 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
785 | &iwe, bss_mesh_id(bss)); | ||
786 | } else { | ||
787 | iwe.u.data.length = bss->ssid_len; | ||
788 | iwe.u.data.flags = 1; | ||
789 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
790 | &iwe, bss->ssid); | ||
791 | } | ||
792 | |||
793 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) | ||
794 | || bss_mesh_cfg(bss)) { | ||
795 | memset(&iwe, 0, sizeof(iwe)); | ||
796 | iwe.cmd = SIOCGIWMODE; | ||
797 | if (bss_mesh_cfg(bss)) | ||
798 | iwe.u.mode = IW_MODE_MESH; | ||
799 | else if (bss->capability & WLAN_CAPABILITY_ESS) | ||
800 | iwe.u.mode = IW_MODE_MASTER; | ||
801 | else | ||
802 | iwe.u.mode = IW_MODE_ADHOC; | ||
803 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
804 | &iwe, IW_EV_UINT_LEN); | ||
805 | } | ||
806 | |||
807 | memset(&iwe, 0, sizeof(iwe)); | ||
808 | iwe.cmd = SIOCGIWFREQ; | ||
809 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); | ||
810 | iwe.u.freq.e = 0; | ||
811 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
812 | IW_EV_FREQ_LEN); | ||
813 | |||
814 | memset(&iwe, 0, sizeof(iwe)); | ||
815 | iwe.cmd = SIOCGIWFREQ; | ||
816 | iwe.u.freq.m = bss->freq; | ||
817 | iwe.u.freq.e = 6; | ||
818 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
819 | IW_EV_FREQ_LEN); | ||
820 | memset(&iwe, 0, sizeof(iwe)); | ||
821 | iwe.cmd = IWEVQUAL; | ||
822 | iwe.u.qual.qual = bss->qual; | ||
823 | iwe.u.qual.level = bss->signal; | ||
824 | iwe.u.qual.noise = bss->noise; | ||
825 | iwe.u.qual.updated = local->wstats_flags; | ||
826 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
827 | IW_EV_QUAL_LEN); | ||
828 | |||
829 | memset(&iwe, 0, sizeof(iwe)); | ||
830 | iwe.cmd = SIOCGIWENCODE; | ||
831 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | ||
832 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
833 | else | ||
834 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
835 | iwe.u.data.length = 0; | ||
836 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
837 | &iwe, ""); | ||
838 | |||
839 | ieee80211_scan_add_ies(info, bss, ¤t_ev, end_buf); | ||
840 | |||
841 | if (bss->supp_rates_len > 0) { | ||
842 | /* display all supported rates in readable format */ | ||
843 | char *p = current_ev + iwe_stream_lcp_len(info); | ||
844 | int i; | ||
845 | |||
846 | memset(&iwe, 0, sizeof(iwe)); | ||
847 | iwe.cmd = SIOCGIWRATE; | ||
848 | /* Those two flags are ignored... */ | ||
849 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
850 | |||
851 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
852 | iwe.u.bitrate.value = ((bss->supp_rates[i] & | ||
853 | 0x7f) * 500000); | ||
854 | p = iwe_stream_add_value(info, current_ev, p, | ||
855 | end_buf, &iwe, IW_EV_PARAM_LEN); | ||
856 | } | ||
857 | current_ev = p; | ||
858 | } | ||
859 | |||
860 | buf = kmalloc(30, GFP_ATOMIC); | ||
861 | if (buf) { | ||
862 | memset(&iwe, 0, sizeof(iwe)); | ||
863 | iwe.cmd = IWEVCUSTOM; | ||
864 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); | ||
865 | iwe.u.data.length = strlen(buf); | ||
866 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
867 | &iwe, buf); | ||
868 | memset(&iwe, 0, sizeof(iwe)); | ||
869 | iwe.cmd = IWEVCUSTOM; | ||
870 | sprintf(buf, " Last beacon: %dms ago", | ||
871 | jiffies_to_msecs(jiffies - bss->last_update)); | ||
872 | iwe.u.data.length = strlen(buf); | ||
873 | current_ev = iwe_stream_add_point(info, current_ev, | ||
874 | end_buf, &iwe, buf); | ||
875 | kfree(buf); | ||
876 | } | ||
877 | |||
878 | if (bss_mesh_cfg(bss)) { | ||
879 | u8 *cfg = bss_mesh_cfg(bss); | ||
880 | buf = kmalloc(50, GFP_ATOMIC); | ||
881 | if (buf) { | ||
882 | memset(&iwe, 0, sizeof(iwe)); | ||
883 | iwe.cmd = IWEVCUSTOM; | ||
884 | sprintf(buf, "Mesh network (version %d)", cfg[0]); | ||
885 | iwe.u.data.length = strlen(buf); | ||
886 | current_ev = iwe_stream_add_point(info, current_ev, | ||
887 | end_buf, | ||
888 | &iwe, buf); | ||
889 | sprintf(buf, "Path Selection Protocol ID: " | ||
890 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], | ||
891 | cfg[4]); | ||
892 | iwe.u.data.length = strlen(buf); | ||
893 | current_ev = iwe_stream_add_point(info, current_ev, | ||
894 | end_buf, | ||
895 | &iwe, buf); | ||
896 | sprintf(buf, "Path Selection Metric ID: " | ||
897 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], | ||
898 | cfg[8]); | ||
899 | iwe.u.data.length = strlen(buf); | ||
900 | current_ev = iwe_stream_add_point(info, current_ev, | ||
901 | end_buf, | ||
902 | &iwe, buf); | ||
903 | sprintf(buf, "Congestion Control Mode ID: " | ||
904 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], | ||
905 | cfg[11], cfg[12]); | ||
906 | iwe.u.data.length = strlen(buf); | ||
907 | current_ev = iwe_stream_add_point(info, current_ev, | ||
908 | end_buf, | ||
909 | &iwe, buf); | ||
910 | sprintf(buf, "Channel Precedence: " | ||
911 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], | ||
912 | cfg[15], cfg[16]); | ||
913 | iwe.u.data.length = strlen(buf); | ||
914 | current_ev = iwe_stream_add_point(info, current_ev, | ||
915 | end_buf, | ||
916 | &iwe, buf); | ||
917 | kfree(buf); | ||
918 | } | ||
919 | } | ||
920 | |||
921 | return current_ev; | ||
922 | } | ||
923 | |||
924 | |||
925 | int ieee80211_scan_results(struct ieee80211_local *local, | ||
926 | struct iw_request_info *info, | ||
927 | char *buf, size_t len) | ||
928 | { | ||
929 | char *current_ev = buf; | ||
930 | char *end_buf = buf + len; | ||
931 | struct ieee80211_bss *bss; | ||
932 | |||
933 | spin_lock_bh(&local->bss_lock); | ||
934 | list_for_each_entry(bss, &local->bss_list, list) { | ||
935 | if (buf + len - current_ev <= IW_EV_ADDR_LEN) { | ||
936 | spin_unlock_bh(&local->bss_lock); | ||
937 | return -E2BIG; | ||
938 | } | ||
939 | current_ev = ieee80211_scan_result(local, info, bss, | ||
940 | current_ev, end_buf); | ||
941 | } | ||
942 | spin_unlock_bh(&local->bss_lock); | ||
943 | return current_ev - buf; | ||
944 | } | ||
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 8d4ec2968f8f..47bb2aed2813 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
@@ -102,8 +102,9 @@ void ieee80211_chswitch_work(struct work_struct *work) | |||
102 | goto exit; | 102 | goto exit; |
103 | 103 | ||
104 | sdata->local->oper_channel = sdata->local->csa_channel; | 104 | sdata->local->oper_channel = sdata->local->csa_channel; |
105 | /* XXX: shouldn't really modify cfg80211-owned data! */ | ||
105 | if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) | 106 | if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) |
106 | bss->freq = sdata->local->oper_channel->center_freq; | 107 | bss->cbss.channel = sdata->local->oper_channel; |
107 | 108 | ||
108 | ieee80211_rx_bss_put(sdata->local, bss); | 109 | ieee80211_rx_bss_put(sdata->local, bss); |
109 | exit: | 110 | exit: |
@@ -158,7 +159,9 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
158 | IEEE80211_QUEUE_STOP_REASON_CSA); | 159 | IEEE80211_QUEUE_STOP_REASON_CSA); |
159 | ifsta->flags |= IEEE80211_STA_CSA_RECEIVED; | 160 | ifsta->flags |= IEEE80211_STA_CSA_RECEIVED; |
160 | mod_timer(&ifsta->chswitch_timer, | 161 | mod_timer(&ifsta->chswitch_timer, |
161 | jiffies + msecs_to_jiffies(sw_elem->count * bss->beacon_int)); | 162 | jiffies + |
163 | msecs_to_jiffies(sw_elem->count * | ||
164 | bss->cbss.beacon_interval)); | ||
162 | } | 165 | } |
163 | } | 166 | } |
164 | 167 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 10c5539c20ab..634f65c0130e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -194,12 +194,41 @@ void sta_info_destroy(struct sta_info *sta) | |||
194 | dev_kfree_skb_any(skb); | 194 | dev_kfree_skb_any(skb); |
195 | 195 | ||
196 | for (i = 0; i < STA_TID_NUM; i++) { | 196 | for (i = 0; i < STA_TID_NUM; i++) { |
197 | struct tid_ampdu_rx *tid_rx; | ||
198 | struct tid_ampdu_tx *tid_tx; | ||
199 | |||
197 | spin_lock_bh(&sta->lock); | 200 | spin_lock_bh(&sta->lock); |
198 | if (sta->ampdu_mlme.tid_rx[i]) | 201 | tid_rx = sta->ampdu_mlme.tid_rx[i]; |
199 | del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer); | 202 | /* Make sure timer won't free the tid_rx struct, see below */ |
200 | if (sta->ampdu_mlme.tid_tx[i]) | 203 | if (tid_rx) |
201 | del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer); | 204 | tid_rx->shutdown = true; |
202 | spin_unlock_bh(&sta->lock); | 205 | spin_unlock_bh(&sta->lock); |
206 | |||
207 | /* | ||
208 | * Outside spinlock - shutdown is true now so that the timer | ||
209 | * won't free tid_rx, we have to do that now. Can't let the | ||
210 | * timer do it because we have to sync the timer outside the | ||
211 | * lock that it takes itself. | ||
212 | */ | ||
213 | if (tid_rx) { | ||
214 | del_timer_sync(&tid_rx->session_timer); | ||
215 | kfree(tid_rx); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * No need to do such complications for TX agg sessions, the | ||
220 | * path leading to freeing the tid_tx struct goes via a call | ||
221 | * from the driver, and thus needs to look up the sta struct | ||
222 | * again, which cannot be found when we get here. Hence, we | ||
223 | * just need to delete the timer and free the aggregation | ||
224 | * info; we won't be telling the peer about it then but that | ||
225 | * doesn't matter if we're not talking to it again anyway. | ||
226 | */ | ||
227 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
228 | if (tid_tx) { | ||
229 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
230 | kfree(tid_tx); | ||
231 | } | ||
203 | } | 232 | } |
204 | 233 | ||
205 | __sta_info_free(local, sta); | 234 | __sta_info_free(local, sta); |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d13a44b935e2..d9653231992f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -65,7 +65,6 @@ enum ieee80211_sta_info_flags { | |||
65 | #define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \ | 65 | #define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \ |
66 | HT_ADDBA_DRV_READY_MSK | \ | 66 | HT_ADDBA_DRV_READY_MSK | \ |
67 | HT_ADDBA_RECEIVED_MSK) | 67 | HT_ADDBA_RECEIVED_MSK) |
68 | #define HT_AGG_STATE_DEBUGFS_CTL BIT(7) | ||
69 | 68 | ||
70 | /** | 69 | /** |
71 | * struct tid_ampdu_tx - TID aggregation information (Tx). | 70 | * struct tid_ampdu_tx - TID aggregation information (Tx). |
@@ -89,7 +88,7 @@ struct tid_ampdu_tx { | |||
89 | * @stored_mpdu_num: number of MPDUs in reordering buffer | 88 | * @stored_mpdu_num: number of MPDUs in reordering buffer |
90 | * @ssn: Starting Sequence Number expected to be aggregated. | 89 | * @ssn: Starting Sequence Number expected to be aggregated. |
91 | * @buf_size: buffer size for incoming A-MPDUs | 90 | * @buf_size: buffer size for incoming A-MPDUs |
92 | * @timeout: reset timer value. | 91 | * @timeout: reset timer value (in TUs). |
93 | * @dialog_token: dialog token for aggregation session | 92 | * @dialog_token: dialog token for aggregation session |
94 | */ | 93 | */ |
95 | struct tid_ampdu_rx { | 94 | struct tid_ampdu_rx { |
@@ -101,6 +100,7 @@ struct tid_ampdu_rx { | |||
101 | u16 buf_size; | 100 | u16 buf_size; |
102 | u16 timeout; | 101 | u16 timeout; |
103 | u8 dialog_token; | 102 | u8 dialog_token; |
103 | bool shutdown; | ||
104 | }; | 104 | }; |
105 | 105 | ||
106 | /** | 106 | /** |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f1c726d94f47..bf73f6d561b7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #define IEEE80211_TX_OK 0 | 35 | #define IEEE80211_TX_OK 0 |
36 | #define IEEE80211_TX_AGAIN 1 | 36 | #define IEEE80211_TX_AGAIN 1 |
37 | #define IEEE80211_TX_FRAG_AGAIN 2 | 37 | #define IEEE80211_TX_FRAG_AGAIN 2 |
38 | #define IEEE80211_TX_PENDING 3 | ||
38 | 39 | ||
39 | /* misc utils */ | 40 | /* misc utils */ |
40 | 41 | ||
@@ -1085,7 +1086,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1085 | 1086 | ||
1086 | if (skb) { | 1087 | if (skb) { |
1087 | if (netif_subqueue_stopped(local->mdev, skb)) | 1088 | if (netif_subqueue_stopped(local->mdev, skb)) |
1088 | return IEEE80211_TX_AGAIN; | 1089 | return IEEE80211_TX_PENDING; |
1089 | 1090 | ||
1090 | ret = local->ops->tx(local_to_hw(local), skb); | 1091 | ret = local->ops->tx(local_to_hw(local), skb); |
1091 | if (ret) | 1092 | if (ret) |
@@ -1211,8 +1212,9 @@ retry: | |||
1211 | * queues, there's no reason for a driver to reject | 1212 | * queues, there's no reason for a driver to reject |
1212 | * a frame there, warn and drop it. | 1213 | * a frame there, warn and drop it. |
1213 | */ | 1214 | */ |
1214 | if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) | 1215 | if (ret != IEEE80211_TX_PENDING) |
1215 | goto drop; | 1216 | if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) |
1217 | goto drop; | ||
1216 | 1218 | ||
1217 | store = &local->pending_packet[queue]; | 1219 | store = &local->pending_packet[queue]; |
1218 | 1220 | ||
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index bad1cfbfdf18..2b023dce8b24 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -145,6 +145,21 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, | |||
145 | return -EOPNOTSUPP; | 145 | return -EOPNOTSUPP; |
146 | } | 146 | } |
147 | 147 | ||
148 | static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local) | ||
149 | { | ||
150 | u8 wstats_flags = 0; | ||
151 | |||
152 | wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | | ||
153 | IEEE80211_HW_SIGNAL_DBM) ? | ||
154 | IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; | ||
155 | wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? | ||
156 | IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; | ||
157 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
158 | wstats_flags |= IW_QUAL_DBM; | ||
159 | |||
160 | return wstats_flags; | ||
161 | } | ||
162 | |||
148 | static int ieee80211_ioctl_giwrange(struct net_device *dev, | 163 | static int ieee80211_ioctl_giwrange(struct net_device *dev, |
149 | struct iw_request_info *info, | 164 | struct iw_request_info *info, |
150 | struct iw_point *data, char *extra) | 165 | struct iw_point *data, char *extra) |
@@ -173,8 +188,9 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
173 | range->num_encoding_sizes = 2; | 188 | range->num_encoding_sizes = 2; |
174 | range->max_encoding_tokens = NUM_DEFAULT_KEYS; | 189 | range->max_encoding_tokens = NUM_DEFAULT_KEYS; |
175 | 190 | ||
191 | /* cfg80211 requires this, and enforces 0..100 */ | ||
176 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 192 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
177 | range->max_qual.level = local->hw.max_signal; | 193 | range->max_qual.level = 100; |
178 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 194 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
179 | range->max_qual.level = -110; | 195 | range->max_qual.level = -110; |
180 | else | 196 | else |
@@ -186,13 +202,13 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, | |||
186 | range->max_qual.noise = 0; | 202 | range->max_qual.noise = 0; |
187 | 203 | ||
188 | range->max_qual.qual = 100; | 204 | range->max_qual.qual = 100; |
189 | range->max_qual.updated = local->wstats_flags; | 205 | range->max_qual.updated = ieee80211_get_wstats_flags(local); |
190 | 206 | ||
191 | range->avg_qual.qual = 50; | 207 | range->avg_qual.qual = 50; |
192 | /* not always true but better than nothing */ | 208 | /* not always true but better than nothing */ |
193 | range->avg_qual.level = range->max_qual.level / 2; | 209 | range->avg_qual.level = range->max_qual.level / 2; |
194 | range->avg_qual.noise = range->max_qual.noise / 2; | 210 | range->avg_qual.noise = range->max_qual.noise / 2; |
195 | range->avg_qual.updated = local->wstats_flags; | 211 | range->avg_qual.updated = ieee80211_get_wstats_flags(local); |
196 | 212 | ||
197 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | 213 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | |
198 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | 214 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; |
@@ -415,58 +431,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, | |||
415 | } | 431 | } |
416 | 432 | ||
417 | 433 | ||
418 | static int ieee80211_ioctl_siwscan(struct net_device *dev, | ||
419 | struct iw_request_info *info, | ||
420 | union iwreq_data *wrqu, char *extra) | ||
421 | { | ||
422 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
423 | struct iw_scan_req *req = NULL; | ||
424 | u8 *ssid = NULL; | ||
425 | size_t ssid_len = 0; | ||
426 | |||
427 | if (!netif_running(dev)) | ||
428 | return -ENETDOWN; | ||
429 | |||
430 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
431 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | ||
432 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
433 | return -EOPNOTSUPP; | ||
434 | |||
435 | /* if SSID was specified explicitly then use that */ | ||
436 | if (wrqu->data.length == sizeof(struct iw_scan_req) && | ||
437 | wrqu->data.flags & IW_SCAN_THIS_ESSID) { | ||
438 | req = (struct iw_scan_req *)extra; | ||
439 | ssid = req->essid; | ||
440 | ssid_len = req->essid_len; | ||
441 | } | ||
442 | |||
443 | return ieee80211_request_scan(sdata, ssid, ssid_len); | ||
444 | } | ||
445 | |||
446 | |||
447 | static int ieee80211_ioctl_giwscan(struct net_device *dev, | ||
448 | struct iw_request_info *info, | ||
449 | struct iw_point *data, char *extra) | ||
450 | { | ||
451 | int res; | ||
452 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
453 | struct ieee80211_sub_if_data *sdata; | ||
454 | |||
455 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
456 | |||
457 | if (local->sw_scanning || local->hw_scanning) | ||
458 | return -EAGAIN; | ||
459 | |||
460 | res = ieee80211_scan_results(local, info, extra, data->length); | ||
461 | if (res >= 0) { | ||
462 | data->length = res; | ||
463 | return 0; | ||
464 | } | ||
465 | data->length = 0; | ||
466 | return res; | ||
467 | } | ||
468 | |||
469 | |||
470 | static int ieee80211_ioctl_siwrate(struct net_device *dev, | 434 | static int ieee80211_ioctl_siwrate(struct net_device *dev, |
471 | struct iw_request_info *info, | 435 | struct iw_request_info *info, |
472 | struct iw_param *rate, char *extra) | 436 | struct iw_param *rate, char *extra) |
@@ -982,9 +946,21 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
982 | break; | 946 | break; |
983 | } | 947 | } |
984 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 948 | if (sdata->vif.type == NL80211_IFTYPE_STATION || |
985 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 949 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
986 | sdata->u.sta.mfp = data->value; | 950 | switch (data->value) { |
987 | else | 951 | case IW_AUTH_MFP_DISABLED: |
952 | sdata->u.sta.mfp = IEEE80211_MFP_DISABLED; | ||
953 | break; | ||
954 | case IW_AUTH_MFP_OPTIONAL: | ||
955 | sdata->u.sta.mfp = IEEE80211_MFP_OPTIONAL; | ||
956 | break; | ||
957 | case IW_AUTH_MFP_REQUIRED: | ||
958 | sdata->u.sta.mfp = IEEE80211_MFP_REQUIRED; | ||
959 | break; | ||
960 | default: | ||
961 | ret = -EINVAL; | ||
962 | } | ||
963 | } else | ||
988 | ret = -EOPNOTSUPP; | 964 | ret = -EOPNOTSUPP; |
989 | break; | 965 | break; |
990 | default: | 966 | default: |
@@ -1018,7 +994,7 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev | |||
1018 | wstats->qual.level = sta->last_signal; | 994 | wstats->qual.level = sta->last_signal; |
1019 | wstats->qual.qual = sta->last_qual; | 995 | wstats->qual.qual = sta->last_qual; |
1020 | wstats->qual.noise = sta->last_noise; | 996 | wstats->qual.noise = sta->last_noise; |
1021 | wstats->qual.updated = local->wstats_flags; | 997 | wstats->qual.updated = ieee80211_get_wstats_flags(local); |
1022 | } | 998 | } |
1023 | 999 | ||
1024 | rcu_read_unlock(); | 1000 | rcu_read_unlock(); |
@@ -1153,8 +1129,8 @@ static const iw_handler ieee80211_handler[] = | |||
1153 | (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ | 1129 | (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ |
1154 | (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ | 1130 | (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ |
1155 | (iw_handler) NULL, /* SIOCGIWAPLIST */ | 1131 | (iw_handler) NULL, /* SIOCGIWAPLIST */ |
1156 | (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */ | 1132 | (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ |
1157 | (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */ | 1133 | (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ |
1158 | (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ | 1134 | (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ |
1159 | (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ | 1135 | (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ |
1160 | (iw_handler) NULL, /* SIOCSIWNICKN */ | 1136 | (iw_handler) NULL, /* SIOCSIWNICKN */ |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 938a334c8dbc..dad43c24f695 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o | |||
5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | 5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o |
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o |
9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o | 9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o |
10 | cfg80211-$(CONFIG_NL80211) += nl80211.o | 10 | cfg80211-$(CONFIG_NL80211) += nl80211.o |
11 | 11 | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 125226476089..0668b2bfc1da 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -240,6 +240,8 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) | |||
240 | mutex_init(&drv->mtx); | 240 | mutex_init(&drv->mtx); |
241 | mutex_init(&drv->devlist_mtx); | 241 | mutex_init(&drv->devlist_mtx); |
242 | INIT_LIST_HEAD(&drv->netdev_list); | 242 | INIT_LIST_HEAD(&drv->netdev_list); |
243 | spin_lock_init(&drv->bss_lock); | ||
244 | INIT_LIST_HEAD(&drv->bss_list); | ||
243 | 245 | ||
244 | device_initialize(&drv->wiphy.dev); | 246 | device_initialize(&drv->wiphy.dev); |
245 | drv->wiphy.dev.class = &ieee80211_class; | 247 | drv->wiphy.dev.class = &ieee80211_class; |
@@ -259,6 +261,9 @@ int wiphy_register(struct wiphy *wiphy) | |||
259 | int i; | 261 | int i; |
260 | u16 ifmodes = wiphy->interface_modes; | 262 | u16 ifmodes = wiphy->interface_modes; |
261 | 263 | ||
264 | if (WARN_ON(wiphy->max_scan_ssids < 1)) | ||
265 | return -EINVAL; | ||
266 | |||
262 | /* sanity check ifmodes */ | 267 | /* sanity check ifmodes */ |
263 | WARN_ON(!ifmodes); | 268 | WARN_ON(!ifmodes); |
264 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; | 269 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; |
@@ -367,8 +372,11 @@ EXPORT_SYMBOL(wiphy_unregister); | |||
367 | 372 | ||
368 | void cfg80211_dev_free(struct cfg80211_registered_device *drv) | 373 | void cfg80211_dev_free(struct cfg80211_registered_device *drv) |
369 | { | 374 | { |
375 | struct cfg80211_internal_bss *scan, *tmp; | ||
370 | mutex_destroy(&drv->mtx); | 376 | mutex_destroy(&drv->mtx); |
371 | mutex_destroy(&drv->devlist_mtx); | 377 | mutex_destroy(&drv->devlist_mtx); |
378 | list_for_each_entry_safe(scan, tmp, &drv->bss_list, list) | ||
379 | cfg80211_put_bss(&scan->pub); | ||
372 | kfree(drv); | 380 | kfree(drv); |
373 | } | 381 | } |
374 | 382 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index f7fb9f413028..e29ad4cd464f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <linux/mutex.h> | 8 | #include <linux/mutex.h> |
9 | #include <linux/list.h> | 9 | #include <linux/list.h> |
10 | #include <linux/netdevice.h> | 10 | #include <linux/netdevice.h> |
11 | #include <linux/kref.h> | ||
12 | #include <linux/rbtree.h> | ||
11 | #include <net/genetlink.h> | 13 | #include <net/genetlink.h> |
12 | #include <net/wireless.h> | 14 | #include <net/wireless.h> |
13 | #include <net/cfg80211.h> | 15 | #include <net/cfg80211.h> |
@@ -41,6 +43,13 @@ struct cfg80211_registered_device { | |||
41 | struct mutex devlist_mtx; | 43 | struct mutex devlist_mtx; |
42 | struct list_head netdev_list; | 44 | struct list_head netdev_list; |
43 | 45 | ||
46 | /* BSSes/scanning */ | ||
47 | spinlock_t bss_lock; | ||
48 | struct list_head bss_list; | ||
49 | struct rb_root bss_tree; | ||
50 | u32 bss_generation; | ||
51 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | ||
52 | |||
44 | /* must be last because of the way we do wiphy_priv(), | 53 | /* must be last because of the way we do wiphy_priv(), |
45 | * and it should at least be aligned to NETDEV_ALIGN */ | 54 | * and it should at least be aligned to NETDEV_ALIGN */ |
46 | struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); | 55 | struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); |
@@ -56,6 +65,15 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) | |||
56 | extern struct mutex cfg80211_drv_mutex; | 65 | extern struct mutex cfg80211_drv_mutex; |
57 | extern struct list_head cfg80211_drv_list; | 66 | extern struct list_head cfg80211_drv_list; |
58 | 67 | ||
68 | struct cfg80211_internal_bss { | ||
69 | struct list_head list; | ||
70 | struct rb_node rbn; | ||
71 | unsigned long ts; | ||
72 | struct kref ref; | ||
73 | /* must be last because of priv member */ | ||
74 | struct cfg80211_bss pub; | ||
75 | }; | ||
76 | |||
59 | /* | 77 | /* |
60 | * This function returns a pointer to the driver | 78 | * This function returns a pointer to the driver |
61 | * that the genl_info item that is passed refers to. | 79 | * that the genl_info item that is passed refers to. |
@@ -94,4 +112,6 @@ extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv, | |||
94 | void ieee80211_set_bitrate_flags(struct wiphy *wiphy); | 112 | void ieee80211_set_bitrate_flags(struct wiphy *wiphy); |
95 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby); | 113 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby); |
96 | 114 | ||
115 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev); | ||
116 | |||
97 | #endif /* __NET_WIRELESS_CORE_H */ | 117 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d452396006ee..298a4de59948 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/nl80211.h> | 14 | #include <linux/nl80211.h> |
15 | #include <linux/rtnetlink.h> | 15 | #include <linux/rtnetlink.h> |
16 | #include <linux/netlink.h> | 16 | #include <linux/netlink.h> |
17 | #include <linux/etherdevice.h> | ||
17 | #include <net/genetlink.h> | 18 | #include <net/genetlink.h> |
18 | #include <net/cfg80211.h> | 19 | #include <net/cfg80211.h> |
19 | #include "core.h" | 20 | #include "core.h" |
@@ -109,6 +110,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
109 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | 110 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, |
110 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | 111 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, |
111 | .len = IEEE80211_MAX_DATA_LEN }, | 112 | .len = IEEE80211_MAX_DATA_LEN }, |
113 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, | ||
114 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, | ||
112 | }; | 115 | }; |
113 | 116 | ||
114 | /* message building helper */ | 117 | /* message building helper */ |
@@ -141,6 +144,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
141 | 144 | ||
142 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); | 145 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); |
143 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 146 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
147 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | ||
148 | dev->wiphy.max_scan_ssids); | ||
144 | 149 | ||
145 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 150 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
146 | if (!nl_modes) | 151 | if (!nl_modes) |
@@ -2270,6 +2275,246 @@ static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb, | |||
2270 | return err; | 2275 | return err; |
2271 | } | 2276 | } |
2272 | 2277 | ||
2278 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | ||
2279 | { | ||
2280 | struct cfg80211_registered_device *drv; | ||
2281 | struct net_device *dev; | ||
2282 | struct cfg80211_scan_request *request; | ||
2283 | struct cfg80211_ssid *ssid; | ||
2284 | struct ieee80211_channel *channel; | ||
2285 | struct nlattr *attr; | ||
2286 | struct wiphy *wiphy; | ||
2287 | int err, tmp, n_ssids = 0, n_channels = 0, i; | ||
2288 | enum ieee80211_band band; | ||
2289 | |||
2290 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2291 | if (err) | ||
2292 | return err; | ||
2293 | |||
2294 | wiphy = &drv->wiphy; | ||
2295 | |||
2296 | if (!drv->ops->scan) { | ||
2297 | err = -EOPNOTSUPP; | ||
2298 | goto out; | ||
2299 | } | ||
2300 | |||
2301 | rtnl_lock(); | ||
2302 | |||
2303 | if (drv->scan_req) { | ||
2304 | err = -EBUSY; | ||
2305 | goto out_unlock; | ||
2306 | } | ||
2307 | |||
2308 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | ||
2309 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) | ||
2310 | n_channels++; | ||
2311 | if (!n_channels) { | ||
2312 | err = -EINVAL; | ||
2313 | goto out_unlock; | ||
2314 | } | ||
2315 | } else { | ||
2316 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
2317 | if (wiphy->bands[band]) | ||
2318 | n_channels += wiphy->bands[band]->n_channels; | ||
2319 | } | ||
2320 | |||
2321 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) | ||
2322 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) | ||
2323 | n_ssids++; | ||
2324 | |||
2325 | if (n_ssids > wiphy->max_scan_ssids) { | ||
2326 | err = -EINVAL; | ||
2327 | goto out_unlock; | ||
2328 | } | ||
2329 | |||
2330 | request = kzalloc(sizeof(*request) | ||
2331 | + sizeof(*ssid) * n_ssids | ||
2332 | + sizeof(channel) * n_channels, GFP_KERNEL); | ||
2333 | if (!request) { | ||
2334 | err = -ENOMEM; | ||
2335 | goto out_unlock; | ||
2336 | } | ||
2337 | |||
2338 | request->channels = (void *)((char *)request + sizeof(*request)); | ||
2339 | request->n_channels = n_channels; | ||
2340 | if (n_ssids) | ||
2341 | request->ssids = (void *)(request->channels + n_channels); | ||
2342 | request->n_ssids = n_ssids; | ||
2343 | |||
2344 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | ||
2345 | /* user specified, bail out if channel not found */ | ||
2346 | request->n_channels = n_channels; | ||
2347 | i = 0; | ||
2348 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], tmp) { | ||
2349 | request->channels[i] = ieee80211_get_channel(wiphy, nla_get_u32(attr)); | ||
2350 | if (!request->channels[i]) { | ||
2351 | err = -EINVAL; | ||
2352 | goto out_free; | ||
2353 | } | ||
2354 | i++; | ||
2355 | } | ||
2356 | } else { | ||
2357 | /* all channels */ | ||
2358 | i = 0; | ||
2359 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
2360 | int j; | ||
2361 | if (!wiphy->bands[band]) | ||
2362 | continue; | ||
2363 | for (j = 0; j < wiphy->bands[band]->n_channels; j++) { | ||
2364 | request->channels[i] = &wiphy->bands[band]->channels[j]; | ||
2365 | i++; | ||
2366 | } | ||
2367 | } | ||
2368 | } | ||
2369 | |||
2370 | i = 0; | ||
2371 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { | ||
2372 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { | ||
2373 | if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) { | ||
2374 | err = -EINVAL; | ||
2375 | goto out_free; | ||
2376 | } | ||
2377 | memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr)); | ||
2378 | request->ssids[i].ssid_len = nla_len(attr); | ||
2379 | i++; | ||
2380 | } | ||
2381 | } | ||
2382 | |||
2383 | request->ifidx = dev->ifindex; | ||
2384 | request->wiphy = &drv->wiphy; | ||
2385 | |||
2386 | drv->scan_req = request; | ||
2387 | err = drv->ops->scan(&drv->wiphy, dev, request); | ||
2388 | |||
2389 | out_free: | ||
2390 | if (err) { | ||
2391 | drv->scan_req = NULL; | ||
2392 | kfree(request); | ||
2393 | } | ||
2394 | out_unlock: | ||
2395 | rtnl_unlock(); | ||
2396 | out: | ||
2397 | cfg80211_put_dev(drv); | ||
2398 | dev_put(dev); | ||
2399 | return err; | ||
2400 | } | ||
2401 | |||
2402 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | ||
2403 | struct cfg80211_registered_device *rdev, | ||
2404 | struct net_device *dev, | ||
2405 | struct cfg80211_bss *res) | ||
2406 | { | ||
2407 | void *hdr; | ||
2408 | struct nlattr *bss; | ||
2409 | |||
2410 | hdr = nl80211hdr_put(msg, pid, seq, flags, | ||
2411 | NL80211_CMD_NEW_SCAN_RESULTS); | ||
2412 | if (!hdr) | ||
2413 | return -1; | ||
2414 | |||
2415 | NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION, | ||
2416 | rdev->bss_generation); | ||
2417 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
2418 | |||
2419 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); | ||
2420 | if (!bss) | ||
2421 | goto nla_put_failure; | ||
2422 | if (!is_zero_ether_addr(res->bssid)) | ||
2423 | NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, res->bssid); | ||
2424 | if (res->information_elements && res->len_information_elements) | ||
2425 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, | ||
2426 | res->len_information_elements, | ||
2427 | res->information_elements); | ||
2428 | if (res->tsf) | ||
2429 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); | ||
2430 | if (res->beacon_interval) | ||
2431 | NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval); | ||
2432 | NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); | ||
2433 | NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); | ||
2434 | |||
2435 | switch (res->signal_type) { | ||
2436 | case CFG80211_SIGNAL_TYPE_MBM: | ||
2437 | NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal); | ||
2438 | break; | ||
2439 | case CFG80211_SIGNAL_TYPE_UNSPEC: | ||
2440 | NLA_PUT_U8(msg, NL80211_BSS_SIGNAL_UNSPEC, res->signal); | ||
2441 | break; | ||
2442 | default: | ||
2443 | break; | ||
2444 | } | ||
2445 | |||
2446 | nla_nest_end(msg, bss); | ||
2447 | |||
2448 | return genlmsg_end(msg, hdr); | ||
2449 | |||
2450 | nla_put_failure: | ||
2451 | genlmsg_cancel(msg, hdr); | ||
2452 | return -EMSGSIZE; | ||
2453 | } | ||
2454 | |||
2455 | static int nl80211_dump_scan(struct sk_buff *skb, | ||
2456 | struct netlink_callback *cb) | ||
2457 | { | ||
2458 | struct cfg80211_registered_device *dev; | ||
2459 | struct net_device *netdev; | ||
2460 | struct cfg80211_internal_bss *scan; | ||
2461 | int ifidx = cb->args[0]; | ||
2462 | int start = cb->args[1], idx = 0; | ||
2463 | int err; | ||
2464 | |||
2465 | if (!ifidx) { | ||
2466 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
2467 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | ||
2468 | nl80211_policy); | ||
2469 | if (err) | ||
2470 | return err; | ||
2471 | |||
2472 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
2473 | return -EINVAL; | ||
2474 | |||
2475 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
2476 | if (!ifidx) | ||
2477 | return -EINVAL; | ||
2478 | cb->args[0] = ifidx; | ||
2479 | } | ||
2480 | |||
2481 | netdev = dev_get_by_index(&init_net, ifidx); | ||
2482 | if (!netdev) | ||
2483 | return -ENODEV; | ||
2484 | |||
2485 | dev = cfg80211_get_dev_from_ifindex(ifidx); | ||
2486 | if (IS_ERR(dev)) { | ||
2487 | err = PTR_ERR(dev); | ||
2488 | goto out_put_netdev; | ||
2489 | } | ||
2490 | |||
2491 | spin_lock_bh(&dev->bss_lock); | ||
2492 | cfg80211_bss_expire(dev); | ||
2493 | |||
2494 | list_for_each_entry(scan, &dev->bss_list, list) { | ||
2495 | if (++idx <= start) | ||
2496 | continue; | ||
2497 | if (nl80211_send_bss(skb, | ||
2498 | NETLINK_CB(cb->skb).pid, | ||
2499 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
2500 | dev, netdev, &scan->pub) < 0) { | ||
2501 | idx--; | ||
2502 | goto out; | ||
2503 | } | ||
2504 | } | ||
2505 | |||
2506 | out: | ||
2507 | spin_unlock_bh(&dev->bss_lock); | ||
2508 | |||
2509 | cb->args[1] = idx; | ||
2510 | err = skb->len; | ||
2511 | cfg80211_put_dev(dev); | ||
2512 | out_put_netdev: | ||
2513 | dev_put(netdev); | ||
2514 | |||
2515 | return err; | ||
2516 | } | ||
2517 | |||
2273 | static struct genl_ops nl80211_ops[] = { | 2518 | static struct genl_ops nl80211_ops[] = { |
2274 | { | 2519 | { |
2275 | .cmd = NL80211_CMD_GET_WIPHY, | 2520 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -2443,12 +2688,26 @@ static struct genl_ops nl80211_ops[] = { | |||
2443 | .policy = nl80211_policy, | 2688 | .policy = nl80211_policy, |
2444 | .flags = GENL_ADMIN_PERM, | 2689 | .flags = GENL_ADMIN_PERM, |
2445 | }, | 2690 | }, |
2691 | { | ||
2692 | .cmd = NL80211_CMD_TRIGGER_SCAN, | ||
2693 | .doit = nl80211_trigger_scan, | ||
2694 | .policy = nl80211_policy, | ||
2695 | .flags = GENL_ADMIN_PERM, | ||
2696 | }, | ||
2697 | { | ||
2698 | .cmd = NL80211_CMD_GET_SCAN, | ||
2699 | .policy = nl80211_policy, | ||
2700 | .dumpit = nl80211_dump_scan, | ||
2701 | }, | ||
2446 | }; | 2702 | }; |
2447 | 2703 | ||
2448 | /* multicast groups */ | 2704 | /* multicast groups */ |
2449 | static struct genl_multicast_group nl80211_config_mcgrp = { | 2705 | static struct genl_multicast_group nl80211_config_mcgrp = { |
2450 | .name = "config", | 2706 | .name = "config", |
2451 | }; | 2707 | }; |
2708 | static struct genl_multicast_group nl80211_scan_mcgrp = { | ||
2709 | .name = "scan", | ||
2710 | }; | ||
2452 | 2711 | ||
2453 | /* notification functions */ | 2712 | /* notification functions */ |
2454 | 2713 | ||
@@ -2468,6 +2727,66 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
2468 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); | 2727 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); |
2469 | } | 2728 | } |
2470 | 2729 | ||
2730 | static int nl80211_send_scan_donemsg(struct sk_buff *msg, | ||
2731 | struct cfg80211_registered_device *rdev, | ||
2732 | struct net_device *netdev, | ||
2733 | u32 pid, u32 seq, int flags, | ||
2734 | u32 cmd) | ||
2735 | { | ||
2736 | void *hdr; | ||
2737 | |||
2738 | hdr = nl80211hdr_put(msg, pid, seq, flags, cmd); | ||
2739 | if (!hdr) | ||
2740 | return -1; | ||
2741 | |||
2742 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx); | ||
2743 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
2744 | |||
2745 | /* XXX: we should probably bounce back the request? */ | ||
2746 | |||
2747 | return genlmsg_end(msg, hdr); | ||
2748 | |||
2749 | nla_put_failure: | ||
2750 | genlmsg_cancel(msg, hdr); | ||
2751 | return -EMSGSIZE; | ||
2752 | } | ||
2753 | |||
2754 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | ||
2755 | struct net_device *netdev) | ||
2756 | { | ||
2757 | struct sk_buff *msg; | ||
2758 | |||
2759 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
2760 | if (!msg) | ||
2761 | return; | ||
2762 | |||
2763 | if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0, | ||
2764 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { | ||
2765 | nlmsg_free(msg); | ||
2766 | return; | ||
2767 | } | ||
2768 | |||
2769 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
2770 | } | ||
2771 | |||
2772 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | ||
2773 | struct net_device *netdev) | ||
2774 | { | ||
2775 | struct sk_buff *msg; | ||
2776 | |||
2777 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
2778 | if (!msg) | ||
2779 | return; | ||
2780 | |||
2781 | if (nl80211_send_scan_donemsg(msg, rdev, netdev, 0, 0, 0, | ||
2782 | NL80211_CMD_SCAN_ABORTED) < 0) { | ||
2783 | nlmsg_free(msg); | ||
2784 | return; | ||
2785 | } | ||
2786 | |||
2787 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
2788 | } | ||
2789 | |||
2471 | /* initialisation/exit functions */ | 2790 | /* initialisation/exit functions */ |
2472 | 2791 | ||
2473 | int nl80211_init(void) | 2792 | int nl80211_init(void) |
@@ -2488,6 +2807,10 @@ int nl80211_init(void) | |||
2488 | if (err) | 2807 | if (err) |
2489 | goto err_out; | 2808 | goto err_out; |
2490 | 2809 | ||
2810 | err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp); | ||
2811 | if (err) | ||
2812 | goto err_out; | ||
2813 | |||
2491 | return 0; | 2814 | return 0; |
2492 | err_out: | 2815 | err_out: |
2493 | genl_unregister_family(&nl80211_fam); | 2816 | genl_unregister_family(&nl80211_fam); |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index f3ea5c029aee..b565a5f84e97 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -7,6 +7,10 @@ | |||
7 | extern int nl80211_init(void); | 7 | extern int nl80211_init(void); |
8 | extern void nl80211_exit(void); | 8 | extern void nl80211_exit(void); |
9 | extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); | 9 | extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); |
10 | extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | ||
11 | struct net_device *netdev); | ||
12 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | ||
13 | struct net_device *netdev); | ||
10 | #else | 14 | #else |
11 | static inline int nl80211_init(void) | 15 | static inline int nl80211_init(void) |
12 | { | 16 | { |
@@ -19,6 +23,10 @@ static inline void nl80211_notify_dev_rename( | |||
19 | struct cfg80211_registered_device *rdev) | 23 | struct cfg80211_registered_device *rdev) |
20 | { | 24 | { |
21 | } | 25 | } |
26 | static inline void | ||
27 | nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | ||
28 | struct net_device *netdev) | ||
29 | {} | ||
22 | #endif /* CONFIG_NL80211 */ | 30 | #endif /* CONFIG_NL80211 */ |
23 | 31 | ||
24 | #endif /* __NET_WIRELESS_NL80211_H */ | 32 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c new file mode 100644 index 000000000000..b1893c863b97 --- /dev/null +++ b/net/wireless/scan.c | |||
@@ -0,0 +1,836 @@ | |||
1 | /* | ||
2 | * cfg80211 scan result handling | ||
3 | * | ||
4 | * Copyright 2008 Johannes Berg <johannes@sipsolutions.net> | ||
5 | */ | ||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/netdevice.h> | ||
9 | #include <linux/wireless.h> | ||
10 | #include <linux/nl80211.h> | ||
11 | #include <linux/etherdevice.h> | ||
12 | #include <net/arp.h> | ||
13 | #include <net/cfg80211.h> | ||
14 | #include <net/iw_handler.h> | ||
15 | #include "core.h" | ||
16 | #include "nl80211.h" | ||
17 | |||
18 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) | ||
19 | |||
20 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | ||
21 | { | ||
22 | struct net_device *dev; | ||
23 | #ifdef CONFIG_WIRELESS_EXT | ||
24 | union iwreq_data wrqu; | ||
25 | #endif | ||
26 | |||
27 | dev = dev_get_by_index(&init_net, request->ifidx); | ||
28 | if (!dev) | ||
29 | goto out; | ||
30 | |||
31 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | ||
32 | wiphy_to_dev(request->wiphy)->scan_req = NULL; | ||
33 | |||
34 | if (aborted) | ||
35 | nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); | ||
36 | else | ||
37 | nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); | ||
38 | |||
39 | #ifdef CONFIG_WIRELESS_EXT | ||
40 | if (!aborted) { | ||
41 | memset(&wrqu, 0, sizeof(wrqu)); | ||
42 | |||
43 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | ||
44 | } | ||
45 | #endif | ||
46 | |||
47 | dev_put(dev); | ||
48 | |||
49 | out: | ||
50 | kfree(request); | ||
51 | } | ||
52 | EXPORT_SYMBOL(cfg80211_scan_done); | ||
53 | |||
54 | static void bss_release(struct kref *ref) | ||
55 | { | ||
56 | struct cfg80211_internal_bss *bss; | ||
57 | |||
58 | bss = container_of(ref, struct cfg80211_internal_bss, ref); | ||
59 | if (bss->pub.free_priv) | ||
60 | bss->pub.free_priv(&bss->pub); | ||
61 | kfree(bss); | ||
62 | } | ||
63 | |||
64 | /* must hold dev->bss_lock! */ | ||
65 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | ||
66 | { | ||
67 | struct cfg80211_internal_bss *bss, *tmp; | ||
68 | bool expired = false; | ||
69 | |||
70 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { | ||
71 | if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
72 | continue; | ||
73 | list_del(&bss->list); | ||
74 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
75 | kref_put(&bss->ref, bss_release); | ||
76 | expired = true; | ||
77 | } | ||
78 | |||
79 | if (expired) | ||
80 | dev->bss_generation++; | ||
81 | } | ||
82 | |||
83 | static u8 *find_ie(u8 num, u8 *ies, size_t len) | ||
84 | { | ||
85 | while (len > 2 && ies[0] != num) { | ||
86 | len -= ies[1] + 2; | ||
87 | ies += ies[1] + 2; | ||
88 | } | ||
89 | if (len < 2) | ||
90 | return NULL; | ||
91 | if (len < 2 + ies[1]) | ||
92 | return NULL; | ||
93 | return ies; | ||
94 | } | ||
95 | |||
96 | static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) | ||
97 | { | ||
98 | const u8 *ie1 = find_ie(num, ies1, len1); | ||
99 | const u8 *ie2 = find_ie(num, ies2, len2); | ||
100 | int r; | ||
101 | |||
102 | if (!ie1 && !ie2) | ||
103 | return 0; | ||
104 | if (!ie1) | ||
105 | return -1; | ||
106 | |||
107 | r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1])); | ||
108 | if (r == 0 && ie1[1] != ie2[1]) | ||
109 | return ie2[1] - ie1[1]; | ||
110 | return r; | ||
111 | } | ||
112 | |||
113 | static bool is_bss(struct cfg80211_bss *a, | ||
114 | const u8 *bssid, | ||
115 | const u8 *ssid, size_t ssid_len) | ||
116 | { | ||
117 | const u8 *ssidie; | ||
118 | |||
119 | if (bssid && compare_ether_addr(a->bssid, bssid)) | ||
120 | return false; | ||
121 | |||
122 | if (!ssid) | ||
123 | return true; | ||
124 | |||
125 | ssidie = find_ie(WLAN_EID_SSID, | ||
126 | a->information_elements, | ||
127 | a->len_information_elements); | ||
128 | if (!ssidie) | ||
129 | return false; | ||
130 | if (ssidie[1] != ssid_len) | ||
131 | return false; | ||
132 | return memcmp(ssidie + 2, ssid, ssid_len) == 0; | ||
133 | } | ||
134 | |||
135 | static bool is_mesh(struct cfg80211_bss *a, | ||
136 | const u8 *meshid, size_t meshidlen, | ||
137 | const u8 *meshcfg) | ||
138 | { | ||
139 | const u8 *ie; | ||
140 | |||
141 | if (!is_zero_ether_addr(a->bssid)) | ||
142 | return false; | ||
143 | |||
144 | ie = find_ie(WLAN_EID_MESH_ID, | ||
145 | a->information_elements, | ||
146 | a->len_information_elements); | ||
147 | if (!ie) | ||
148 | return false; | ||
149 | if (ie[1] != meshidlen) | ||
150 | return false; | ||
151 | if (memcmp(ie + 2, meshid, meshidlen)) | ||
152 | return false; | ||
153 | |||
154 | ie = find_ie(WLAN_EID_MESH_CONFIG, | ||
155 | a->information_elements, | ||
156 | a->len_information_elements); | ||
157 | if (ie[1] != IEEE80211_MESH_CONFIG_LEN) | ||
158 | return false; | ||
159 | |||
160 | /* | ||
161 | * Ignore mesh capability (last two bytes of the IE) when | ||
162 | * comparing since that may differ between stations taking | ||
163 | * part in the same mesh. | ||
164 | */ | ||
165 | return memcmp(ie + 2, meshcfg, IEEE80211_MESH_CONFIG_LEN - 2) == 0; | ||
166 | } | ||
167 | |||
168 | static int cmp_bss(struct cfg80211_bss *a, | ||
169 | struct cfg80211_bss *b) | ||
170 | { | ||
171 | int r; | ||
172 | |||
173 | if (a->channel != b->channel) | ||
174 | return b->channel->center_freq - a->channel->center_freq; | ||
175 | |||
176 | r = memcmp(a->bssid, b->bssid, ETH_ALEN); | ||
177 | if (r) | ||
178 | return r; | ||
179 | |||
180 | if (is_zero_ether_addr(a->bssid)) { | ||
181 | r = cmp_ies(WLAN_EID_MESH_ID, | ||
182 | a->information_elements, | ||
183 | a->len_information_elements, | ||
184 | b->information_elements, | ||
185 | b->len_information_elements); | ||
186 | if (r) | ||
187 | return r; | ||
188 | return cmp_ies(WLAN_EID_MESH_CONFIG, | ||
189 | a->information_elements, | ||
190 | a->len_information_elements, | ||
191 | b->information_elements, | ||
192 | b->len_information_elements); | ||
193 | } | ||
194 | |||
195 | return cmp_ies(WLAN_EID_SSID, | ||
196 | a->information_elements, | ||
197 | a->len_information_elements, | ||
198 | b->information_elements, | ||
199 | b->len_information_elements); | ||
200 | } | ||
201 | |||
202 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | ||
203 | struct ieee80211_channel *channel, | ||
204 | const u8 *bssid, | ||
205 | const u8 *ssid, size_t ssid_len, | ||
206 | u16 capa_mask, u16 capa_val) | ||
207 | { | ||
208 | struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); | ||
209 | struct cfg80211_internal_bss *bss, *res = NULL; | ||
210 | |||
211 | spin_lock_bh(&dev->bss_lock); | ||
212 | |||
213 | list_for_each_entry(bss, &dev->bss_list, list) { | ||
214 | if ((bss->pub.capability & capa_mask) != capa_val) | ||
215 | continue; | ||
216 | if (channel && bss->pub.channel != channel) | ||
217 | continue; | ||
218 | if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { | ||
219 | res = bss; | ||
220 | kref_get(&res->ref); | ||
221 | break; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | spin_unlock_bh(&dev->bss_lock); | ||
226 | if (!res) | ||
227 | return NULL; | ||
228 | return &res->pub; | ||
229 | } | ||
230 | EXPORT_SYMBOL(cfg80211_get_bss); | ||
231 | |||
232 | struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, | ||
233 | struct ieee80211_channel *channel, | ||
234 | const u8 *meshid, size_t meshidlen, | ||
235 | const u8 *meshcfg) | ||
236 | { | ||
237 | struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); | ||
238 | struct cfg80211_internal_bss *bss, *res = NULL; | ||
239 | |||
240 | spin_lock_bh(&dev->bss_lock); | ||
241 | |||
242 | list_for_each_entry(bss, &dev->bss_list, list) { | ||
243 | if (channel && bss->pub.channel != channel) | ||
244 | continue; | ||
245 | if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) { | ||
246 | res = bss; | ||
247 | kref_get(&res->ref); | ||
248 | break; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | spin_unlock_bh(&dev->bss_lock); | ||
253 | if (!res) | ||
254 | return NULL; | ||
255 | return &res->pub; | ||
256 | } | ||
257 | EXPORT_SYMBOL(cfg80211_get_mesh); | ||
258 | |||
259 | |||
260 | static void rb_insert_bss(struct cfg80211_registered_device *dev, | ||
261 | struct cfg80211_internal_bss *bss) | ||
262 | { | ||
263 | struct rb_node **p = &dev->bss_tree.rb_node; | ||
264 | struct rb_node *parent = NULL; | ||
265 | struct cfg80211_internal_bss *tbss; | ||
266 | int cmp; | ||
267 | |||
268 | while (*p) { | ||
269 | parent = *p; | ||
270 | tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn); | ||
271 | |||
272 | cmp = cmp_bss(&bss->pub, &tbss->pub); | ||
273 | |||
274 | if (WARN_ON(!cmp)) { | ||
275 | /* will sort of leak this BSS */ | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | if (cmp < 0) | ||
280 | p = &(*p)->rb_left; | ||
281 | else | ||
282 | p = &(*p)->rb_right; | ||
283 | } | ||
284 | |||
285 | rb_link_node(&bss->rbn, parent, p); | ||
286 | rb_insert_color(&bss->rbn, &dev->bss_tree); | ||
287 | } | ||
288 | |||
289 | static struct cfg80211_internal_bss * | ||
290 | rb_find_bss(struct cfg80211_registered_device *dev, | ||
291 | struct cfg80211_internal_bss *res) | ||
292 | { | ||
293 | struct rb_node *n = dev->bss_tree.rb_node; | ||
294 | struct cfg80211_internal_bss *bss; | ||
295 | int r; | ||
296 | |||
297 | while (n) { | ||
298 | bss = rb_entry(n, struct cfg80211_internal_bss, rbn); | ||
299 | r = cmp_bss(&res->pub, &bss->pub); | ||
300 | |||
301 | if (r == 0) | ||
302 | return bss; | ||
303 | else if (r < 0) | ||
304 | n = n->rb_left; | ||
305 | else | ||
306 | n = n->rb_right; | ||
307 | } | ||
308 | |||
309 | return NULL; | ||
310 | } | ||
311 | |||
312 | static struct cfg80211_internal_bss * | ||
313 | cfg80211_bss_update(struct cfg80211_registered_device *dev, | ||
314 | struct cfg80211_internal_bss *res, | ||
315 | bool overwrite) | ||
316 | { | ||
317 | struct cfg80211_internal_bss *found = NULL; | ||
318 | const u8 *meshid, *meshcfg; | ||
319 | |||
320 | /* | ||
321 | * The reference to "res" is donated to this function. | ||
322 | */ | ||
323 | |||
324 | if (WARN_ON(!res->pub.channel)) { | ||
325 | kref_put(&res->ref, bss_release); | ||
326 | return NULL; | ||
327 | } | ||
328 | |||
329 | res->ts = jiffies; | ||
330 | |||
331 | if (is_zero_ether_addr(res->pub.bssid)) { | ||
332 | /* must be mesh, verify */ | ||
333 | meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements, | ||
334 | res->pub.len_information_elements); | ||
335 | meshcfg = find_ie(WLAN_EID_MESH_CONFIG, | ||
336 | res->pub.information_elements, | ||
337 | res->pub.len_information_elements); | ||
338 | if (!meshid || !meshcfg || | ||
339 | meshcfg[1] != IEEE80211_MESH_CONFIG_LEN) { | ||
340 | /* bogus mesh */ | ||
341 | kref_put(&res->ref, bss_release); | ||
342 | return NULL; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | spin_lock_bh(&dev->bss_lock); | ||
347 | |||
348 | found = rb_find_bss(dev, res); | ||
349 | |||
350 | if (found && overwrite) { | ||
351 | list_replace(&found->list, &res->list); | ||
352 | rb_replace_node(&found->rbn, &res->rbn, | ||
353 | &dev->bss_tree); | ||
354 | kref_put(&found->ref, bss_release); | ||
355 | found = res; | ||
356 | } else if (found) { | ||
357 | kref_get(&found->ref); | ||
358 | found->pub.beacon_interval = res->pub.beacon_interval; | ||
359 | found->pub.tsf = res->pub.tsf; | ||
360 | found->pub.signal = res->pub.signal; | ||
361 | found->pub.signal_type = res->pub.signal_type; | ||
362 | found->pub.capability = res->pub.capability; | ||
363 | found->ts = res->ts; | ||
364 | kref_put(&res->ref, bss_release); | ||
365 | } else { | ||
366 | /* this "consumes" the reference */ | ||
367 | list_add_tail(&res->list, &dev->bss_list); | ||
368 | rb_insert_bss(dev, res); | ||
369 | found = res; | ||
370 | } | ||
371 | |||
372 | dev->bss_generation++; | ||
373 | spin_unlock_bh(&dev->bss_lock); | ||
374 | |||
375 | kref_get(&found->ref); | ||
376 | return found; | ||
377 | } | ||
378 | |||
379 | struct cfg80211_bss * | ||
380 | cfg80211_inform_bss_frame(struct wiphy *wiphy, | ||
381 | struct ieee80211_channel *channel, | ||
382 | struct ieee80211_mgmt *mgmt, size_t len, | ||
383 | s32 signal, enum cfg80211_signal_type sigtype, | ||
384 | gfp_t gfp) | ||
385 | { | ||
386 | struct cfg80211_internal_bss *res; | ||
387 | size_t ielen = len - offsetof(struct ieee80211_mgmt, | ||
388 | u.probe_resp.variable); | ||
389 | bool overwrite; | ||
390 | size_t privsz = wiphy->bss_priv_size; | ||
391 | |||
392 | if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC && | ||
393 | (signal < 0 || signal > 100))) | ||
394 | return NULL; | ||
395 | |||
396 | if (WARN_ON(!mgmt || !wiphy || | ||
397 | len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) | ||
398 | return NULL; | ||
399 | |||
400 | res = kzalloc(sizeof(*res) + privsz + ielen, gfp); | ||
401 | if (!res) | ||
402 | return NULL; | ||
403 | |||
404 | memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); | ||
405 | res->pub.channel = channel; | ||
406 | res->pub.signal_type = sigtype; | ||
407 | res->pub.signal = signal; | ||
408 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); | ||
409 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); | ||
410 | res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); | ||
411 | /* point to after the private area */ | ||
412 | res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; | ||
413 | memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen); | ||
414 | res->pub.len_information_elements = ielen; | ||
415 | |||
416 | kref_init(&res->ref); | ||
417 | |||
418 | overwrite = ieee80211_is_probe_resp(mgmt->frame_control); | ||
419 | |||
420 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite); | ||
421 | if (!res) | ||
422 | return NULL; | ||
423 | |||
424 | /* cfg80211_bss_update gives us a referenced result */ | ||
425 | return &res->pub; | ||
426 | } | ||
427 | EXPORT_SYMBOL(cfg80211_inform_bss_frame); | ||
428 | |||
429 | void cfg80211_put_bss(struct cfg80211_bss *pub) | ||
430 | { | ||
431 | struct cfg80211_internal_bss *bss; | ||
432 | |||
433 | if (!pub) | ||
434 | return; | ||
435 | |||
436 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | ||
437 | kref_put(&bss->ref, bss_release); | ||
438 | } | ||
439 | EXPORT_SYMBOL(cfg80211_put_bss); | ||
440 | |||
441 | void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | ||
442 | { | ||
443 | struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); | ||
444 | struct cfg80211_internal_bss *bss; | ||
445 | |||
446 | if (WARN_ON(!pub)) | ||
447 | return; | ||
448 | |||
449 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | ||
450 | |||
451 | spin_lock_bh(&dev->bss_lock); | ||
452 | |||
453 | list_del(&bss->list); | ||
454 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
455 | |||
456 | spin_unlock_bh(&dev->bss_lock); | ||
457 | |||
458 | kref_put(&bss->ref, bss_release); | ||
459 | } | ||
460 | EXPORT_SYMBOL(cfg80211_unlink_bss); | ||
461 | |||
462 | #ifdef CONFIG_WIRELESS_EXT | ||
463 | int cfg80211_wext_siwscan(struct net_device *dev, | ||
464 | struct iw_request_info *info, | ||
465 | union iwreq_data *wrqu, char *extra) | ||
466 | { | ||
467 | struct cfg80211_registered_device *rdev; | ||
468 | struct wiphy *wiphy; | ||
469 | struct iw_scan_req *wreq = NULL; | ||
470 | struct cfg80211_scan_request *creq; | ||
471 | int i, err, n_channels = 0; | ||
472 | enum ieee80211_band band; | ||
473 | |||
474 | if (!netif_running(dev)) | ||
475 | return -ENETDOWN; | ||
476 | |||
477 | rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); | ||
478 | |||
479 | if (IS_ERR(rdev)) | ||
480 | return PTR_ERR(rdev); | ||
481 | |||
482 | if (rdev->scan_req) { | ||
483 | err = -EBUSY; | ||
484 | goto out; | ||
485 | } | ||
486 | |||
487 | wiphy = &rdev->wiphy; | ||
488 | |||
489 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
490 | if (wiphy->bands[band]) | ||
491 | n_channels += wiphy->bands[band]->n_channels; | ||
492 | |||
493 | creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + | ||
494 | n_channels * sizeof(void *), | ||
495 | GFP_ATOMIC); | ||
496 | if (!creq) { | ||
497 | err = -ENOMEM; | ||
498 | goto out; | ||
499 | } | ||
500 | |||
501 | creq->wiphy = wiphy; | ||
502 | creq->ifidx = dev->ifindex; | ||
503 | creq->ssids = (void *)(creq + 1); | ||
504 | creq->channels = (void *)(creq->ssids + 1); | ||
505 | creq->n_channels = n_channels; | ||
506 | creq->n_ssids = 1; | ||
507 | |||
508 | /* all channels */ | ||
509 | i = 0; | ||
510 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
511 | int j; | ||
512 | if (!wiphy->bands[band]) | ||
513 | continue; | ||
514 | for (j = 0; j < wiphy->bands[band]->n_channels; j++) { | ||
515 | creq->channels[i] = &wiphy->bands[band]->channels[j]; | ||
516 | i++; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | /* translate scan request */ | ||
521 | if (wrqu->data.length == sizeof(struct iw_scan_req)) { | ||
522 | wreq = (struct iw_scan_req *)extra; | ||
523 | |||
524 | if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { | ||
525 | if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) | ||
526 | return -EINVAL; | ||
527 | memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len); | ||
528 | creq->ssids[0].ssid_len = wreq->essid_len; | ||
529 | } | ||
530 | if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE) | ||
531 | creq->n_ssids = 0; | ||
532 | } | ||
533 | |||
534 | rdev->scan_req = creq; | ||
535 | err = rdev->ops->scan(wiphy, dev, creq); | ||
536 | if (err) { | ||
537 | rdev->scan_req = NULL; | ||
538 | kfree(creq); | ||
539 | } | ||
540 | out: | ||
541 | cfg80211_put_dev(rdev); | ||
542 | return err; | ||
543 | } | ||
544 | EXPORT_SYMBOL(cfg80211_wext_siwscan); | ||
545 | |||
546 | static void ieee80211_scan_add_ies(struct iw_request_info *info, | ||
547 | struct cfg80211_bss *bss, | ||
548 | char **current_ev, char *end_buf) | ||
549 | { | ||
550 | u8 *pos, *end, *next; | ||
551 | struct iw_event iwe; | ||
552 | |||
553 | if (!bss->information_elements || | ||
554 | !bss->len_information_elements) | ||
555 | return; | ||
556 | |||
557 | /* | ||
558 | * If needed, fragment the IEs buffer (at IE boundaries) into short | ||
559 | * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. | ||
560 | */ | ||
561 | pos = bss->information_elements; | ||
562 | end = pos + bss->len_information_elements; | ||
563 | |||
564 | while (end - pos > IW_GENERIC_IE_MAX) { | ||
565 | next = pos + 2 + pos[1]; | ||
566 | while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) | ||
567 | next = next + 2 + next[1]; | ||
568 | |||
569 | memset(&iwe, 0, sizeof(iwe)); | ||
570 | iwe.cmd = IWEVGENIE; | ||
571 | iwe.u.data.length = next - pos; | ||
572 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
573 | end_buf, &iwe, pos); | ||
574 | |||
575 | pos = next; | ||
576 | } | ||
577 | |||
578 | if (end > pos) { | ||
579 | memset(&iwe, 0, sizeof(iwe)); | ||
580 | iwe.cmd = IWEVGENIE; | ||
581 | iwe.u.data.length = end - pos; | ||
582 | *current_ev = iwe_stream_add_point(info, *current_ev, | ||
583 | end_buf, &iwe, pos); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | |||
588 | static char * | ||
589 | ieee80211_bss(struct iw_request_info *info, | ||
590 | struct cfg80211_internal_bss *bss, | ||
591 | char *current_ev, char *end_buf) | ||
592 | { | ||
593 | struct iw_event iwe; | ||
594 | u8 *buf, *cfg, *p; | ||
595 | u8 *ie = bss->pub.information_elements; | ||
596 | int rem = bss->pub.len_information_elements, i; | ||
597 | bool ismesh = false; | ||
598 | |||
599 | memset(&iwe, 0, sizeof(iwe)); | ||
600 | iwe.cmd = SIOCGIWAP; | ||
601 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
602 | memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN); | ||
603 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
604 | IW_EV_ADDR_LEN); | ||
605 | |||
606 | memset(&iwe, 0, sizeof(iwe)); | ||
607 | iwe.cmd = SIOCGIWFREQ; | ||
608 | iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq); | ||
609 | iwe.u.freq.e = 0; | ||
610 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
611 | IW_EV_FREQ_LEN); | ||
612 | |||
613 | memset(&iwe, 0, sizeof(iwe)); | ||
614 | iwe.cmd = SIOCGIWFREQ; | ||
615 | iwe.u.freq.m = bss->pub.channel->center_freq; | ||
616 | iwe.u.freq.e = 6; | ||
617 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | ||
618 | IW_EV_FREQ_LEN); | ||
619 | |||
620 | if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) { | ||
621 | memset(&iwe, 0, sizeof(iwe)); | ||
622 | iwe.cmd = IWEVQUAL; | ||
623 | iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED | | ||
624 | IW_QUAL_NOISE_INVALID | | ||
625 | IW_QUAL_QUAL_INVALID; | ||
626 | switch (bss->pub.signal_type) { | ||
627 | case CFG80211_SIGNAL_TYPE_MBM: | ||
628 | iwe.u.qual.level = bss->pub.signal / 100; | ||
629 | iwe.u.qual.updated |= IW_QUAL_DBM; | ||
630 | break; | ||
631 | case CFG80211_SIGNAL_TYPE_UNSPEC: | ||
632 | iwe.u.qual.level = bss->pub.signal; | ||
633 | break; | ||
634 | default: | ||
635 | /* not reached */ | ||
636 | break; | ||
637 | } | ||
638 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
639 | &iwe, IW_EV_QUAL_LEN); | ||
640 | } | ||
641 | |||
642 | memset(&iwe, 0, sizeof(iwe)); | ||
643 | iwe.cmd = SIOCGIWENCODE; | ||
644 | if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY) | ||
645 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
646 | else | ||
647 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
648 | iwe.u.data.length = 0; | ||
649 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
650 | &iwe, ""); | ||
651 | |||
652 | while (rem >= 2) { | ||
653 | /* invalid data */ | ||
654 | if (ie[1] > rem - 2) | ||
655 | break; | ||
656 | |||
657 | switch (ie[0]) { | ||
658 | case WLAN_EID_SSID: | ||
659 | memset(&iwe, 0, sizeof(iwe)); | ||
660 | iwe.cmd = SIOCGIWESSID; | ||
661 | iwe.u.data.length = ie[1]; | ||
662 | iwe.u.data.flags = 1; | ||
663 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
664 | &iwe, ie + 2); | ||
665 | break; | ||
666 | case WLAN_EID_MESH_ID: | ||
667 | memset(&iwe, 0, sizeof(iwe)); | ||
668 | iwe.cmd = SIOCGIWESSID; | ||
669 | iwe.u.data.length = ie[1]; | ||
670 | iwe.u.data.flags = 1; | ||
671 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
672 | &iwe, ie + 2); | ||
673 | break; | ||
674 | case WLAN_EID_MESH_CONFIG: | ||
675 | ismesh = true; | ||
676 | if (ie[1] != IEEE80211_MESH_CONFIG_LEN) | ||
677 | break; | ||
678 | buf = kmalloc(50, GFP_ATOMIC); | ||
679 | if (!buf) | ||
680 | break; | ||
681 | cfg = ie + 2; | ||
682 | memset(&iwe, 0, sizeof(iwe)); | ||
683 | iwe.cmd = IWEVCUSTOM; | ||
684 | sprintf(buf, "Mesh network (version %d)", cfg[0]); | ||
685 | iwe.u.data.length = strlen(buf); | ||
686 | current_ev = iwe_stream_add_point(info, current_ev, | ||
687 | end_buf, | ||
688 | &iwe, buf); | ||
689 | sprintf(buf, "Path Selection Protocol ID: " | ||
690 | "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], | ||
691 | cfg[4]); | ||
692 | iwe.u.data.length = strlen(buf); | ||
693 | current_ev = iwe_stream_add_point(info, current_ev, | ||
694 | end_buf, | ||
695 | &iwe, buf); | ||
696 | sprintf(buf, "Path Selection Metric ID: " | ||
697 | "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], | ||
698 | cfg[8]); | ||
699 | iwe.u.data.length = strlen(buf); | ||
700 | current_ev = iwe_stream_add_point(info, current_ev, | ||
701 | end_buf, | ||
702 | &iwe, buf); | ||
703 | sprintf(buf, "Congestion Control Mode ID: " | ||
704 | "0x%02X%02X%02X%02X", cfg[9], cfg[10], | ||
705 | cfg[11], cfg[12]); | ||
706 | iwe.u.data.length = strlen(buf); | ||
707 | current_ev = iwe_stream_add_point(info, current_ev, | ||
708 | end_buf, | ||
709 | &iwe, buf); | ||
710 | sprintf(buf, "Channel Precedence: " | ||
711 | "0x%02X%02X%02X%02X", cfg[13], cfg[14], | ||
712 | cfg[15], cfg[16]); | ||
713 | iwe.u.data.length = strlen(buf); | ||
714 | current_ev = iwe_stream_add_point(info, current_ev, | ||
715 | end_buf, | ||
716 | &iwe, buf); | ||
717 | kfree(buf); | ||
718 | break; | ||
719 | case WLAN_EID_SUPP_RATES: | ||
720 | case WLAN_EID_EXT_SUPP_RATES: | ||
721 | /* display all supported rates in readable format */ | ||
722 | p = current_ev + iwe_stream_lcp_len(info); | ||
723 | |||
724 | memset(&iwe, 0, sizeof(iwe)); | ||
725 | iwe.cmd = SIOCGIWRATE; | ||
726 | /* Those two flags are ignored... */ | ||
727 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
728 | |||
729 | for (i = 0; i < ie[1]; i++) { | ||
730 | iwe.u.bitrate.value = | ||
731 | ((ie[i + 2] & 0x7f) * 500000); | ||
732 | p = iwe_stream_add_value(info, current_ev, p, | ||
733 | end_buf, &iwe, IW_EV_PARAM_LEN); | ||
734 | } | ||
735 | current_ev = p; | ||
736 | break; | ||
737 | } | ||
738 | rem -= ie[1] + 2; | ||
739 | ie += ie[1] + 2; | ||
740 | } | ||
741 | |||
742 | if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) | ||
743 | || ismesh) { | ||
744 | memset(&iwe, 0, sizeof(iwe)); | ||
745 | iwe.cmd = SIOCGIWMODE; | ||
746 | if (ismesh) | ||
747 | iwe.u.mode = IW_MODE_MESH; | ||
748 | else if (bss->pub.capability & WLAN_CAPABILITY_ESS) | ||
749 | iwe.u.mode = IW_MODE_MASTER; | ||
750 | else | ||
751 | iwe.u.mode = IW_MODE_ADHOC; | ||
752 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
753 | &iwe, IW_EV_UINT_LEN); | ||
754 | } | ||
755 | |||
756 | buf = kmalloc(30, GFP_ATOMIC); | ||
757 | if (buf) { | ||
758 | memset(&iwe, 0, sizeof(iwe)); | ||
759 | iwe.cmd = IWEVCUSTOM; | ||
760 | sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf)); | ||
761 | iwe.u.data.length = strlen(buf); | ||
762 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
763 | &iwe, buf); | ||
764 | memset(&iwe, 0, sizeof(iwe)); | ||
765 | iwe.cmd = IWEVCUSTOM; | ||
766 | sprintf(buf, " Last beacon: %dms ago", | ||
767 | jiffies_to_msecs(jiffies - bss->ts)); | ||
768 | iwe.u.data.length = strlen(buf); | ||
769 | current_ev = iwe_stream_add_point(info, current_ev, | ||
770 | end_buf, &iwe, buf); | ||
771 | kfree(buf); | ||
772 | } | ||
773 | |||
774 | ieee80211_scan_add_ies(info, &bss->pub, ¤t_ev, end_buf); | ||
775 | |||
776 | return current_ev; | ||
777 | } | ||
778 | |||
779 | |||
780 | static int ieee80211_scan_results(struct cfg80211_registered_device *dev, | ||
781 | struct iw_request_info *info, | ||
782 | char *buf, size_t len) | ||
783 | { | ||
784 | char *current_ev = buf; | ||
785 | char *end_buf = buf + len; | ||
786 | struct cfg80211_internal_bss *bss; | ||
787 | |||
788 | spin_lock_bh(&dev->bss_lock); | ||
789 | cfg80211_bss_expire(dev); | ||
790 | |||
791 | list_for_each_entry(bss, &dev->bss_list, list) { | ||
792 | if (buf + len - current_ev <= IW_EV_ADDR_LEN) { | ||
793 | spin_unlock_bh(&dev->bss_lock); | ||
794 | return -E2BIG; | ||
795 | } | ||
796 | current_ev = ieee80211_bss(info, bss, | ||
797 | current_ev, end_buf); | ||
798 | } | ||
799 | spin_unlock_bh(&dev->bss_lock); | ||
800 | return current_ev - buf; | ||
801 | } | ||
802 | |||
803 | |||
804 | int cfg80211_wext_giwscan(struct net_device *dev, | ||
805 | struct iw_request_info *info, | ||
806 | struct iw_point *data, char *extra) | ||
807 | { | ||
808 | struct cfg80211_registered_device *rdev; | ||
809 | int res; | ||
810 | |||
811 | if (!netif_running(dev)) | ||
812 | return -ENETDOWN; | ||
813 | |||
814 | rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); | ||
815 | |||
816 | if (IS_ERR(rdev)) | ||
817 | return PTR_ERR(rdev); | ||
818 | |||
819 | if (rdev->scan_req) { | ||
820 | res = -EAGAIN; | ||
821 | goto out; | ||
822 | } | ||
823 | |||
824 | res = ieee80211_scan_results(rdev, info, extra, data->length); | ||
825 | data->length = 0; | ||
826 | if (res >= 0) { | ||
827 | data->length = res; | ||
828 | res = 0; | ||
829 | } | ||
830 | |||
831 | out: | ||
832 | cfg80211_put_dev(rdev); | ||
833 | return res; | ||
834 | } | ||
835 | EXPORT_SYMBOL(cfg80211_wext_giwscan); | ||
836 | #endif | ||