diff options
author | David S. Miller <davem@davemloft.net> | 2009-03-01 01:32:16 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-01 01:32:16 -0500 |
commit | 8010dc306ba39a8cdb3993d1e809fcb7dfdf089a (patch) | |
tree | d1fa3fe2e1501a6780fc007f2f57b1fe0995e18e /net | |
parent | 5d242f1cee2c85721bbe9d8205e98c1c01f5d805 (diff) | |
parent | 2a07954b83a3d4dc93031d3ce030fb9380a8e15a (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
32 files changed, 3216 insertions, 2149 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 3503a3d21318..0e3ab88bb706 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -9,6 +9,7 @@ mac80211-y := \ | |||
9 | wpa.o \ | 9 | wpa.o \ |
10 | scan.o \ | 10 | scan.o \ |
11 | ht.o agg-tx.o agg-rx.o \ | 11 | ht.o agg-tx.o agg-rx.o \ |
12 | ibss.o \ | ||
12 | mlme.o \ | 13 | mlme.o \ |
13 | iface.o \ | 14 | iface.o \ |
14 | rate.o \ | 15 | rate.o \ |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 3112bfd441b6..a95affc94629 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -129,7 +129,6 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
129 | u8 dialog_token, u16 status, u16 policy, | 129 | u8 dialog_token, u16 status, u16 policy, |
130 | u16 buf_size, u16 timeout) | 130 | u16 buf_size, u16 timeout) |
131 | { | 131 | { |
132 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
133 | struct ieee80211_local *local = sdata->local; | 132 | struct ieee80211_local *local = sdata->local; |
134 | struct sk_buff *skb; | 133 | struct sk_buff *skb; |
135 | struct ieee80211_mgmt *mgmt; | 134 | struct ieee80211_mgmt *mgmt; |
@@ -151,8 +150,9 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
151 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 150 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
152 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 151 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
153 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 152 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
154 | else | 153 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
155 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 154 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
155 | |||
156 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 156 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
157 | IEEE80211_STYPE_ACTION); | 157 | IEEE80211_STYPE_ACTION); |
158 | 158 | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 1232d9f01ca9..1df116d4d6e7 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -49,7 +49,6 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | |||
49 | u16 agg_size, u16 timeout) | 49 | u16 agg_size, u16 timeout) |
50 | { | 50 | { |
51 | struct ieee80211_local *local = sdata->local; | 51 | struct ieee80211_local *local = sdata->local; |
52 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
53 | struct sk_buff *skb; | 52 | struct sk_buff *skb; |
54 | struct ieee80211_mgmt *mgmt; | 53 | struct ieee80211_mgmt *mgmt; |
55 | u16 capab; | 54 | u16 capab; |
@@ -69,8 +68,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | |||
69 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 68 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
70 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 69 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
71 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 70 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
72 | else | 71 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
73 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 72 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
74 | 73 | ||
75 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 74 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
76 | IEEE80211_STYPE_ACTION); | 75 | IEEE80211_STYPE_ACTION); |
@@ -132,9 +131,24 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
132 | 131 | ||
133 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 132 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
134 | 133 | ||
135 | if (local->hw.ampdu_queues) | 134 | if (local->hw.ampdu_queues) { |
136 | ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]); | 135 | if (initiator) { |
136 | /* | ||
137 | * Stop the AC queue to avoid issues where we send | ||
138 | * unaggregated frames already before the delba. | ||
139 | */ | ||
140 | ieee80211_stop_queue_by_reason(&local->hw, | ||
141 | local->hw.queues + sta->tid_to_tx_q[tid], | ||
142 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
143 | } | ||
137 | 144 | ||
145 | /* | ||
146 | * Pretend the driver woke the queue, just in case | ||
147 | * it disabled it before the session was stopped. | ||
148 | */ | ||
149 | ieee80211_wake_queue( | ||
150 | &local->hw, local->hw.queues + sta->tid_to_tx_q[tid]); | ||
151 | } | ||
138 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | 152 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | |
139 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | 153 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); |
140 | 154 | ||
@@ -144,8 +158,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
144 | /* HW shall not deny going back to legacy */ | 158 | /* HW shall not deny going back to legacy */ |
145 | if (WARN_ON(ret)) { | 159 | if (WARN_ON(ret)) { |
146 | *state = HT_AGG_STATE_OPERATIONAL; | 160 | *state = HT_AGG_STATE_OPERATIONAL; |
147 | if (local->hw.ampdu_queues) | ||
148 | ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]); | ||
149 | } | 161 | } |
150 | 162 | ||
151 | return ret; | 163 | return ret; |
@@ -189,14 +201,19 @@ static void sta_addba_resp_timer_expired(unsigned long data) | |||
189 | spin_unlock_bh(&sta->lock); | 201 | spin_unlock_bh(&sta->lock); |
190 | } | 202 | } |
191 | 203 | ||
204 | static inline int ieee80211_ac_from_tid(int tid) | ||
205 | { | ||
206 | return ieee802_1d_to_ac[tid & 7]; | ||
207 | } | ||
208 | |||
192 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | 209 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) |
193 | { | 210 | { |
194 | struct ieee80211_local *local = hw_to_local(hw); | 211 | struct ieee80211_local *local = hw_to_local(hw); |
195 | struct sta_info *sta; | 212 | struct sta_info *sta; |
196 | struct ieee80211_sub_if_data *sdata; | 213 | struct ieee80211_sub_if_data *sdata; |
197 | u16 start_seq_num; | ||
198 | u8 *state; | 214 | u8 *state; |
199 | int ret = 0; | 215 | int i, qn = -1, ret = 0; |
216 | u16 start_seq_num; | ||
200 | 217 | ||
201 | if (WARN_ON(!local->ops->ampdu_action)) | 218 | if (WARN_ON(!local->ops->ampdu_action)) |
202 | return -EINVAL; | 219 | return -EINVAL; |
@@ -209,6 +226,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
209 | ra, tid); | 226 | ra, tid); |
210 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 227 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
211 | 228 | ||
229 | if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) { | ||
230 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
231 | printk(KERN_DEBUG "rejecting on voice AC\n"); | ||
232 | #endif | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
212 | rcu_read_lock(); | 236 | rcu_read_lock(); |
213 | 237 | ||
214 | sta = sta_info_get(local, ra); | 238 | sta = sta_info_get(local, ra); |
@@ -217,7 +241,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
217 | printk(KERN_DEBUG "Could not find the station\n"); | 241 | printk(KERN_DEBUG "Could not find the station\n"); |
218 | #endif | 242 | #endif |
219 | ret = -ENOENT; | 243 | ret = -ENOENT; |
220 | goto exit; | 244 | goto unlock; |
221 | } | 245 | } |
222 | 246 | ||
223 | /* | 247 | /* |
@@ -230,11 +254,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
230 | sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 254 | sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
231 | sta->sdata->vif.type != NL80211_IFTYPE_AP) { | 255 | sta->sdata->vif.type != NL80211_IFTYPE_AP) { |
232 | ret = -EINVAL; | 256 | ret = -EINVAL; |
233 | goto exit; | 257 | goto unlock; |
234 | } | 258 | } |
235 | 259 | ||
236 | spin_lock_bh(&sta->lock); | 260 | spin_lock_bh(&sta->lock); |
237 | 261 | ||
262 | sdata = sta->sdata; | ||
263 | |||
238 | /* we have tried too many times, receiver does not want A-MPDU */ | 264 | /* 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) { | 265 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { |
240 | ret = -EBUSY; | 266 | ret = -EBUSY; |
@@ -252,6 +278,42 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
252 | goto err_unlock_sta; | 278 | goto err_unlock_sta; |
253 | } | 279 | } |
254 | 280 | ||
281 | if (hw->ampdu_queues) { | ||
282 | spin_lock(&local->queue_stop_reason_lock); | ||
283 | /* reserve a new queue for this session */ | ||
284 | for (i = 0; i < local->hw.ampdu_queues; i++) { | ||
285 | if (local->ampdu_ac_queue[i] < 0) { | ||
286 | qn = i; | ||
287 | local->ampdu_ac_queue[qn] = | ||
288 | ieee80211_ac_from_tid(tid); | ||
289 | break; | ||
290 | } | ||
291 | } | ||
292 | spin_unlock(&local->queue_stop_reason_lock); | ||
293 | |||
294 | if (qn < 0) { | ||
295 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
296 | printk(KERN_DEBUG "BA request denied - " | ||
297 | "queue unavailable for tid %d\n", tid); | ||
298 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
299 | ret = -ENOSPC; | ||
300 | goto err_unlock_sta; | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | * If we successfully allocate the session, we can't have | ||
305 | * anything going on on the queue this TID maps into, so | ||
306 | * stop it for now. This is a "virtual" stop using the same | ||
307 | * mechanism that drivers will use. | ||
308 | * | ||
309 | * XXX: queue up frames for this session in the sta_info | ||
310 | * struct instead to avoid hitting all other STAs. | ||
311 | */ | ||
312 | ieee80211_stop_queue_by_reason( | ||
313 | &local->hw, hw->queues + qn, | ||
314 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
315 | } | ||
316 | |||
255 | /* prepare A-MPDU MLME for Tx aggregation */ | 317 | /* prepare A-MPDU MLME for Tx aggregation */ |
256 | sta->ampdu_mlme.tid_tx[tid] = | 318 | sta->ampdu_mlme.tid_tx[tid] = |
257 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | 319 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); |
@@ -262,8 +324,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
262 | tid); | 324 | tid); |
263 | #endif | 325 | #endif |
264 | ret = -ENOMEM; | 326 | ret = -ENOMEM; |
265 | goto err_unlock_sta; | 327 | goto err_return_queue; |
266 | } | 328 | } |
329 | |||
267 | /* Tx timer */ | 330 | /* Tx timer */ |
268 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | 331 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = |
269 | sta_addba_resp_timer_expired; | 332 | sta_addba_resp_timer_expired; |
@@ -271,49 +334,25 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
271 | (unsigned long)&sta->timer_to_tid[tid]; | 334 | (unsigned long)&sta->timer_to_tid[tid]; |
272 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | 335 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); |
273 | 336 | ||
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 | 337 | /* 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 */ | 338 | * call back right away, it must see that the flow has begun */ |
292 | *state |= HT_ADDBA_REQUESTED_MSK; | 339 | *state |= HT_ADDBA_REQUESTED_MSK; |
293 | 340 | ||
294 | /* This is slightly racy because the queue isn't stopped */ | ||
295 | start_seq_num = sta->tid_seq[tid]; | 341 | start_seq_num = sta->tid_seq[tid]; |
296 | 342 | ||
297 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, | 343 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, |
298 | &sta->sta, tid, &start_seq_num); | 344 | &sta->sta, tid, &start_seq_num); |
299 | 345 | ||
300 | if (ret) { | 346 | 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 | 347 | #ifdef CONFIG_MAC80211_HT_DEBUG |
307 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | 348 | printk(KERN_DEBUG "BA request denied - HW unavailable for" |
308 | " tid %d\n", tid); | 349 | " tid %d\n", tid); |
309 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 350 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
310 | *state = HT_AGG_STATE_IDLE; | 351 | *state = HT_AGG_STATE_IDLE; |
311 | goto err_unlock_queue; | 352 | goto err_free; |
312 | } | 353 | } |
354 | sta->tid_to_tx_q[tid] = qn; | ||
313 | 355 | ||
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); | 356 | spin_unlock_bh(&sta->lock); |
318 | 357 | ||
319 | /* send an addBA request */ | 358 | /* send an addBA request */ |
@@ -322,7 +361,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
322 | sta->ampdu_mlme.dialog_token_allocator; | 361 | sta->ampdu_mlme.dialog_token_allocator; |
323 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | 362 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; |
324 | 363 | ||
325 | |||
326 | ieee80211_send_addba_request(sta->sdata, ra, tid, | 364 | ieee80211_send_addba_request(sta->sdata, ra, tid, |
327 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | 365 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, |
328 | sta->ampdu_mlme.tid_tx[tid]->ssn, | 366 | sta->ampdu_mlme.tid_tx[tid]->ssn, |
@@ -334,15 +372,24 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
334 | #ifdef CONFIG_MAC80211_HT_DEBUG | 372 | #ifdef CONFIG_MAC80211_HT_DEBUG |
335 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | 373 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); |
336 | #endif | 374 | #endif |
337 | goto exit; | 375 | goto unlock; |
338 | 376 | ||
339 | err_unlock_queue: | 377 | err_free: |
340 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 378 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
341 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 379 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
342 | ret = -EBUSY; | 380 | err_return_queue: |
343 | err_unlock_sta: | 381 | if (qn >= 0) { |
382 | /* We failed, so start queue again right away. */ | ||
383 | ieee80211_wake_queue_by_reason(hw, hw->queues + qn, | ||
384 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
385 | /* give queue back to pool */ | ||
386 | spin_lock(&local->queue_stop_reason_lock); | ||
387 | local->ampdu_ac_queue[qn] = -1; | ||
388 | spin_unlock(&local->queue_stop_reason_lock); | ||
389 | } | ||
390 | err_unlock_sta: | ||
344 | spin_unlock_bh(&sta->lock); | 391 | spin_unlock_bh(&sta->lock); |
345 | exit: | 392 | unlock: |
346 | rcu_read_unlock(); | 393 | rcu_read_unlock(); |
347 | return ret; | 394 | return ret; |
348 | } | 395 | } |
@@ -375,7 +422,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
375 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 422 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
376 | spin_lock_bh(&sta->lock); | 423 | spin_lock_bh(&sta->lock); |
377 | 424 | ||
378 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | 425 | if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) { |
379 | #ifdef CONFIG_MAC80211_HT_DEBUG | 426 | #ifdef CONFIG_MAC80211_HT_DEBUG |
380 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | 427 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", |
381 | *state); | 428 | *state); |
@@ -385,7 +432,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
385 | return; | 432 | return; |
386 | } | 433 | } |
387 | 434 | ||
388 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); | 435 | if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK)) |
436 | goto out; | ||
389 | 437 | ||
390 | *state |= HT_ADDBA_DRV_READY_MSK; | 438 | *state |= HT_ADDBA_DRV_READY_MSK; |
391 | 439 | ||
@@ -393,9 +441,18 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
393 | #ifdef CONFIG_MAC80211_HT_DEBUG | 441 | #ifdef CONFIG_MAC80211_HT_DEBUG |
394 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | 442 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); |
395 | #endif | 443 | #endif |
396 | if (hw->ampdu_queues) | 444 | if (hw->ampdu_queues) { |
397 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 445 | /* |
446 | * Wake up this queue, we stopped it earlier, | ||
447 | * this will in turn wake the entire AC. | ||
448 | */ | ||
449 | ieee80211_wake_queue_by_reason(hw, | ||
450 | hw->queues + sta->tid_to_tx_q[tid], | ||
451 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
452 | } | ||
398 | } | 453 | } |
454 | |||
455 | out: | ||
399 | spin_unlock_bh(&sta->lock); | 456 | spin_unlock_bh(&sta->lock); |
400 | rcu_read_unlock(); | 457 | rcu_read_unlock(); |
401 | } | 458 | } |
@@ -485,7 +542,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
485 | struct ieee80211_local *local = hw_to_local(hw); | 542 | struct ieee80211_local *local = hw_to_local(hw); |
486 | struct sta_info *sta; | 543 | struct sta_info *sta; |
487 | u8 *state; | 544 | u8 *state; |
488 | int agg_queue; | ||
489 | 545 | ||
490 | if (tid >= STA_TID_NUM) { | 546 | if (tid >= STA_TID_NUM) { |
491 | #ifdef CONFIG_MAC80211_HT_DEBUG | 547 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -527,19 +583,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
527 | ieee80211_send_delba(sta->sdata, ra, tid, | 583 | ieee80211_send_delba(sta->sdata, ra, tid, |
528 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | 584 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
529 | 585 | ||
530 | if (hw->ampdu_queues) { | 586 | spin_lock_bh(&sta->lock); |
531 | agg_queue = sta->tid_to_tx_q[tid]; | ||
532 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); | ||
533 | 587 | ||
534 | /* We just requeued the all the frames that were in the | 588 | if (*state & HT_AGG_STATE_INITIATOR_MSK && |
535 | * removed queue, and since we might miss a softirq we do | 589 | hw->ampdu_queues) { |
536 | * netif_schedule_queue. ieee80211_wake_queue is not used | 590 | /* |
537 | * here as this queue is not necessarily stopped | 591 | * Wake up this queue, we stopped it earlier, |
592 | * this will in turn wake the entire AC. | ||
538 | */ | 593 | */ |
539 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, | 594 | ieee80211_wake_queue_by_reason(hw, |
540 | agg_queue)); | 595 | hw->queues + sta->tid_to_tx_q[tid], |
596 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
541 | } | 597 | } |
542 | spin_lock_bh(&sta->lock); | 598 | |
543 | *state = HT_AGG_STATE_IDLE; | 599 | *state = HT_AGG_STATE_IDLE; |
544 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 600 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
545 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 601 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
@@ -613,12 +669,21 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
613 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 669 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
614 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) | 670 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) |
615 | == WLAN_STATUS_SUCCESS) { | 671 | == WLAN_STATUS_SUCCESS) { |
672 | u8 curstate = *state; | ||
673 | |||
616 | *state |= HT_ADDBA_RECEIVED_MSK; | 674 | *state |= HT_ADDBA_RECEIVED_MSK; |
617 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
618 | 675 | ||
619 | if (*state == HT_AGG_STATE_OPERATIONAL && | 676 | if (hw->ampdu_queues && *state != curstate && |
620 | local->hw.ampdu_queues) | 677 | *state == HT_AGG_STATE_OPERATIONAL) { |
621 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 678 | /* |
679 | * Wake up this queue, we stopped it earlier, | ||
680 | * this will in turn wake the entire AC. | ||
681 | */ | ||
682 | ieee80211_wake_queue_by_reason(hw, | ||
683 | hw->queues + sta->tid_to_tx_q[tid], | ||
684 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
685 | } | ||
686 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
622 | 687 | ||
623 | if (local->ops->ampdu_action) { | 688 | if (local->ops->ampdu_action) { |
624 | (void)local->ops->ampdu_action(hw, | 689 | (void)local->ops->ampdu_action(hw, |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c8d969be440b..c43129efc3bf 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -341,11 +341,15 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
341 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 341 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
342 | STATION_INFO_RX_BYTES | | 342 | STATION_INFO_RX_BYTES | |
343 | STATION_INFO_TX_BYTES | | 343 | STATION_INFO_TX_BYTES | |
344 | STATION_INFO_RX_PACKETS | | ||
345 | STATION_INFO_TX_PACKETS | | ||
344 | STATION_INFO_TX_BITRATE; | 346 | STATION_INFO_TX_BITRATE; |
345 | 347 | ||
346 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 348 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
347 | sinfo->rx_bytes = sta->rx_bytes; | 349 | sinfo->rx_bytes = sta->rx_bytes; |
348 | sinfo->tx_bytes = sta->tx_bytes; | 350 | sinfo->tx_bytes = sta->tx_bytes; |
351 | sinfo->rx_packets = sta->rx_packets; | ||
352 | sinfo->tx_packets = sta->tx_packets; | ||
349 | 353 | ||
350 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | 354 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { |
351 | sinfo->filled |= STATION_INFO_SIGNAL; | 355 | sinfo->filled |= STATION_INFO_SIGNAL; |
@@ -1180,45 +1184,45 @@ static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata, | |||
1180 | u8 subtype, u8 *ies, size_t ies_len) | 1184 | u8 subtype, u8 *ies, size_t ies_len) |
1181 | { | 1185 | { |
1182 | struct ieee80211_local *local = sdata->local; | 1186 | struct ieee80211_local *local = sdata->local; |
1183 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1187 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1184 | 1188 | ||
1185 | switch (subtype) { | 1189 | switch (subtype) { |
1186 | case IEEE80211_STYPE_PROBE_REQ >> 4: | 1190 | case IEEE80211_STYPE_PROBE_REQ >> 4: |
1187 | if (local->ops->hw_scan) | 1191 | if (local->ops->hw_scan) |
1188 | break; | 1192 | break; |
1189 | kfree(ifsta->ie_probereq); | 1193 | kfree(ifmgd->ie_probereq); |
1190 | ifsta->ie_probereq = ies; | 1194 | ifmgd->ie_probereq = ies; |
1191 | ifsta->ie_probereq_len = ies_len; | 1195 | ifmgd->ie_probereq_len = ies_len; |
1192 | return 0; | 1196 | return 0; |
1193 | case IEEE80211_STYPE_PROBE_RESP >> 4: | 1197 | case IEEE80211_STYPE_PROBE_RESP >> 4: |
1194 | kfree(ifsta->ie_proberesp); | 1198 | kfree(ifmgd->ie_proberesp); |
1195 | ifsta->ie_proberesp = ies; | 1199 | ifmgd->ie_proberesp = ies; |
1196 | ifsta->ie_proberesp_len = ies_len; | 1200 | ifmgd->ie_proberesp_len = ies_len; |
1197 | return 0; | 1201 | return 0; |
1198 | case IEEE80211_STYPE_AUTH >> 4: | 1202 | case IEEE80211_STYPE_AUTH >> 4: |
1199 | kfree(ifsta->ie_auth); | 1203 | kfree(ifmgd->ie_auth); |
1200 | ifsta->ie_auth = ies; | 1204 | ifmgd->ie_auth = ies; |
1201 | ifsta->ie_auth_len = ies_len; | 1205 | ifmgd->ie_auth_len = ies_len; |
1202 | return 0; | 1206 | return 0; |
1203 | case IEEE80211_STYPE_ASSOC_REQ >> 4: | 1207 | case IEEE80211_STYPE_ASSOC_REQ >> 4: |
1204 | kfree(ifsta->ie_assocreq); | 1208 | kfree(ifmgd->ie_assocreq); |
1205 | ifsta->ie_assocreq = ies; | 1209 | ifmgd->ie_assocreq = ies; |
1206 | ifsta->ie_assocreq_len = ies_len; | 1210 | ifmgd->ie_assocreq_len = ies_len; |
1207 | return 0; | 1211 | return 0; |
1208 | case IEEE80211_STYPE_REASSOC_REQ >> 4: | 1212 | case IEEE80211_STYPE_REASSOC_REQ >> 4: |
1209 | kfree(ifsta->ie_reassocreq); | 1213 | kfree(ifmgd->ie_reassocreq); |
1210 | ifsta->ie_reassocreq = ies; | 1214 | ifmgd->ie_reassocreq = ies; |
1211 | ifsta->ie_reassocreq_len = ies_len; | 1215 | ifmgd->ie_reassocreq_len = ies_len; |
1212 | return 0; | 1216 | return 0; |
1213 | case IEEE80211_STYPE_DEAUTH >> 4: | 1217 | case IEEE80211_STYPE_DEAUTH >> 4: |
1214 | kfree(ifsta->ie_deauth); | 1218 | kfree(ifmgd->ie_deauth); |
1215 | ifsta->ie_deauth = ies; | 1219 | ifmgd->ie_deauth = ies; |
1216 | ifsta->ie_deauth_len = ies_len; | 1220 | ifmgd->ie_deauth_len = ies_len; |
1217 | return 0; | 1221 | return 0; |
1218 | case IEEE80211_STYPE_DISASSOC >> 4: | 1222 | case IEEE80211_STYPE_DISASSOC >> 4: |
1219 | kfree(ifsta->ie_disassoc); | 1223 | kfree(ifmgd->ie_disassoc); |
1220 | ifsta->ie_disassoc = ies; | 1224 | ifmgd->ie_disassoc = ies; |
1221 | ifsta->ie_disassoc_len = ies_len; | 1225 | ifmgd->ie_disassoc_len = ies_len; |
1222 | return 0; | 1226 | return 0; |
1223 | } | 1227 | } |
1224 | 1228 | ||
@@ -1248,7 +1252,6 @@ static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy, | |||
1248 | 1252 | ||
1249 | switch (sdata->vif.type) { | 1253 | switch (sdata->vif.type) { |
1250 | case NL80211_IFTYPE_STATION: | 1254 | case NL80211_IFTYPE_STATION: |
1251 | case NL80211_IFTYPE_ADHOC: | ||
1252 | ret = set_mgmt_extra_ie_sta(sdata, params->subtype, | 1255 | ret = set_mgmt_extra_ie_sta(sdata, params->subtype, |
1253 | ies, ies_len); | 1256 | ies, ies_len); |
1254 | break; | 1257 | break; |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index c54219301724..e3420329f4e6 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -94,31 +94,31 @@ IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | |||
94 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); | 94 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); |
95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | 95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); |
96 | 96 | ||
97 | /* STA/IBSS attributes */ | 97 | /* STA attributes */ |
98 | IEEE80211_IF_FILE(state, u.sta.state, DEC); | 98 | IEEE80211_IF_FILE(state, u.mgd.state, DEC); |
99 | IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC); | 99 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
100 | IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC); | 100 | IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC); |
101 | IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE); | 101 | IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE); |
102 | IEEE80211_IF_FILE(aid, u.sta.aid, DEC); | 102 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); |
103 | IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX); | 103 | IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX); |
104 | IEEE80211_IF_FILE(capab, u.sta.capab, HEX); | 104 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); |
105 | IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE); | 105 | IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); |
106 | IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC); | 106 | IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); |
107 | IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC); | 107 | IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC); |
108 | IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX); | 108 | IEEE80211_IF_FILE(auth_algs, u.mgd.auth_algs, HEX); |
109 | IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC); | 109 | IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); |
110 | IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC); | 110 | IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); |
111 | 111 | ||
112 | static ssize_t ieee80211_if_fmt_flags( | 112 | static ssize_t ieee80211_if_fmt_flags( |
113 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | 113 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) |
114 | { | 114 | { |
115 | return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n", | 115 | return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n", |
116 | sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", | 116 | sdata->u.mgd.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", |
117 | sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", | 117 | sdata->u.mgd.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", |
118 | sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", | 118 | sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", |
119 | sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", | 119 | sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", |
120 | sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", | 120 | sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", |
121 | sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", | 121 | sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", |
122 | sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); | 122 | sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); |
123 | } | 123 | } |
124 | __IEEE80211_IF_FILE(flags); | 124 | __IEEE80211_IF_FILE(flags); |
@@ -283,9 +283,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
283 | #endif | 283 | #endif |
284 | break; | 284 | break; |
285 | case NL80211_IFTYPE_STATION: | 285 | case NL80211_IFTYPE_STATION: |
286 | case NL80211_IFTYPE_ADHOC: | ||
287 | add_sta_files(sdata); | 286 | add_sta_files(sdata); |
288 | break; | 287 | break; |
288 | case NL80211_IFTYPE_ADHOC: | ||
289 | /* XXX */ | ||
290 | break; | ||
289 | case NL80211_IFTYPE_AP: | 291 | case NL80211_IFTYPE_AP: |
290 | add_ap_files(sdata); | 292 | add_ap_files(sdata); |
291 | break; | 293 | break; |
@@ -418,9 +420,11 @@ static void del_files(struct ieee80211_sub_if_data *sdata) | |||
418 | #endif | 420 | #endif |
419 | break; | 421 | break; |
420 | case NL80211_IFTYPE_STATION: | 422 | case NL80211_IFTYPE_STATION: |
421 | case NL80211_IFTYPE_ADHOC: | ||
422 | del_sta_files(sdata); | 423 | del_sta_files(sdata); |
423 | break; | 424 | break; |
425 | case NL80211_IFTYPE_ADHOC: | ||
426 | /* XXX */ | ||
427 | break; | ||
424 | case NL80211_IFTYPE_AP: | 428 | case NL80211_IFTYPE_AP: |
425 | del_ap_files(sdata); | 429 | del_ap_files(sdata); |
426 | break; | 430 | break; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 82ea0b63a386..4e3c72f20de7 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -17,6 +17,7 @@ | |||
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 "rate.h" | ||
20 | 21 | ||
21 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 22 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, |
22 | struct ieee80211_ht_cap *ht_cap_ie, | 23 | struct ieee80211_ht_cap *ht_cap_ie, |
@@ -93,7 +94,9 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
93 | { | 94 | { |
94 | struct ieee80211_local *local = sdata->local; | 95 | struct ieee80211_local *local = sdata->local; |
95 | struct ieee80211_supported_band *sband; | 96 | struct ieee80211_supported_band *sband; |
97 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
96 | struct ieee80211_bss_ht_conf ht; | 98 | struct ieee80211_bss_ht_conf ht; |
99 | struct sta_info *sta; | ||
97 | u32 changed = 0; | 100 | u32 changed = 0; |
98 | bool enable_ht = true, ht_changed; | 101 | bool enable_ht = true, ht_changed; |
99 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 102 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
@@ -136,6 +139,16 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
136 | if (ht_changed) { | 139 | if (ht_changed) { |
137 | /* channel_type change automatically detected */ | 140 | /* channel_type change automatically detected */ |
138 | ieee80211_hw_config(local, 0); | 141 | ieee80211_hw_config(local, 0); |
142 | |||
143 | rcu_read_lock(); | ||
144 | |||
145 | sta = sta_info_get(local, ifmgd->bssid); | ||
146 | if (sta) | ||
147 | rate_control_rate_update(local, sband, sta, | ||
148 | IEEE80211_RC_HT_CHANGED); | ||
149 | |||
150 | rcu_read_unlock(); | ||
151 | |||
139 | } | 152 | } |
140 | 153 | ||
141 | /* disable HT */ | 154 | /* disable HT */ |
@@ -169,7 +182,6 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
169 | u16 initiator, u16 reason_code) | 182 | u16 initiator, u16 reason_code) |
170 | { | 183 | { |
171 | struct ieee80211_local *local = sdata->local; | 184 | struct ieee80211_local *local = sdata->local; |
172 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
173 | struct sk_buff *skb; | 185 | struct sk_buff *skb; |
174 | struct ieee80211_mgmt *mgmt; | 186 | struct ieee80211_mgmt *mgmt; |
175 | u16 params; | 187 | u16 params; |
@@ -190,8 +202,9 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
190 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 202 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
191 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 203 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
192 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 204 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
193 | else | 205 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
194 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 206 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
207 | |||
195 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 208 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
196 | IEEE80211_STYPE_ACTION); | 209 | IEEE80211_STYPE_ACTION); |
197 | 210 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c new file mode 100644 index 000000000000..a96ce9dfc6b5 --- /dev/null +++ b/net/mac80211/ibss.c | |||
@@ -0,0 +1,905 @@ | |||
1 | /* | ||
2 | * IBSS mode implementation | ||
3 | * Copyright 2003-2008, Jouni Malinen <j@w1.fi> | ||
4 | * Copyright 2004, Instant802 Networks, Inc. | ||
5 | * Copyright 2005, Devicescape Software, Inc. | ||
6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
7 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
8 | * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | #include <linux/if_ether.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/if_arp.h> | ||
19 | #include <linux/etherdevice.h> | ||
20 | #include <linux/rtnetlink.h> | ||
21 | #include <net/mac80211.h> | ||
22 | #include <asm/unaligned.h> | ||
23 | |||
24 | #include "ieee80211_i.h" | ||
25 | #include "rate.h" | ||
26 | |||
27 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | ||
28 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) | ||
29 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | ||
30 | |||
31 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | ||
32 | #define IEEE80211_IBSS_MERGE_DELAY 0x400000 | ||
33 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | ||
34 | |||
35 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | ||
36 | |||
37 | |||
38 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | ||
39 | struct ieee80211_mgmt *mgmt, | ||
40 | size_t len) | ||
41 | { | ||
42 | u16 auth_alg, auth_transaction, status_code; | ||
43 | |||
44 | if (len < 24 + 6) | ||
45 | return; | ||
46 | |||
47 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
48 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
49 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
50 | |||
51 | /* | ||
52 | * IEEE 802.11 standard does not require authentication in IBSS | ||
53 | * networks and most implementations do not seem to use it. | ||
54 | * However, try to reply to authentication attempts if someone | ||
55 | * has actually implemented this. | ||
56 | */ | ||
57 | if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) | ||
58 | ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, | ||
59 | sdata->u.ibss.bssid, 0); | ||
60 | } | ||
61 | |||
62 | static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||
63 | const u8 *bssid, const int beacon_int, | ||
64 | const int freq, | ||
65 | const size_t supp_rates_len, | ||
66 | const u8 *supp_rates, | ||
67 | const u16 capability) | ||
68 | { | ||
69 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
70 | struct ieee80211_local *local = sdata->local; | ||
71 | int res = 0, rates, i, j; | ||
72 | struct sk_buff *skb; | ||
73 | struct ieee80211_mgmt *mgmt; | ||
74 | u8 *pos; | ||
75 | struct ieee80211_supported_band *sband; | ||
76 | union iwreq_data wrqu; | ||
77 | |||
78 | if (local->ops->reset_tsf) { | ||
79 | /* Reset own TSF to allow time synchronization work. */ | ||
80 | local->ops->reset_tsf(local_to_hw(local)); | ||
81 | } | ||
82 | |||
83 | if ((ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) && | ||
84 | memcmp(ifibss->bssid, bssid, ETH_ALEN) == 0) | ||
85 | return res; | ||
86 | |||
87 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | ||
88 | if (!skb) { | ||
89 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
90 | "response\n", sdata->dev->name); | ||
91 | return -ENOMEM; | ||
92 | } | ||
93 | |||
94 | if (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) { | ||
95 | /* Remove possible STA entries from other IBSS networks. */ | ||
96 | sta_info_flush_delayed(sdata); | ||
97 | } | ||
98 | |||
99 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
100 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
101 | if (res) | ||
102 | return res; | ||
103 | |||
104 | local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; | ||
105 | |||
106 | sdata->drop_unencrypted = capability & | ||
107 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
108 | |||
109 | res = ieee80211_set_freq(sdata, freq); | ||
110 | |||
111 | if (res) | ||
112 | return res; | ||
113 | |||
114 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
115 | |||
116 | /* Build IBSS probe response */ | ||
117 | |||
118 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
119 | |||
120 | mgmt = (struct ieee80211_mgmt *) | ||
121 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | ||
122 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | ||
123 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
124 | IEEE80211_STYPE_PROBE_RESP); | ||
125 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
126 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
127 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | ||
128 | mgmt->u.beacon.beacon_int = | ||
129 | cpu_to_le16(local->hw.conf.beacon_int); | ||
130 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | ||
131 | |||
132 | pos = skb_put(skb, 2 + ifibss->ssid_len); | ||
133 | *pos++ = WLAN_EID_SSID; | ||
134 | *pos++ = ifibss->ssid_len; | ||
135 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); | ||
136 | |||
137 | rates = supp_rates_len; | ||
138 | if (rates > 8) | ||
139 | rates = 8; | ||
140 | pos = skb_put(skb, 2 + rates); | ||
141 | *pos++ = WLAN_EID_SUPP_RATES; | ||
142 | *pos++ = rates; | ||
143 | memcpy(pos, supp_rates, rates); | ||
144 | |||
145 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
146 | pos = skb_put(skb, 2 + 1); | ||
147 | *pos++ = WLAN_EID_DS_PARAMS; | ||
148 | *pos++ = 1; | ||
149 | *pos++ = ieee80211_frequency_to_channel(freq); | ||
150 | } | ||
151 | |||
152 | pos = skb_put(skb, 2 + 2); | ||
153 | *pos++ = WLAN_EID_IBSS_PARAMS; | ||
154 | *pos++ = 2; | ||
155 | /* FIX: set ATIM window based on scan results */ | ||
156 | *pos++ = 0; | ||
157 | *pos++ = 0; | ||
158 | |||
159 | if (supp_rates_len > 8) { | ||
160 | rates = supp_rates_len - 8; | ||
161 | pos = skb_put(skb, 2 + rates); | ||
162 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
163 | *pos++ = rates; | ||
164 | memcpy(pos, &supp_rates[8], rates); | ||
165 | } | ||
166 | |||
167 | ifibss->probe_resp = skb; | ||
168 | |||
169 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | | ||
170 | IEEE80211_IFCC_BEACON_ENABLED); | ||
171 | |||
172 | |||
173 | rates = 0; | ||
174 | for (i = 0; i < supp_rates_len; i++) { | ||
175 | int bitrate = (supp_rates[i] & 0x7f) * 5; | ||
176 | for (j = 0; j < sband->n_bitrates; j++) | ||
177 | if (sband->bitrates[j].bitrate == bitrate) | ||
178 | rates |= BIT(j); | ||
179 | } | ||
180 | |||
181 | ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); | ||
182 | |||
183 | ifibss->flags |= IEEE80211_IBSS_PREV_BSSID_SET; | ||
184 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; | ||
185 | mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
186 | |||
187 | memset(&wrqu, 0, sizeof(wrqu)); | ||
188 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | ||
189 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | ||
190 | |||
191 | return res; | ||
192 | } | ||
193 | |||
194 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||
195 | struct ieee80211_bss *bss) | ||
196 | { | ||
197 | return __ieee80211_sta_join_ibss(sdata, | ||
198 | bss->cbss.bssid, | ||
199 | bss->cbss.beacon_interval, | ||
200 | bss->cbss.channel->center_freq, | ||
201 | bss->supp_rates_len, bss->supp_rates, | ||
202 | bss->cbss.capability); | ||
203 | } | ||
204 | |||
205 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||
206 | struct ieee80211_mgmt *mgmt, | ||
207 | size_t len, | ||
208 | struct ieee80211_rx_status *rx_status, | ||
209 | struct ieee802_11_elems *elems, | ||
210 | bool beacon) | ||
211 | { | ||
212 | struct ieee80211_local *local = sdata->local; | ||
213 | int freq; | ||
214 | struct ieee80211_bss *bss; | ||
215 | struct sta_info *sta; | ||
216 | struct ieee80211_channel *channel; | ||
217 | u64 beacon_timestamp, rx_timestamp; | ||
218 | u32 supp_rates = 0; | ||
219 | enum ieee80211_band band = rx_status->band; | ||
220 | |||
221 | if (elems->ds_params && elems->ds_params_len == 1) | ||
222 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | ||
223 | else | ||
224 | freq = rx_status->freq; | ||
225 | |||
226 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
227 | |||
228 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
229 | return; | ||
230 | |||
231 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && | ||
232 | memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) { | ||
233 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
234 | |||
235 | rcu_read_lock(); | ||
236 | |||
237 | sta = sta_info_get(local, mgmt->sa); | ||
238 | if (sta) { | ||
239 | u32 prev_rates; | ||
240 | |||
241 | prev_rates = sta->sta.supp_rates[band]; | ||
242 | /* make sure mandatory rates are always added */ | ||
243 | sta->sta.supp_rates[band] = supp_rates | | ||
244 | ieee80211_mandatory_rates(local, band); | ||
245 | |||
246 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
247 | if (sta->sta.supp_rates[band] != prev_rates) | ||
248 | printk(KERN_DEBUG "%s: updated supp_rates set " | ||
249 | "for %pM based on beacon info (0x%llx | " | ||
250 | "0x%llx -> 0x%llx)\n", | ||
251 | sdata->dev->name, | ||
252 | sta->sta.addr, | ||
253 | (unsigned long long) prev_rates, | ||
254 | (unsigned long long) supp_rates, | ||
255 | (unsigned long long) sta->sta.supp_rates[band]); | ||
256 | #endif | ||
257 | } else | ||
258 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
259 | |||
260 | rcu_read_unlock(); | ||
261 | } | ||
262 | |||
263 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | ||
264 | channel, beacon); | ||
265 | if (!bss) | ||
266 | return; | ||
267 | |||
268 | /* was just updated in ieee80211_bss_info_update */ | ||
269 | beacon_timestamp = bss->cbss.tsf; | ||
270 | |||
271 | /* check if we need to merge IBSS */ | ||
272 | |||
273 | /* merge only on beacons (???) */ | ||
274 | if (!beacon) | ||
275 | goto put_bss; | ||
276 | |||
277 | /* we use a fixed BSSID */ | ||
278 | if (sdata->u.ibss.flags & IEEE80211_IBSS_BSSID_SET) | ||
279 | goto put_bss; | ||
280 | |||
281 | /* not an IBSS */ | ||
282 | if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) | ||
283 | goto put_bss; | ||
284 | |||
285 | /* different channel */ | ||
286 | if (bss->cbss.channel != local->oper_channel) | ||
287 | goto put_bss; | ||
288 | |||
289 | /* different SSID */ | ||
290 | if (elems->ssid_len != sdata->u.ibss.ssid_len || | ||
291 | memcmp(elems->ssid, sdata->u.ibss.ssid, | ||
292 | sdata->u.ibss.ssid_len)) | ||
293 | goto put_bss; | ||
294 | |||
295 | /* same BSSID */ | ||
296 | if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) | ||
297 | goto put_bss; | ||
298 | |||
299 | if (rx_status->flag & RX_FLAG_TSFT) { | ||
300 | /* | ||
301 | * For correct IBSS merging we need mactime; since mactime is | ||
302 | * defined as the time the first data symbol of the frame hits | ||
303 | * the PHY, and the timestamp of the beacon is defined as "the | ||
304 | * time that the data symbol containing the first bit of the | ||
305 | * timestamp is transmitted to the PHY plus the transmitting | ||
306 | * STA's delays through its local PHY from the MAC-PHY | ||
307 | * interface to its interface with the WM" (802.11 11.1.2) | ||
308 | * - equals the time this bit arrives at the receiver - we have | ||
309 | * to take into account the offset between the two. | ||
310 | * | ||
311 | * E.g. at 1 MBit that means mactime is 192 usec earlier | ||
312 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | ||
313 | */ | ||
314 | int rate; | ||
315 | |||
316 | if (rx_status->flag & RX_FLAG_HT) | ||
317 | rate = 65; /* TODO: HT rates */ | ||
318 | else | ||
319 | rate = local->hw.wiphy->bands[band]-> | ||
320 | bitrates[rx_status->rate_idx].bitrate; | ||
321 | |||
322 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
323 | } else if (local && local->ops && local->ops->get_tsf) | ||
324 | /* second best option: get current TSF */ | ||
325 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | ||
326 | else | ||
327 | /* can't merge without knowing the TSF */ | ||
328 | rx_timestamp = -1LLU; | ||
329 | |||
330 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
331 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | ||
332 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | ||
333 | mgmt->sa, mgmt->bssid, | ||
334 | (unsigned long long)rx_timestamp, | ||
335 | (unsigned long long)beacon_timestamp, | ||
336 | (unsigned long long)(rx_timestamp - beacon_timestamp), | ||
337 | jiffies); | ||
338 | #endif | ||
339 | |||
340 | /* give slow hardware some time to do the TSF sync */ | ||
341 | if (rx_timestamp < IEEE80211_IBSS_MERGE_DELAY) | ||
342 | goto put_bss; | ||
343 | |||
344 | if (beacon_timestamp > rx_timestamp) { | ||
345 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
346 | printk(KERN_DEBUG "%s: beacon TSF higher than " | ||
347 | "local TSF - IBSS merge with BSSID %pM\n", | ||
348 | sdata->dev->name, mgmt->bssid); | ||
349 | #endif | ||
350 | ieee80211_sta_join_ibss(sdata, bss); | ||
351 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
352 | } | ||
353 | |||
354 | put_bss: | ||
355 | ieee80211_rx_bss_put(local, bss); | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * Add a new IBSS station, will also be called by the RX code when, | ||
360 | * in IBSS mode, receiving a frame from a yet-unknown station, hence | ||
361 | * must be callable in atomic context. | ||
362 | */ | ||
363 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
364 | u8 *bssid,u8 *addr, u32 supp_rates) | ||
365 | { | ||
366 | struct ieee80211_local *local = sdata->local; | ||
367 | struct sta_info *sta; | ||
368 | int band = local->hw.conf.channel->band; | ||
369 | |||
370 | /* TODO: Could consider removing the least recently used entry and | ||
371 | * allow new one to be added. */ | ||
372 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | ||
373 | if (net_ratelimit()) { | ||
374 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | ||
375 | "entry %pM\n", sdata->dev->name, addr); | ||
376 | } | ||
377 | return NULL; | ||
378 | } | ||
379 | |||
380 | if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) | ||
381 | return NULL; | ||
382 | |||
383 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
384 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", | ||
385 | wiphy_name(local->hw.wiphy), addr, sdata->dev->name); | ||
386 | #endif | ||
387 | |||
388 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
389 | if (!sta) | ||
390 | return NULL; | ||
391 | |||
392 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
393 | |||
394 | /* make sure mandatory rates are always added */ | ||
395 | sta->sta.supp_rates[band] = supp_rates | | ||
396 | ieee80211_mandatory_rates(local, band); | ||
397 | |||
398 | rate_control_rate_init(sta); | ||
399 | |||
400 | if (sta_info_insert(sta)) | ||
401 | return NULL; | ||
402 | |||
403 | return sta; | ||
404 | } | ||
405 | |||
406 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
407 | { | ||
408 | struct ieee80211_local *local = sdata->local; | ||
409 | int active = 0; | ||
410 | struct sta_info *sta; | ||
411 | |||
412 | rcu_read_lock(); | ||
413 | |||
414 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
415 | if (sta->sdata == sdata && | ||
416 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
417 | jiffies)) { | ||
418 | active++; | ||
419 | break; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | rcu_read_unlock(); | ||
424 | |||
425 | return active; | ||
426 | } | ||
427 | |||
428 | |||
429 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | ||
430 | { | ||
431 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
432 | |||
433 | mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
434 | |||
435 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | ||
436 | if (ieee80211_sta_active_ibss(sdata)) | ||
437 | return; | ||
438 | |||
439 | if ((ifibss->flags & IEEE80211_IBSS_BSSID_SET) && | ||
440 | (!(ifibss->flags & IEEE80211_IBSS_AUTO_CHANNEL_SEL))) | ||
441 | return; | ||
442 | |||
443 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | ||
444 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | ||
445 | |||
446 | /* XXX maybe racy? */ | ||
447 | if (sdata->local->scan_req) | ||
448 | return; | ||
449 | |||
450 | memcpy(sdata->local->int_scan_req.ssids[0].ssid, | ||
451 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | ||
452 | sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; | ||
453 | ieee80211_request_scan(sdata, &sdata->local->int_scan_req); | ||
454 | } | ||
455 | |||
456 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | ||
457 | { | ||
458 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
459 | struct ieee80211_local *local = sdata->local; | ||
460 | struct ieee80211_supported_band *sband; | ||
461 | u8 *pos; | ||
462 | u8 bssid[ETH_ALEN]; | ||
463 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
464 | u16 capability; | ||
465 | int i; | ||
466 | |||
467 | if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) { | ||
468 | memcpy(bssid, ifibss->bssid, ETH_ALEN); | ||
469 | } else { | ||
470 | /* Generate random, not broadcast, locally administered BSSID. Mix in | ||
471 | * own MAC address to make sure that devices that do not have proper | ||
472 | * random number generator get different BSSID. */ | ||
473 | get_random_bytes(bssid, ETH_ALEN); | ||
474 | for (i = 0; i < ETH_ALEN; i++) | ||
475 | bssid[i] ^= sdata->dev->dev_addr[i]; | ||
476 | bssid[0] &= ~0x01; | ||
477 | bssid[0] |= 0x02; | ||
478 | } | ||
479 | |||
480 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | ||
481 | sdata->dev->name, bssid); | ||
482 | |||
483 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
484 | |||
485 | if (local->hw.conf.beacon_int == 0) | ||
486 | local->hw.conf.beacon_int = 100; | ||
487 | |||
488 | capability = WLAN_CAPABILITY_IBSS; | ||
489 | |||
490 | if (sdata->default_key) | ||
491 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
492 | else | ||
493 | sdata->drop_unencrypted = 0; | ||
494 | |||
495 | pos = supp_rates; | ||
496 | for (i = 0; i < sband->n_bitrates; i++) { | ||
497 | int rate = sband->bitrates[i].bitrate; | ||
498 | *pos++ = (u8) (rate / 5); | ||
499 | } | ||
500 | |||
501 | return __ieee80211_sta_join_ibss(sdata, | ||
502 | bssid, local->hw.conf.beacon_int, | ||
503 | local->hw.conf.channel->center_freq, | ||
504 | sband->n_bitrates, supp_rates, | ||
505 | capability); | ||
506 | } | ||
507 | |||
508 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | ||
509 | { | ||
510 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
511 | struct ieee80211_local *local = sdata->local; | ||
512 | struct ieee80211_bss *bss; | ||
513 | const u8 *bssid = NULL; | ||
514 | int active_ibss; | ||
515 | |||
516 | if (ifibss->ssid_len == 0) | ||
517 | return -EINVAL; | ||
518 | |||
519 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
520 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
521 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | ||
522 | sdata->dev->name, active_ibss); | ||
523 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
524 | |||
525 | if (active_ibss) | ||
526 | return 0; | ||
527 | |||
528 | if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) | ||
529 | bssid = ifibss->bssid; | ||
530 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, NULL, bssid, | ||
531 | ifibss->ssid, ifibss->ssid_len, | ||
532 | WLAN_CAPABILITY_IBSS, | ||
533 | WLAN_CAPABILITY_IBSS); | ||
534 | |||
535 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
536 | if (bss) | ||
537 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " | ||
538 | "%pM\n", bss->cbss.bssid, ifibss->bssid); | ||
539 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
540 | |||
541 | if (bss && | ||
542 | (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) || | ||
543 | memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN))) { | ||
544 | int ret; | ||
545 | |||
546 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | ||
547 | " based on configured SSID\n", | ||
548 | sdata->dev->name, bss->cbss.bssid); | ||
549 | |||
550 | ret = ieee80211_sta_join_ibss(sdata, bss); | ||
551 | ieee80211_rx_bss_put(local, bss); | ||
552 | return ret; | ||
553 | } else if (bss) | ||
554 | ieee80211_rx_bss_put(local, bss); | ||
555 | |||
556 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
557 | printk(KERN_DEBUG " did not try to join ibss\n"); | ||
558 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
559 | |||
560 | /* Selected IBSS not found in current scan results - try to scan */ | ||
561 | if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && | ||
562 | !ieee80211_sta_active_ibss(sdata)) { | ||
563 | mod_timer(&ifibss->timer, jiffies + | ||
564 | IEEE80211_IBSS_MERGE_INTERVAL); | ||
565 | } else if (time_after(jiffies, local->last_scan_completed + | ||
566 | IEEE80211_SCAN_INTERVAL)) { | ||
567 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | ||
568 | "join\n", sdata->dev->name); | ||
569 | |||
570 | /* XXX maybe racy? */ | ||
571 | if (local->scan_req) | ||
572 | return -EBUSY; | ||
573 | |||
574 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
575 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | ||
576 | local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; | ||
577 | return ieee80211_request_scan(sdata, &local->int_scan_req); | ||
578 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { | ||
579 | int interval = IEEE80211_SCAN_INTERVAL; | ||
580 | |||
581 | if (time_after(jiffies, ifibss->ibss_join_req + | ||
582 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | ||
583 | if (!(local->oper_channel->flags & | ||
584 | IEEE80211_CHAN_NO_IBSS)) | ||
585 | return ieee80211_sta_create_ibss(sdata); | ||
586 | printk(KERN_DEBUG "%s: IBSS not allowed on" | ||
587 | " %d MHz\n", sdata->dev->name, | ||
588 | local->hw.conf.channel->center_freq); | ||
589 | |||
590 | /* No IBSS found - decrease scan interval and continue | ||
591 | * scanning. */ | ||
592 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | ||
593 | } | ||
594 | |||
595 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
596 | mod_timer(&ifibss->timer, jiffies + interval); | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | ||
604 | struct ieee80211_mgmt *mgmt, | ||
605 | size_t len) | ||
606 | { | ||
607 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
608 | struct ieee80211_local *local = sdata->local; | ||
609 | int tx_last_beacon; | ||
610 | struct sk_buff *skb; | ||
611 | struct ieee80211_mgmt *resp; | ||
612 | u8 *pos, *end; | ||
613 | |||
614 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || | ||
615 | len < 24 + 2 || !ifibss->probe_resp) | ||
616 | return; | ||
617 | |||
618 | if (local->ops->tx_last_beacon) | ||
619 | tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); | ||
620 | else | ||
621 | tx_last_beacon = 1; | ||
622 | |||
623 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
624 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" | ||
625 | " (tx_last_beacon=%d)\n", | ||
626 | sdata->dev->name, mgmt->sa, mgmt->da, | ||
627 | mgmt->bssid, tx_last_beacon); | ||
628 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
629 | |||
630 | if (!tx_last_beacon) | ||
631 | return; | ||
632 | |||
633 | if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 && | ||
634 | memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) | ||
635 | return; | ||
636 | |||
637 | end = ((u8 *) mgmt) + len; | ||
638 | pos = mgmt->u.probe_req.variable; | ||
639 | if (pos[0] != WLAN_EID_SSID || | ||
640 | pos + 2 + pos[1] > end) { | ||
641 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
642 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " | ||
643 | "from %pM\n", | ||
644 | sdata->dev->name, mgmt->sa); | ||
645 | #endif | ||
646 | return; | ||
647 | } | ||
648 | if (pos[1] != 0 && | ||
649 | (pos[1] != ifibss->ssid_len || | ||
650 | memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len) != 0)) { | ||
651 | /* Ignore ProbeReq for foreign SSID */ | ||
652 | return; | ||
653 | } | ||
654 | |||
655 | /* Reply with ProbeResp */ | ||
656 | skb = skb_copy(ifibss->probe_resp, GFP_KERNEL); | ||
657 | if (!skb) | ||
658 | return; | ||
659 | |||
660 | resp = (struct ieee80211_mgmt *) skb->data; | ||
661 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | ||
662 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
663 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", | ||
664 | sdata->dev->name, resp->da); | ||
665 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
666 | ieee80211_tx_skb(sdata, skb, 0); | ||
667 | } | ||
668 | |||
669 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | ||
670 | struct ieee80211_mgmt *mgmt, | ||
671 | size_t len, | ||
672 | struct ieee80211_rx_status *rx_status) | ||
673 | { | ||
674 | size_t baselen; | ||
675 | struct ieee802_11_elems elems; | ||
676 | |||
677 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | ||
678 | return; /* ignore ProbeResp to foreign address */ | ||
679 | |||
680 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | ||
681 | if (baselen > len) | ||
682 | return; | ||
683 | |||
684 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | ||
685 | &elems); | ||
686 | |||
687 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | ||
688 | } | ||
689 | |||
690 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | ||
691 | struct ieee80211_mgmt *mgmt, | ||
692 | size_t len, | ||
693 | struct ieee80211_rx_status *rx_status) | ||
694 | { | ||
695 | size_t baselen; | ||
696 | struct ieee802_11_elems elems; | ||
697 | |||
698 | /* Process beacon from the current BSS */ | ||
699 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | ||
700 | if (baselen > len) | ||
701 | return; | ||
702 | |||
703 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | ||
704 | |||
705 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); | ||
706 | } | ||
707 | |||
708 | static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | ||
709 | struct sk_buff *skb) | ||
710 | { | ||
711 | struct ieee80211_rx_status *rx_status; | ||
712 | struct ieee80211_mgmt *mgmt; | ||
713 | u16 fc; | ||
714 | |||
715 | rx_status = (struct ieee80211_rx_status *) skb->cb; | ||
716 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
717 | fc = le16_to_cpu(mgmt->frame_control); | ||
718 | |||
719 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
720 | case IEEE80211_STYPE_PROBE_REQ: | ||
721 | ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len); | ||
722 | break; | ||
723 | case IEEE80211_STYPE_PROBE_RESP: | ||
724 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, | ||
725 | rx_status); | ||
726 | break; | ||
727 | case IEEE80211_STYPE_BEACON: | ||
728 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | ||
729 | rx_status); | ||
730 | break; | ||
731 | case IEEE80211_STYPE_AUTH: | ||
732 | ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); | ||
733 | break; | ||
734 | } | ||
735 | |||
736 | kfree_skb(skb); | ||
737 | } | ||
738 | |||
739 | static void ieee80211_ibss_work(struct work_struct *work) | ||
740 | { | ||
741 | struct ieee80211_sub_if_data *sdata = | ||
742 | container_of(work, struct ieee80211_sub_if_data, u.ibss.work); | ||
743 | struct ieee80211_local *local = sdata->local; | ||
744 | struct ieee80211_if_ibss *ifibss; | ||
745 | struct sk_buff *skb; | ||
746 | |||
747 | if (!netif_running(sdata->dev)) | ||
748 | return; | ||
749 | |||
750 | if (local->sw_scanning || local->hw_scanning) | ||
751 | return; | ||
752 | |||
753 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC)) | ||
754 | return; | ||
755 | ifibss = &sdata->u.ibss; | ||
756 | |||
757 | while ((skb = skb_dequeue(&ifibss->skb_queue))) | ||
758 | ieee80211_ibss_rx_queued_mgmt(sdata, skb); | ||
759 | |||
760 | if (!test_and_clear_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request)) | ||
761 | return; | ||
762 | |||
763 | switch (ifibss->state) { | ||
764 | case IEEE80211_IBSS_MLME_SEARCH: | ||
765 | ieee80211_sta_find_ibss(sdata); | ||
766 | break; | ||
767 | case IEEE80211_IBSS_MLME_JOINED: | ||
768 | ieee80211_sta_merge_ibss(sdata); | ||
769 | break; | ||
770 | default: | ||
771 | WARN_ON(1); | ||
772 | break; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | static void ieee80211_ibss_timer(unsigned long data) | ||
777 | { | ||
778 | struct ieee80211_sub_if_data *sdata = | ||
779 | (struct ieee80211_sub_if_data *) data; | ||
780 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
781 | struct ieee80211_local *local = sdata->local; | ||
782 | |||
783 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); | ||
784 | queue_work(local->hw.workqueue, &ifibss->work); | ||
785 | } | ||
786 | |||
787 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | ||
788 | { | ||
789 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
790 | |||
791 | INIT_WORK(&ifibss->work, ieee80211_ibss_work); | ||
792 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, | ||
793 | (unsigned long) sdata); | ||
794 | skb_queue_head_init(&ifibss->skb_queue); | ||
795 | |||
796 | ifibss->flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | | ||
797 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; | ||
798 | } | ||
799 | |||
800 | int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata) | ||
801 | { | ||
802 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
803 | |||
804 | ifibss->flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; | ||
805 | |||
806 | if (ifibss->ssid_len) | ||
807 | ifibss->flags |= IEEE80211_IBSS_SSID_SET; | ||
808 | else | ||
809 | ifibss->flags &= ~IEEE80211_IBSS_SSID_SET; | ||
810 | |||
811 | ifibss->ibss_join_req = jiffies; | ||
812 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
813 | |||
814 | return ieee80211_sta_find_ibss(sdata); | ||
815 | } | ||
816 | |||
817 | int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | ||
818 | { | ||
819 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
820 | |||
821 | if (len > IEEE80211_MAX_SSID_LEN) | ||
822 | return -EINVAL; | ||
823 | |||
824 | if (ifibss->ssid_len != len || memcmp(ifibss->ssid, ssid, len) != 0) { | ||
825 | memset(ifibss->ssid, 0, sizeof(ifibss->ssid)); | ||
826 | memcpy(ifibss->ssid, ssid, len); | ||
827 | ifibss->ssid_len = len; | ||
828 | } | ||
829 | |||
830 | return ieee80211_ibss_commit(sdata); | ||
831 | } | ||
832 | |||
833 | int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | ||
834 | { | ||
835 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
836 | |||
837 | memcpy(ssid, ifibss->ssid, ifibss->ssid_len); | ||
838 | *len = ifibss->ssid_len; | ||
839 | |||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | ||
844 | { | ||
845 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
846 | |||
847 | if (is_valid_ether_addr(bssid)) { | ||
848 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
849 | ifibss->flags |= IEEE80211_IBSS_BSSID_SET; | ||
850 | } else { | ||
851 | memset(ifibss->bssid, 0, ETH_ALEN); | ||
852 | ifibss->flags &= ~IEEE80211_IBSS_BSSID_SET; | ||
853 | } | ||
854 | |||
855 | if (netif_running(sdata->dev)) { | ||
856 | if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { | ||
857 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | ||
858 | "the low-level driver\n", sdata->dev->name); | ||
859 | } | ||
860 | } | ||
861 | |||
862 | return ieee80211_ibss_commit(sdata); | ||
863 | } | ||
864 | |||
865 | /* scan finished notification */ | ||
866 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) | ||
867 | { | ||
868 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
869 | struct ieee80211_if_ibss *ifibss; | ||
870 | |||
871 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
872 | ifibss = &sdata->u.ibss; | ||
873 | if ((!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) || | ||
874 | !ieee80211_sta_active_ibss(sdata)) | ||
875 | ieee80211_sta_find_ibss(sdata); | ||
876 | } | ||
877 | } | ||
878 | |||
879 | ieee80211_rx_result | ||
880 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
881 | struct ieee80211_rx_status *rx_status) | ||
882 | { | ||
883 | struct ieee80211_local *local = sdata->local; | ||
884 | struct ieee80211_mgmt *mgmt; | ||
885 | u16 fc; | ||
886 | |||
887 | if (skb->len < 24) | ||
888 | return RX_DROP_MONITOR; | ||
889 | |||
890 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
891 | fc = le16_to_cpu(mgmt->frame_control); | ||
892 | |||
893 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
894 | case IEEE80211_STYPE_PROBE_RESP: | ||
895 | case IEEE80211_STYPE_BEACON: | ||
896 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); | ||
897 | case IEEE80211_STYPE_PROBE_REQ: | ||
898 | case IEEE80211_STYPE_AUTH: | ||
899 | skb_queue_tail(&sdata->u.ibss.skb_queue, skb); | ||
900 | queue_work(local->hw.workqueue, &sdata->u.ibss.work); | ||
901 | return RX_QUEUED; | ||
902 | } | ||
903 | |||
904 | return RX_DROP_MONITOR; | ||
905 | } | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2cb743ed9f9c..ecbc8e0cb3e7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -239,7 +239,7 @@ struct mesh_preq_queue { | |||
239 | u8 flags; | 239 | u8 flags; |
240 | }; | 240 | }; |
241 | 241 | ||
242 | /* flags used in struct ieee80211_if_sta.flags */ | 242 | /* flags used in struct ieee80211_if_managed.flags */ |
243 | #define IEEE80211_STA_SSID_SET BIT(0) | 243 | #define IEEE80211_STA_SSID_SET BIT(0) |
244 | #define IEEE80211_STA_BSSID_SET BIT(1) | 244 | #define IEEE80211_STA_BSSID_SET BIT(1) |
245 | #define IEEE80211_STA_PREV_BSSID_SET BIT(2) | 245 | #define IEEE80211_STA_PREV_BSSID_SET BIT(2) |
@@ -262,31 +262,30 @@ struct mesh_preq_queue { | |||
262 | #define IEEE80211_STA_REQ_AUTH 2 | 262 | #define IEEE80211_STA_REQ_AUTH 2 |
263 | #define IEEE80211_STA_REQ_RUN 3 | 263 | #define IEEE80211_STA_REQ_RUN 3 |
264 | 264 | ||
265 | /* STA/IBSS MLME states */ | ||
266 | enum ieee80211_sta_mlme_state { | ||
267 | IEEE80211_STA_MLME_DISABLED, | ||
268 | IEEE80211_STA_MLME_DIRECT_PROBE, | ||
269 | IEEE80211_STA_MLME_AUTHENTICATE, | ||
270 | IEEE80211_STA_MLME_ASSOCIATE, | ||
271 | IEEE80211_STA_MLME_ASSOCIATED, | ||
272 | IEEE80211_STA_MLME_IBSS_SEARCH, | ||
273 | IEEE80211_STA_MLME_IBSS_JOINED, | ||
274 | }; | ||
275 | |||
276 | /* bitfield of allowed auth algs */ | 265 | /* bitfield of allowed auth algs */ |
277 | #define IEEE80211_AUTH_ALG_OPEN BIT(0) | 266 | #define IEEE80211_AUTH_ALG_OPEN BIT(0) |
278 | #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) | 267 | #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) |
279 | #define IEEE80211_AUTH_ALG_LEAP BIT(2) | 268 | #define IEEE80211_AUTH_ALG_LEAP BIT(2) |
280 | 269 | ||
281 | struct ieee80211_if_sta { | 270 | struct ieee80211_if_managed { |
282 | struct timer_list timer; | 271 | struct timer_list timer; |
283 | struct timer_list chswitch_timer; | 272 | struct timer_list chswitch_timer; |
284 | struct work_struct work; | 273 | struct work_struct work; |
285 | struct work_struct chswitch_work; | 274 | struct work_struct chswitch_work; |
275 | |||
286 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 276 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
277 | |||
287 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 278 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
288 | enum ieee80211_sta_mlme_state state; | ||
289 | size_t ssid_len; | 279 | size_t ssid_len; |
280 | |||
281 | enum { | ||
282 | IEEE80211_STA_MLME_DISABLED, | ||
283 | IEEE80211_STA_MLME_DIRECT_PROBE, | ||
284 | IEEE80211_STA_MLME_AUTHENTICATE, | ||
285 | IEEE80211_STA_MLME_ASSOCIATE, | ||
286 | IEEE80211_STA_MLME_ASSOCIATED, | ||
287 | } state; | ||
288 | |||
290 | u16 aid; | 289 | u16 aid; |
291 | u16 ap_capab, capab; | 290 | u16 ap_capab, capab; |
292 | u8 *extra_ie; /* to be added to the end of AssocReq */ | 291 | u8 *extra_ie; /* to be added to the end of AssocReq */ |
@@ -319,10 +318,6 @@ struct ieee80211_if_sta { | |||
319 | IEEE80211_MFP_REQUIRED | 318 | IEEE80211_MFP_REQUIRED |
320 | } mfp; /* management frame protection */ | 319 | } mfp; /* management frame protection */ |
321 | 320 | ||
322 | unsigned long ibss_join_req; | ||
323 | struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ | ||
324 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; | ||
325 | |||
326 | int wmm_last_param_set; | 321 | int wmm_last_param_set; |
327 | 322 | ||
328 | /* Extra IE data for management frames */ | 323 | /* Extra IE data for management frames */ |
@@ -342,6 +337,42 @@ struct ieee80211_if_sta { | |||
342 | size_t ie_disassoc_len; | 337 | size_t ie_disassoc_len; |
343 | }; | 338 | }; |
344 | 339 | ||
340 | enum ieee80211_ibss_flags { | ||
341 | IEEE80211_IBSS_AUTO_CHANNEL_SEL = BIT(0), | ||
342 | IEEE80211_IBSS_AUTO_BSSID_SEL = BIT(1), | ||
343 | IEEE80211_IBSS_BSSID_SET = BIT(2), | ||
344 | IEEE80211_IBSS_PREV_BSSID_SET = BIT(3), | ||
345 | IEEE80211_IBSS_SSID_SET = BIT(4), | ||
346 | }; | ||
347 | |||
348 | enum ieee80211_ibss_request { | ||
349 | IEEE80211_IBSS_REQ_RUN = 0, | ||
350 | }; | ||
351 | |||
352 | struct ieee80211_if_ibss { | ||
353 | struct timer_list timer; | ||
354 | struct work_struct work; | ||
355 | |||
356 | struct sk_buff_head skb_queue; | ||
357 | |||
358 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
359 | u8 ssid_len; | ||
360 | |||
361 | u32 flags; | ||
362 | |||
363 | u8 bssid[ETH_ALEN]; | ||
364 | |||
365 | unsigned long request; | ||
366 | |||
367 | unsigned long ibss_join_req; | ||
368 | struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ | ||
369 | |||
370 | enum { | ||
371 | IEEE80211_IBSS_MLME_SEARCH, | ||
372 | IEEE80211_IBSS_MLME_JOINED, | ||
373 | } state; | ||
374 | }; | ||
375 | |||
345 | struct ieee80211_if_mesh { | 376 | struct ieee80211_if_mesh { |
346 | struct work_struct work; | 377 | struct work_struct work; |
347 | struct timer_list housekeeping_timer; | 378 | struct timer_list housekeeping_timer; |
@@ -445,7 +476,8 @@ struct ieee80211_sub_if_data { | |||
445 | struct ieee80211_if_ap ap; | 476 | struct ieee80211_if_ap ap; |
446 | struct ieee80211_if_wds wds; | 477 | struct ieee80211_if_wds wds; |
447 | struct ieee80211_if_vlan vlan; | 478 | struct ieee80211_if_vlan vlan; |
448 | struct ieee80211_if_sta sta; | 479 | struct ieee80211_if_managed mgd; |
480 | struct ieee80211_if_ibss ibss; | ||
449 | #ifdef CONFIG_MAC80211_MESH | 481 | #ifdef CONFIG_MAC80211_MESH |
450 | struct ieee80211_if_mesh mesh; | 482 | struct ieee80211_if_mesh mesh; |
451 | #endif | 483 | #endif |
@@ -564,12 +596,10 @@ enum { | |||
564 | enum queue_stop_reason { | 596 | enum queue_stop_reason { |
565 | IEEE80211_QUEUE_STOP_REASON_DRIVER, | 597 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
566 | IEEE80211_QUEUE_STOP_REASON_PS, | 598 | IEEE80211_QUEUE_STOP_REASON_PS, |
567 | IEEE80211_QUEUE_STOP_REASON_CSA | 599 | IEEE80211_QUEUE_STOP_REASON_CSA, |
600 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, | ||
568 | }; | 601 | }; |
569 | 602 | ||
570 | /* maximum number of hardware queues we support. */ | ||
571 | #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) | ||
572 | |||
573 | struct ieee80211_master_priv { | 603 | struct ieee80211_master_priv { |
574 | struct ieee80211_local *local; | 604 | struct ieee80211_local *local; |
575 | }; | 605 | }; |
@@ -582,9 +612,15 @@ struct ieee80211_local { | |||
582 | 612 | ||
583 | const struct ieee80211_ops *ops; | 613 | const struct ieee80211_ops *ops; |
584 | 614 | ||
585 | unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; | 615 | /* AC queue corresponding to each AMPDU queue */ |
586 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; | 616 | s8 ampdu_ac_queue[IEEE80211_MAX_AMPDU_QUEUES]; |
617 | unsigned int amdpu_ac_stop_refcnt[IEEE80211_MAX_AMPDU_QUEUES]; | ||
618 | |||
619 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES + | ||
620 | IEEE80211_MAX_AMPDU_QUEUES]; | ||
621 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ | ||
587 | spinlock_t queue_stop_reason_lock; | 622 | spinlock_t queue_stop_reason_lock; |
623 | |||
588 | struct net_device *mdev; /* wmaster# - "master" 802.11 device */ | 624 | struct net_device *mdev; /* wmaster# - "master" 802.11 device */ |
589 | int open_count; | 625 | int open_count; |
590 | int monitors, cooked_mntrs; | 626 | int monitors, cooked_mntrs; |
@@ -888,34 +924,41 @@ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); | |||
888 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 924 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
889 | u32 changed); | 925 | u32 changed); |
890 | void ieee80211_configure_filter(struct ieee80211_local *local); | 926 | void ieee80211_configure_filter(struct ieee80211_local *local); |
927 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); | ||
891 | 928 | ||
892 | /* wireless extensions */ | 929 | /* wireless extensions */ |
893 | extern const struct iw_handler_def ieee80211_iw_handler_def; | 930 | extern const struct iw_handler_def ieee80211_iw_handler_def; |
894 | 931 | ||
895 | /* STA/IBSS code */ | 932 | /* STA code */ |
896 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); | 933 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); |
897 | void ieee80211_scan_work(struct work_struct *work); | 934 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, |
898 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 935 | struct sk_buff *skb, |
899 | struct ieee80211_rx_status *rx_status); | 936 | struct ieee80211_rx_status *rx_status); |
937 | int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata); | ||
900 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); | 938 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); |
901 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); | 939 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); |
902 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); | 940 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); |
903 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | 941 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata); |
904 | struct ieee80211_if_sta *ifsta); | ||
905 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
906 | u8 *bssid, u8 *addr, u32 supp_rates); | ||
907 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); | 942 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); |
908 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); | 943 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); |
909 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); | ||
910 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
911 | struct ieee802_11_elems *elems, | ||
912 | enum ieee80211_band band); | ||
913 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
914 | u8 *ssid, size_t ssid_len); | ||
915 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 944 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
916 | struct ieee80211_sub_if_data *sdata); | 945 | struct ieee80211_sub_if_data *sdata); |
917 | 946 | ||
947 | /* IBSS code */ | ||
948 | int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata); | ||
949 | int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); | ||
950 | int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); | ||
951 | int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); | ||
952 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | ||
953 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); | ||
954 | ieee80211_rx_result | ||
955 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
956 | struct ieee80211_rx_status *rx_status); | ||
957 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
958 | u8 *bssid, u8 *addr, u32 supp_rates); | ||
959 | |||
918 | /* scan/BSS handling */ | 960 | /* scan/BSS handling */ |
961 | void ieee80211_scan_work(struct work_struct *work); | ||
919 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 962 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
920 | struct cfg80211_scan_request *req); | 963 | struct cfg80211_scan_request *req); |
921 | int ieee80211_scan_results(struct ieee80211_local *local, | 964 | int ieee80211_scan_results(struct ieee80211_local *local, |
@@ -1042,6 +1085,25 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
1042 | enum queue_stop_reason reason); | 1085 | enum queue_stop_reason reason); |
1043 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 1086 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
1044 | enum queue_stop_reason reason); | 1087 | enum queue_stop_reason reason); |
1088 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | ||
1089 | enum queue_stop_reason reason); | ||
1090 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | ||
1091 | enum queue_stop_reason reason); | ||
1092 | |||
1093 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
1094 | u16 transaction, u16 auth_alg, | ||
1095 | u8 *extra, size_t extra_len, | ||
1096 | const u8 *bssid, int encrypt); | ||
1097 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
1098 | u8 *ssid, size_t ssid_len, | ||
1099 | u8 *ie, size_t ie_len); | ||
1100 | |||
1101 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
1102 | const size_t supp_rates_len, | ||
1103 | const u8 *supp_rates); | ||
1104 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
1105 | struct ieee802_11_elems *elems, | ||
1106 | enum ieee80211_band band); | ||
1045 | 1107 | ||
1046 | #ifdef CONFIG_MAC80211_NOINLINE | 1108 | #ifdef CONFIG_MAC80211_NOINLINE |
1047 | #define debug_noinline noinline | 1109 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index df94b9365264..2acc416e77e1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -236,7 +236,10 @@ static int ieee80211_open(struct net_device *dev) | |||
236 | break; | 236 | break; |
237 | case NL80211_IFTYPE_STATION: | 237 | case NL80211_IFTYPE_STATION: |
238 | case NL80211_IFTYPE_ADHOC: | 238 | case NL80211_IFTYPE_ADHOC: |
239 | sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 239 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
240 | sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
241 | else | ||
242 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; | ||
240 | /* fall through */ | 243 | /* fall through */ |
241 | default: | 244 | default: |
242 | conf.vif = &sdata->vif; | 245 | conf.vif = &sdata->vif; |
@@ -321,11 +324,10 @@ static int ieee80211_open(struct net_device *dev) | |||
321 | * yet be effective. Trigger execution of ieee80211_sta_work | 324 | * yet be effective. Trigger execution of ieee80211_sta_work |
322 | * to fix this. | 325 | * to fix this. |
323 | */ | 326 | */ |
324 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 327 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
325 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 328 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); |
326 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 329 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
327 | queue_work(local->hw.workqueue, &ifsta->work); | 330 | queue_work(local->hw.workqueue, &sdata->u.ibss.work); |
328 | } | ||
329 | 331 | ||
330 | netif_tx_start_all_queues(dev); | 332 | netif_tx_start_all_queues(dev); |
331 | 333 | ||
@@ -452,15 +454,13 @@ static int ieee80211_stop(struct net_device *dev) | |||
452 | netif_addr_unlock_bh(local->mdev); | 454 | netif_addr_unlock_bh(local->mdev); |
453 | break; | 455 | break; |
454 | case NL80211_IFTYPE_STATION: | 456 | case NL80211_IFTYPE_STATION: |
455 | case NL80211_IFTYPE_ADHOC: | ||
456 | /* Announce that we are leaving the network. */ | 457 | /* Announce that we are leaving the network. */ |
457 | if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED) | 458 | if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED) |
458 | ieee80211_sta_deauthenticate(sdata, | 459 | ieee80211_sta_deauthenticate(sdata, |
459 | WLAN_REASON_DEAUTH_LEAVING); | 460 | WLAN_REASON_DEAUTH_LEAVING); |
460 | 461 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | |
461 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); | 462 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
462 | del_timer_sync(&sdata->u.sta.chswitch_timer); | 463 | del_timer_sync(&sdata->u.mgd.timer); |
463 | del_timer_sync(&sdata->u.sta.timer); | ||
464 | /* | 464 | /* |
465 | * If the timer fired while we waited for it, it will have | 465 | * If the timer fired while we waited for it, it will have |
466 | * requeued the work. Now the work will be running again | 466 | * requeued the work. Now the work will be running again |
@@ -468,8 +468,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
468 | * whether the interface is running, which, at this point, | 468 | * whether the interface is running, which, at this point, |
469 | * it no longer is. | 469 | * it no longer is. |
470 | */ | 470 | */ |
471 | cancel_work_sync(&sdata->u.sta.work); | 471 | cancel_work_sync(&sdata->u.mgd.work); |
472 | cancel_work_sync(&sdata->u.sta.chswitch_work); | 472 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
473 | /* | 473 | /* |
474 | * When we get here, the interface is marked down. | 474 | * When we get here, the interface is marked down. |
475 | * Call synchronize_rcu() to wait for the RX path | 475 | * Call synchronize_rcu() to wait for the RX path |
@@ -477,13 +477,22 @@ static int ieee80211_stop(struct net_device *dev) | |||
477 | * frames at this very time on another CPU. | 477 | * frames at this very time on another CPU. |
478 | */ | 478 | */ |
479 | synchronize_rcu(); | 479 | synchronize_rcu(); |
480 | skb_queue_purge(&sdata->u.sta.skb_queue); | 480 | skb_queue_purge(&sdata->u.mgd.skb_queue); |
481 | 481 | ||
482 | sdata->u.sta.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | | 482 | sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | |
483 | IEEE80211_STA_TKIP_WEP_USED); | 483 | IEEE80211_STA_TKIP_WEP_USED); |
484 | kfree(sdata->u.sta.extra_ie); | 484 | kfree(sdata->u.mgd.extra_ie); |
485 | sdata->u.sta.extra_ie = NULL; | 485 | sdata->u.mgd.extra_ie = NULL; |
486 | sdata->u.sta.extra_ie_len = 0; | 486 | sdata->u.mgd.extra_ie_len = 0; |
487 | /* fall through */ | ||
488 | case NL80211_IFTYPE_ADHOC: | ||
489 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
490 | memset(sdata->u.ibss.bssid, 0, ETH_ALEN); | ||
491 | del_timer_sync(&sdata->u.ibss.timer); | ||
492 | cancel_work_sync(&sdata->u.ibss.work); | ||
493 | synchronize_rcu(); | ||
494 | skb_queue_purge(&sdata->u.ibss.skb_queue); | ||
495 | } | ||
487 | /* fall through */ | 496 | /* fall through */ |
488 | case NL80211_IFTYPE_MESH_POINT: | 497 | case NL80211_IFTYPE_MESH_POINT: |
489 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 498 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
@@ -629,19 +638,20 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
629 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 638 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
630 | mesh_rmc_free(sdata); | 639 | mesh_rmc_free(sdata); |
631 | break; | 640 | break; |
632 | case NL80211_IFTYPE_STATION: | ||
633 | case NL80211_IFTYPE_ADHOC: | 641 | case NL80211_IFTYPE_ADHOC: |
634 | kfree(sdata->u.sta.extra_ie); | 642 | kfree_skb(sdata->u.ibss.probe_resp); |
635 | kfree(sdata->u.sta.assocreq_ies); | 643 | break; |
636 | kfree(sdata->u.sta.assocresp_ies); | 644 | case NL80211_IFTYPE_STATION: |
637 | kfree_skb(sdata->u.sta.probe_resp); | 645 | kfree(sdata->u.mgd.extra_ie); |
638 | kfree(sdata->u.sta.ie_probereq); | 646 | kfree(sdata->u.mgd.assocreq_ies); |
639 | kfree(sdata->u.sta.ie_proberesp); | 647 | kfree(sdata->u.mgd.assocresp_ies); |
640 | kfree(sdata->u.sta.ie_auth); | 648 | kfree(sdata->u.mgd.ie_probereq); |
641 | kfree(sdata->u.sta.ie_assocreq); | 649 | kfree(sdata->u.mgd.ie_proberesp); |
642 | kfree(sdata->u.sta.ie_reassocreq); | 650 | kfree(sdata->u.mgd.ie_auth); |
643 | kfree(sdata->u.sta.ie_deauth); | 651 | kfree(sdata->u.mgd.ie_assocreq); |
644 | kfree(sdata->u.sta.ie_disassoc); | 652 | kfree(sdata->u.mgd.ie_reassocreq); |
653 | kfree(sdata->u.mgd.ie_deauth); | ||
654 | kfree(sdata->u.mgd.ie_disassoc); | ||
645 | break; | 655 | break; |
646 | case NL80211_IFTYPE_WDS: | 656 | case NL80211_IFTYPE_WDS: |
647 | case NL80211_IFTYPE_AP_VLAN: | 657 | case NL80211_IFTYPE_AP_VLAN: |
@@ -708,9 +718,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
708 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 718 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
709 | break; | 719 | break; |
710 | case NL80211_IFTYPE_STATION: | 720 | case NL80211_IFTYPE_STATION: |
711 | case NL80211_IFTYPE_ADHOC: | ||
712 | ieee80211_sta_setup_sdata(sdata); | 721 | ieee80211_sta_setup_sdata(sdata); |
713 | break; | 722 | break; |
723 | case NL80211_IFTYPE_ADHOC: | ||
724 | ieee80211_ibss_setup_sdata(sdata); | ||
725 | break; | ||
714 | case NL80211_IFTYPE_MESH_POINT: | 726 | case NL80211_IFTYPE_MESH_POINT: |
715 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 727 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
716 | ieee80211_mesh_init_sdata(sdata); | 728 | ieee80211_mesh_init_sdata(sdata); |
@@ -798,6 +810,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
798 | 810 | ||
799 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 811 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); |
800 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 812 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
813 | ndev->features |= NETIF_F_NETNS_LOCAL; | ||
801 | 814 | ||
802 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ | 815 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ |
803 | sdata = netdev_priv(ndev); | 816 | sdata = netdev_priv(ndev); |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 19b480de4bbc..687acf23054d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -400,7 +400,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
400 | */ | 400 | */ |
401 | 401 | ||
402 | /* same here, the AP could be using QoS */ | 402 | /* same here, the AP could be using QoS */ |
403 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); | 403 | ap = sta_info_get(key->local, key->sdata->u.mgd.bssid); |
404 | if (ap) { | 404 | if (ap) { |
405 | if (test_sta_flags(ap, WLAN_STA_WME)) | 405 | if (test_sta_flags(ap, WLAN_STA_WME)) |
406 | key->conf.flags |= | 406 | key->conf.flags |= |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5667f4e8067f..f38db4d37e5d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -169,9 +169,10 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
169 | 169 | ||
170 | memset(&conf, 0, sizeof(conf)); | 170 | memset(&conf, 0, sizeof(conf)); |
171 | 171 | ||
172 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 172 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
173 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 173 | conf.bssid = sdata->u.mgd.bssid; |
174 | conf.bssid = sdata->u.sta.bssid; | 174 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
175 | conf.bssid = sdata->u.ibss.bssid; | ||
175 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
176 | conf.bssid = sdata->dev->dev_addr; | 177 | conf.bssid = sdata->dev->dev_addr; |
177 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
@@ -210,7 +211,7 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
210 | !!rcu_dereference(sdata->u.ap.beacon); | 211 | !!rcu_dereference(sdata->u.ap.beacon); |
211 | break; | 212 | break; |
212 | case NL80211_IFTYPE_ADHOC: | 213 | case NL80211_IFTYPE_ADHOC: |
213 | conf.enable_beacon = !!sdata->u.sta.probe_resp; | 214 | conf.enable_beacon = !!sdata->u.ibss.probe_resp; |
214 | break; | 215 | break; |
215 | case NL80211_IFTYPE_MESH_POINT: | 216 | case NL80211_IFTYPE_MESH_POINT: |
216 | conf.enable_beacon = true; | 217 | conf.enable_beacon = true; |
@@ -705,7 +706,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
705 | const struct ieee80211_ops *ops) | 706 | const struct ieee80211_ops *ops) |
706 | { | 707 | { |
707 | struct ieee80211_local *local; | 708 | struct ieee80211_local *local; |
708 | int priv_size; | 709 | int priv_size, i; |
709 | struct wiphy *wiphy; | 710 | struct wiphy *wiphy; |
710 | 711 | ||
711 | /* Ensure 32-byte alignment of our private data and hw private data. | 712 | /* Ensure 32-byte alignment of our private data and hw private data. |
@@ -779,6 +780,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
779 | setup_timer(&local->dynamic_ps_timer, | 780 | setup_timer(&local->dynamic_ps_timer, |
780 | ieee80211_dynamic_ps_timer, (unsigned long) local); | 781 | ieee80211_dynamic_ps_timer, (unsigned long) local); |
781 | 782 | ||
783 | for (i = 0; i < IEEE80211_MAX_AMPDU_QUEUES; i++) | ||
784 | local->ampdu_ac_queue[i] = -1; | ||
785 | /* using an s8 won't work with more than that */ | ||
786 | BUILD_BUG_ON(IEEE80211_MAX_AMPDU_QUEUES > 127); | ||
787 | |||
782 | sta_info_init(local); | 788 | sta_info_init(local); |
783 | 789 | ||
784 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 790 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
@@ -855,6 +861,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
855 | /* mac80211 always supports monitor */ | 861 | /* mac80211 always supports monitor */ |
856 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 862 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
857 | 863 | ||
864 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
865 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
866 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | ||
867 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | ||
868 | |||
858 | result = wiphy_register(local->hw.wiphy); | 869 | result = wiphy_register(local->hw.wiphy); |
859 | if (result < 0) | 870 | if (result < 0) |
860 | goto fail_wiphy_register; | 871 | goto fail_wiphy_register; |
@@ -872,7 +883,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
872 | 883 | ||
873 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), | 884 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), |
874 | "wmaster%d", ieee80211_master_setup, | 885 | "wmaster%d", ieee80211_master_setup, |
875 | ieee80211_num_queues(hw)); | 886 | hw->queues); |
876 | if (!mdev) | 887 | if (!mdev) |
877 | goto fail_mdev_alloc; | 888 | goto fail_mdev_alloc; |
878 | 889 | ||
@@ -916,6 +927,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
916 | 927 | ||
917 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 928 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); |
918 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); | 929 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); |
930 | local->mdev->features |= NETIF_F_NETNS_LOCAL; | ||
919 | 931 | ||
920 | result = register_netdevice(local->mdev); | 932 | result = register_netdevice(local->mdev); |
921 | if (result < 0) | 933 | if (result < 0) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fbb766afe599..7f238589b6ff 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -15,11 +15,8 @@ | |||
15 | #include <linux/if_ether.h> | 15 | #include <linux/if_ether.h> |
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/if_arp.h> | 17 | #include <linux/if_arp.h> |
18 | #include <linux/wireless.h> | ||
19 | #include <linux/random.h> | ||
20 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
21 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
22 | #include <net/iw_handler.h> | ||
23 | #include <net/mac80211.h> | 20 | #include <net/mac80211.h> |
24 | #include <asm/unaligned.h> | 21 | #include <asm/unaligned.h> |
25 | 22 | ||
@@ -35,15 +32,6 @@ | |||
35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 32 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
36 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) | 33 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) |
37 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 34 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
38 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | ||
39 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) | ||
40 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | ||
41 | |||
42 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | ||
43 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | ||
44 | |||
45 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | ||
46 | |||
47 | 35 | ||
48 | /* utils */ | 36 | /* utils */ |
49 | static int ecw2cw(int ecw) | 37 | static int ecw2cw(int ecw) |
@@ -92,43 +80,6 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | |||
92 | return count; | 80 | return count; |
93 | } | 81 | } |
94 | 82 | ||
95 | /* also used by mesh code */ | ||
96 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
97 | struct ieee802_11_elems *elems, | ||
98 | enum ieee80211_band band) | ||
99 | { | ||
100 | struct ieee80211_supported_band *sband; | ||
101 | struct ieee80211_rate *bitrates; | ||
102 | size_t num_rates; | ||
103 | u32 supp_rates; | ||
104 | int i, j; | ||
105 | sband = local->hw.wiphy->bands[band]; | ||
106 | |||
107 | if (!sband) { | ||
108 | WARN_ON(1); | ||
109 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
110 | } | ||
111 | |||
112 | bitrates = sband->bitrates; | ||
113 | num_rates = sband->n_bitrates; | ||
114 | supp_rates = 0; | ||
115 | for (i = 0; i < elems->supp_rates_len + | ||
116 | elems->ext_supp_rates_len; i++) { | ||
117 | u8 rate = 0; | ||
118 | int own_rate; | ||
119 | if (i < elems->supp_rates_len) | ||
120 | rate = elems->supp_rates[i]; | ||
121 | else if (elems->ext_supp_rates) | ||
122 | rate = elems->ext_supp_rates | ||
123 | [i - elems->supp_rates_len]; | ||
124 | own_rate = 5 * (rate & 0x7f); | ||
125 | for (j = 0; j < num_rates; j++) | ||
126 | if (bitrates[j].bitrate == own_rate) | ||
127 | supp_rates |= BIT(j); | ||
128 | } | ||
129 | return supp_rates; | ||
130 | } | ||
131 | |||
132 | /* frame sending functions */ | 83 | /* frame sending functions */ |
133 | 84 | ||
134 | static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) | 85 | static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) |
@@ -137,113 +88,9 @@ static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) | |||
137 | memcpy(skb_put(skb, ies_len), ies, ies_len); | 88 | memcpy(skb_put(skb, ies_len), ies, ies_len); |
138 | } | 89 | } |
139 | 90 | ||
140 | /* also used by scanning code */ | 91 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) |
141 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
142 | u8 *ssid, size_t ssid_len) | ||
143 | { | ||
144 | struct ieee80211_local *local = sdata->local; | ||
145 | struct ieee80211_supported_band *sband; | ||
146 | struct sk_buff *skb; | ||
147 | struct ieee80211_mgmt *mgmt; | ||
148 | u8 *pos, *supp_rates, *esupp_rates = NULL; | ||
149 | int i; | ||
150 | |||
151 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | ||
152 | sdata->u.sta.ie_probereq_len); | ||
153 | if (!skb) { | ||
154 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
155 | "request\n", sdata->dev->name); | ||
156 | return; | ||
157 | } | ||
158 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
159 | |||
160 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
161 | memset(mgmt, 0, 24); | ||
162 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
163 | IEEE80211_STYPE_PROBE_REQ); | ||
164 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
165 | if (dst) { | ||
166 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
167 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
168 | } else { | ||
169 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
170 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
171 | } | ||
172 | pos = skb_put(skb, 2 + ssid_len); | ||
173 | *pos++ = WLAN_EID_SSID; | ||
174 | *pos++ = ssid_len; | ||
175 | memcpy(pos, ssid, ssid_len); | ||
176 | |||
177 | supp_rates = skb_put(skb, 2); | ||
178 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
179 | supp_rates[1] = 0; | ||
180 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
181 | |||
182 | for (i = 0; i < sband->n_bitrates; i++) { | ||
183 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
184 | if (esupp_rates) { | ||
185 | pos = skb_put(skb, 1); | ||
186 | esupp_rates[1]++; | ||
187 | } else if (supp_rates[1] == 8) { | ||
188 | esupp_rates = skb_put(skb, 3); | ||
189 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
190 | esupp_rates[1] = 1; | ||
191 | pos = &esupp_rates[2]; | ||
192 | } else { | ||
193 | pos = skb_put(skb, 1); | ||
194 | supp_rates[1]++; | ||
195 | } | ||
196 | *pos = rate->bitrate / 5; | ||
197 | } | ||
198 | |||
199 | add_extra_ies(skb, sdata->u.sta.ie_probereq, | ||
200 | sdata->u.sta.ie_probereq_len); | ||
201 | |||
202 | ieee80211_tx_skb(sdata, skb, 0); | ||
203 | } | ||
204 | |||
205 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
206 | struct ieee80211_if_sta *ifsta, | ||
207 | int transaction, u8 *extra, size_t extra_len, | ||
208 | int encrypt) | ||
209 | { | ||
210 | struct ieee80211_local *local = sdata->local; | ||
211 | struct sk_buff *skb; | ||
212 | struct ieee80211_mgmt *mgmt; | ||
213 | |||
214 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
215 | sizeof(*mgmt) + 6 + extra_len + | ||
216 | sdata->u.sta.ie_auth_len); | ||
217 | if (!skb) { | ||
218 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
219 | "frame\n", sdata->dev->name); | ||
220 | return; | ||
221 | } | ||
222 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
223 | |||
224 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
225 | memset(mgmt, 0, 24 + 6); | ||
226 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
227 | IEEE80211_STYPE_AUTH); | ||
228 | if (encrypt) | ||
229 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
230 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
231 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
232 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
233 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | ||
234 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
235 | ifsta->auth_transaction = transaction + 1; | ||
236 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
237 | if (extra) | ||
238 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
239 | add_extra_ies(skb, sdata->u.sta.ie_auth, sdata->u.sta.ie_auth_len); | ||
240 | |||
241 | ieee80211_tx_skb(sdata, skb, encrypt); | ||
242 | } | ||
243 | |||
244 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
245 | struct ieee80211_if_sta *ifsta) | ||
246 | { | 92 | { |
93 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
247 | struct ieee80211_local *local = sdata->local; | 94 | struct ieee80211_local *local = sdata->local; |
248 | struct sk_buff *skb; | 95 | struct sk_buff *skb; |
249 | struct ieee80211_mgmt *mgmt; | 96 | struct ieee80211_mgmt *mgmt; |
@@ -256,17 +103,17 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
256 | u32 rates = 0; | 103 | u32 rates = 0; |
257 | size_t e_ies_len; | 104 | size_t e_ies_len; |
258 | 105 | ||
259 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | 106 | if (ifmgd->flags & IEEE80211_IBSS_PREV_BSSID_SET) { |
260 | e_ies = sdata->u.sta.ie_reassocreq; | 107 | e_ies = sdata->u.mgd.ie_reassocreq; |
261 | e_ies_len = sdata->u.sta.ie_reassocreq_len; | 108 | e_ies_len = sdata->u.mgd.ie_reassocreq_len; |
262 | } else { | 109 | } else { |
263 | e_ies = sdata->u.sta.ie_assocreq; | 110 | e_ies = sdata->u.mgd.ie_assocreq; |
264 | e_ies_len = sdata->u.sta.ie_assocreq_len; | 111 | e_ies_len = sdata->u.mgd.ie_assocreq_len; |
265 | } | 112 | } |
266 | 113 | ||
267 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 114 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
268 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | 115 | sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + |
269 | ifsta->ssid_len + e_ies_len); | 116 | ifmgd->ssid_len + e_ies_len); |
270 | if (!skb) { | 117 | if (!skb) { |
271 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 118 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
272 | "frame\n", sdata->dev->name); | 119 | "frame\n", sdata->dev->name); |
@@ -276,7 +123,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
276 | 123 | ||
277 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 124 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
278 | 125 | ||
279 | capab = ifsta->capab; | 126 | capab = ifmgd->capab; |
280 | 127 | ||
281 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | 128 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { |
282 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | 129 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) |
@@ -285,9 +132,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
285 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | 132 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; |
286 | } | 133 | } |
287 | 134 | ||
288 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 135 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
289 | local->hw.conf.channel->center_freq, | 136 | local->hw.conf.channel->center_freq, |
290 | ifsta->ssid, ifsta->ssid_len); | 137 | ifmgd->ssid, ifmgd->ssid_len); |
291 | if (bss) { | 138 | if (bss) { |
292 | if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) | 139 | if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) |
293 | capab |= WLAN_CAPABILITY_PRIVACY; | 140 | capab |= WLAN_CAPABILITY_PRIVACY; |
@@ -312,18 +159,18 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
312 | 159 | ||
313 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 160 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
314 | memset(mgmt, 0, 24); | 161 | memset(mgmt, 0, 24); |
315 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 162 | memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); |
316 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 163 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
317 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 164 | memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); |
318 | 165 | ||
319 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | 166 | if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) { |
320 | skb_put(skb, 10); | 167 | skb_put(skb, 10); |
321 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 168 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
322 | IEEE80211_STYPE_REASSOC_REQ); | 169 | IEEE80211_STYPE_REASSOC_REQ); |
323 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | 170 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); |
324 | mgmt->u.reassoc_req.listen_interval = | 171 | mgmt->u.reassoc_req.listen_interval = |
325 | cpu_to_le16(local->hw.conf.listen_interval); | 172 | cpu_to_le16(local->hw.conf.listen_interval); |
326 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, | 173 | memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid, |
327 | ETH_ALEN); | 174 | ETH_ALEN); |
328 | } else { | 175 | } else { |
329 | skb_put(skb, 4); | 176 | skb_put(skb, 4); |
@@ -335,10 +182,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
335 | } | 182 | } |
336 | 183 | ||
337 | /* SSID */ | 184 | /* SSID */ |
338 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); | 185 | ies = pos = skb_put(skb, 2 + ifmgd->ssid_len); |
339 | *pos++ = WLAN_EID_SSID; | 186 | *pos++ = WLAN_EID_SSID; |
340 | *pos++ = ifsta->ssid_len; | 187 | *pos++ = ifmgd->ssid_len; |
341 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | 188 | memcpy(pos, ifmgd->ssid, ifmgd->ssid_len); |
342 | 189 | ||
343 | /* add all rates which were marked to be used above */ | 190 | /* add all rates which were marked to be used above */ |
344 | supp_rates_len = rates_len; | 191 | supp_rates_len = rates_len; |
@@ -393,12 +240,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
393 | } | 240 | } |
394 | } | 241 | } |
395 | 242 | ||
396 | if (ifsta->extra_ie) { | 243 | if (ifmgd->extra_ie) { |
397 | pos = skb_put(skb, ifsta->extra_ie_len); | 244 | pos = skb_put(skb, ifmgd->extra_ie_len); |
398 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); | 245 | memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len); |
399 | } | 246 | } |
400 | 247 | ||
401 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | 248 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { |
402 | pos = skb_put(skb, 9); | 249 | pos = skb_put(skb, 9); |
403 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 250 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
404 | *pos++ = 7; /* len */ | 251 | *pos++ = 7; /* len */ |
@@ -418,11 +265,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
418 | * mode (11a/b/g) if any one of these ciphers is | 265 | * mode (11a/b/g) if any one of these ciphers is |
419 | * configured as pairwise. | 266 | * configured as pairwise. |
420 | */ | 267 | */ |
421 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | 268 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && |
422 | sband->ht_cap.ht_supported && | 269 | sband->ht_cap.ht_supported && |
423 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && | 270 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && |
424 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && | 271 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && |
425 | (!(ifsta->flags & IEEE80211_STA_TKIP_WEP_USED))) { | 272 | (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) { |
426 | struct ieee80211_ht_info *ht_info = | 273 | struct ieee80211_ht_info *ht_info = |
427 | (struct ieee80211_ht_info *)(ht_ie + 2); | 274 | (struct ieee80211_ht_info *)(ht_ie + 2); |
428 | u16 cap = sband->ht_cap.cap; | 275 | u16 cap = sband->ht_cap.cap; |
@@ -459,11 +306,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
459 | 306 | ||
460 | add_extra_ies(skb, e_ies, e_ies_len); | 307 | add_extra_ies(skb, e_ies, e_ies_len); |
461 | 308 | ||
462 | kfree(ifsta->assocreq_ies); | 309 | kfree(ifmgd->assocreq_ies); |
463 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | 310 | ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; |
464 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | 311 | ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); |
465 | if (ifsta->assocreq_ies) | 312 | if (ifmgd->assocreq_ies) |
466 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); | 313 | memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len); |
467 | 314 | ||
468 | ieee80211_tx_skb(sdata, skb, 0); | 315 | ieee80211_tx_skb(sdata, skb, 0); |
469 | } | 316 | } |
@@ -473,18 +320,18 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
473 | u16 stype, u16 reason) | 320 | u16 stype, u16 reason) |
474 | { | 321 | { |
475 | struct ieee80211_local *local = sdata->local; | 322 | struct ieee80211_local *local = sdata->local; |
476 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 323 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
477 | struct sk_buff *skb; | 324 | struct sk_buff *skb; |
478 | struct ieee80211_mgmt *mgmt; | 325 | struct ieee80211_mgmt *mgmt; |
479 | u8 *ies; | 326 | u8 *ies; |
480 | size_t ies_len; | 327 | size_t ies_len; |
481 | 328 | ||
482 | if (stype == IEEE80211_STYPE_DEAUTH) { | 329 | if (stype == IEEE80211_STYPE_DEAUTH) { |
483 | ies = sdata->u.sta.ie_deauth; | 330 | ies = sdata->u.mgd.ie_deauth; |
484 | ies_len = sdata->u.sta.ie_deauth_len; | 331 | ies_len = sdata->u.mgd.ie_deauth_len; |
485 | } else { | 332 | } else { |
486 | ies = sdata->u.sta.ie_disassoc; | 333 | ies = sdata->u.mgd.ie_disassoc; |
487 | ies_len = sdata->u.sta.ie_disassoc_len; | 334 | ies_len = sdata->u.mgd.ie_disassoc_len; |
488 | } | 335 | } |
489 | 336 | ||
490 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + | 337 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + |
@@ -498,9 +345,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
498 | 345 | ||
499 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 346 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
500 | memset(mgmt, 0, 24); | 347 | memset(mgmt, 0, 24); |
501 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 348 | memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); |
502 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 349 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
503 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 350 | memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); |
504 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | 351 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); |
505 | skb_put(skb, 2); | 352 | skb_put(skb, 2); |
506 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 353 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
@@ -508,13 +355,13 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
508 | 355 | ||
509 | add_extra_ies(skb, ies, ies_len); | 356 | add_extra_ies(skb, ies, ies_len); |
510 | 357 | ||
511 | ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED); | 358 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); |
512 | } | 359 | } |
513 | 360 | ||
514 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 361 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
515 | struct ieee80211_sub_if_data *sdata) | 362 | struct ieee80211_sub_if_data *sdata) |
516 | { | 363 | { |
517 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 364 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
518 | struct ieee80211_pspoll *pspoll; | 365 | struct ieee80211_pspoll *pspoll; |
519 | struct sk_buff *skb; | 366 | struct sk_buff *skb; |
520 | u16 fc; | 367 | u16 fc; |
@@ -531,43 +378,20 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, | |||
531 | memset(pspoll, 0, sizeof(*pspoll)); | 378 | memset(pspoll, 0, sizeof(*pspoll)); |
532 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; | 379 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; |
533 | pspoll->frame_control = cpu_to_le16(fc); | 380 | pspoll->frame_control = cpu_to_le16(fc); |
534 | pspoll->aid = cpu_to_le16(ifsta->aid); | 381 | pspoll->aid = cpu_to_le16(ifmgd->aid); |
535 | 382 | ||
536 | /* aid in PS-Poll has its two MSBs each set to 1 */ | 383 | /* aid in PS-Poll has its two MSBs each set to 1 */ |
537 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | 384 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); |
538 | 385 | ||
539 | memcpy(pspoll->bssid, ifsta->bssid, ETH_ALEN); | 386 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); |
540 | memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); | 387 | memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); |
541 | 388 | ||
542 | ieee80211_tx_skb(sdata, skb, 0); | 389 | ieee80211_tx_skb(sdata, skb, 0); |
543 | |||
544 | return; | ||
545 | } | 390 | } |
546 | 391 | ||
547 | /* MLME */ | 392 | /* MLME */ |
548 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
549 | const size_t supp_rates_len, | ||
550 | const u8 *supp_rates) | ||
551 | { | ||
552 | struct ieee80211_local *local = sdata->local; | ||
553 | int i, have_higher_than_11mbit = 0; | ||
554 | |||
555 | /* cf. IEEE 802.11 9.2.12 */ | ||
556 | for (i = 0; i < supp_rates_len; i++) | ||
557 | if ((supp_rates[i] & 0x7f) * 5 > 110) | ||
558 | have_higher_than_11mbit = 1; | ||
559 | |||
560 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
561 | have_higher_than_11mbit) | ||
562 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
563 | else | ||
564 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
565 | |||
566 | ieee80211_set_wmm_default(sdata); | ||
567 | } | ||
568 | |||
569 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | 393 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, |
570 | struct ieee80211_if_sta *ifsta, | 394 | struct ieee80211_if_managed *ifmgd, |
571 | u8 *wmm_param, size_t wmm_param_len) | 395 | u8 *wmm_param, size_t wmm_param_len) |
572 | { | 396 | { |
573 | struct ieee80211_tx_queue_params params; | 397 | struct ieee80211_tx_queue_params params; |
@@ -575,7 +399,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
575 | int count; | 399 | int count; |
576 | u8 *pos; | 400 | u8 *pos; |
577 | 401 | ||
578 | if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED)) | 402 | if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) |
579 | return; | 403 | return; |
580 | 404 | ||
581 | if (!wmm_param) | 405 | if (!wmm_param) |
@@ -584,9 +408,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
584 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) | 408 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) |
585 | return; | 409 | return; |
586 | count = wmm_param[6] & 0x0f; | 410 | count = wmm_param[6] & 0x0f; |
587 | if (count == ifsta->wmm_last_param_set) | 411 | if (count == ifmgd->wmm_last_param_set) |
588 | return; | 412 | return; |
589 | ifsta->wmm_last_param_set = count; | 413 | ifmgd->wmm_last_param_set = count; |
590 | 414 | ||
591 | pos = wmm_param + 8; | 415 | pos = wmm_param + 8; |
592 | left = wmm_param_len - 8; | 416 | left = wmm_param_len - 8; |
@@ -671,7 +495,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
671 | { | 495 | { |
672 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 496 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
673 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 497 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
674 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 498 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
675 | #endif | 499 | #endif |
676 | u32 changed = 0; | 500 | u32 changed = 0; |
677 | bool use_protection; | 501 | bool use_protection; |
@@ -694,7 +518,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
694 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", | 518 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", |
695 | sdata->dev->name, | 519 | sdata->dev->name, |
696 | use_protection ? "enabled" : "disabled", | 520 | use_protection ? "enabled" : "disabled", |
697 | ifsta->bssid); | 521 | ifmgd->bssid); |
698 | } | 522 | } |
699 | #endif | 523 | #endif |
700 | bss_conf->use_cts_prot = use_protection; | 524 | bss_conf->use_cts_prot = use_protection; |
@@ -708,7 +532,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
708 | " (BSSID=%pM)\n", | 532 | " (BSSID=%pM)\n", |
709 | sdata->dev->name, | 533 | sdata->dev->name, |
710 | use_short_preamble ? "short" : "long", | 534 | use_short_preamble ? "short" : "long", |
711 | ifsta->bssid); | 535 | ifmgd->bssid); |
712 | } | 536 | } |
713 | #endif | 537 | #endif |
714 | bss_conf->use_short_preamble = use_short_preamble; | 538 | bss_conf->use_short_preamble = use_short_preamble; |
@@ -722,7 +546,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
722 | " (BSSID=%pM)\n", | 546 | " (BSSID=%pM)\n", |
723 | sdata->dev->name, | 547 | sdata->dev->name, |
724 | use_short_slot ? "short" : "long", | 548 | use_short_slot ? "short" : "long", |
725 | ifsta->bssid); | 549 | ifmgd->bssid); |
726 | } | 550 | } |
727 | #endif | 551 | #endif |
728 | bss_conf->use_short_slot = use_short_slot; | 552 | bss_conf->use_short_slot = use_short_slot; |
@@ -732,57 +556,57 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
732 | return changed; | 556 | return changed; |
733 | } | 557 | } |
734 | 558 | ||
735 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata, | 559 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata) |
736 | struct ieee80211_if_sta *ifsta) | ||
737 | { | 560 | { |
738 | union iwreq_data wrqu; | 561 | union iwreq_data wrqu; |
562 | |||
739 | memset(&wrqu, 0, sizeof(wrqu)); | 563 | memset(&wrqu, 0, sizeof(wrqu)); |
740 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 564 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) |
741 | memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); | 565 | memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN); |
742 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 566 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
743 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | 567 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); |
744 | } | 568 | } |
745 | 569 | ||
746 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | 570 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata) |
747 | struct ieee80211_if_sta *ifsta) | ||
748 | { | 571 | { |
572 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
749 | char *buf; | 573 | char *buf; |
750 | size_t len; | 574 | size_t len; |
751 | int i; | 575 | int i; |
752 | union iwreq_data wrqu; | 576 | union iwreq_data wrqu; |
753 | 577 | ||
754 | if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) | 578 | if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies) |
755 | return; | 579 | return; |
756 | 580 | ||
757 | buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + | 581 | buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len + |
758 | ifsta->assocresp_ies_len), GFP_KERNEL); | 582 | ifmgd->assocresp_ies_len), GFP_KERNEL); |
759 | if (!buf) | 583 | if (!buf) |
760 | return; | 584 | return; |
761 | 585 | ||
762 | len = sprintf(buf, "ASSOCINFO("); | 586 | len = sprintf(buf, "ASSOCINFO("); |
763 | if (ifsta->assocreq_ies) { | 587 | if (ifmgd->assocreq_ies) { |
764 | len += sprintf(buf + len, "ReqIEs="); | 588 | len += sprintf(buf + len, "ReqIEs="); |
765 | for (i = 0; i < ifsta->assocreq_ies_len; i++) { | 589 | for (i = 0; i < ifmgd->assocreq_ies_len; i++) { |
766 | len += sprintf(buf + len, "%02x", | 590 | len += sprintf(buf + len, "%02x", |
767 | ifsta->assocreq_ies[i]); | 591 | ifmgd->assocreq_ies[i]); |
768 | } | 592 | } |
769 | } | 593 | } |
770 | if (ifsta->assocresp_ies) { | 594 | if (ifmgd->assocresp_ies) { |
771 | if (ifsta->assocreq_ies) | 595 | if (ifmgd->assocreq_ies) |
772 | len += sprintf(buf + len, " "); | 596 | len += sprintf(buf + len, " "); |
773 | len += sprintf(buf + len, "RespIEs="); | 597 | len += sprintf(buf + len, "RespIEs="); |
774 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { | 598 | for (i = 0; i < ifmgd->assocresp_ies_len; i++) { |
775 | len += sprintf(buf + len, "%02x", | 599 | len += sprintf(buf + len, "%02x", |
776 | ifsta->assocresp_ies[i]); | 600 | ifmgd->assocresp_ies[i]); |
777 | } | 601 | } |
778 | } | 602 | } |
779 | len += sprintf(buf + len, ")"); | 603 | len += sprintf(buf + len, ")"); |
780 | 604 | ||
781 | if (len > IW_CUSTOM_MAX) { | 605 | if (len > IW_CUSTOM_MAX) { |
782 | len = sprintf(buf, "ASSOCRESPIE="); | 606 | len = sprintf(buf, "ASSOCRESPIE="); |
783 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { | 607 | for (i = 0; i < ifmgd->assocresp_ies_len; i++) { |
784 | len += sprintf(buf + len, "%02x", | 608 | len += sprintf(buf + len, "%02x", |
785 | ifsta->assocresp_ies[i]); | 609 | ifmgd->assocresp_ies[i]); |
786 | } | 610 | } |
787 | } | 611 | } |
788 | 612 | ||
@@ -797,20 +621,20 @@ static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | |||
797 | 621 | ||
798 | 622 | ||
799 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 623 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
800 | struct ieee80211_if_sta *ifsta, | ||
801 | u32 bss_info_changed) | 624 | u32 bss_info_changed) |
802 | { | 625 | { |
626 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
803 | struct ieee80211_local *local = sdata->local; | 627 | struct ieee80211_local *local = sdata->local; |
804 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | 628 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; |
805 | 629 | ||
806 | struct ieee80211_bss *bss; | 630 | struct ieee80211_bss *bss; |
807 | 631 | ||
808 | bss_info_changed |= BSS_CHANGED_ASSOC; | 632 | bss_info_changed |= BSS_CHANGED_ASSOC; |
809 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; | 633 | ifmgd->flags |= IEEE80211_STA_ASSOCIATED; |
810 | 634 | ||
811 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 635 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
812 | conf->channel->center_freq, | 636 | conf->channel->center_freq, |
813 | ifsta->ssid, ifsta->ssid_len); | 637 | ifmgd->ssid, ifmgd->ssid_len); |
814 | if (bss) { | 638 | if (bss) { |
815 | /* set timing information */ | 639 | /* set timing information */ |
816 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; | 640 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; |
@@ -823,11 +647,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
823 | ieee80211_rx_bss_put(local, bss); | 647 | ieee80211_rx_bss_put(local, bss); |
824 | } | 648 | } |
825 | 649 | ||
826 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | 650 | ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET; |
827 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); | 651 | memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN); |
828 | ieee80211_sta_send_associnfo(sdata, ifsta); | 652 | ieee80211_sta_send_associnfo(sdata); |
829 | 653 | ||
830 | ifsta->last_probe = jiffies; | 654 | ifmgd->last_probe = jiffies; |
831 | ieee80211_led_assoc(local, 1); | 655 | ieee80211_led_assoc(local, 1); |
832 | 656 | ||
833 | sdata->vif.bss_conf.assoc = 1; | 657 | sdata->vif.bss_conf.assoc = 1; |
@@ -856,70 +680,74 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
856 | netif_tx_start_all_queues(sdata->dev); | 680 | netif_tx_start_all_queues(sdata->dev); |
857 | netif_carrier_on(sdata->dev); | 681 | netif_carrier_on(sdata->dev); |
858 | 682 | ||
859 | ieee80211_sta_send_apinfo(sdata, ifsta); | 683 | ieee80211_sta_send_apinfo(sdata); |
860 | } | 684 | } |
861 | 685 | ||
862 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | 686 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) |
863 | struct ieee80211_if_sta *ifsta) | ||
864 | { | 687 | { |
865 | ifsta->direct_probe_tries++; | 688 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
866 | if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | 689 | |
690 | ifmgd->direct_probe_tries++; | ||
691 | if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | ||
867 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | 692 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", |
868 | sdata->dev->name, ifsta->bssid); | 693 | sdata->dev->name, ifmgd->bssid); |
869 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 694 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
870 | ieee80211_sta_send_apinfo(sdata, ifsta); | 695 | ieee80211_sta_send_apinfo(sdata); |
871 | 696 | ||
872 | /* | 697 | /* |
873 | * Most likely AP is not in the range so remove the | 698 | * Most likely AP is not in the range so remove the |
874 | * bss information associated to the AP | 699 | * bss information associated to the AP |
875 | */ | 700 | */ |
876 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | 701 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
877 | sdata->local->hw.conf.channel->center_freq, | 702 | sdata->local->hw.conf.channel->center_freq, |
878 | ifsta->ssid, ifsta->ssid_len); | 703 | ifmgd->ssid, ifmgd->ssid_len); |
879 | return; | 704 | return; |
880 | } | 705 | } |
881 | 706 | ||
882 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", | 707 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", |
883 | sdata->dev->name, ifsta->bssid, | 708 | sdata->dev->name, ifmgd->bssid, |
884 | ifsta->direct_probe_tries); | 709 | ifmgd->direct_probe_tries); |
885 | 710 | ||
886 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 711 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
887 | 712 | ||
888 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request); | 713 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request); |
889 | 714 | ||
890 | /* Direct probe is sent to broadcast address as some APs | 715 | /* Direct probe is sent to broadcast address as some APs |
891 | * will not answer to direct packet in unassociated state. | 716 | * will not answer to direct packet in unassociated state. |
892 | */ | 717 | */ |
893 | ieee80211_send_probe_req(sdata, NULL, | 718 | ieee80211_send_probe_req(sdata, NULL, |
894 | ifsta->ssid, ifsta->ssid_len); | 719 | ifmgd->ssid, ifmgd->ssid_len, NULL, 0); |
895 | 720 | ||
896 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 721 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
897 | } | 722 | } |
898 | 723 | ||
899 | 724 | ||
900 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | 725 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) |
901 | struct ieee80211_if_sta *ifsta) | ||
902 | { | 726 | { |
903 | ifsta->auth_tries++; | 727 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
904 | if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | 728 | |
729 | ifmgd->auth_tries++; | ||
730 | if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | ||
905 | printk(KERN_DEBUG "%s: authentication with AP %pM" | 731 | printk(KERN_DEBUG "%s: authentication with AP %pM" |
906 | " timed out\n", | 732 | " timed out\n", |
907 | sdata->dev->name, ifsta->bssid); | 733 | sdata->dev->name, ifmgd->bssid); |
908 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 734 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
909 | ieee80211_sta_send_apinfo(sdata, ifsta); | 735 | ieee80211_sta_send_apinfo(sdata); |
910 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | 736 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
911 | sdata->local->hw.conf.channel->center_freq, | 737 | sdata->local->hw.conf.channel->center_freq, |
912 | ifsta->ssid, ifsta->ssid_len); | 738 | ifmgd->ssid, ifmgd->ssid_len); |
913 | return; | 739 | return; |
914 | } | 740 | } |
915 | 741 | ||
916 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 742 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
917 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", | 743 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", |
918 | sdata->dev->name, ifsta->bssid); | 744 | sdata->dev->name, ifmgd->bssid); |
919 | 745 | ||
920 | ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0); | 746 | ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0, |
747 | ifmgd->bssid, 0); | ||
748 | ifmgd->auth_transaction = 2; | ||
921 | 749 | ||
922 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 750 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
923 | } | 751 | } |
924 | 752 | ||
925 | /* | 753 | /* |
@@ -927,27 +755,28 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
927 | * if self disconnected or a reason code from the AP. | 755 | * if self disconnected or a reason code from the AP. |
928 | */ | 756 | */ |
929 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 757 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
930 | struct ieee80211_if_sta *ifsta, bool deauth, | 758 | bool deauth, bool self_disconnected, |
931 | bool self_disconnected, u16 reason) | 759 | u16 reason) |
932 | { | 760 | { |
761 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
933 | struct ieee80211_local *local = sdata->local; | 762 | struct ieee80211_local *local = sdata->local; |
934 | struct sta_info *sta; | 763 | struct sta_info *sta; |
935 | u32 changed = 0, config_changed = 0; | 764 | u32 changed = 0, config_changed = 0; |
936 | 765 | ||
937 | rcu_read_lock(); | 766 | rcu_read_lock(); |
938 | 767 | ||
939 | sta = sta_info_get(local, ifsta->bssid); | 768 | sta = sta_info_get(local, ifmgd->bssid); |
940 | if (!sta) { | 769 | if (!sta) { |
941 | rcu_read_unlock(); | 770 | rcu_read_unlock(); |
942 | return; | 771 | return; |
943 | } | 772 | } |
944 | 773 | ||
945 | if (deauth) { | 774 | if (deauth) { |
946 | ifsta->direct_probe_tries = 0; | 775 | ifmgd->direct_probe_tries = 0; |
947 | ifsta->auth_tries = 0; | 776 | ifmgd->auth_tries = 0; |
948 | } | 777 | } |
949 | ifsta->assoc_scan_tries = 0; | 778 | ifmgd->assoc_scan_tries = 0; |
950 | ifsta->assoc_tries = 0; | 779 | ifmgd->assoc_tries = 0; |
951 | 780 | ||
952 | netif_tx_stop_all_queues(sdata->dev); | 781 | netif_tx_stop_all_queues(sdata->dev); |
953 | netif_carrier_off(sdata->dev); | 782 | netif_carrier_off(sdata->dev); |
@@ -963,20 +792,20 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
963 | IEEE80211_STYPE_DISASSOC, reason); | 792 | IEEE80211_STYPE_DISASSOC, reason); |
964 | } | 793 | } |
965 | 794 | ||
966 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 795 | ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; |
967 | changed |= ieee80211_reset_erp_info(sdata); | 796 | changed |= ieee80211_reset_erp_info(sdata); |
968 | 797 | ||
969 | ieee80211_led_assoc(local, 0); | 798 | ieee80211_led_assoc(local, 0); |
970 | changed |= BSS_CHANGED_ASSOC; | 799 | changed |= BSS_CHANGED_ASSOC; |
971 | sdata->vif.bss_conf.assoc = false; | 800 | sdata->vif.bss_conf.assoc = false; |
972 | 801 | ||
973 | ieee80211_sta_send_apinfo(sdata, ifsta); | 802 | ieee80211_sta_send_apinfo(sdata); |
974 | 803 | ||
975 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { | 804 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { |
976 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 805 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
977 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | 806 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
978 | sdata->local->hw.conf.channel->center_freq, | 807 | sdata->local->hw.conf.channel->center_freq, |
979 | ifsta->ssid, ifsta->ssid_len); | 808 | ifmgd->ssid, ifmgd->ssid_len); |
980 | } | 809 | } |
981 | 810 | ||
982 | rcu_read_unlock(); | 811 | rcu_read_unlock(); |
@@ -999,7 +828,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
999 | 828 | ||
1000 | rcu_read_lock(); | 829 | rcu_read_lock(); |
1001 | 830 | ||
1002 | sta = sta_info_get(local, ifsta->bssid); | 831 | sta = sta_info_get(local, ifmgd->bssid); |
1003 | if (!sta) { | 832 | if (!sta) { |
1004 | rcu_read_unlock(); | 833 | rcu_read_unlock(); |
1005 | return; | 834 | return; |
@@ -1020,27 +849,27 @@ static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | |||
1020 | return 1; | 849 | return 1; |
1021 | } | 850 | } |
1022 | 851 | ||
1023 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | 852 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) |
1024 | struct ieee80211_if_sta *ifsta) | ||
1025 | { | 853 | { |
854 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1026 | struct ieee80211_local *local = sdata->local; | 855 | struct ieee80211_local *local = sdata->local; |
1027 | struct ieee80211_bss *bss; | 856 | struct ieee80211_bss *bss; |
1028 | int bss_privacy; | 857 | int bss_privacy; |
1029 | int wep_privacy; | 858 | int wep_privacy; |
1030 | int privacy_invoked; | 859 | int privacy_invoked; |
1031 | 860 | ||
1032 | if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) | 861 | if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL)) |
1033 | return 0; | 862 | return 0; |
1034 | 863 | ||
1035 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 864 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
1036 | local->hw.conf.channel->center_freq, | 865 | local->hw.conf.channel->center_freq, |
1037 | ifsta->ssid, ifsta->ssid_len); | 866 | ifmgd->ssid, ifmgd->ssid_len); |
1038 | if (!bss) | 867 | if (!bss) |
1039 | return 0; | 868 | return 0; |
1040 | 869 | ||
1041 | bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY); | 870 | bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY); |
1042 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); | 871 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); |
1043 | privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); | 872 | privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED); |
1044 | 873 | ||
1045 | ieee80211_rx_bss_put(local, bss); | 874 | ieee80211_rx_bss_put(local, bss); |
1046 | 875 | ||
@@ -1050,41 +879,42 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | |||
1050 | return 1; | 879 | return 1; |
1051 | } | 880 | } |
1052 | 881 | ||
1053 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, | 882 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) |
1054 | struct ieee80211_if_sta *ifsta) | ||
1055 | { | 883 | { |
1056 | ifsta->assoc_tries++; | 884 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1057 | if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | 885 | |
886 | ifmgd->assoc_tries++; | ||
887 | if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
1058 | printk(KERN_DEBUG "%s: association with AP %pM" | 888 | printk(KERN_DEBUG "%s: association with AP %pM" |
1059 | " timed out\n", | 889 | " timed out\n", |
1060 | sdata->dev->name, ifsta->bssid); | 890 | sdata->dev->name, ifmgd->bssid); |
1061 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 891 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
1062 | ieee80211_sta_send_apinfo(sdata, ifsta); | 892 | ieee80211_sta_send_apinfo(sdata); |
1063 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | 893 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
1064 | sdata->local->hw.conf.channel->center_freq, | 894 | sdata->local->hw.conf.channel->center_freq, |
1065 | ifsta->ssid, ifsta->ssid_len); | 895 | ifmgd->ssid, ifmgd->ssid_len); |
1066 | return; | 896 | return; |
1067 | } | 897 | } |
1068 | 898 | ||
1069 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 899 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; |
1070 | printk(KERN_DEBUG "%s: associate with AP %pM\n", | 900 | printk(KERN_DEBUG "%s: associate with AP %pM\n", |
1071 | sdata->dev->name, ifsta->bssid); | 901 | sdata->dev->name, ifmgd->bssid); |
1072 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | 902 | if (ieee80211_privacy_mismatch(sdata)) { |
1073 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " | 903 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " |
1074 | "mixed-cell disabled - abort association\n", sdata->dev->name); | 904 | "mixed-cell disabled - abort association\n", sdata->dev->name); |
1075 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 905 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
1076 | return; | 906 | return; |
1077 | } | 907 | } |
1078 | 908 | ||
1079 | ieee80211_send_assoc(sdata, ifsta); | 909 | ieee80211_send_assoc(sdata); |
1080 | 910 | ||
1081 | mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); | 911 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); |
1082 | } | 912 | } |
1083 | 913 | ||
1084 | 914 | ||
1085 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | 915 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) |
1086 | struct ieee80211_if_sta *ifsta) | ||
1087 | { | 916 | { |
917 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1088 | struct ieee80211_local *local = sdata->local; | 918 | struct ieee80211_local *local = sdata->local; |
1089 | struct sta_info *sta; | 919 | struct sta_info *sta; |
1090 | int disassoc; | 920 | int disassoc; |
@@ -1094,38 +924,40 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1094 | * for better APs. */ | 924 | * for better APs. */ |
1095 | /* TODO: remove expired BSSes */ | 925 | /* TODO: remove expired BSSes */ |
1096 | 926 | ||
1097 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATED; | 927 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED; |
1098 | 928 | ||
1099 | rcu_read_lock(); | 929 | rcu_read_lock(); |
1100 | 930 | ||
1101 | sta = sta_info_get(local, ifsta->bssid); | 931 | sta = sta_info_get(local, ifmgd->bssid); |
1102 | if (!sta) { | 932 | if (!sta) { |
1103 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", | 933 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", |
1104 | sdata->dev->name, ifsta->bssid); | 934 | sdata->dev->name, ifmgd->bssid); |
1105 | disassoc = 1; | 935 | disassoc = 1; |
1106 | } else { | 936 | } else { |
1107 | disassoc = 0; | 937 | disassoc = 0; |
1108 | if (time_after(jiffies, | 938 | if (time_after(jiffies, |
1109 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | 939 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { |
1110 | if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { | 940 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { |
1111 | printk(KERN_DEBUG "%s: No ProbeResp from " | 941 | printk(KERN_DEBUG "%s: No ProbeResp from " |
1112 | "current AP %pM - assume out of " | 942 | "current AP %pM - assume out of " |
1113 | "range\n", | 943 | "range\n", |
1114 | sdata->dev->name, ifsta->bssid); | 944 | sdata->dev->name, ifmgd->bssid); |
1115 | disassoc = 1; | 945 | disassoc = 1; |
1116 | } else | 946 | } else |
1117 | ieee80211_send_probe_req(sdata, ifsta->bssid, | 947 | ieee80211_send_probe_req(sdata, ifmgd->bssid, |
1118 | ifsta->ssid, | 948 | ifmgd->ssid, |
1119 | ifsta->ssid_len); | 949 | ifmgd->ssid_len, |
1120 | ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; | 950 | NULL, 0); |
951 | ifmgd->flags ^= IEEE80211_STA_PROBEREQ_POLL; | ||
1121 | } else { | 952 | } else { |
1122 | ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | 953 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; |
1123 | if (time_after(jiffies, ifsta->last_probe + | 954 | if (time_after(jiffies, ifmgd->last_probe + |
1124 | IEEE80211_PROBE_INTERVAL)) { | 955 | IEEE80211_PROBE_INTERVAL)) { |
1125 | ifsta->last_probe = jiffies; | 956 | ifmgd->last_probe = jiffies; |
1126 | ieee80211_send_probe_req(sdata, ifsta->bssid, | 957 | ieee80211_send_probe_req(sdata, ifmgd->bssid, |
1127 | ifsta->ssid, | 958 | ifmgd->ssid, |
1128 | ifsta->ssid_len); | 959 | ifmgd->ssid_len, |
960 | NULL, 0); | ||
1129 | } | 961 | } |
1130 | } | 962 | } |
1131 | } | 963 | } |
@@ -1133,25 +965,25 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1133 | rcu_read_unlock(); | 965 | rcu_read_unlock(); |
1134 | 966 | ||
1135 | if (disassoc) | 967 | if (disassoc) |
1136 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 968 | ieee80211_set_disassoc(sdata, true, true, |
1137 | WLAN_REASON_PREV_AUTH_NOT_VALID); | 969 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
1138 | else | 970 | else |
1139 | mod_timer(&ifsta->timer, jiffies + | 971 | mod_timer(&ifmgd->timer, jiffies + |
1140 | IEEE80211_MONITORING_INTERVAL); | 972 | IEEE80211_MONITORING_INTERVAL); |
1141 | } | 973 | } |
1142 | 974 | ||
1143 | 975 | ||
1144 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | 976 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) |
1145 | struct ieee80211_if_sta *ifsta) | ||
1146 | { | 977 | { |
978 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
979 | |||
1147 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); | 980 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); |
1148 | ifsta->flags |= IEEE80211_STA_AUTHENTICATED; | 981 | ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; |
1149 | ieee80211_associate(sdata, ifsta); | 982 | ieee80211_associate(sdata); |
1150 | } | 983 | } |
1151 | 984 | ||
1152 | 985 | ||
1153 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | 986 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, |
1154 | struct ieee80211_if_sta *ifsta, | ||
1155 | struct ieee80211_mgmt *mgmt, | 987 | struct ieee80211_mgmt *mgmt, |
1156 | size_t len) | 988 | size_t len) |
1157 | { | 989 | { |
@@ -1162,59 +994,37 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1162 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 994 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); |
1163 | if (!elems.challenge) | 995 | if (!elems.challenge) |
1164 | return; | 996 | return; |
1165 | ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2, | 997 | ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg, |
1166 | elems.challenge_len + 2, 1); | 998 | elems.challenge - 2, elems.challenge_len + 2, |
1167 | } | 999 | sdata->u.mgd.bssid, 1); |
1168 | 1000 | sdata->u.mgd.auth_transaction = 4; | |
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 | } | 1001 | } |
1192 | 1002 | ||
1193 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 1003 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
1194 | struct ieee80211_if_sta *ifsta, | ||
1195 | struct ieee80211_mgmt *mgmt, | 1004 | struct ieee80211_mgmt *mgmt, |
1196 | size_t len) | 1005 | size_t len) |
1197 | { | 1006 | { |
1007 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1198 | u16 auth_alg, auth_transaction, status_code; | 1008 | u16 auth_alg, auth_transaction, status_code; |
1199 | 1009 | ||
1200 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE) | 1010 | if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE) |
1201 | return; | 1011 | return; |
1202 | 1012 | ||
1203 | if (len < 24 + 6) | 1013 | if (len < 24 + 6) |
1204 | return; | 1014 | return; |
1205 | 1015 | ||
1206 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | 1016 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) |
1207 | return; | 1017 | return; |
1208 | 1018 | ||
1209 | if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1019 | if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1210 | return; | 1020 | return; |
1211 | 1021 | ||
1212 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 1022 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
1213 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 1023 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
1214 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | 1024 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
1215 | 1025 | ||
1216 | if (auth_alg != ifsta->auth_alg || | 1026 | if (auth_alg != ifmgd->auth_alg || |
1217 | auth_transaction != ifsta->auth_transaction) | 1027 | auth_transaction != ifmgd->auth_transaction) |
1218 | return; | 1028 | return; |
1219 | 1029 | ||
1220 | if (status_code != WLAN_STATUS_SUCCESS) { | 1030 | if (status_code != WLAN_STATUS_SUCCESS) { |
@@ -1223,15 +1033,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1223 | const int num_algs = ARRAY_SIZE(algs); | 1033 | const int num_algs = ARRAY_SIZE(algs); |
1224 | int i, pos; | 1034 | int i, pos; |
1225 | algs[0] = algs[1] = algs[2] = 0xff; | 1035 | algs[0] = algs[1] = algs[2] = 0xff; |
1226 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) | 1036 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) |
1227 | algs[0] = WLAN_AUTH_OPEN; | 1037 | algs[0] = WLAN_AUTH_OPEN; |
1228 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) | 1038 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) |
1229 | algs[1] = WLAN_AUTH_SHARED_KEY; | 1039 | algs[1] = WLAN_AUTH_SHARED_KEY; |
1230 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1040 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
1231 | algs[2] = WLAN_AUTH_LEAP; | 1041 | algs[2] = WLAN_AUTH_LEAP; |
1232 | if (ifsta->auth_alg == WLAN_AUTH_OPEN) | 1042 | if (ifmgd->auth_alg == WLAN_AUTH_OPEN) |
1233 | pos = 0; | 1043 | pos = 0; |
1234 | else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY) | 1044 | else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY) |
1235 | pos = 1; | 1045 | pos = 1; |
1236 | else | 1046 | else |
1237 | pos = 2; | 1047 | pos = 2; |
@@ -1239,101 +1049,101 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1239 | pos++; | 1049 | pos++; |
1240 | if (pos >= num_algs) | 1050 | if (pos >= num_algs) |
1241 | pos = 0; | 1051 | pos = 0; |
1242 | if (algs[pos] == ifsta->auth_alg || | 1052 | if (algs[pos] == ifmgd->auth_alg || |
1243 | algs[pos] == 0xff) | 1053 | algs[pos] == 0xff) |
1244 | continue; | 1054 | continue; |
1245 | if (algs[pos] == WLAN_AUTH_SHARED_KEY && | 1055 | if (algs[pos] == WLAN_AUTH_SHARED_KEY && |
1246 | !ieee80211_sta_wep_configured(sdata)) | 1056 | !ieee80211_sta_wep_configured(sdata)) |
1247 | continue; | 1057 | continue; |
1248 | ifsta->auth_alg = algs[pos]; | 1058 | ifmgd->auth_alg = algs[pos]; |
1249 | break; | 1059 | break; |
1250 | } | 1060 | } |
1251 | } | 1061 | } |
1252 | return; | 1062 | return; |
1253 | } | 1063 | } |
1254 | 1064 | ||
1255 | switch (ifsta->auth_alg) { | 1065 | switch (ifmgd->auth_alg) { |
1256 | case WLAN_AUTH_OPEN: | 1066 | case WLAN_AUTH_OPEN: |
1257 | case WLAN_AUTH_LEAP: | 1067 | case WLAN_AUTH_LEAP: |
1258 | ieee80211_auth_completed(sdata, ifsta); | 1068 | ieee80211_auth_completed(sdata); |
1259 | break; | 1069 | break; |
1260 | case WLAN_AUTH_SHARED_KEY: | 1070 | case WLAN_AUTH_SHARED_KEY: |
1261 | if (ifsta->auth_transaction == 4) | 1071 | if (ifmgd->auth_transaction == 4) |
1262 | ieee80211_auth_completed(sdata, ifsta); | 1072 | ieee80211_auth_completed(sdata); |
1263 | else | 1073 | else |
1264 | ieee80211_auth_challenge(sdata, ifsta, mgmt, len); | 1074 | ieee80211_auth_challenge(sdata, mgmt, len); |
1265 | break; | 1075 | break; |
1266 | } | 1076 | } |
1267 | } | 1077 | } |
1268 | 1078 | ||
1269 | 1079 | ||
1270 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1080 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1271 | struct ieee80211_if_sta *ifsta, | ||
1272 | struct ieee80211_mgmt *mgmt, | 1081 | struct ieee80211_mgmt *mgmt, |
1273 | size_t len) | 1082 | size_t len) |
1274 | { | 1083 | { |
1084 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1275 | u16 reason_code; | 1085 | u16 reason_code; |
1276 | 1086 | ||
1277 | if (len < 24 + 2) | 1087 | if (len < 24 + 2) |
1278 | return; | 1088 | return; |
1279 | 1089 | ||
1280 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) | 1090 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) |
1281 | return; | 1091 | return; |
1282 | 1092 | ||
1283 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 1093 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
1284 | 1094 | ||
1285 | if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) | 1095 | if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED) |
1286 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", | 1096 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", |
1287 | sdata->dev->name, reason_code); | 1097 | sdata->dev->name, reason_code); |
1288 | 1098 | ||
1289 | if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || | 1099 | if (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || |
1290 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || | 1100 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || |
1291 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1101 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { |
1292 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1102 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
1293 | mod_timer(&ifsta->timer, jiffies + | 1103 | mod_timer(&ifmgd->timer, jiffies + |
1294 | IEEE80211_RETRY_AUTH_INTERVAL); | 1104 | IEEE80211_RETRY_AUTH_INTERVAL); |
1295 | } | 1105 | } |
1296 | 1106 | ||
1297 | ieee80211_set_disassoc(sdata, ifsta, true, false, 0); | 1107 | ieee80211_set_disassoc(sdata, true, false, 0); |
1298 | ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1108 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1299 | } | 1109 | } |
1300 | 1110 | ||
1301 | 1111 | ||
1302 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | 1112 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, |
1303 | struct ieee80211_if_sta *ifsta, | ||
1304 | struct ieee80211_mgmt *mgmt, | 1113 | struct ieee80211_mgmt *mgmt, |
1305 | size_t len) | 1114 | size_t len) |
1306 | { | 1115 | { |
1116 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1307 | u16 reason_code; | 1117 | u16 reason_code; |
1308 | 1118 | ||
1309 | if (len < 24 + 2) | 1119 | if (len < 24 + 2) |
1310 | return; | 1120 | return; |
1311 | 1121 | ||
1312 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) | 1122 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) |
1313 | return; | 1123 | return; |
1314 | 1124 | ||
1315 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 1125 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
1316 | 1126 | ||
1317 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 1127 | if (ifmgd->flags & IEEE80211_STA_ASSOCIATED) |
1318 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1128 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1319 | sdata->dev->name, reason_code); | 1129 | sdata->dev->name, reason_code); |
1320 | 1130 | ||
1321 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1131 | if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { |
1322 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 1132 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; |
1323 | mod_timer(&ifsta->timer, jiffies + | 1133 | mod_timer(&ifmgd->timer, jiffies + |
1324 | IEEE80211_RETRY_AUTH_INTERVAL); | 1134 | IEEE80211_RETRY_AUTH_INTERVAL); |
1325 | } | 1135 | } |
1326 | 1136 | ||
1327 | ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code); | 1137 | ieee80211_set_disassoc(sdata, false, false, reason_code); |
1328 | } | 1138 | } |
1329 | 1139 | ||
1330 | 1140 | ||
1331 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 1141 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, |
1332 | struct ieee80211_if_sta *ifsta, | ||
1333 | struct ieee80211_mgmt *mgmt, | 1142 | struct ieee80211_mgmt *mgmt, |
1334 | size_t len, | 1143 | size_t len, |
1335 | int reassoc) | 1144 | int reassoc) |
1336 | { | 1145 | { |
1146 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1337 | struct ieee80211_local *local = sdata->local; | 1147 | struct ieee80211_local *local = sdata->local; |
1338 | struct ieee80211_supported_band *sband; | 1148 | struct ieee80211_supported_band *sband; |
1339 | struct sta_info *sta; | 1149 | struct sta_info *sta; |
@@ -1350,13 +1160,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1350 | /* AssocResp and ReassocResp have identical structure, so process both | 1160 | /* AssocResp and ReassocResp have identical structure, so process both |
1351 | * of them in this function. */ | 1161 | * of them in this function. */ |
1352 | 1162 | ||
1353 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATE) | 1163 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) |
1354 | return; | 1164 | return; |
1355 | 1165 | ||
1356 | if (len < 24 + 6) | 1166 | if (len < 24 + 6) |
1357 | return; | 1167 | return; |
1358 | 1168 | ||
1359 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | 1169 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) |
1360 | return; | 1170 | return; |
1361 | 1171 | ||
1362 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | 1172 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
@@ -1381,7 +1191,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1381 | "comeback duration %u TU (%u ms)\n", | 1191 | "comeback duration %u TU (%u ms)\n", |
1382 | sdata->dev->name, tu, ms); | 1192 | sdata->dev->name, tu, ms); |
1383 | if (ms > IEEE80211_ASSOC_TIMEOUT) | 1193 | if (ms > IEEE80211_ASSOC_TIMEOUT) |
1384 | mod_timer(&ifsta->timer, | 1194 | mod_timer(&ifmgd->timer, |
1385 | jiffies + msecs_to_jiffies(ms)); | 1195 | jiffies + msecs_to_jiffies(ms)); |
1386 | return; | 1196 | return; |
1387 | } | 1197 | } |
@@ -1392,7 +1202,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1392 | /* if this was a reassociation, ensure we try a "full" | 1202 | /* if this was a reassociation, ensure we try a "full" |
1393 | * association next time. This works around some broken APs | 1203 | * association next time. This works around some broken APs |
1394 | * which do not correctly reject reassociation requests. */ | 1204 | * which do not correctly reject reassociation requests. */ |
1395 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 1205 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
1396 | return; | 1206 | return; |
1397 | } | 1207 | } |
1398 | 1208 | ||
@@ -1408,23 +1218,23 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1408 | } | 1218 | } |
1409 | 1219 | ||
1410 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); | 1220 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); |
1411 | ifsta->aid = aid; | 1221 | ifmgd->aid = aid; |
1412 | ifsta->ap_capab = capab_info; | 1222 | ifmgd->ap_capab = capab_info; |
1413 | 1223 | ||
1414 | kfree(ifsta->assocresp_ies); | 1224 | kfree(ifmgd->assocresp_ies); |
1415 | ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); | 1225 | ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt); |
1416 | ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); | 1226 | ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL); |
1417 | if (ifsta->assocresp_ies) | 1227 | if (ifmgd->assocresp_ies) |
1418 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); | 1228 | memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len); |
1419 | 1229 | ||
1420 | rcu_read_lock(); | 1230 | rcu_read_lock(); |
1421 | 1231 | ||
1422 | /* Add STA entry for the AP */ | 1232 | /* Add STA entry for the AP */ |
1423 | sta = sta_info_get(local, ifsta->bssid); | 1233 | sta = sta_info_get(local, ifmgd->bssid); |
1424 | if (!sta) { | 1234 | if (!sta) { |
1425 | newsta = true; | 1235 | newsta = true; |
1426 | 1236 | ||
1427 | sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); | 1237 | sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC); |
1428 | if (!sta) { | 1238 | if (!sta) { |
1429 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | 1239 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" |
1430 | " the AP\n", sdata->dev->name); | 1240 | " the AP\n", sdata->dev->name); |
@@ -1505,7 +1315,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1505 | 1315 | ||
1506 | rate_control_rate_init(sta); | 1316 | rate_control_rate_init(sta); |
1507 | 1317 | ||
1508 | if (ifsta->flags & IEEE80211_STA_MFP_ENABLED) | 1318 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) |
1509 | set_sta_flags(sta, WLAN_STA_MFP); | 1319 | set_sta_flags(sta, WLAN_STA_MFP); |
1510 | 1320 | ||
1511 | if (elems.wmm_param) | 1321 | if (elems.wmm_param) |
@@ -1524,11 +1334,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1524 | rcu_read_unlock(); | 1334 | rcu_read_unlock(); |
1525 | 1335 | ||
1526 | if (elems.wmm_param) | 1336 | if (elems.wmm_param) |
1527 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1337 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
1528 | elems.wmm_param_len); | 1338 | elems.wmm_param_len); |
1529 | 1339 | ||
1530 | if (elems.ht_info_elem && elems.wmm_param && | 1340 | if (elems.ht_info_elem && elems.wmm_param && |
1531 | (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) | 1341 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && |
1342 | !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) | ||
1532 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1343 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1533 | ap_ht_cap_flags); | 1344 | ap_ht_cap_flags); |
1534 | 1345 | ||
@@ -1536,162 +1347,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1536 | * ieee80211_set_associated() will tell the driver */ | 1347 | * ieee80211_set_associated() will tell the driver */ |
1537 | bss_conf->aid = aid; | 1348 | bss_conf->aid = aid; |
1538 | bss_conf->assoc_capability = capab_info; | 1349 | bss_conf->assoc_capability = capab_info; |
1539 | ieee80211_set_associated(sdata, ifsta, changed); | 1350 | ieee80211_set_associated(sdata, changed); |
1540 | |||
1541 | ieee80211_associated(sdata, ifsta); | ||
1542 | } | ||
1543 | |||
1544 | 1351 | ||
1545 | static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 1352 | ieee80211_associated(sdata); |
1546 | struct ieee80211_if_sta *ifsta, | ||
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) | ||
1552 | { | ||
1553 | struct ieee80211_local *local = sdata->local; | ||
1554 | int res = 0, rates, i, j; | ||
1555 | struct sk_buff *skb; | ||
1556 | struct ieee80211_mgmt *mgmt; | ||
1557 | u8 *pos; | ||
1558 | struct ieee80211_supported_band *sband; | ||
1559 | union iwreq_data wrqu; | ||
1560 | |||
1561 | if (local->ops->reset_tsf) { | ||
1562 | /* Reset own TSF to allow time synchronization work. */ | ||
1563 | local->ops->reset_tsf(local_to_hw(local)); | ||
1564 | } | ||
1565 | |||
1566 | if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) && | ||
1567 | memcmp(ifsta->bssid, bssid, ETH_ALEN) == 0) | ||
1568 | return res; | ||
1569 | |||
1570 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + | ||
1571 | sdata->u.sta.ie_proberesp_len); | ||
1572 | if (!skb) { | ||
1573 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
1574 | "response\n", sdata->dev->name); | ||
1575 | return -ENOMEM; | ||
1576 | } | ||
1577 | |||
1578 | if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) { | ||
1579 | /* Remove possible STA entries from other IBSS networks. */ | ||
1580 | sta_info_flush_delayed(sdata); | ||
1581 | } | ||
1582 | |||
1583 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | ||
1584 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
1585 | if (res) | ||
1586 | return res; | ||
1587 | |||
1588 | local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; | ||
1589 | |||
1590 | sdata->drop_unencrypted = capability & | ||
1591 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
1592 | |||
1593 | res = ieee80211_set_freq(sdata, freq); | ||
1594 | |||
1595 | if (res) | ||
1596 | return res; | ||
1597 | |||
1598 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1599 | |||
1600 | /* Build IBSS probe response */ | ||
1601 | |||
1602 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1603 | |||
1604 | mgmt = (struct ieee80211_mgmt *) | ||
1605 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | ||
1606 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | ||
1607 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1608 | IEEE80211_STYPE_PROBE_RESP); | ||
1609 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1610 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1611 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
1612 | mgmt->u.beacon.beacon_int = | ||
1613 | cpu_to_le16(local->hw.conf.beacon_int); | ||
1614 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | ||
1615 | |||
1616 | pos = skb_put(skb, 2 + ifsta->ssid_len); | ||
1617 | *pos++ = WLAN_EID_SSID; | ||
1618 | *pos++ = ifsta->ssid_len; | ||
1619 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | ||
1620 | |||
1621 | rates = supp_rates_len; | ||
1622 | if (rates > 8) | ||
1623 | rates = 8; | ||
1624 | pos = skb_put(skb, 2 + rates); | ||
1625 | *pos++ = WLAN_EID_SUPP_RATES; | ||
1626 | *pos++ = rates; | ||
1627 | memcpy(pos, supp_rates, rates); | ||
1628 | |||
1629 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
1630 | pos = skb_put(skb, 2 + 1); | ||
1631 | *pos++ = WLAN_EID_DS_PARAMS; | ||
1632 | *pos++ = 1; | ||
1633 | *pos++ = ieee80211_frequency_to_channel(freq); | ||
1634 | } | ||
1635 | |||
1636 | pos = skb_put(skb, 2 + 2); | ||
1637 | *pos++ = WLAN_EID_IBSS_PARAMS; | ||
1638 | *pos++ = 2; | ||
1639 | /* FIX: set ATIM window based on scan results */ | ||
1640 | *pos++ = 0; | ||
1641 | *pos++ = 0; | ||
1642 | |||
1643 | if (supp_rates_len > 8) { | ||
1644 | rates = supp_rates_len - 8; | ||
1645 | pos = skb_put(skb, 2 + rates); | ||
1646 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
1647 | *pos++ = rates; | ||
1648 | memcpy(pos, &supp_rates[8], rates); | ||
1649 | } | ||
1650 | |||
1651 | add_extra_ies(skb, sdata->u.sta.ie_proberesp, | ||
1652 | sdata->u.sta.ie_proberesp_len); | ||
1653 | |||
1654 | ifsta->probe_resp = skb; | ||
1655 | |||
1656 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | | ||
1657 | IEEE80211_IFCC_BEACON_ENABLED); | ||
1658 | |||
1659 | |||
1660 | rates = 0; | ||
1661 | for (i = 0; i < supp_rates_len; i++) { | ||
1662 | int bitrate = (supp_rates[i] & 0x7f) * 5; | ||
1663 | for (j = 0; j < sband->n_bitrates; j++) | ||
1664 | if (sband->bitrates[j].bitrate == bitrate) | ||
1665 | rates |= BIT(j); | ||
1666 | } | ||
1667 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; | ||
1668 | |||
1669 | ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); | ||
1670 | |||
1671 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | ||
1672 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; | ||
1673 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
1674 | |||
1675 | ieee80211_led_assoc(local, true); | ||
1676 | |||
1677 | memset(&wrqu, 0, sizeof(wrqu)); | ||
1678 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | ||
1679 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | ||
1680 | |||
1681 | return res; | ||
1682 | } | 1353 | } |
1683 | 1354 | ||
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 | 1355 | ||
1696 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 1356 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
1697 | struct ieee80211_mgmt *mgmt, | 1357 | struct ieee80211_mgmt *mgmt, |
@@ -1703,11 +1363,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1703 | struct ieee80211_local *local = sdata->local; | 1363 | struct ieee80211_local *local = sdata->local; |
1704 | int freq; | 1364 | int freq; |
1705 | struct ieee80211_bss *bss; | 1365 | struct ieee80211_bss *bss; |
1706 | struct sta_info *sta; | ||
1707 | struct ieee80211_channel *channel; | 1366 | struct ieee80211_channel *channel; |
1708 | u64 beacon_timestamp, rx_timestamp; | ||
1709 | u32 supp_rates = 0; | ||
1710 | enum ieee80211_band band = rx_status->band; | ||
1711 | 1367 | ||
1712 | if (elems->ds_params && elems->ds_params_len == 1) | 1368 | if (elems->ds_params && elems->ds_params_len == 1) |
1713 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | 1369 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); |
@@ -1719,133 +1375,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1719 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 1375 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
1720 | return; | 1376 | return; |
1721 | 1377 | ||
1722 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && | ||
1723 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { | ||
1724 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
1725 | |||
1726 | rcu_read_lock(); | ||
1727 | |||
1728 | sta = sta_info_get(local, mgmt->sa); | ||
1729 | if (sta) { | ||
1730 | u32 prev_rates; | ||
1731 | |||
1732 | prev_rates = sta->sta.supp_rates[band]; | ||
1733 | /* make sure mandatory rates are always added */ | ||
1734 | sta->sta.supp_rates[band] = supp_rates | | ||
1735 | ieee80211_mandatory_rates(local, band); | ||
1736 | |||
1737 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1738 | if (sta->sta.supp_rates[band] != prev_rates) | ||
1739 | printk(KERN_DEBUG "%s: updated supp_rates set " | ||
1740 | "for %pM based on beacon info (0x%llx | " | ||
1741 | "0x%llx -> 0x%llx)\n", | ||
1742 | sdata->dev->name, | ||
1743 | sta->sta.addr, | ||
1744 | (unsigned long long) prev_rates, | ||
1745 | (unsigned long long) supp_rates, | ||
1746 | (unsigned long long) sta->sta.supp_rates[band]); | ||
1747 | #endif | ||
1748 | } else { | ||
1749 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
1750 | } | ||
1751 | |||
1752 | rcu_read_unlock(); | ||
1753 | } | ||
1754 | |||
1755 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 1378 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
1756 | channel, beacon); | 1379 | channel, beacon); |
1757 | if (!bss) | 1380 | if (!bss) |
1758 | return; | 1381 | return; |
1759 | 1382 | ||
1760 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | 1383 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && |
1761 | (memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0)) { | 1384 | (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { |
1762 | struct ieee80211_channel_sw_ie *sw_elem = | 1385 | struct ieee80211_channel_sw_ie *sw_elem = |
1763 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | 1386 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
1764 | ieee80211_process_chanswitch(sdata, sw_elem, bss); | 1387 | ieee80211_process_chanswitch(sdata, sw_elem, bss); |
1765 | } | 1388 | } |
1766 | 1389 | ||
1767 | /* was just updated in ieee80211_bss_info_update */ | ||
1768 | beacon_timestamp = bss->cbss.tsf; | ||
1769 | |||
1770 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
1771 | goto put_bss; | ||
1772 | |||
1773 | /* check if we need to merge IBSS */ | ||
1774 | |||
1775 | /* merge only on beacons (???) */ | ||
1776 | if (!beacon) | ||
1777 | goto put_bss; | ||
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 || | ||
1793 | memcmp(elems->ssid, sdata->u.sta.ssid, | ||
1794 | sdata->u.sta.ssid_len)) | ||
1795 | goto put_bss; | ||
1796 | |||
1797 | if (rx_status->flag & RX_FLAG_TSFT) { | ||
1798 | /* | ||
1799 | * For correct IBSS merging we need mactime; since mactime is | ||
1800 | * defined as the time the first data symbol of the frame hits | ||
1801 | * the PHY, and the timestamp of the beacon is defined as "the | ||
1802 | * time that the data symbol containing the first bit of the | ||
1803 | * timestamp is transmitted to the PHY plus the transmitting | ||
1804 | * STA's delays through its local PHY from the MAC-PHY | ||
1805 | * interface to its interface with the WM" (802.11 11.1.2) | ||
1806 | * - equals the time this bit arrives at the receiver - we have | ||
1807 | * to take into account the offset between the two. | ||
1808 | * | ||
1809 | * E.g. at 1 MBit that means mactime is 192 usec earlier | ||
1810 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | ||
1811 | */ | ||
1812 | int rate; | ||
1813 | |||
1814 | if (rx_status->flag & RX_FLAG_HT) | ||
1815 | rate = 65; /* TODO: HT rates */ | ||
1816 | else | ||
1817 | rate = local->hw.wiphy->bands[band]-> | ||
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 | |||
1828 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1829 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | ||
1830 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | ||
1831 | mgmt->sa, mgmt->bssid, | ||
1832 | (unsigned long long)rx_timestamp, | ||
1833 | (unsigned long long)beacon_timestamp, | ||
1834 | (unsigned long long)(rx_timestamp - beacon_timestamp), | ||
1835 | jiffies); | ||
1836 | #endif | ||
1837 | |||
1838 | if (beacon_timestamp > rx_timestamp) { | ||
1839 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1840 | printk(KERN_DEBUG "%s: beacon TSF higher than " | ||
1841 | "local TSF - IBSS merge with BSSID %pM\n", | ||
1842 | sdata->dev->name, mgmt->bssid); | ||
1843 | #endif | ||
1844 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); | ||
1845 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
1846 | } | ||
1847 | |||
1848 | put_bss: | ||
1849 | ieee80211_rx_bss_put(local, bss); | 1390 | ieee80211_rx_bss_put(local, bss); |
1850 | } | 1391 | } |
1851 | 1392 | ||
@@ -1857,7 +1398,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1857 | { | 1398 | { |
1858 | size_t baselen; | 1399 | size_t baselen; |
1859 | struct ieee802_11_elems elems; | 1400 | struct ieee802_11_elems elems; |
1860 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1861 | 1401 | ||
1862 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 1402 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) |
1863 | return; /* ignore ProbeResp to foreign address */ | 1403 | return; /* ignore ProbeResp to foreign address */ |
@@ -1873,20 +1413,19 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1873 | 1413 | ||
1874 | /* direct probe may be part of the association flow */ | 1414 | /* direct probe may be part of the association flow */ |
1875 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 1415 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, |
1876 | &ifsta->request)) { | 1416 | &sdata->u.mgd.request)) { |
1877 | printk(KERN_DEBUG "%s direct probe responded\n", | 1417 | printk(KERN_DEBUG "%s direct probe responded\n", |
1878 | sdata->dev->name); | 1418 | sdata->dev->name); |
1879 | ieee80211_authenticate(sdata, ifsta); | 1419 | ieee80211_authenticate(sdata); |
1880 | } | 1420 | } |
1881 | } | 1421 | } |
1882 | 1422 | ||
1883 | |||
1884 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 1423 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
1885 | struct ieee80211_mgmt *mgmt, | 1424 | struct ieee80211_mgmt *mgmt, |
1886 | size_t len, | 1425 | size_t len, |
1887 | struct ieee80211_rx_status *rx_status) | 1426 | struct ieee80211_rx_status *rx_status) |
1888 | { | 1427 | { |
1889 | struct ieee80211_if_sta *ifsta; | 1428 | struct ieee80211_if_managed *ifmgd; |
1890 | size_t baselen; | 1429 | size_t baselen; |
1891 | struct ieee802_11_elems elems; | 1430 | struct ieee802_11_elems elems; |
1892 | struct ieee80211_local *local = sdata->local; | 1431 | struct ieee80211_local *local = sdata->local; |
@@ -1905,21 +1444,22 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1905 | 1444 | ||
1906 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1445 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
1907 | return; | 1446 | return; |
1908 | ifsta = &sdata->u.sta; | ||
1909 | 1447 | ||
1910 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || | 1448 | ifmgd = &sdata->u.mgd; |
1911 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1449 | |
1450 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || | ||
1451 | memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1912 | return; | 1452 | return; |
1913 | 1453 | ||
1914 | if (rx_status->freq != local->hw.conf.channel->center_freq) | 1454 | if (rx_status->freq != local->hw.conf.channel->center_freq) |
1915 | return; | 1455 | return; |
1916 | 1456 | ||
1917 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1457 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
1918 | elems.wmm_param_len); | 1458 | elems.wmm_param_len); |
1919 | 1459 | ||
1920 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && | 1460 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && |
1921 | local->hw.conf.flags & IEEE80211_CONF_PS) { | 1461 | local->hw.conf.flags & IEEE80211_CONF_PS) { |
1922 | directed_tim = ieee80211_check_tim(&elems, ifsta->aid); | 1462 | directed_tim = ieee80211_check_tim(&elems, ifmgd->aid); |
1923 | 1463 | ||
1924 | if (directed_tim) { | 1464 | if (directed_tim) { |
1925 | if (local->hw.conf.dynamic_ps_timeout > 0) { | 1465 | if (local->hw.conf.dynamic_ps_timeout > 0) { |
@@ -1954,14 +1494,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1954 | erp_valid, erp_value); | 1494 | erp_valid, erp_value); |
1955 | 1495 | ||
1956 | 1496 | ||
1957 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { | 1497 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && |
1498 | !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) { | ||
1958 | struct sta_info *sta; | 1499 | struct sta_info *sta; |
1959 | struct ieee80211_supported_band *sband; | 1500 | struct ieee80211_supported_band *sband; |
1960 | u16 ap_ht_cap_flags; | 1501 | u16 ap_ht_cap_flags; |
1961 | 1502 | ||
1962 | rcu_read_lock(); | 1503 | rcu_read_lock(); |
1963 | 1504 | ||
1964 | sta = sta_info_get(local, ifsta->bssid); | 1505 | sta = sta_info_get(local, ifmgd->bssid); |
1965 | if (!sta) { | 1506 | if (!sta) { |
1966 | rcu_read_unlock(); | 1507 | rcu_read_unlock(); |
1967 | return; | 1508 | return; |
@@ -1997,85 +1538,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1997 | ieee80211_bss_info_change_notify(sdata, changed); | 1538 | ieee80211_bss_info_change_notify(sdata, changed); |
1998 | } | 1539 | } |
1999 | 1540 | ||
2000 | 1541 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |
2001 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | 1542 | struct sk_buff *skb, |
2002 | struct ieee80211_if_sta *ifsta, | 1543 | struct ieee80211_rx_status *rx_status) |
2003 | struct ieee80211_mgmt *mgmt, | ||
2004 | size_t len) | ||
2005 | { | 1544 | { |
2006 | struct ieee80211_local *local = sdata->local; | 1545 | struct ieee80211_local *local = sdata->local; |
2007 | int tx_last_beacon; | ||
2008 | struct sk_buff *skb; | ||
2009 | struct ieee80211_mgmt *resp; | ||
2010 | u8 *pos, *end; | ||
2011 | |||
2012 | if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || | ||
2013 | len < 24 + 2 || !ifsta->probe_resp) | ||
2014 | return; | ||
2015 | |||
2016 | if (local->ops->tx_last_beacon) | ||
2017 | tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); | ||
2018 | else | ||
2019 | tx_last_beacon = 1; | ||
2020 | |||
2021 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2022 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" | ||
2023 | " (tx_last_beacon=%d)\n", | ||
2024 | sdata->dev->name, mgmt->sa, mgmt->da, | ||
2025 | mgmt->bssid, tx_last_beacon); | ||
2026 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2027 | |||
2028 | if (!tx_last_beacon) | ||
2029 | return; | ||
2030 | |||
2031 | if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 && | ||
2032 | memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) | ||
2033 | return; | ||
2034 | |||
2035 | end = ((u8 *) mgmt) + len; | ||
2036 | pos = mgmt->u.probe_req.variable; | ||
2037 | if (pos[0] != WLAN_EID_SSID || | ||
2038 | pos + 2 + pos[1] > end) { | ||
2039 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2040 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " | ||
2041 | "from %pM\n", | ||
2042 | sdata->dev->name, mgmt->sa); | ||
2043 | #endif | ||
2044 | return; | ||
2045 | } | ||
2046 | if (pos[1] != 0 && | ||
2047 | (pos[1] != ifsta->ssid_len || | ||
2048 | memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) { | ||
2049 | /* Ignore ProbeReq for foreign SSID */ | ||
2050 | return; | ||
2051 | } | ||
2052 | |||
2053 | /* Reply with ProbeResp */ | ||
2054 | skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); | ||
2055 | if (!skb) | ||
2056 | return; | ||
2057 | |||
2058 | resp = (struct ieee80211_mgmt *) skb->data; | ||
2059 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | ||
2060 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2061 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", | ||
2062 | sdata->dev->name, resp->da); | ||
2063 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2064 | ieee80211_tx_skb(sdata, skb, 0); | ||
2065 | } | ||
2066 | |||
2067 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
2068 | struct ieee80211_rx_status *rx_status) | ||
2069 | { | ||
2070 | struct ieee80211_local *local = sdata->local; | ||
2071 | struct ieee80211_if_sta *ifsta; | ||
2072 | struct ieee80211_mgmt *mgmt; | 1546 | struct ieee80211_mgmt *mgmt; |
2073 | u16 fc; | 1547 | u16 fc; |
2074 | 1548 | ||
2075 | if (skb->len < 24) | 1549 | if (skb->len < 24) |
2076 | goto fail; | 1550 | return RX_DROP_MONITOR; |
2077 | |||
2078 | ifsta = &sdata->u.sta; | ||
2079 | 1551 | ||
2080 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1552 | mgmt = (struct ieee80211_mgmt *) skb->data; |
2081 | fc = le16_to_cpu(mgmt->frame_control); | 1553 | fc = le16_to_cpu(mgmt->frame_control); |
@@ -2090,147 +1562,68 @@ void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff * | |||
2090 | case IEEE80211_STYPE_REASSOC_RESP: | 1562 | case IEEE80211_STYPE_REASSOC_RESP: |
2091 | case IEEE80211_STYPE_DEAUTH: | 1563 | case IEEE80211_STYPE_DEAUTH: |
2092 | case IEEE80211_STYPE_DISASSOC: | 1564 | case IEEE80211_STYPE_DISASSOC: |
2093 | skb_queue_tail(&ifsta->skb_queue, skb); | 1565 | skb_queue_tail(&sdata->u.mgd.skb_queue, skb); |
2094 | queue_work(local->hw.workqueue, &ifsta->work); | 1566 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); |
2095 | return; | 1567 | return RX_QUEUED; |
2096 | } | 1568 | } |
2097 | 1569 | ||
2098 | fail: | 1570 | return RX_DROP_MONITOR; |
2099 | kfree_skb(skb); | ||
2100 | } | 1571 | } |
2101 | 1572 | ||
2102 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1573 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
2103 | struct sk_buff *skb) | 1574 | struct sk_buff *skb) |
2104 | { | 1575 | { |
2105 | struct ieee80211_rx_status *rx_status; | 1576 | struct ieee80211_rx_status *rx_status; |
2106 | struct ieee80211_if_sta *ifsta; | ||
2107 | struct ieee80211_mgmt *mgmt; | 1577 | struct ieee80211_mgmt *mgmt; |
2108 | u16 fc; | 1578 | u16 fc; |
2109 | 1579 | ||
2110 | ifsta = &sdata->u.sta; | ||
2111 | |||
2112 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 1580 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
2113 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1581 | mgmt = (struct ieee80211_mgmt *) skb->data; |
2114 | fc = le16_to_cpu(mgmt->frame_control); | 1582 | fc = le16_to_cpu(mgmt->frame_control); |
2115 | 1583 | ||
2116 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1584 | switch (fc & IEEE80211_FCTL_STYPE) { |
2117 | switch (fc & IEEE80211_FCTL_STYPE) { | 1585 | case IEEE80211_STYPE_PROBE_RESP: |
2118 | case IEEE80211_STYPE_PROBE_REQ: | 1586 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, |
2119 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, | 1587 | rx_status); |
2120 | skb->len); | 1588 | break; |
2121 | break; | 1589 | case IEEE80211_STYPE_BEACON: |
2122 | case IEEE80211_STYPE_PROBE_RESP: | 1590 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
2123 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, | 1591 | rx_status); |
2124 | rx_status); | 1592 | break; |
2125 | break; | 1593 | case IEEE80211_STYPE_AUTH: |
2126 | case IEEE80211_STYPE_BEACON: | 1594 | ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); |
2127 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 1595 | break; |
2128 | rx_status); | 1596 | case IEEE80211_STYPE_ASSOC_RESP: |
2129 | break; | 1597 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0); |
2130 | case IEEE80211_STYPE_AUTH: | 1598 | break; |
2131 | ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt, | 1599 | case IEEE80211_STYPE_REASSOC_RESP: |
2132 | skb->len); | 1600 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1); |
2133 | break; | 1601 | break; |
2134 | } | 1602 | case IEEE80211_STYPE_DEAUTH: |
2135 | } else { /* NL80211_IFTYPE_STATION */ | 1603 | ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
2136 | switch (fc & IEEE80211_FCTL_STYPE) { | 1604 | break; |
2137 | case IEEE80211_STYPE_PROBE_RESP: | 1605 | case IEEE80211_STYPE_DISASSOC: |
2138 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, | 1606 | ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
2139 | rx_status); | 1607 | 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 | } | ||
2164 | } | 1608 | } |
2165 | 1609 | ||
2166 | kfree_skb(skb); | 1610 | kfree_skb(skb); |
2167 | } | 1611 | } |
2168 | 1612 | ||
2169 | |||
2170 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
2171 | { | ||
2172 | struct ieee80211_local *local = sdata->local; | ||
2173 | int active = 0; | ||
2174 | struct sta_info *sta; | ||
2175 | |||
2176 | rcu_read_lock(); | ||
2177 | |||
2178 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
2179 | if (sta->sdata == sdata && | ||
2180 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
2181 | jiffies)) { | ||
2182 | active++; | ||
2183 | break; | ||
2184 | } | ||
2185 | } | ||
2186 | |||
2187 | rcu_read_unlock(); | ||
2188 | |||
2189 | return active; | ||
2190 | } | ||
2191 | |||
2192 | |||
2193 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata, | ||
2194 | struct ieee80211_if_sta *ifsta) | ||
2195 | { | ||
2196 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
2197 | |||
2198 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | ||
2199 | if (ieee80211_sta_active_ibss(sdata)) | ||
2200 | return; | ||
2201 | |||
2202 | if ((sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) && | ||
2203 | (!(sdata->u.sta.flags & IEEE80211_STA_AUTO_CHANNEL_SEL))) | ||
2204 | return; | ||
2205 | |||
2206 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | ||
2207 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | ||
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); | ||
2217 | } | ||
2218 | |||
2219 | |||
2220 | static void ieee80211_sta_timer(unsigned long data) | 1613 | static void ieee80211_sta_timer(unsigned long data) |
2221 | { | 1614 | { |
2222 | struct ieee80211_sub_if_data *sdata = | 1615 | struct ieee80211_sub_if_data *sdata = |
2223 | (struct ieee80211_sub_if_data *) data; | 1616 | (struct ieee80211_sub_if_data *) data; |
2224 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1617 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2225 | struct ieee80211_local *local = sdata->local; | 1618 | struct ieee80211_local *local = sdata->local; |
2226 | 1619 | ||
2227 | set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | 1620 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
2228 | queue_work(local->hw.workqueue, &ifsta->work); | 1621 | queue_work(local->hw.workqueue, &ifmgd->work); |
2229 | } | 1622 | } |
2230 | 1623 | ||
2231 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | 1624 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) |
2232 | struct ieee80211_if_sta *ifsta) | ||
2233 | { | 1625 | { |
1626 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2234 | struct ieee80211_local *local = sdata->local; | 1627 | struct ieee80211_local *local = sdata->local; |
2235 | 1628 | ||
2236 | if (local->ops->reset_tsf) { | 1629 | if (local->ops->reset_tsf) { |
@@ -2238,191 +1631,39 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | |||
2238 | local->ops->reset_tsf(local_to_hw(local)); | 1631 | local->ops->reset_tsf(local_to_hw(local)); |
2239 | } | 1632 | } |
2240 | 1633 | ||
2241 | ifsta->wmm_last_param_set = -1; /* allow any WMM update */ | 1634 | ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ |
2242 | 1635 | ||
2243 | 1636 | ||
2244 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) | 1637 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) |
2245 | ifsta->auth_alg = WLAN_AUTH_OPEN; | 1638 | ifmgd->auth_alg = WLAN_AUTH_OPEN; |
2246 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) | 1639 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) |
2247 | ifsta->auth_alg = WLAN_AUTH_SHARED_KEY; | 1640 | ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; |
2248 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1641 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
2249 | ifsta->auth_alg = WLAN_AUTH_LEAP; | 1642 | ifmgd->auth_alg = WLAN_AUTH_LEAP; |
2250 | else | 1643 | else |
2251 | ifsta->auth_alg = WLAN_AUTH_OPEN; | 1644 | ifmgd->auth_alg = WLAN_AUTH_OPEN; |
2252 | ifsta->auth_transaction = -1; | 1645 | ifmgd->auth_transaction = -1; |
2253 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 1646 | ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; |
2254 | ifsta->assoc_scan_tries = 0; | 1647 | ifmgd->assoc_scan_tries = 0; |
2255 | ifsta->direct_probe_tries = 0; | 1648 | ifmgd->direct_probe_tries = 0; |
2256 | ifsta->auth_tries = 0; | 1649 | ifmgd->auth_tries = 0; |
2257 | ifsta->assoc_tries = 0; | 1650 | ifmgd->assoc_tries = 0; |
2258 | netif_tx_stop_all_queues(sdata->dev); | 1651 | netif_tx_stop_all_queues(sdata->dev); |
2259 | netif_carrier_off(sdata->dev); | 1652 | netif_carrier_off(sdata->dev); |
2260 | } | 1653 | } |
2261 | 1654 | ||
2262 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | 1655 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) |
2263 | struct ieee80211_if_sta *ifsta) | ||
2264 | { | ||
2265 | struct ieee80211_local *local = sdata->local; | ||
2266 | struct ieee80211_supported_band *sband; | ||
2267 | u8 *pos; | ||
2268 | u8 bssid[ETH_ALEN]; | ||
2269 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
2270 | u16 capability; | ||
2271 | int i; | ||
2272 | |||
2273 | if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) { | ||
2274 | memcpy(bssid, ifsta->bssid, ETH_ALEN); | ||
2275 | } else { | ||
2276 | /* Generate random, not broadcast, locally administered BSSID. Mix in | ||
2277 | * own MAC address to make sure that devices that do not have proper | ||
2278 | * random number generator get different BSSID. */ | ||
2279 | get_random_bytes(bssid, ETH_ALEN); | ||
2280 | for (i = 0; i < ETH_ALEN; i++) | ||
2281 | bssid[i] ^= sdata->dev->dev_addr[i]; | ||
2282 | bssid[0] &= ~0x01; | ||
2283 | bssid[0] |= 0x02; | ||
2284 | } | ||
2285 | |||
2286 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | ||
2287 | sdata->dev->name, bssid); | ||
2288 | |||
2289 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
2290 | |||
2291 | if (local->hw.conf.beacon_int == 0) | ||
2292 | local->hw.conf.beacon_int = 100; | ||
2293 | |||
2294 | capability = WLAN_CAPABILITY_IBSS; | ||
2295 | |||
2296 | if (sdata->default_key) | ||
2297 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
2298 | else | ||
2299 | sdata->drop_unencrypted = 0; | ||
2300 | |||
2301 | pos = supp_rates; | ||
2302 | for (i = 0; i < sband->n_bitrates; i++) { | ||
2303 | int rate = sband->bitrates[i].bitrate; | ||
2304 | *pos++ = (u8) (rate / 5); | ||
2305 | } | ||
2306 | |||
2307 | return __ieee80211_sta_join_ibss(sdata, ifsta, | ||
2308 | bssid, local->hw.conf.beacon_int, | ||
2309 | local->hw.conf.channel->center_freq, | ||
2310 | sband->n_bitrates, supp_rates, | ||
2311 | capability); | ||
2312 | } | ||
2313 | |||
2314 | |||
2315 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | ||
2316 | struct ieee80211_if_sta *ifsta) | ||
2317 | { | 1656 | { |
1657 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2318 | struct ieee80211_local *local = sdata->local; | 1658 | struct ieee80211_local *local = sdata->local; |
2319 | struct ieee80211_bss *bss; | 1659 | struct ieee80211_bss *bss; |
2320 | int active_ibss; | 1660 | u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid; |
2321 | 1661 | u8 ssid_len = ifmgd->ssid_len; | |
2322 | if (ifsta->ssid_len == 0) | ||
2323 | return -EINVAL; | ||
2324 | |||
2325 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
2326 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2327 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | ||
2328 | sdata->dev->name, active_ibss); | ||
2329 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2330 | |||
2331 | if (active_ibss) | ||
2332 | return 0; | ||
2333 | |||
2334 | if (ifsta->flags & IEEE80211_STA_BSSID_SET) | ||
2335 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, 0, | ||
2336 | ifsta->ssid, ifsta->ssid_len); | ||
2337 | else | ||
2338 | bss = (void *)cfg80211_get_ibss(local->hw.wiphy, | ||
2339 | NULL, | ||
2340 | ifsta->ssid, ifsta->ssid_len); | ||
2341 | |||
2342 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2343 | if (bss) | ||
2344 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " | ||
2345 | "%pM\n", bss->cbss.bssid, ifsta->bssid); | ||
2346 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2347 | |||
2348 | if (bss && | ||
2349 | (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) || | ||
2350 | memcmp(ifsta->bssid, bss->cbss.bssid, ETH_ALEN))) { | ||
2351 | int ret; | ||
2352 | |||
2353 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | ||
2354 | " based on configured SSID\n", | ||
2355 | sdata->dev->name, bss->cbss.bssid); | ||
2356 | |||
2357 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); | ||
2358 | ieee80211_rx_bss_put(local, bss); | ||
2359 | return ret; | ||
2360 | } else if (bss) | ||
2361 | ieee80211_rx_bss_put(local, bss); | ||
2362 | |||
2363 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2364 | printk(KERN_DEBUG " did not try to join ibss\n"); | ||
2365 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2366 | |||
2367 | /* Selected IBSS not found in current scan results - try to scan */ | ||
2368 | if (ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED && | ||
2369 | !ieee80211_sta_active_ibss(sdata)) { | ||
2370 | mod_timer(&ifsta->timer, jiffies + | ||
2371 | IEEE80211_IBSS_MERGE_INTERVAL); | ||
2372 | } else if (time_after(jiffies, local->last_scan_completed + | ||
2373 | IEEE80211_SCAN_INTERVAL)) { | ||
2374 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | ||
2375 | "join\n", sdata->dev->name); | ||
2376 | |||
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); | ||
2385 | } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) { | ||
2386 | int interval = IEEE80211_SCAN_INTERVAL; | ||
2387 | |||
2388 | if (time_after(jiffies, ifsta->ibss_join_req + | ||
2389 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | ||
2390 | if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && | ||
2391 | (!(local->oper_channel->flags & | ||
2392 | IEEE80211_CHAN_NO_IBSS))) | ||
2393 | return ieee80211_sta_create_ibss(sdata, ifsta); | ||
2394 | if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { | ||
2395 | printk(KERN_DEBUG "%s: IBSS not allowed on" | ||
2396 | " %d MHz\n", sdata->dev->name, | ||
2397 | local->hw.conf.channel->center_freq); | ||
2398 | } | ||
2399 | |||
2400 | /* No IBSS found - decrease scan interval and continue | ||
2401 | * scanning. */ | ||
2402 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | ||
2403 | } | ||
2404 | |||
2405 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | ||
2406 | mod_timer(&ifsta->timer, jiffies + interval); | ||
2407 | return 0; | ||
2408 | } | ||
2409 | |||
2410 | return 0; | ||
2411 | } | ||
2412 | |||
2413 | |||
2414 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | ||
2415 | struct ieee80211_if_sta *ifsta) | ||
2416 | { | ||
2417 | struct ieee80211_local *local = sdata->local; | ||
2418 | struct ieee80211_bss *bss; | ||
2419 | u8 *bssid = ifsta->bssid, *ssid = ifsta->ssid; | ||
2420 | u8 ssid_len = ifsta->ssid_len; | ||
2421 | u16 capa_mask = WLAN_CAPABILITY_ESS; | 1662 | u16 capa_mask = WLAN_CAPABILITY_ESS; |
2422 | u16 capa_val = WLAN_CAPABILITY_ESS; | 1663 | u16 capa_val = WLAN_CAPABILITY_ESS; |
2423 | struct ieee80211_channel *chan = local->oper_channel; | 1664 | struct ieee80211_channel *chan = local->oper_channel; |
2424 | 1665 | ||
2425 | if (ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | 1666 | if (ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | |
2426 | IEEE80211_STA_AUTO_BSSID_SEL | | 1667 | IEEE80211_STA_AUTO_BSSID_SEL | |
2427 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { | 1668 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { |
2428 | capa_mask |= WLAN_CAPABILITY_PRIVACY; | 1669 | capa_mask |= WLAN_CAPABILITY_PRIVACY; |
@@ -2430,13 +1671,13 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2430 | capa_val |= WLAN_CAPABILITY_PRIVACY; | 1671 | capa_val |= WLAN_CAPABILITY_PRIVACY; |
2431 | } | 1672 | } |
2432 | 1673 | ||
2433 | if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) | 1674 | if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) |
2434 | chan = NULL; | 1675 | chan = NULL; |
2435 | 1676 | ||
2436 | if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) | 1677 | if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL) |
2437 | bssid = NULL; | 1678 | bssid = NULL; |
2438 | 1679 | ||
2439 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) { | 1680 | if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) { |
2440 | ssid = NULL; | 1681 | ssid = NULL; |
2441 | ssid_len = 0; | 1682 | ssid_len = 0; |
2442 | } | 1683 | } |
@@ -2447,16 +1688,16 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2447 | 1688 | ||
2448 | if (bss) { | 1689 | if (bss) { |
2449 | ieee80211_set_freq(sdata, bss->cbss.channel->center_freq); | 1690 | ieee80211_set_freq(sdata, bss->cbss.channel->center_freq); |
2450 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | 1691 | if (!(ifmgd->flags & IEEE80211_STA_SSID_SET)) |
2451 | ieee80211_sta_set_ssid(sdata, bss->ssid, | 1692 | ieee80211_sta_set_ssid(sdata, bss->ssid, |
2452 | bss->ssid_len); | 1693 | bss->ssid_len); |
2453 | ieee80211_sta_set_bssid(sdata, bss->cbss.bssid); | 1694 | ieee80211_sta_set_bssid(sdata, bss->cbss.bssid); |
2454 | ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, | 1695 | ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, |
2455 | bss->supp_rates); | 1696 | bss->supp_rates); |
2456 | if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED) | 1697 | if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED) |
2457 | sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED; | 1698 | sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; |
2458 | else | 1699 | else |
2459 | sdata->u.sta.flags &= ~IEEE80211_STA_MFP_ENABLED; | 1700 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; |
2460 | 1701 | ||
2461 | /* Send out direct probe if no probe resp was received or | 1702 | /* Send out direct probe if no probe resp was received or |
2462 | * the one we have is outdated | 1703 | * the one we have is outdated |
@@ -2464,31 +1705,31 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2464 | if (!bss->last_probe_resp || | 1705 | if (!bss->last_probe_resp || |
2465 | time_after(jiffies, bss->last_probe_resp | 1706 | time_after(jiffies, bss->last_probe_resp |
2466 | + IEEE80211_SCAN_RESULT_EXPIRE)) | 1707 | + IEEE80211_SCAN_RESULT_EXPIRE)) |
2467 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1708 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
2468 | else | 1709 | else |
2469 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 1710 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2470 | 1711 | ||
2471 | ieee80211_rx_bss_put(local, bss); | 1712 | ieee80211_rx_bss_put(local, bss); |
2472 | ieee80211_sta_reset_auth(sdata, ifsta); | 1713 | ieee80211_sta_reset_auth(sdata); |
2473 | return 0; | 1714 | return 0; |
2474 | } else { | 1715 | } else { |
2475 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | 1716 | if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { |
2476 | ifsta->assoc_scan_tries++; | 1717 | ifmgd->assoc_scan_tries++; |
2477 | /* XXX maybe racy? */ | 1718 | /* XXX maybe racy? */ |
2478 | if (local->scan_req) | 1719 | if (local->scan_req) |
2479 | return -1; | 1720 | return -1; |
2480 | memcpy(local->int_scan_req.ssids[0].ssid, | 1721 | memcpy(local->int_scan_req.ssids[0].ssid, |
2481 | ifsta->ssid, IEEE80211_MAX_SSID_LEN); | 1722 | ifmgd->ssid, IEEE80211_MAX_SSID_LEN); |
2482 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | 1723 | if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) |
2483 | local->int_scan_req.ssids[0].ssid_len = 0; | 1724 | local->int_scan_req.ssids[0].ssid_len = 0; |
2484 | else | 1725 | else |
2485 | local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len; | 1726 | local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len; |
2486 | ieee80211_start_scan(sdata, &local->int_scan_req); | 1727 | ieee80211_start_scan(sdata, &local->int_scan_req); |
2487 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 1728 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2488 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 1729 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); |
2489 | } else { | 1730 | } else { |
2490 | ifsta->assoc_scan_tries = 0; | 1731 | ifmgd->assoc_scan_tries = 0; |
2491 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 1732 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
2492 | } | 1733 | } |
2493 | } | 1734 | } |
2494 | return -1; | 1735 | return -1; |
@@ -2498,9 +1739,9 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2498 | static void ieee80211_sta_work(struct work_struct *work) | 1739 | static void ieee80211_sta_work(struct work_struct *work) |
2499 | { | 1740 | { |
2500 | struct ieee80211_sub_if_data *sdata = | 1741 | struct ieee80211_sub_if_data *sdata = |
2501 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | 1742 | container_of(work, struct ieee80211_sub_if_data, u.mgd.work); |
2502 | struct ieee80211_local *local = sdata->local; | 1743 | struct ieee80211_local *local = sdata->local; |
2503 | struct ieee80211_if_sta *ifsta; | 1744 | struct ieee80211_if_managed *ifmgd; |
2504 | struct sk_buff *skb; | 1745 | struct sk_buff *skb; |
2505 | 1746 | ||
2506 | if (!netif_running(sdata->dev)) | 1747 | if (!netif_running(sdata->dev)) |
@@ -2509,60 +1750,53 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2509 | if (local->sw_scanning || local->hw_scanning) | 1750 | if (local->sw_scanning || local->hw_scanning) |
2510 | return; | 1751 | return; |
2511 | 1752 | ||
2512 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION && | 1753 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2513 | sdata->vif.type != NL80211_IFTYPE_ADHOC)) | ||
2514 | return; | 1754 | return; |
2515 | ifsta = &sdata->u.sta; | 1755 | ifmgd = &sdata->u.mgd; |
2516 | 1756 | ||
2517 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | 1757 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) |
2518 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | 1758 | ieee80211_sta_rx_queued_mgmt(sdata, skb); |
2519 | 1759 | ||
2520 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && | 1760 | if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE && |
2521 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 1761 | ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && |
2522 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | 1762 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && |
2523 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | 1763 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { |
2524 | ieee80211_start_scan(sdata, local->scan_req); | 1764 | ieee80211_start_scan(sdata, local->scan_req); |
2525 | return; | 1765 | return; |
2526 | } | 1766 | } |
2527 | 1767 | ||
2528 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { | 1768 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) { |
2529 | if (ieee80211_sta_config_auth(sdata, ifsta)) | 1769 | if (ieee80211_sta_config_auth(sdata)) |
2530 | return; | 1770 | return; |
2531 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | 1771 | clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
2532 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) | 1772 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) |
2533 | return; | 1773 | return; |
2534 | 1774 | ||
2535 | switch (ifsta->state) { | 1775 | switch (ifmgd->state) { |
2536 | case IEEE80211_STA_MLME_DISABLED: | 1776 | case IEEE80211_STA_MLME_DISABLED: |
2537 | break; | 1777 | break; |
2538 | case IEEE80211_STA_MLME_DIRECT_PROBE: | 1778 | case IEEE80211_STA_MLME_DIRECT_PROBE: |
2539 | ieee80211_direct_probe(sdata, ifsta); | 1779 | ieee80211_direct_probe(sdata); |
2540 | break; | 1780 | break; |
2541 | case IEEE80211_STA_MLME_AUTHENTICATE: | 1781 | case IEEE80211_STA_MLME_AUTHENTICATE: |
2542 | ieee80211_authenticate(sdata, ifsta); | 1782 | ieee80211_authenticate(sdata); |
2543 | break; | 1783 | break; |
2544 | case IEEE80211_STA_MLME_ASSOCIATE: | 1784 | case IEEE80211_STA_MLME_ASSOCIATE: |
2545 | ieee80211_associate(sdata, ifsta); | 1785 | ieee80211_associate(sdata); |
2546 | break; | 1786 | break; |
2547 | case IEEE80211_STA_MLME_ASSOCIATED: | 1787 | case IEEE80211_STA_MLME_ASSOCIATED: |
2548 | ieee80211_associated(sdata, ifsta); | 1788 | ieee80211_associated(sdata); |
2549 | break; | ||
2550 | case IEEE80211_STA_MLME_IBSS_SEARCH: | ||
2551 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
2552 | break; | ||
2553 | case IEEE80211_STA_MLME_IBSS_JOINED: | ||
2554 | ieee80211_sta_merge_ibss(sdata, ifsta); | ||
2555 | break; | 1789 | break; |
2556 | default: | 1790 | default: |
2557 | WARN_ON(1); | 1791 | WARN_ON(1); |
2558 | break; | 1792 | break; |
2559 | } | 1793 | } |
2560 | 1794 | ||
2561 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | 1795 | if (ieee80211_privacy_mismatch(sdata)) { |
2562 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " | 1796 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " |
2563 | "mixed-cell disabled - disassociate\n", sdata->dev->name); | 1797 | "mixed-cell disabled - disassociate\n", sdata->dev->name); |
2564 | 1798 | ||
2565 | ieee80211_set_disassoc(sdata, ifsta, false, true, | 1799 | ieee80211_set_disassoc(sdata, false, true, |
2566 | WLAN_REASON_UNSPECIFIED); | 1800 | WLAN_REASON_UNSPECIFIED); |
2567 | } | 1801 | } |
2568 | } | 1802 | } |
@@ -2571,155 +1805,106 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
2571 | { | 1805 | { |
2572 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 1806 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
2573 | queue_work(sdata->local->hw.workqueue, | 1807 | queue_work(sdata->local->hw.workqueue, |
2574 | &sdata->u.sta.work); | 1808 | &sdata->u.mgd.work); |
2575 | } | 1809 | } |
2576 | 1810 | ||
2577 | /* interface setup */ | 1811 | /* interface setup */ |
2578 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 1812 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
2579 | { | 1813 | { |
2580 | struct ieee80211_if_sta *ifsta; | 1814 | struct ieee80211_if_managed *ifmgd; |
2581 | 1815 | ||
2582 | ifsta = &sdata->u.sta; | 1816 | ifmgd = &sdata->u.mgd; |
2583 | INIT_WORK(&ifsta->work, ieee80211_sta_work); | 1817 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
2584 | INIT_WORK(&ifsta->chswitch_work, ieee80211_chswitch_work); | 1818 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
2585 | setup_timer(&ifsta->timer, ieee80211_sta_timer, | 1819 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
2586 | (unsigned long) sdata); | 1820 | (unsigned long) sdata); |
2587 | setup_timer(&ifsta->chswitch_timer, ieee80211_chswitch_timer, | 1821 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
2588 | (unsigned long) sdata); | 1822 | (unsigned long) sdata); |
2589 | skb_queue_head_init(&ifsta->skb_queue); | 1823 | skb_queue_head_init(&ifmgd->skb_queue); |
2590 | 1824 | ||
2591 | ifsta->capab = WLAN_CAPABILITY_ESS; | 1825 | ifmgd->capab = WLAN_CAPABILITY_ESS; |
2592 | ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | | 1826 | ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN | |
2593 | IEEE80211_AUTH_ALG_SHARED_KEY; | 1827 | IEEE80211_AUTH_ALG_SHARED_KEY; |
2594 | ifsta->flags |= IEEE80211_STA_CREATE_IBSS | | 1828 | ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | |
2595 | IEEE80211_STA_AUTO_BSSID_SEL | | 1829 | IEEE80211_STA_AUTO_BSSID_SEL | |
2596 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 1830 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
2597 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) | 1831 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) |
2598 | ifsta->flags |= IEEE80211_STA_WMM_ENABLED; | 1832 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; |
2599 | } | ||
2600 | |||
2601 | /* | ||
2602 | * Add a new IBSS station, will also be called by the RX code when, | ||
2603 | * in IBSS mode, receiving a frame from a yet-unknown station, hence | ||
2604 | * must be callable in atomic context. | ||
2605 | */ | ||
2606 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
2607 | u8 *bssid,u8 *addr, u32 supp_rates) | ||
2608 | { | ||
2609 | struct ieee80211_local *local = sdata->local; | ||
2610 | struct sta_info *sta; | ||
2611 | int band = local->hw.conf.channel->band; | ||
2612 | |||
2613 | /* TODO: Could consider removing the least recently used entry and | ||
2614 | * allow new one to be added. */ | ||
2615 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | ||
2616 | if (net_ratelimit()) { | ||
2617 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | ||
2618 | "entry %pM\n", sdata->dev->name, addr); | ||
2619 | } | ||
2620 | return NULL; | ||
2621 | } | ||
2622 | |||
2623 | if (compare_ether_addr(bssid, sdata->u.sta.bssid)) | ||
2624 | return NULL; | ||
2625 | |||
2626 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
2627 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", | ||
2628 | wiphy_name(local->hw.wiphy), addr, sdata->dev->name); | ||
2629 | #endif | ||
2630 | |||
2631 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
2632 | if (!sta) | ||
2633 | return NULL; | ||
2634 | |||
2635 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
2636 | |||
2637 | /* make sure mandatory rates are always added */ | ||
2638 | sta->sta.supp_rates[band] = supp_rates | | ||
2639 | ieee80211_mandatory_rates(local, band); | ||
2640 | |||
2641 | rate_control_rate_init(sta); | ||
2642 | |||
2643 | if (sta_info_insert(sta)) | ||
2644 | return NULL; | ||
2645 | |||
2646 | return sta; | ||
2647 | } | 1833 | } |
2648 | 1834 | ||
2649 | /* configuration hooks */ | 1835 | /* configuration hooks */ |
2650 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | 1836 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) |
2651 | struct ieee80211_if_sta *ifsta) | ||
2652 | { | 1837 | { |
1838 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2653 | struct ieee80211_local *local = sdata->local; | 1839 | struct ieee80211_local *local = sdata->local; |
2654 | 1840 | ||
2655 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1841 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2656 | return; | 1842 | return; |
2657 | 1843 | ||
2658 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | | 1844 | if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET | |
2659 | IEEE80211_STA_AUTO_BSSID_SEL)) && | 1845 | IEEE80211_STA_AUTO_BSSID_SEL)) && |
2660 | (ifsta->flags & (IEEE80211_STA_SSID_SET | | 1846 | (ifmgd->flags & (IEEE80211_STA_SSID_SET | |
2661 | IEEE80211_STA_AUTO_SSID_SEL))) { | 1847 | IEEE80211_STA_AUTO_SSID_SEL))) { |
2662 | 1848 | ||
2663 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) | 1849 | if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) |
2664 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 1850 | ieee80211_set_disassoc(sdata, true, true, |
2665 | WLAN_REASON_DEAUTH_LEAVING); | 1851 | WLAN_REASON_DEAUTH_LEAVING); |
2666 | 1852 | ||
2667 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 1853 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); |
2668 | queue_work(local->hw.workqueue, &ifsta->work); | 1854 | queue_work(local->hw.workqueue, &ifmgd->work); |
2669 | } | 1855 | } |
2670 | } | 1856 | } |
2671 | 1857 | ||
2672 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | 1858 | int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata) |
2673 | { | 1859 | { |
2674 | struct ieee80211_if_sta *ifsta; | 1860 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2675 | 1861 | ||
2676 | if (len > IEEE80211_MAX_SSID_LEN) | 1862 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
2677 | return -EINVAL; | ||
2678 | 1863 | ||
2679 | ifsta = &sdata->u.sta; | 1864 | if (ifmgd->ssid_len) |
1865 | ifmgd->flags |= IEEE80211_STA_SSID_SET; | ||
1866 | else | ||
1867 | ifmgd->flags &= ~IEEE80211_STA_SSID_SET; | ||
2680 | 1868 | ||
2681 | if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { | 1869 | return 0; |
2682 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); | 1870 | } |
2683 | memcpy(ifsta->ssid, ssid, len); | ||
2684 | ifsta->ssid_len = len; | ||
2685 | } | ||
2686 | 1871 | ||
2687 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 1872 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) |
1873 | { | ||
1874 | struct ieee80211_if_managed *ifmgd; | ||
2688 | 1875 | ||
2689 | if (len) | 1876 | if (len > IEEE80211_MAX_SSID_LEN) |
2690 | ifsta->flags |= IEEE80211_STA_SSID_SET; | 1877 | return -EINVAL; |
2691 | else | 1878 | |
2692 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; | 1879 | ifmgd = &sdata->u.mgd; |
2693 | 1880 | ||
2694 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1881 | if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { |
2695 | ifsta->ibss_join_req = jiffies; | 1882 | memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); |
2696 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | 1883 | memcpy(ifmgd->ssid, ssid, len); |
2697 | return ieee80211_sta_find_ibss(sdata, ifsta); | 1884 | ifmgd->ssid_len = len; |
2698 | } | 1885 | } |
2699 | 1886 | ||
2700 | return 0; | 1887 | return ieee80211_sta_commit(sdata); |
2701 | } | 1888 | } |
2702 | 1889 | ||
2703 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | 1890 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) |
2704 | { | 1891 | { |
2705 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1892 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2706 | memcpy(ssid, ifsta->ssid, ifsta->ssid_len); | 1893 | memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len); |
2707 | *len = ifsta->ssid_len; | 1894 | *len = ifmgd->ssid_len; |
2708 | return 0; | 1895 | return 0; |
2709 | } | 1896 | } |
2710 | 1897 | ||
2711 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | 1898 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) |
2712 | { | 1899 | { |
2713 | struct ieee80211_if_sta *ifsta; | 1900 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2714 | |||
2715 | ifsta = &sdata->u.sta; | ||
2716 | 1901 | ||
2717 | if (is_valid_ether_addr(bssid)) { | 1902 | if (is_valid_ether_addr(bssid)) { |
2718 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | 1903 | memcpy(ifmgd->bssid, bssid, ETH_ALEN); |
2719 | ifsta->flags |= IEEE80211_STA_BSSID_SET; | 1904 | ifmgd->flags |= IEEE80211_STA_BSSID_SET; |
2720 | } else { | 1905 | } else { |
2721 | memset(ifsta->bssid, 0, ETH_ALEN); | 1906 | memset(ifmgd->bssid, 0, ETH_ALEN); |
2722 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; | 1907 | ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; |
2723 | } | 1908 | } |
2724 | 1909 | ||
2725 | if (netif_running(sdata->dev)) { | 1910 | if (netif_running(sdata->dev)) { |
@@ -2729,47 +1914,44 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | |||
2729 | } | 1914 | } |
2730 | } | 1915 | } |
2731 | 1916 | ||
2732 | return ieee80211_sta_set_ssid(sdata, ifsta->ssid, ifsta->ssid_len); | 1917 | return ieee80211_sta_commit(sdata); |
2733 | } | 1918 | } |
2734 | 1919 | ||
2735 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 1920 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) |
2736 | { | 1921 | { |
2737 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1922 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2738 | 1923 | ||
2739 | kfree(ifsta->extra_ie); | 1924 | kfree(ifmgd->extra_ie); |
2740 | if (len == 0) { | 1925 | if (len == 0) { |
2741 | ifsta->extra_ie = NULL; | 1926 | ifmgd->extra_ie = NULL; |
2742 | ifsta->extra_ie_len = 0; | 1927 | ifmgd->extra_ie_len = 0; |
2743 | return 0; | 1928 | return 0; |
2744 | } | 1929 | } |
2745 | ifsta->extra_ie = kmalloc(len, GFP_KERNEL); | 1930 | ifmgd->extra_ie = kmalloc(len, GFP_KERNEL); |
2746 | if (!ifsta->extra_ie) { | 1931 | if (!ifmgd->extra_ie) { |
2747 | ifsta->extra_ie_len = 0; | 1932 | ifmgd->extra_ie_len = 0; |
2748 | return -ENOMEM; | 1933 | return -ENOMEM; |
2749 | } | 1934 | } |
2750 | memcpy(ifsta->extra_ie, ie, len); | 1935 | memcpy(ifmgd->extra_ie, ie, len); |
2751 | ifsta->extra_ie_len = len; | 1936 | ifmgd->extra_ie_len = len; |
2752 | return 0; | 1937 | return 0; |
2753 | } | 1938 | } |
2754 | 1939 | ||
2755 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | 1940 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) |
2756 | { | 1941 | { |
2757 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2758 | |||
2759 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", | 1942 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", |
2760 | sdata->dev->name, reason); | 1943 | sdata->dev->name, reason); |
2761 | 1944 | ||
2762 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 1945 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2763 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
2764 | return -EINVAL; | 1946 | return -EINVAL; |
2765 | 1947 | ||
2766 | ieee80211_set_disassoc(sdata, ifsta, true, true, reason); | 1948 | ieee80211_set_disassoc(sdata, true, true, reason); |
2767 | return 0; | 1949 | return 0; |
2768 | } | 1950 | } |
2769 | 1951 | ||
2770 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | 1952 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) |
2771 | { | 1953 | { |
2772 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1954 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2773 | 1955 | ||
2774 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", | 1956 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", |
2775 | sdata->dev->name, reason); | 1957 | sdata->dev->name, reason); |
@@ -2777,10 +1959,10 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | |||
2777 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1959 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2778 | return -EINVAL; | 1960 | return -EINVAL; |
2779 | 1961 | ||
2780 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) | 1962 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) |
2781 | return -1; | 1963 | return -ENOLINK; |
2782 | 1964 | ||
2783 | ieee80211_set_disassoc(sdata, ifsta, false, true, reason); | 1965 | ieee80211_set_disassoc(sdata, false, true, reason); |
2784 | return 0; | 1966 | return 0; |
2785 | } | 1967 | } |
2786 | 1968 | ||
@@ -2788,14 +1970,6 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | |||
2788 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | 1970 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) |
2789 | { | 1971 | { |
2790 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 1972 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
2791 | struct ieee80211_if_sta *ifsta; | ||
2792 | |||
2793 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
2794 | ifsta = &sdata->u.sta; | ||
2795 | if ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) || | ||
2796 | !ieee80211_sta_active_ibss(sdata)) | ||
2797 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
2798 | } | ||
2799 | 1973 | ||
2800 | /* Restart STA timers */ | 1974 | /* Restart STA timers */ |
2801 | rcu_read_lock(); | 1975 | rcu_read_lock(); |
@@ -2842,3 +2016,36 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
2842 | 2016 | ||
2843 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | 2017 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); |
2844 | } | 2018 | } |
2019 | |||
2020 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
2021 | struct ieee80211_sub_if_data *sdata, | ||
2022 | int powersave) | ||
2023 | { | ||
2024 | struct sk_buff *skb; | ||
2025 | struct ieee80211_hdr *nullfunc; | ||
2026 | __le16 fc; | ||
2027 | |||
2028 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
2029 | return; | ||
2030 | |||
2031 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
2032 | if (!skb) { | ||
2033 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
2034 | "frame\n", sdata->dev->name); | ||
2035 | return; | ||
2036 | } | ||
2037 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2038 | |||
2039 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
2040 | memset(nullfunc, 0, 24); | ||
2041 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
2042 | IEEE80211_FCTL_TODS); | ||
2043 | if (powersave) | ||
2044 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
2045 | nullfunc->frame_control = fc; | ||
2046 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); | ||
2047 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
2048 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); | ||
2049 | |||
2050 | ieee80211_tx_skb(sdata, skb, 0); | ||
2051 | } | ||
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 928da625e281..b9164c9a9563 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -62,6 +62,18 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
62 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 62 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); |
63 | } | 63 | } |
64 | 64 | ||
65 | static inline void rate_control_rate_update(struct ieee80211_local *local, | ||
66 | struct ieee80211_supported_band *sband, | ||
67 | struct sta_info *sta, u32 changed) | ||
68 | { | ||
69 | struct rate_control_ref *ref = local->rate_ctrl; | ||
70 | struct ieee80211_sta *ista = &sta->sta; | ||
71 | void *priv_sta = sta->rate_ctrl_priv; | ||
72 | |||
73 | if (ref->ops->rate_update) | ||
74 | ref->ops->rate_update(ref->priv, sband, ista, | ||
75 | priv_sta, changed); | ||
76 | } | ||
65 | 77 | ||
66 | static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, | 78 | static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, |
67 | struct ieee80211_sta *sta, | 79 | struct ieee80211_sta *sta, |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1327d424bf31..66f7ecf51b92 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -838,7 +838,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
838 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 838 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
839 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | 839 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, |
840 | NL80211_IFTYPE_ADHOC); | 840 | NL80211_IFTYPE_ADHOC); |
841 | if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0) | 841 | if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) |
842 | sta->last_rx = jiffies; | 842 | sta->last_rx = jiffies; |
843 | } else | 843 | } else |
844 | if (!is_multicast_ether_addr(hdr->addr1) || | 844 | if (!is_multicast_ether_addr(hdr->addr1) || |
@@ -1702,13 +1702,13 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
1702 | return; | 1702 | return; |
1703 | } | 1703 | } |
1704 | 1704 | ||
1705 | if (compare_ether_addr(mgmt->sa, sdata->u.sta.bssid) != 0 || | 1705 | if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 || |
1706 | compare_ether_addr(mgmt->bssid, sdata->u.sta.bssid) != 0) { | 1706 | compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) { |
1707 | /* Not from the current AP. */ | 1707 | /* Not from the current AP. */ |
1708 | return; | 1708 | return; |
1709 | } | 1709 | } |
1710 | 1710 | ||
1711 | if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATE) { | 1711 | if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) { |
1712 | /* Association in progress; ignore SA Query */ | 1712 | /* Association in progress; ignore SA Query */ |
1713 | return; | 1713 | return; |
1714 | } | 1714 | } |
@@ -1727,7 +1727,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
1727 | memset(resp, 0, 24); | 1727 | memset(resp, 0, 24); |
1728 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | 1728 | memcpy(resp->da, mgmt->sa, ETH_ALEN); |
1729 | memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN); | 1729 | memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN); |
1730 | memcpy(resp->bssid, sdata->u.sta.bssid, ETH_ALEN); | 1730 | memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
1731 | resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1731 | resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
1732 | IEEE80211_STYPE_ACTION); | 1732 | IEEE80211_STYPE_ACTION); |
1733 | skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query)); | 1733 | skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query)); |
@@ -1745,7 +1745,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1745 | { | 1745 | { |
1746 | struct ieee80211_local *local = rx->local; | 1746 | struct ieee80211_local *local = rx->local; |
1747 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 1747 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
1748 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1749 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | 1748 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
1750 | struct ieee80211_bss *bss; | 1749 | struct ieee80211_bss *bss; |
1751 | int len = rx->skb->len; | 1750 | int len = rx->skb->len; |
@@ -1803,6 +1802,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1803 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 1802 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
1804 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | 1803 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) |
1805 | return RX_DROP_MONITOR; | 1804 | return RX_DROP_MONITOR; |
1805 | |||
1806 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1807 | return RX_DROP_MONITOR; | ||
1808 | |||
1806 | switch (mgmt->u.action.u.measurement.action_code) { | 1809 | switch (mgmt->u.action.u.measurement.action_code) { |
1807 | case WLAN_ACTION_SPCT_MSR_REQ: | 1810 | case WLAN_ACTION_SPCT_MSR_REQ: |
1808 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1811 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
@@ -1815,12 +1818,13 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1815 | sizeof(mgmt->u.action.u.chan_switch))) | 1818 | sizeof(mgmt->u.action.u.chan_switch))) |
1816 | return RX_DROP_MONITOR; | 1819 | return RX_DROP_MONITOR; |
1817 | 1820 | ||
1818 | if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0) | 1821 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) |
1819 | return RX_DROP_MONITOR; | 1822 | return RX_DROP_MONITOR; |
1820 | 1823 | ||
1821 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 1824 | bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid, |
1822 | local->hw.conf.channel->center_freq, | 1825 | local->hw.conf.channel->center_freq, |
1823 | ifsta->ssid, ifsta->ssid_len); | 1826 | sdata->u.mgd.ssid, |
1827 | sdata->u.mgd.ssid_len); | ||
1824 | if (!bss) | 1828 | if (!bss) |
1825 | return RX_DROP_MONITOR; | 1829 | return RX_DROP_MONITOR; |
1826 | 1830 | ||
@@ -1876,11 +1880,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
1876 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | 1880 | sdata->vif.type != NL80211_IFTYPE_ADHOC) |
1877 | return RX_DROP_MONITOR; | 1881 | return RX_DROP_MONITOR; |
1878 | 1882 | ||
1879 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) | ||
1880 | return RX_DROP_MONITOR; | ||
1881 | 1883 | ||
1882 | ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); | 1884 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
1883 | return RX_QUEUED; | 1885 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) |
1886 | return RX_DROP_MONITOR; | ||
1887 | return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); | ||
1888 | } | ||
1889 | |||
1890 | return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status); | ||
1884 | } | 1891 | } |
1885 | 1892 | ||
1886 | static void ieee80211_rx_michael_mic_report(struct net_device *dev, | 1893 | static void ieee80211_rx_michael_mic_report(struct net_device *dev, |
@@ -2083,7 +2090,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2083 | case NL80211_IFTYPE_STATION: | 2090 | case NL80211_IFTYPE_STATION: |
2084 | if (!bssid) | 2091 | if (!bssid) |
2085 | return 0; | 2092 | return 0; |
2086 | if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { | 2093 | if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) { |
2087 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) | 2094 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) |
2088 | return 0; | 2095 | return 0; |
2089 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2096 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
@@ -2101,7 +2108,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2101 | if (ieee80211_is_beacon(hdr->frame_control)) { | 2108 | if (ieee80211_is_beacon(hdr->frame_control)) { |
2102 | return 1; | 2109 | return 1; |
2103 | } | 2110 | } |
2104 | else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { | 2111 | else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { |
2105 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) | 2112 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) |
2106 | return 0; | 2113 | return 0; |
2107 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2114 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f883ab9f1e6e..0e81e1633a66 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -63,20 +63,15 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
63 | { | 63 | { |
64 | struct ieee80211_bss *bss; | 64 | struct ieee80211_bss *bss; |
65 | int clen; | 65 | int clen; |
66 | enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE; | ||
67 | s32 signal = 0; | 66 | s32 signal = 0; |
68 | 67 | ||
69 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | 68 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
70 | sigtype = CFG80211_SIGNAL_TYPE_MBM; | ||
71 | signal = rx_status->signal * 100; | 69 | signal = rx_status->signal * 100; |
72 | } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) { | 70 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
73 | sigtype = CFG80211_SIGNAL_TYPE_UNSPEC; | ||
74 | signal = (rx_status->signal * 100) / local->hw.max_signal; | 71 | signal = (rx_status->signal * 100) / local->hw.max_signal; |
75 | } | ||
76 | 72 | ||
77 | bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, | 73 | bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, |
78 | mgmt, len, signal, sigtype, | 74 | mgmt, len, signal, GFP_ATOMIC); |
79 | GFP_ATOMIC); | ||
80 | 75 | ||
81 | if (!bss) | 76 | if (!bss) |
82 | return NULL; | 77 | return NULL; |
@@ -207,36 +202,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
207 | return RX_QUEUED; | 202 | return RX_QUEUED; |
208 | } | 203 | } |
209 | 204 | ||
210 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
211 | struct ieee80211_sub_if_data *sdata, | ||
212 | int powersave) | ||
213 | { | ||
214 | struct sk_buff *skb; | ||
215 | struct ieee80211_hdr *nullfunc; | ||
216 | __le16 fc; | ||
217 | |||
218 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
219 | if (!skb) { | ||
220 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
221 | "frame\n", sdata->dev->name); | ||
222 | return; | ||
223 | } | ||
224 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
225 | |||
226 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
227 | memset(nullfunc, 0, 24); | ||
228 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
229 | IEEE80211_FCTL_TODS); | ||
230 | if (powersave) | ||
231 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
232 | nullfunc->frame_control = fc; | ||
233 | memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); | ||
234 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
235 | memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); | ||
236 | |||
237 | ieee80211_tx_skb(sdata, skb, 0); | ||
238 | } | ||
239 | |||
240 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 205 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
241 | { | 206 | { |
242 | struct ieee80211_local *local = hw_to_local(hw); | 207 | struct ieee80211_local *local = hw_to_local(hw); |
@@ -280,6 +245,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
280 | netif_addr_unlock(local->mdev); | 245 | netif_addr_unlock(local->mdev); |
281 | netif_tx_unlock_bh(local->mdev); | 246 | netif_tx_unlock_bh(local->mdev); |
282 | 247 | ||
248 | if (local->ops->sw_scan_complete) | ||
249 | local->ops->sw_scan_complete(local_to_hw(local)); | ||
250 | |||
283 | mutex_lock(&local->iflist_mtx); | 251 | mutex_lock(&local->iflist_mtx); |
284 | list_for_each_entry(sdata, &local->interfaces, list) { | 252 | list_for_each_entry(sdata, &local->interfaces, list) { |
285 | if (!netif_running(sdata->dev)) | 253 | if (!netif_running(sdata->dev)) |
@@ -287,7 +255,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
287 | 255 | ||
288 | /* Tell AP we're back */ | 256 | /* Tell AP we're back */ |
289 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 257 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
290 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 258 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { |
291 | ieee80211_send_nullfunc(local, sdata, 0); | 259 | ieee80211_send_nullfunc(local, sdata, 0); |
292 | netif_tx_wake_all_queues(sdata->dev); | 260 | netif_tx_wake_all_queues(sdata->dev); |
293 | } | 261 | } |
@@ -305,6 +273,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
305 | 273 | ||
306 | done: | 274 | done: |
307 | ieee80211_mlme_notify_scan_completed(local); | 275 | ieee80211_mlme_notify_scan_completed(local); |
276 | ieee80211_ibss_notify_scan_completed(local); | ||
308 | ieee80211_mesh_notify_scan_completed(local); | 277 | ieee80211_mesh_notify_scan_completed(local); |
309 | } | 278 | } |
310 | EXPORT_SYMBOL(ieee80211_scan_completed); | 279 | EXPORT_SYMBOL(ieee80211_scan_completed); |
@@ -367,7 +336,8 @@ void ieee80211_scan_work(struct work_struct *work) | |||
367 | ieee80211_send_probe_req( | 336 | ieee80211_send_probe_req( |
368 | sdata, NULL, | 337 | sdata, NULL, |
369 | local->scan_req->ssids[i].ssid, | 338 | local->scan_req->ssids[i].ssid, |
370 | local->scan_req->ssids[i].ssid_len); | 339 | local->scan_req->ssids[i].ssid_len, |
340 | local->scan_req->ie, local->scan_req->ie_len); | ||
371 | next_delay = IEEE80211_CHANNEL_TIME; | 341 | next_delay = IEEE80211_CHANNEL_TIME; |
372 | break; | 342 | break; |
373 | } | 343 | } |
@@ -428,6 +398,8 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
428 | } | 398 | } |
429 | 399 | ||
430 | local->sw_scanning = true; | 400 | local->sw_scanning = true; |
401 | if (local->ops->sw_scan_start) | ||
402 | local->ops->sw_scan_start(local_to_hw(local)); | ||
431 | 403 | ||
432 | mutex_lock(&local->iflist_mtx); | 404 | mutex_lock(&local->iflist_mtx); |
433 | list_for_each_entry(sdata, &local->interfaces, list) { | 405 | list_for_each_entry(sdata, &local->interfaces, list) { |
@@ -442,7 +414,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
442 | IEEE80211_IFCC_BEACON_ENABLED); | 414 | IEEE80211_IFCC_BEACON_ENABLED); |
443 | 415 | ||
444 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 416 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
445 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 417 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { |
446 | netif_tx_stop_all_queues(sdata->dev); | 418 | netif_tx_stop_all_queues(sdata->dev); |
447 | ieee80211_send_nullfunc(local, sdata, 1); | 419 | ieee80211_send_nullfunc(local, sdata, 1); |
448 | } | 420 | } |
@@ -477,7 +449,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
477 | struct cfg80211_scan_request *req) | 449 | struct cfg80211_scan_request *req) |
478 | { | 450 | { |
479 | struct ieee80211_local *local = sdata->local; | 451 | struct ieee80211_local *local = sdata->local; |
480 | struct ieee80211_if_sta *ifsta; | 452 | struct ieee80211_if_managed *ifmgd; |
481 | 453 | ||
482 | if (!req) | 454 | if (!req) |
483 | return -EINVAL; | 455 | return -EINVAL; |
@@ -502,9 +474,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
502 | return -EBUSY; | 474 | return -EBUSY; |
503 | } | 475 | } |
504 | 476 | ||
505 | ifsta = &sdata->u.sta; | 477 | ifmgd = &sdata->u.mgd; |
506 | set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); | 478 | set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); |
507 | queue_work(local->hw.workqueue, &ifsta->work); | 479 | queue_work(local->hw.workqueue, &ifmgd->work); |
508 | 480 | ||
509 | return 0; | 481 | return 0; |
510 | } | 482 | } |
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 47bb2aed2813..5f7a2624ed74 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
@@ -88,16 +88,16 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | |||
88 | void ieee80211_chswitch_work(struct work_struct *work) | 88 | void ieee80211_chswitch_work(struct work_struct *work) |
89 | { | 89 | { |
90 | struct ieee80211_sub_if_data *sdata = | 90 | struct ieee80211_sub_if_data *sdata = |
91 | container_of(work, struct ieee80211_sub_if_data, u.sta.chswitch_work); | 91 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
92 | struct ieee80211_bss *bss; | 92 | struct ieee80211_bss *bss; |
93 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 93 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
94 | 94 | ||
95 | if (!netif_running(sdata->dev)) | 95 | if (!netif_running(sdata->dev)) |
96 | return; | 96 | return; |
97 | 97 | ||
98 | bss = ieee80211_rx_bss_get(sdata->local, ifsta->bssid, | 98 | bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, |
99 | sdata->local->hw.conf.channel->center_freq, | 99 | sdata->local->hw.conf.channel->center_freq, |
100 | ifsta->ssid, ifsta->ssid_len); | 100 | ifmgd->ssid, ifmgd->ssid_len); |
101 | if (!bss) | 101 | if (!bss) |
102 | goto exit; | 102 | goto exit; |
103 | 103 | ||
@@ -108,7 +108,7 @@ void ieee80211_chswitch_work(struct work_struct *work) | |||
108 | 108 | ||
109 | ieee80211_rx_bss_put(sdata->local, bss); | 109 | ieee80211_rx_bss_put(sdata->local, bss); |
110 | exit: | 110 | exit: |
111 | ifsta->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 111 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
112 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 112 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
113 | IEEE80211_QUEUE_STOP_REASON_CSA); | 113 | IEEE80211_QUEUE_STOP_REASON_CSA); |
114 | } | 114 | } |
@@ -117,9 +117,9 @@ void ieee80211_chswitch_timer(unsigned long data) | |||
117 | { | 117 | { |
118 | struct ieee80211_sub_if_data *sdata = | 118 | struct ieee80211_sub_if_data *sdata = |
119 | (struct ieee80211_sub_if_data *) data; | 119 | (struct ieee80211_sub_if_data *) data; |
120 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 120 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
121 | 121 | ||
122 | queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work); | 122 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); |
123 | } | 123 | } |
124 | 124 | ||
125 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 125 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
@@ -127,14 +127,14 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
127 | struct ieee80211_bss *bss) | 127 | struct ieee80211_bss *bss) |
128 | { | 128 | { |
129 | struct ieee80211_channel *new_ch; | 129 | struct ieee80211_channel *new_ch; |
130 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 130 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
131 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | 131 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); |
132 | 132 | ||
133 | /* FIXME: Handle ADHOC later */ | 133 | /* FIXME: Handle ADHOC later */ |
134 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 134 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
135 | return; | 135 | return; |
136 | 136 | ||
137 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATED) | 137 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) |
138 | return; | 138 | return; |
139 | 139 | ||
140 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) | 140 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) |
@@ -143,7 +143,7 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
143 | /* Disregard subsequent beacons if we are already running a timer | 143 | /* Disregard subsequent beacons if we are already running a timer |
144 | processing a CSA */ | 144 | processing a CSA */ |
145 | 145 | ||
146 | if (ifsta->flags & IEEE80211_STA_CSA_RECEIVED) | 146 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
147 | return; | 147 | return; |
148 | 148 | ||
149 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | 149 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); |
@@ -153,12 +153,12 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
153 | sdata->local->csa_channel = new_ch; | 153 | sdata->local->csa_channel = new_ch; |
154 | 154 | ||
155 | if (sw_elem->count <= 1) { | 155 | if (sw_elem->count <= 1) { |
156 | queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work); | 156 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); |
157 | } else { | 157 | } else { |
158 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | 158 | ieee80211_stop_queues_by_reason(&sdata->local->hw, |
159 | IEEE80211_QUEUE_STOP_REASON_CSA); | 159 | IEEE80211_QUEUE_STOP_REASON_CSA); |
160 | ifsta->flags |= IEEE80211_STA_CSA_RECEIVED; | 160 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
161 | mod_timer(&ifsta->chswitch_timer, | 161 | mod_timer(&ifmgd->chswitch_timer, |
162 | jiffies + | 162 | jiffies + |
163 | msecs_to_jiffies(sw_elem->count * | 163 | msecs_to_jiffies(sw_elem->count * |
164 | bss->cbss.beacon_interval)); | 164 | bss->cbss.beacon_interval)); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 634f65c0130e..4ba3c540fcf3 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -202,6 +202,18 @@ void sta_info_destroy(struct sta_info *sta) | |||
202 | /* Make sure timer won't free the tid_rx struct, see below */ | 202 | /* Make sure timer won't free the tid_rx struct, see below */ |
203 | if (tid_rx) | 203 | if (tid_rx) |
204 | tid_rx->shutdown = true; | 204 | tid_rx->shutdown = true; |
205 | |||
206 | /* | ||
207 | * The stop callback cannot find this station any more, but | ||
208 | * it didn't complete its work -- start the queue if necessary | ||
209 | */ | ||
210 | if (sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_INITIATOR_MSK && | ||
211 | sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_REQ_STOP_BA_MSK && | ||
212 | local->hw.ampdu_queues) | ||
213 | ieee80211_wake_queue_by_reason(&local->hw, | ||
214 | local->hw.queues + sta->tid_to_tx_q[i], | ||
215 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
216 | |||
205 | spin_unlock_bh(&sta->lock); | 217 | spin_unlock_bh(&sta->lock); |
206 | 218 | ||
207 | /* | 219 | /* |
@@ -275,8 +287,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
275 | * enable session_timer's data differentiation. refer to | 287 | * enable session_timer's data differentiation. refer to |
276 | * sta_rx_agg_session_timer_expired for useage */ | 288 | * sta_rx_agg_session_timer_expired for useage */ |
277 | sta->timer_to_tid[i] = i; | 289 | sta->timer_to_tid[i] = i; |
278 | /* tid to tx queue: initialize according to HW (0 is valid) */ | 290 | sta->tid_to_tx_q[i] = -1; |
279 | sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw); | ||
280 | /* rx */ | 291 | /* rx */ |
281 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; | 292 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; |
282 | sta->ampdu_mlme.tid_rx[i] = NULL; | 293 | sta->ampdu_mlme.tid_rx[i] = NULL; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d9653231992f..1f45573c580c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -90,6 +90,7 @@ struct tid_ampdu_tx { | |||
90 | * @buf_size: buffer size for incoming A-MPDUs | 90 | * @buf_size: buffer size for incoming A-MPDUs |
91 | * @timeout: reset timer value (in TUs). | 91 | * @timeout: reset timer value (in TUs). |
92 | * @dialog_token: dialog token for aggregation session | 92 | * @dialog_token: dialog token for aggregation session |
93 | * @shutdown: this session is being shut down due to STA removal | ||
93 | */ | 94 | */ |
94 | struct tid_ampdu_rx { | 95 | struct tid_ampdu_rx { |
95 | struct sk_buff **reorder_buf; | 96 | struct sk_buff **reorder_buf; |
@@ -200,7 +201,7 @@ struct sta_ampdu_mlme { | |||
200 | * @tid_seq: per-TID sequence numbers for sending to this STA | 201 | * @tid_seq: per-TID sequence numbers for sending to this STA |
201 | * @ampdu_mlme: A-MPDU state machine state | 202 | * @ampdu_mlme: A-MPDU state machine state |
202 | * @timer_to_tid: identity mapping to ID timers | 203 | * @timer_to_tid: identity mapping to ID timers |
203 | * @tid_to_tx_q: map tid to tx queue | 204 | * @tid_to_tx_q: map tid to tx queue (invalid == negative values) |
204 | * @llid: Local link ID | 205 | * @llid: Local link ID |
205 | * @plid: Peer link ID | 206 | * @plid: Peer link ID |
206 | * @reason: Cancel reason on PLINK_HOLDING state | 207 | * @reason: Cancel reason on PLINK_HOLDING state |
@@ -275,7 +276,7 @@ struct sta_info { | |||
275 | */ | 276 | */ |
276 | struct sta_ampdu_mlme ampdu_mlme; | 277 | struct sta_ampdu_mlme ampdu_mlme; |
277 | u8 timer_to_tid[STA_TID_NUM]; | 278 | u8 timer_to_tid[STA_TID_NUM]; |
278 | u8 tid_to_tx_q[STA_TID_NUM]; | 279 | s8 tid_to_tx_q[STA_TID_NUM]; |
279 | 280 | ||
280 | #ifdef CONFIG_MAC80211_MESH | 281 | #ifdef CONFIG_MAC80211_MESH |
281 | /* | 282 | /* |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 33926831c648..c3f0e950125b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -876,7 +876,6 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | |||
876 | return TX_CONTINUE; | 876 | return TX_CONTINUE; |
877 | } | 877 | } |
878 | 878 | ||
879 | |||
880 | /* actual transmit path */ | 879 | /* actual transmit path */ |
881 | 880 | ||
882 | /* | 881 | /* |
@@ -1016,12 +1015,20 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
1016 | tx->sta = sta_info_get(local, hdr->addr1); | 1015 | tx->sta = sta_info_get(local, hdr->addr1); |
1017 | 1016 | ||
1018 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) { | 1017 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) { |
1018 | unsigned long flags; | ||
1019 | qc = ieee80211_get_qos_ctl(hdr); | 1019 | qc = ieee80211_get_qos_ctl(hdr); |
1020 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; | 1020 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; |
1021 | 1021 | ||
1022 | spin_lock_irqsave(&tx->sta->lock, flags); | ||
1022 | state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; | 1023 | state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; |
1023 | if (*state == HT_AGG_STATE_OPERATIONAL) | 1024 | if (*state == HT_AGG_STATE_OPERATIONAL) { |
1024 | info->flags |= IEEE80211_TX_CTL_AMPDU; | 1025 | info->flags |= IEEE80211_TX_CTL_AMPDU; |
1026 | if (local->hw.ampdu_queues) | ||
1027 | skb_set_queue_mapping( | ||
1028 | skb, tx->local->hw.queues + | ||
1029 | tx->sta->tid_to_tx_q[tid]); | ||
1030 | } | ||
1031 | spin_unlock_irqrestore(&tx->sta->lock, flags); | ||
1025 | } | 1032 | } |
1026 | 1033 | ||
1027 | if (is_multicast_ether_addr(hdr->addr1)) { | 1034 | if (is_multicast_ether_addr(hdr->addr1)) { |
@@ -1085,7 +1092,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1085 | int ret, i; | 1092 | int ret, i; |
1086 | 1093 | ||
1087 | if (skb) { | 1094 | if (skb) { |
1088 | if (netif_subqueue_stopped(local->mdev, skb)) | 1095 | if (ieee80211_queue_stopped(&local->hw, |
1096 | skb_get_queue_mapping(skb))) | ||
1089 | return IEEE80211_TX_PENDING; | 1097 | return IEEE80211_TX_PENDING; |
1090 | 1098 | ||
1091 | ret = local->ops->tx(local_to_hw(local), skb); | 1099 | ret = local->ops->tx(local_to_hw(local), skb); |
@@ -1101,8 +1109,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1101 | info = IEEE80211_SKB_CB(tx->extra_frag[i]); | 1109 | info = IEEE80211_SKB_CB(tx->extra_frag[i]); |
1102 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | | 1110 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | |
1103 | IEEE80211_TX_CTL_FIRST_FRAGMENT); | 1111 | IEEE80211_TX_CTL_FIRST_FRAGMENT); |
1104 | if (netif_subqueue_stopped(local->mdev, | 1112 | if (ieee80211_queue_stopped(&local->hw, |
1105 | tx->extra_frag[i])) | 1113 | skb_get_queue_mapping(tx->extra_frag[i]))) |
1106 | return IEEE80211_TX_FRAG_AGAIN; | 1114 | return IEEE80211_TX_FRAG_AGAIN; |
1107 | 1115 | ||
1108 | ret = local->ops->tx(local_to_hw(local), | 1116 | ret = local->ops->tx(local_to_hw(local), |
@@ -1625,7 +1633,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1625 | case NL80211_IFTYPE_STATION: | 1633 | case NL80211_IFTYPE_STATION: |
1626 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 1634 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
1627 | /* BSSID SA DA */ | 1635 | /* BSSID SA DA */ |
1628 | memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); | 1636 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); |
1629 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1637 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
1630 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1638 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
1631 | hdrlen = 24; | 1639 | hdrlen = 24; |
@@ -1634,7 +1642,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1634 | /* DA SA BSSID */ | 1642 | /* DA SA BSSID */ |
1635 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1643 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
1636 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1644 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
1637 | memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN); | 1645 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); |
1638 | hdrlen = 24; | 1646 | hdrlen = 24; |
1639 | break; | 1647 | break; |
1640 | default: | 1648 | default: |
@@ -1920,7 +1928,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1920 | struct ieee80211_tx_info *info; | 1928 | struct ieee80211_tx_info *info; |
1921 | struct ieee80211_sub_if_data *sdata = NULL; | 1929 | struct ieee80211_sub_if_data *sdata = NULL; |
1922 | struct ieee80211_if_ap *ap = NULL; | 1930 | struct ieee80211_if_ap *ap = NULL; |
1923 | struct ieee80211_if_sta *ifsta = NULL; | ||
1924 | struct beacon_data *beacon; | 1931 | struct beacon_data *beacon; |
1925 | struct ieee80211_supported_band *sband; | 1932 | struct ieee80211_supported_band *sband; |
1926 | enum ieee80211_band band = local->hw.conf.channel->band; | 1933 | enum ieee80211_band band = local->hw.conf.channel->band; |
@@ -1972,13 +1979,13 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1972 | } else | 1979 | } else |
1973 | goto out; | 1980 | goto out; |
1974 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1981 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
1982 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
1975 | struct ieee80211_hdr *hdr; | 1983 | struct ieee80211_hdr *hdr; |
1976 | ifsta = &sdata->u.sta; | ||
1977 | 1984 | ||
1978 | if (!ifsta->probe_resp) | 1985 | if (!ifibss->probe_resp) |
1979 | goto out; | 1986 | goto out; |
1980 | 1987 | ||
1981 | skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC); | 1988 | skb = skb_copy(ifibss->probe_resp, GFP_ATOMIC); |
1982 | if (!skb) | 1989 | if (!skb) |
1983 | goto out; | 1990 | goto out; |
1984 | 1991 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 73c7d7345abd..e0431a1d218b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -344,15 +344,36 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
344 | { | 344 | { |
345 | struct ieee80211_local *local = hw_to_local(hw); | 345 | struct ieee80211_local *local = hw_to_local(hw); |
346 | 346 | ||
347 | /* we don't need to track ampdu queues */ | 347 | if (queue >= hw->queues) { |
348 | if (queue < ieee80211_num_regular_queues(hw)) { | 348 | if (local->ampdu_ac_queue[queue - hw->queues] < 0) |
349 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 349 | return; |
350 | |||
351 | /* | ||
352 | * for virtual aggregation queues, we need to refcount the | ||
353 | * internal mac80211 disable (multiple times!), keep track of | ||
354 | * driver disable _and_ make sure the regular queue is | ||
355 | * actually enabled. | ||
356 | */ | ||
357 | if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION) | ||
358 | local->amdpu_ac_stop_refcnt[queue - hw->queues]--; | ||
359 | else | ||
360 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
350 | 361 | ||
351 | if (local->queue_stop_reasons[queue] != 0) | 362 | if (local->queue_stop_reasons[queue] || |
352 | /* someone still has this queue stopped */ | 363 | local->amdpu_ac_stop_refcnt[queue - hw->queues]) |
353 | return; | 364 | return; |
365 | |||
366 | /* now go on to treat the corresponding regular queue */ | ||
367 | queue = local->ampdu_ac_queue[queue - hw->queues]; | ||
368 | reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION; | ||
354 | } | 369 | } |
355 | 370 | ||
371 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
372 | |||
373 | if (local->queue_stop_reasons[queue] != 0) | ||
374 | /* someone still has this queue stopped */ | ||
375 | return; | ||
376 | |||
356 | if (test_bit(queue, local->queues_pending)) { | 377 | if (test_bit(queue, local->queues_pending)) { |
357 | set_bit(queue, local->queues_pending_run); | 378 | set_bit(queue, local->queues_pending_run); |
358 | tasklet_schedule(&local->tx_pending_tasklet); | 379 | tasklet_schedule(&local->tx_pending_tasklet); |
@@ -361,8 +382,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
361 | } | 382 | } |
362 | } | 383 | } |
363 | 384 | ||
364 | static void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 385 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
365 | enum queue_stop_reason reason) | 386 | enum queue_stop_reason reason) |
366 | { | 387 | { |
367 | struct ieee80211_local *local = hw_to_local(hw); | 388 | struct ieee80211_local *local = hw_to_local(hw); |
368 | unsigned long flags; | 389 | unsigned long flags; |
@@ -384,15 +405,33 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
384 | { | 405 | { |
385 | struct ieee80211_local *local = hw_to_local(hw); | 406 | struct ieee80211_local *local = hw_to_local(hw); |
386 | 407 | ||
387 | /* we don't need to track ampdu queues */ | 408 | if (queue >= hw->queues) { |
388 | if (queue < ieee80211_num_regular_queues(hw)) | 409 | if (local->ampdu_ac_queue[queue - hw->queues] < 0) |
389 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 410 | return; |
411 | |||
412 | /* | ||
413 | * for virtual aggregation queues, we need to refcount the | ||
414 | * internal mac80211 disable (multiple times!), keep track of | ||
415 | * driver disable _and_ make sure the regular queue is | ||
416 | * actually enabled. | ||
417 | */ | ||
418 | if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION) | ||
419 | local->amdpu_ac_stop_refcnt[queue - hw->queues]++; | ||
420 | else | ||
421 | __set_bit(reason, &local->queue_stop_reasons[queue]); | ||
422 | |||
423 | /* now go on to treat the corresponding regular queue */ | ||
424 | queue = local->ampdu_ac_queue[queue - hw->queues]; | ||
425 | reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION; | ||
426 | } | ||
427 | |||
428 | __set_bit(reason, &local->queue_stop_reasons[queue]); | ||
390 | 429 | ||
391 | netif_stop_subqueue(local->mdev, queue); | 430 | netif_stop_subqueue(local->mdev, queue); |
392 | } | 431 | } |
393 | 432 | ||
394 | static void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 433 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
395 | enum queue_stop_reason reason) | 434 | enum queue_stop_reason reason) |
396 | { | 435 | { |
397 | struct ieee80211_local *local = hw_to_local(hw); | 436 | struct ieee80211_local *local = hw_to_local(hw); |
398 | unsigned long flags; | 437 | unsigned long flags; |
@@ -418,7 +457,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
418 | 457 | ||
419 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 458 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
420 | 459 | ||
421 | for (i = 0; i < ieee80211_num_queues(hw); i++) | 460 | for (i = 0; i < hw->queues; i++) |
422 | __ieee80211_stop_queue(hw, i, reason); | 461 | __ieee80211_stop_queue(hw, i, reason); |
423 | 462 | ||
424 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 463 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
@@ -434,6 +473,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues); | |||
434 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | 473 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) |
435 | { | 474 | { |
436 | struct ieee80211_local *local = hw_to_local(hw); | 475 | struct ieee80211_local *local = hw_to_local(hw); |
476 | unsigned long flags; | ||
477 | |||
478 | if (queue >= hw->queues) { | ||
479 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
480 | queue = local->ampdu_ac_queue[queue - hw->queues]; | ||
481 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
482 | if (queue < 0) | ||
483 | return true; | ||
484 | } | ||
485 | |||
437 | return __netif_subqueue_stopped(local->mdev, queue); | 486 | return __netif_subqueue_stopped(local->mdev, queue); |
438 | } | 487 | } |
439 | EXPORT_SYMBOL(ieee80211_queue_stopped); | 488 | EXPORT_SYMBOL(ieee80211_queue_stopped); |
@@ -701,6 +750,27 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
701 | local->ops->conf_tx(local_to_hw(local), i, &qparam); | 750 | local->ops->conf_tx(local_to_hw(local), i, &qparam); |
702 | } | 751 | } |
703 | 752 | ||
753 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
754 | const size_t supp_rates_len, | ||
755 | const u8 *supp_rates) | ||
756 | { | ||
757 | struct ieee80211_local *local = sdata->local; | ||
758 | int i, have_higher_than_11mbit = 0; | ||
759 | |||
760 | /* cf. IEEE 802.11 9.2.12 */ | ||
761 | for (i = 0; i < supp_rates_len; i++) | ||
762 | if ((supp_rates[i] & 0x7f) * 5 > 110) | ||
763 | have_higher_than_11mbit = 1; | ||
764 | |||
765 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
766 | have_higher_than_11mbit) | ||
767 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
768 | else | ||
769 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
770 | |||
771 | ieee80211_set_wmm_default(sdata); | ||
772 | } | ||
773 | |||
704 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 774 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
705 | int encrypt) | 775 | int encrypt) |
706 | { | 776 | { |
@@ -767,3 +837,161 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
767 | mandatory_rates |= BIT(i); | 837 | mandatory_rates |= BIT(i); |
768 | return mandatory_rates; | 838 | return mandatory_rates; |
769 | } | 839 | } |
840 | |||
841 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
842 | u16 transaction, u16 auth_alg, | ||
843 | u8 *extra, size_t extra_len, | ||
844 | const u8 *bssid, int encrypt) | ||
845 | { | ||
846 | struct ieee80211_local *local = sdata->local; | ||
847 | struct sk_buff *skb; | ||
848 | struct ieee80211_mgmt *mgmt; | ||
849 | const u8 *ie_auth = NULL; | ||
850 | int ie_auth_len = 0; | ||
851 | |||
852 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
853 | ie_auth_len = sdata->u.mgd.ie_auth_len; | ||
854 | ie_auth = sdata->u.mgd.ie_auth; | ||
855 | } | ||
856 | |||
857 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
858 | sizeof(*mgmt) + 6 + extra_len + ie_auth_len); | ||
859 | if (!skb) { | ||
860 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
861 | "frame\n", sdata->dev->name); | ||
862 | return; | ||
863 | } | ||
864 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
865 | |||
866 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
867 | memset(mgmt, 0, 24 + 6); | ||
868 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
869 | IEEE80211_STYPE_AUTH); | ||
870 | if (encrypt) | ||
871 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
872 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
873 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
874 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
875 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); | ||
876 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
877 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
878 | if (extra) | ||
879 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
880 | if (ie_auth) | ||
881 | memcpy(skb_put(skb, ie_auth_len), ie_auth, ie_auth_len); | ||
882 | |||
883 | ieee80211_tx_skb(sdata, skb, encrypt); | ||
884 | } | ||
885 | |||
886 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
887 | u8 *ssid, size_t ssid_len, | ||
888 | u8 *ie, size_t ie_len) | ||
889 | { | ||
890 | struct ieee80211_local *local = sdata->local; | ||
891 | struct ieee80211_supported_band *sband; | ||
892 | struct sk_buff *skb; | ||
893 | struct ieee80211_mgmt *mgmt; | ||
894 | u8 *pos, *supp_rates, *esupp_rates = NULL, *extra_preq_ie = NULL; | ||
895 | int i, extra_preq_ie_len = 0; | ||
896 | |||
897 | switch (sdata->vif.type) { | ||
898 | case NL80211_IFTYPE_STATION: | ||
899 | extra_preq_ie_len = sdata->u.mgd.ie_probereq_len; | ||
900 | extra_preq_ie = sdata->u.mgd.ie_probereq; | ||
901 | break; | ||
902 | default: | ||
903 | break; | ||
904 | } | ||
905 | |||
906 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | ||
907 | ie_len + extra_preq_ie_len); | ||
908 | if (!skb) { | ||
909 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
910 | "request\n", sdata->dev->name); | ||
911 | return; | ||
912 | } | ||
913 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
914 | |||
915 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
916 | memset(mgmt, 0, 24); | ||
917 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
918 | IEEE80211_STYPE_PROBE_REQ); | ||
919 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
920 | if (dst) { | ||
921 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
922 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
923 | } else { | ||
924 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
925 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
926 | } | ||
927 | pos = skb_put(skb, 2 + ssid_len); | ||
928 | *pos++ = WLAN_EID_SSID; | ||
929 | *pos++ = ssid_len; | ||
930 | memcpy(pos, ssid, ssid_len); | ||
931 | |||
932 | supp_rates = skb_put(skb, 2); | ||
933 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
934 | supp_rates[1] = 0; | ||
935 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
936 | |||
937 | for (i = 0; i < sband->n_bitrates; i++) { | ||
938 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
939 | if (esupp_rates) { | ||
940 | pos = skb_put(skb, 1); | ||
941 | esupp_rates[1]++; | ||
942 | } else if (supp_rates[1] == 8) { | ||
943 | esupp_rates = skb_put(skb, 3); | ||
944 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
945 | esupp_rates[1] = 1; | ||
946 | pos = &esupp_rates[2]; | ||
947 | } else { | ||
948 | pos = skb_put(skb, 1); | ||
949 | supp_rates[1]++; | ||
950 | } | ||
951 | *pos = rate->bitrate / 5; | ||
952 | } | ||
953 | |||
954 | if (ie) | ||
955 | memcpy(skb_put(skb, ie_len), ie, ie_len); | ||
956 | if (extra_preq_ie) | ||
957 | memcpy(skb_put(skb, extra_preq_ie_len), extra_preq_ie, | ||
958 | extra_preq_ie_len); | ||
959 | |||
960 | ieee80211_tx_skb(sdata, skb, 0); | ||
961 | } | ||
962 | |||
963 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
964 | struct ieee802_11_elems *elems, | ||
965 | enum ieee80211_band band) | ||
966 | { | ||
967 | struct ieee80211_supported_band *sband; | ||
968 | struct ieee80211_rate *bitrates; | ||
969 | size_t num_rates; | ||
970 | u32 supp_rates; | ||
971 | int i, j; | ||
972 | sband = local->hw.wiphy->bands[band]; | ||
973 | |||
974 | if (!sband) { | ||
975 | WARN_ON(1); | ||
976 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
977 | } | ||
978 | |||
979 | bitrates = sband->bitrates; | ||
980 | num_rates = sband->n_bitrates; | ||
981 | supp_rates = 0; | ||
982 | for (i = 0; i < elems->supp_rates_len + | ||
983 | elems->ext_supp_rates_len; i++) { | ||
984 | u8 rate = 0; | ||
985 | int own_rate; | ||
986 | if (i < elems->supp_rates_len) | ||
987 | rate = elems->supp_rates[i]; | ||
988 | else if (elems->ext_supp_rates) | ||
989 | rate = elems->ext_supp_rates | ||
990 | [i - elems->supp_rates_len]; | ||
991 | own_rate = 5 * (rate & 0x7f); | ||
992 | for (j = 0; j < num_rates; j++) | ||
993 | if (bitrates[j].bitrate == own_rate) | ||
994 | supp_rates |= BIT(j); | ||
995 | } | ||
996 | return supp_rates; | ||
997 | } | ||
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 2b023dce8b24..f6924fc065d3 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -132,139 +132,37 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, | |||
132 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) | 132 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) |
133 | return -EOPNOTSUPP; | 133 | return -EOPNOTSUPP; |
134 | 134 | ||
135 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 135 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
136 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
137 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); | 136 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); |
138 | if (ret) | 137 | if (ret) |
139 | return ret; | 138 | return ret; |
140 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 139 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; |
141 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 140 | ieee80211_sta_req_auth(sdata); |
142 | return 0; | 141 | return 0; |
143 | } | 142 | } |
144 | 143 | ||
145 | return -EOPNOTSUPP; | 144 | return -EOPNOTSUPP; |
146 | } | 145 | } |
147 | 146 | ||
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 | |||
163 | static int ieee80211_ioctl_giwrange(struct net_device *dev, | ||
164 | struct iw_request_info *info, | ||
165 | struct iw_point *data, char *extra) | ||
166 | { | ||
167 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
168 | struct iw_range *range = (struct iw_range *) extra; | ||
169 | enum ieee80211_band band; | ||
170 | int c = 0; | ||
171 | |||
172 | data->length = sizeof(struct iw_range); | ||
173 | memset(range, 0, sizeof(struct iw_range)); | ||
174 | |||
175 | range->we_version_compiled = WIRELESS_EXT; | ||
176 | range->we_version_source = 21; | ||
177 | range->retry_capa = IW_RETRY_LIMIT; | ||
178 | range->retry_flags = IW_RETRY_LIMIT; | ||
179 | range->min_retry = 0; | ||
180 | range->max_retry = 255; | ||
181 | range->min_rts = 0; | ||
182 | range->max_rts = 2347; | ||
183 | range->min_frag = 256; | ||
184 | range->max_frag = 2346; | ||
185 | |||
186 | range->encoding_size[0] = 5; | ||
187 | range->encoding_size[1] = 13; | ||
188 | range->num_encoding_sizes = 2; | ||
189 | range->max_encoding_tokens = NUM_DEFAULT_KEYS; | ||
190 | |||
191 | /* cfg80211 requires this, and enforces 0..100 */ | ||
192 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | ||
193 | range->max_qual.level = 100; | ||
194 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
195 | range->max_qual.level = -110; | ||
196 | else | ||
197 | range->max_qual.level = 0; | ||
198 | |||
199 | if (local->hw.flags & IEEE80211_HW_NOISE_DBM) | ||
200 | range->max_qual.noise = -110; | ||
201 | else | ||
202 | range->max_qual.noise = 0; | ||
203 | |||
204 | range->max_qual.qual = 100; | ||
205 | range->max_qual.updated = ieee80211_get_wstats_flags(local); | ||
206 | |||
207 | range->avg_qual.qual = 50; | ||
208 | /* not always true but better than nothing */ | ||
209 | range->avg_qual.level = range->max_qual.level / 2; | ||
210 | range->avg_qual.noise = range->max_qual.noise / 2; | ||
211 | range->avg_qual.updated = ieee80211_get_wstats_flags(local); | ||
212 | |||
213 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
214 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | ||
215 | |||
216 | |||
217 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { | ||
218 | int i; | ||
219 | struct ieee80211_supported_band *sband; | ||
220 | |||
221 | sband = local->hw.wiphy->bands[band]; | ||
222 | |||
223 | if (!sband) | ||
224 | continue; | ||
225 | |||
226 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { | ||
227 | struct ieee80211_channel *chan = &sband->channels[i]; | ||
228 | |||
229 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { | ||
230 | range->freq[c].i = | ||
231 | ieee80211_frequency_to_channel( | ||
232 | chan->center_freq); | ||
233 | range->freq[c].m = chan->center_freq; | ||
234 | range->freq[c].e = 6; | ||
235 | c++; | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | range->num_channels = c; | ||
240 | range->num_frequency = c; | ||
241 | |||
242 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | ||
243 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | ||
244 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | ||
245 | |||
246 | range->scan_capa |= IW_SCAN_CAPA_ESSID; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | |||
252 | static int ieee80211_ioctl_siwfreq(struct net_device *dev, | 147 | static int ieee80211_ioctl_siwfreq(struct net_device *dev, |
253 | struct iw_request_info *info, | 148 | struct iw_request_info *info, |
254 | struct iw_freq *freq, char *extra) | 149 | struct iw_freq *freq, char *extra) |
255 | { | 150 | { |
256 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 151 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
257 | 152 | ||
258 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC || | 153 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
259 | sdata->vif.type == NL80211_IFTYPE_STATION) | 154 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL; |
260 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; | 155 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
156 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; | ||
261 | 157 | ||
262 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ | 158 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ |
263 | if (freq->e == 0) { | 159 | if (freq->e == 0) { |
264 | if (freq->m < 0) { | 160 | if (freq->m < 0) { |
265 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC || | 161 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
266 | sdata->vif.type == NL80211_IFTYPE_STATION) | 162 | sdata->u.ibss.flags |= |
267 | sdata->u.sta.flags |= | 163 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; |
164 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
165 | sdata->u.mgd.flags |= | ||
268 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 166 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
269 | return 0; | 167 | return 0; |
270 | } else | 168 | } else |
@@ -301,32 +199,35 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, | |||
301 | { | 199 | { |
302 | struct ieee80211_sub_if_data *sdata; | 200 | struct ieee80211_sub_if_data *sdata; |
303 | size_t len = data->length; | 201 | size_t len = data->length; |
202 | int ret; | ||
304 | 203 | ||
305 | /* iwconfig uses nul termination in SSID.. */ | 204 | /* iwconfig uses nul termination in SSID.. */ |
306 | if (len > 0 && ssid[len - 1] == '\0') | 205 | if (len > 0 && ssid[len - 1] == '\0') |
307 | len--; | 206 | len--; |
308 | 207 | ||
309 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 208 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
310 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 209 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
311 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
312 | int ret; | ||
313 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { | 210 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { |
314 | if (len > IEEE80211_MAX_SSID_LEN) | 211 | if (len > IEEE80211_MAX_SSID_LEN) |
315 | return -EINVAL; | 212 | return -EINVAL; |
316 | memcpy(sdata->u.sta.ssid, ssid, len); | 213 | memcpy(sdata->u.mgd.ssid, ssid, len); |
317 | sdata->u.sta.ssid_len = len; | 214 | sdata->u.mgd.ssid_len = len; |
318 | return 0; | 215 | return 0; |
319 | } | 216 | } |
217 | |||
320 | if (data->flags) | 218 | if (data->flags) |
321 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | 219 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; |
322 | else | 220 | else |
323 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL; | 221 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; |
222 | |||
324 | ret = ieee80211_sta_set_ssid(sdata, ssid, len); | 223 | ret = ieee80211_sta_set_ssid(sdata, ssid, len); |
325 | if (ret) | 224 | if (ret) |
326 | return ret; | 225 | return ret; |
327 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 226 | |
227 | ieee80211_sta_req_auth(sdata); | ||
328 | return 0; | 228 | return 0; |
329 | } | 229 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
230 | return ieee80211_ibss_set_ssid(sdata, ssid, len); | ||
330 | 231 | ||
331 | return -EOPNOTSUPP; | 232 | return -EOPNOTSUPP; |
332 | } | 233 | } |
@@ -340,8 +241,7 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, | |||
340 | 241 | ||
341 | struct ieee80211_sub_if_data *sdata; | 242 | struct ieee80211_sub_if_data *sdata; |
342 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 243 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
343 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 244 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
344 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
345 | int res = ieee80211_sta_get_ssid(sdata, ssid, &len); | 245 | int res = ieee80211_sta_get_ssid(sdata, ssid, &len); |
346 | if (res == 0) { | 246 | if (res == 0) { |
347 | data->length = len; | 247 | data->length = len; |
@@ -349,6 +249,14 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, | |||
349 | } else | 249 | } else |
350 | data->flags = 0; | 250 | data->flags = 0; |
351 | return res; | 251 | return res; |
252 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
253 | int res = ieee80211_ibss_get_ssid(sdata, ssid, &len); | ||
254 | if (res == 0) { | ||
255 | data->length = len; | ||
256 | data->flags = 1; | ||
257 | } else | ||
258 | data->flags = 0; | ||
259 | return res; | ||
352 | } | 260 | } |
353 | 261 | ||
354 | return -EOPNOTSUPP; | 262 | return -EOPNOTSUPP; |
@@ -362,26 +270,35 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, | |||
362 | struct ieee80211_sub_if_data *sdata; | 270 | struct ieee80211_sub_if_data *sdata; |
363 | 271 | ||
364 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 272 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
365 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 273 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
366 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
367 | int ret; | 274 | int ret; |
368 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { | 275 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { |
369 | memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, | 276 | memcpy(sdata->u.mgd.bssid, (u8 *) &ap_addr->sa_data, |
370 | ETH_ALEN); | 277 | ETH_ALEN); |
371 | return 0; | 278 | return 0; |
372 | } | 279 | } |
373 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) | 280 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) |
374 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL | | 281 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL | |
375 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 282 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
376 | else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) | 283 | else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) |
377 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL; | 284 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL; |
378 | else | 285 | else |
379 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 286 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; |
380 | ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); | 287 | ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); |
381 | if (ret) | 288 | if (ret) |
382 | return ret; | 289 | return ret; |
383 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 290 | ieee80211_sta_req_auth(sdata); |
384 | return 0; | 291 | return 0; |
292 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
293 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) | ||
294 | sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | | ||
295 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; | ||
296 | else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) | ||
297 | sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL; | ||
298 | else | ||
299 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL; | ||
300 | |||
301 | return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data); | ||
385 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 302 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
386 | /* | 303 | /* |
387 | * If it is necessary to update the WDS peer address | 304 | * If it is necessary to update the WDS peer address |
@@ -410,17 +327,20 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, | |||
410 | struct ieee80211_sub_if_data *sdata; | 327 | struct ieee80211_sub_if_data *sdata; |
411 | 328 | ||
412 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 329 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
413 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 330 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
414 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 331 | if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { |
415 | if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATED || | ||
416 | sdata->u.sta.state == IEEE80211_STA_MLME_IBSS_JOINED) { | ||
417 | ap_addr->sa_family = ARPHRD_ETHER; | 332 | ap_addr->sa_family = ARPHRD_ETHER; |
418 | memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN); | 333 | memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN); |
419 | return 0; | 334 | } else |
420 | } else { | ||
421 | memset(&ap_addr->sa_data, 0, ETH_ALEN); | 335 | memset(&ap_addr->sa_data, 0, ETH_ALEN); |
422 | return 0; | 336 | return 0; |
423 | } | 337 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
338 | if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) { | ||
339 | ap_addr->sa_family = ARPHRD_ETHER; | ||
340 | memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN); | ||
341 | } else | ||
342 | memset(&ap_addr->sa_data, 0, ETH_ALEN); | ||
343 | return 0; | ||
424 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 344 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
425 | ap_addr->sa_family = ARPHRD_ETHER; | 345 | ap_addr->sa_family = ARPHRD_ETHER; |
426 | memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); | 346 | memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); |
@@ -486,7 +406,7 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, | |||
486 | 406 | ||
487 | rcu_read_lock(); | 407 | rcu_read_lock(); |
488 | 408 | ||
489 | sta = sta_info_get(local, sdata->u.sta.bssid); | 409 | sta = sta_info_get(local, sdata->u.mgd.bssid); |
490 | 410 | ||
491 | if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) | 411 | if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) |
492 | rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; | 412 | rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; |
@@ -687,8 +607,7 @@ static int ieee80211_ioctl_siwmlme(struct net_device *dev, | |||
687 | struct iw_mlme *mlme = (struct iw_mlme *) extra; | 607 | struct iw_mlme *mlme = (struct iw_mlme *) extra; |
688 | 608 | ||
689 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 609 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
690 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 610 | if (!(sdata->vif.type == NL80211_IFTYPE_STATION)) |
691 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
692 | return -EINVAL; | 611 | return -EINVAL; |
693 | 612 | ||
694 | switch (mlme->cmd) { | 613 | switch (mlme->cmd) { |
@@ -784,8 +703,7 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev, | |||
784 | erq->flags |= IW_ENCODE_ENABLED; | 703 | erq->flags |= IW_ENCODE_ENABLED; |
785 | 704 | ||
786 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 705 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
787 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 706 | switch (sdata->u.mgd.auth_alg) { |
788 | switch (ifsta->auth_alg) { | ||
789 | case WLAN_AUTH_OPEN: | 707 | case WLAN_AUTH_OPEN: |
790 | case WLAN_AUTH_LEAP: | 708 | case WLAN_AUTH_LEAP: |
791 | erq->flags |= IW_ENCODE_OPEN; | 709 | erq->flags |= IW_ENCODE_OPEN; |
@@ -849,7 +767,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
849 | ret = ieee80211_hw_config(local, | 767 | ret = ieee80211_hw_config(local, |
850 | IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); | 768 | IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); |
851 | 769 | ||
852 | if (!(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) | 770 | if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) |
853 | return ret; | 771 | return ret; |
854 | 772 | ||
855 | if (conf->dynamic_ps_timeout > 0 && | 773 | if (conf->dynamic_ps_timeout > 0 && |
@@ -908,10 +826,10 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
908 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 826 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
909 | if (data->value & (IW_AUTH_CIPHER_WEP40 | | 827 | if (data->value & (IW_AUTH_CIPHER_WEP40 | |
910 | IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP)) | 828 | IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP)) |
911 | sdata->u.sta.flags |= | 829 | sdata->u.mgd.flags |= |
912 | IEEE80211_STA_TKIP_WEP_USED; | 830 | IEEE80211_STA_TKIP_WEP_USED; |
913 | else | 831 | else |
914 | sdata->u.sta.flags &= | 832 | sdata->u.mgd.flags &= |
915 | ~IEEE80211_STA_TKIP_WEP_USED; | 833 | ~IEEE80211_STA_TKIP_WEP_USED; |
916 | } | 834 | } |
917 | break; | 835 | break; |
@@ -922,21 +840,20 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
922 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 840 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
923 | ret = -EINVAL; | 841 | ret = -EINVAL; |
924 | else { | 842 | else { |
925 | sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; | 843 | sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; |
926 | /* | 844 | /* |
927 | * Privacy invoked by wpa_supplicant, store the | 845 | * Privacy invoked by wpa_supplicant, store the |
928 | * value and allow associating to a protected | 846 | * value and allow associating to a protected |
929 | * network without having a key up front. | 847 | * network without having a key up front. |
930 | */ | 848 | */ |
931 | if (data->value) | 849 | if (data->value) |
932 | sdata->u.sta.flags |= | 850 | sdata->u.mgd.flags |= |
933 | IEEE80211_STA_PRIVACY_INVOKED; | 851 | IEEE80211_STA_PRIVACY_INVOKED; |
934 | } | 852 | } |
935 | break; | 853 | break; |
936 | case IW_AUTH_80211_AUTH_ALG: | 854 | case IW_AUTH_80211_AUTH_ALG: |
937 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 855 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
938 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 856 | sdata->u.mgd.auth_algs = data->value; |
939 | sdata->u.sta.auth_algs = data->value; | ||
940 | else | 857 | else |
941 | ret = -EOPNOTSUPP; | 858 | ret = -EOPNOTSUPP; |
942 | break; | 859 | break; |
@@ -945,17 +862,16 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
945 | ret = -EOPNOTSUPP; | 862 | ret = -EOPNOTSUPP; |
946 | break; | 863 | break; |
947 | } | 864 | } |
948 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 865 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
949 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
950 | switch (data->value) { | 866 | switch (data->value) { |
951 | case IW_AUTH_MFP_DISABLED: | 867 | case IW_AUTH_MFP_DISABLED: |
952 | sdata->u.sta.mfp = IEEE80211_MFP_DISABLED; | 868 | sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; |
953 | break; | 869 | break; |
954 | case IW_AUTH_MFP_OPTIONAL: | 870 | case IW_AUTH_MFP_OPTIONAL: |
955 | sdata->u.sta.mfp = IEEE80211_MFP_OPTIONAL; | 871 | sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL; |
956 | break; | 872 | break; |
957 | case IW_AUTH_MFP_REQUIRED: | 873 | case IW_AUTH_MFP_REQUIRED: |
958 | sdata->u.sta.mfp = IEEE80211_MFP_REQUIRED; | 874 | sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; |
959 | break; | 875 | break; |
960 | default: | 876 | default: |
961 | ret = -EINVAL; | 877 | ret = -EINVAL; |
@@ -970,6 +886,21 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
970 | return ret; | 886 | return ret; |
971 | } | 887 | } |
972 | 888 | ||
889 | static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local) | ||
890 | { | ||
891 | u8 wstats_flags = 0; | ||
892 | |||
893 | wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | | ||
894 | IEEE80211_HW_SIGNAL_DBM) ? | ||
895 | IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; | ||
896 | wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? | ||
897 | IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; | ||
898 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
899 | wstats_flags |= IW_QUAL_DBM; | ||
900 | |||
901 | return wstats_flags; | ||
902 | } | ||
903 | |||
973 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ | 904 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ |
974 | static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) | 905 | static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) |
975 | { | 906 | { |
@@ -980,9 +911,9 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev | |||
980 | 911 | ||
981 | rcu_read_lock(); | 912 | rcu_read_lock(); |
982 | 913 | ||
983 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 914 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
984 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 915 | sta = sta_info_get(local, sdata->u.mgd.bssid); |
985 | sta = sta_info_get(local, sdata->u.sta.bssid); | 916 | |
986 | if (!sta) { | 917 | if (!sta) { |
987 | wstats->discard.fragment = 0; | 918 | wstats->discard.fragment = 0; |
988 | wstats->discard.misc = 0; | 919 | wstats->discard.misc = 0; |
@@ -1011,9 +942,8 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev, | |||
1011 | 942 | ||
1012 | switch (data->flags & IW_AUTH_INDEX) { | 943 | switch (data->flags & IW_AUTH_INDEX) { |
1013 | case IW_AUTH_80211_AUTH_ALG: | 944 | case IW_AUTH_80211_AUTH_ALG: |
1014 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 945 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
1015 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 946 | data->value = sdata->u.mgd.auth_algs; |
1016 | data->value = sdata->u.sta.auth_algs; | ||
1017 | else | 947 | else |
1018 | ret = -EOPNOTSUPP; | 948 | ret = -EOPNOTSUPP; |
1019 | break; | 949 | break; |
@@ -1116,7 +1046,7 @@ static const iw_handler ieee80211_handler[] = | |||
1116 | (iw_handler) NULL, /* SIOCSIWSENS */ | 1046 | (iw_handler) NULL, /* SIOCSIWSENS */ |
1117 | (iw_handler) NULL, /* SIOCGIWSENS */ | 1047 | (iw_handler) NULL, /* SIOCGIWSENS */ |
1118 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ | 1048 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ |
1119 | (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */ | 1049 | (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ |
1120 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ | 1050 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ |
1121 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ | 1051 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ |
1122 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ | 1052 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index ac71b38f7cb5..093a4ab7f28b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -114,9 +114,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) | |||
114 | { | 114 | { |
115 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); | 115 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); |
116 | struct ieee80211_local *local = mpriv->local; | 116 | struct ieee80211_local *local = mpriv->local; |
117 | struct ieee80211_hw *hw = &local->hw; | ||
118 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 117 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
119 | struct sta_info *sta; | ||
120 | u16 queue; | 118 | u16 queue; |
121 | u8 tid; | 119 | u8 tid; |
122 | 120 | ||
@@ -124,29 +122,11 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) | |||
124 | if (unlikely(queue >= local->hw.queues)) | 122 | if (unlikely(queue >= local->hw.queues)) |
125 | queue = local->hw.queues - 1; | 123 | queue = local->hw.queues - 1; |
126 | 124 | ||
127 | if (skb->requeue) { | 125 | /* |
128 | if (!hw->ampdu_queues) | 126 | * Now we know the 1d priority, fill in the QoS header if |
129 | return queue; | 127 | * there is one (and we haven't done this before). |
130 | |||
131 | rcu_read_lock(); | ||
132 | sta = sta_info_get(local, hdr->addr1); | ||
133 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | ||
134 | if (sta) { | ||
135 | int ampdu_queue = sta->tid_to_tx_q[tid]; | ||
136 | |||
137 | if ((ampdu_queue < ieee80211_num_queues(hw)) && | ||
138 | test_bit(ampdu_queue, local->queue_pool)) | ||
139 | queue = ampdu_queue; | ||
140 | } | ||
141 | rcu_read_unlock(); | ||
142 | |||
143 | return queue; | ||
144 | } | ||
145 | |||
146 | /* Now we know the 1d priority, fill in the QoS header if | ||
147 | * there is one. | ||
148 | */ | 128 | */ |
149 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 129 | if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) { |
150 | u8 *p = ieee80211_get_qos_ctl(hdr); | 130 | u8 *p = ieee80211_get_qos_ctl(hdr); |
151 | u8 ack_policy = 0; | 131 | u8 ack_policy = 0; |
152 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | 132 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
@@ -156,140 +136,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) | |||
156 | /* qos header is 2 bytes, second reserved */ | 136 | /* qos header is 2 bytes, second reserved */ |
157 | *p++ = ack_policy | tid; | 137 | *p++ = ack_policy | tid; |
158 | *p = 0; | 138 | *p = 0; |
159 | |||
160 | if (!hw->ampdu_queues) | ||
161 | return queue; | ||
162 | |||
163 | rcu_read_lock(); | ||
164 | |||
165 | sta = sta_info_get(local, hdr->addr1); | ||
166 | if (sta) { | ||
167 | int ampdu_queue = sta->tid_to_tx_q[tid]; | ||
168 | |||
169 | if ((ampdu_queue < ieee80211_num_queues(hw)) && | ||
170 | test_bit(ampdu_queue, local->queue_pool)) | ||
171 | queue = ampdu_queue; | ||
172 | } | ||
173 | |||
174 | rcu_read_unlock(); | ||
175 | } | 139 | } |
176 | 140 | ||
177 | return queue; | 141 | return queue; |
178 | } | 142 | } |
179 | |||
180 | int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, | ||
181 | struct sta_info *sta, u16 tid) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | /* XXX: currently broken due to cb/requeue use */ | ||
186 | return -EPERM; | ||
187 | |||
188 | /* prepare the filter and save it for the SW queue | ||
189 | * matching the received HW queue */ | ||
190 | |||
191 | if (!local->hw.ampdu_queues) | ||
192 | return -EPERM; | ||
193 | |||
194 | /* try to get a Qdisc from the pool */ | ||
195 | for (i = local->hw.queues; i < ieee80211_num_queues(&local->hw); i++) | ||
196 | if (!test_and_set_bit(i, local->queue_pool)) { | ||
197 | ieee80211_stop_queue(local_to_hw(local), i); | ||
198 | sta->tid_to_tx_q[tid] = i; | ||
199 | |||
200 | /* IF there are already pending packets | ||
201 | * on this tid first we need to drain them | ||
202 | * on the previous queue | ||
203 | * since HT is strict in order */ | ||
204 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
205 | if (net_ratelimit()) | ||
206 | printk(KERN_DEBUG "allocated aggregation queue" | ||
207 | " %d tid %d addr %pM pool=0x%lX\n", | ||
208 | i, tid, sta->sta.addr, | ||
209 | local->queue_pool[0]); | ||
210 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | return -EAGAIN; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * the caller needs to hold netdev_get_tx_queue(local->mdev, X)->lock | ||
219 | */ | ||
220 | void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, | ||
221 | struct sta_info *sta, u16 tid, | ||
222 | u8 requeue) | ||
223 | { | ||
224 | int agg_queue = sta->tid_to_tx_q[tid]; | ||
225 | struct ieee80211_hw *hw = &local->hw; | ||
226 | |||
227 | /* return the qdisc to the pool */ | ||
228 | clear_bit(agg_queue, local->queue_pool); | ||
229 | sta->tid_to_tx_q[tid] = ieee80211_num_queues(hw); | ||
230 | |||
231 | if (requeue) { | ||
232 | ieee80211_requeue(local, agg_queue); | ||
233 | } else { | ||
234 | struct netdev_queue *txq; | ||
235 | spinlock_t *root_lock; | ||
236 | struct Qdisc *q; | ||
237 | |||
238 | txq = netdev_get_tx_queue(local->mdev, agg_queue); | ||
239 | q = rcu_dereference(txq->qdisc); | ||
240 | root_lock = qdisc_lock(q); | ||
241 | |||
242 | spin_lock_bh(root_lock); | ||
243 | qdisc_reset(q); | ||
244 | spin_unlock_bh(root_lock); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | void ieee80211_requeue(struct ieee80211_local *local, int queue) | ||
249 | { | ||
250 | struct netdev_queue *txq = netdev_get_tx_queue(local->mdev, queue); | ||
251 | struct sk_buff_head list; | ||
252 | spinlock_t *root_lock; | ||
253 | struct Qdisc *qdisc; | ||
254 | u32 len; | ||
255 | |||
256 | rcu_read_lock_bh(); | ||
257 | |||
258 | qdisc = rcu_dereference(txq->qdisc); | ||
259 | if (!qdisc || !qdisc->dequeue) | ||
260 | goto out_unlock; | ||
261 | |||
262 | skb_queue_head_init(&list); | ||
263 | |||
264 | root_lock = qdisc_root_lock(qdisc); | ||
265 | spin_lock(root_lock); | ||
266 | for (len = qdisc->q.qlen; len > 0; len--) { | ||
267 | struct sk_buff *skb = qdisc->dequeue(qdisc); | ||
268 | |||
269 | if (skb) | ||
270 | __skb_queue_tail(&list, skb); | ||
271 | } | ||
272 | spin_unlock(root_lock); | ||
273 | |||
274 | for (len = list.qlen; len > 0; len--) { | ||
275 | struct sk_buff *skb = __skb_dequeue(&list); | ||
276 | u16 new_queue; | ||
277 | |||
278 | BUG_ON(!skb); | ||
279 | new_queue = ieee80211_select_queue(local->mdev, skb); | ||
280 | skb_set_queue_mapping(skb, new_queue); | ||
281 | |||
282 | txq = netdev_get_tx_queue(local->mdev, new_queue); | ||
283 | |||
284 | |||
285 | qdisc = rcu_dereference(txq->qdisc); | ||
286 | root_lock = qdisc_root_lock(qdisc); | ||
287 | |||
288 | spin_lock(root_lock); | ||
289 | qdisc_enqueue_root(skb, qdisc); | ||
290 | spin_unlock(root_lock); | ||
291 | } | ||
292 | |||
293 | out_unlock: | ||
294 | rcu_read_unlock_bh(); | ||
295 | } | ||
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index bc62f28a4d3d..7520d2e014dc 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -21,11 +21,5 @@ | |||
21 | extern const int ieee802_1d_to_ac[8]; | 21 | extern const int ieee802_1d_to_ac[8]; |
22 | 22 | ||
23 | u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb); | 23 | u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb); |
24 | int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, | ||
25 | struct sta_info *sta, u16 tid); | ||
26 | void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, | ||
27 | struct sta_info *sta, u16 tid, | ||
28 | u8 requeue); | ||
29 | void ieee80211_requeue(struct ieee80211_local *local, int queue); | ||
30 | 24 | ||
31 | #endif /* _WME_H */ | 25 | #endif /* _WME_H */ |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 0668b2bfc1da..dd7f222919fe 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
10 | #include <linux/mutex.h> | ||
11 | #include <linux/list.h> | 10 | #include <linux/list.h> |
12 | #include <linux/nl80211.h> | 11 | #include <linux/nl80211.h> |
13 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
@@ -31,18 +30,29 @@ MODULE_DESCRIPTION("wireless configuration support"); | |||
31 | * only read the list, and that can happen quite | 30 | * only read the list, and that can happen quite |
32 | * often because we need to do it for each command */ | 31 | * often because we need to do it for each command */ |
33 | LIST_HEAD(cfg80211_drv_list); | 32 | LIST_HEAD(cfg80211_drv_list); |
34 | DEFINE_MUTEX(cfg80211_drv_mutex); | 33 | |
34 | /* | ||
35 | * This is used to protect the cfg80211_drv_list, cfg80211_regdomain, | ||
36 | * country_ie_regdomain, the reg_beacon_list and the the last regulatory | ||
37 | * request receipt (last_request). | ||
38 | */ | ||
39 | DEFINE_MUTEX(cfg80211_mutex); | ||
35 | 40 | ||
36 | /* for debugfs */ | 41 | /* for debugfs */ |
37 | static struct dentry *ieee80211_debugfs_dir; | 42 | static struct dentry *ieee80211_debugfs_dir; |
38 | 43 | ||
39 | /* requires cfg80211_drv_mutex to be held! */ | 44 | /* requires cfg80211_mutex to be held! */ |
40 | static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy) | 45 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx) |
41 | { | 46 | { |
42 | struct cfg80211_registered_device *result = NULL, *drv; | 47 | struct cfg80211_registered_device *result = NULL, *drv; |
43 | 48 | ||
49 | if (!wiphy_idx_valid(wiphy_idx)) | ||
50 | return NULL; | ||
51 | |||
52 | assert_cfg80211_lock(); | ||
53 | |||
44 | list_for_each_entry(drv, &cfg80211_drv_list, list) { | 54 | list_for_each_entry(drv, &cfg80211_drv_list, list) { |
45 | if (drv->idx == wiphy) { | 55 | if (drv->wiphy_idx == wiphy_idx) { |
46 | result = drv; | 56 | result = drv; |
47 | break; | 57 | break; |
48 | } | 58 | } |
@@ -51,17 +61,44 @@ static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy) | |||
51 | return result; | 61 | return result; |
52 | } | 62 | } |
53 | 63 | ||
64 | int get_wiphy_idx(struct wiphy *wiphy) | ||
65 | { | ||
66 | struct cfg80211_registered_device *drv; | ||
67 | if (!wiphy) | ||
68 | return WIPHY_IDX_STALE; | ||
69 | drv = wiphy_to_dev(wiphy); | ||
70 | return drv->wiphy_idx; | ||
71 | } | ||
72 | |||
54 | /* requires cfg80211_drv_mutex to be held! */ | 73 | /* requires cfg80211_drv_mutex to be held! */ |
74 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | ||
75 | { | ||
76 | struct cfg80211_registered_device *drv; | ||
77 | |||
78 | if (!wiphy_idx_valid(wiphy_idx)) | ||
79 | return NULL; | ||
80 | |||
81 | assert_cfg80211_lock(); | ||
82 | |||
83 | drv = cfg80211_drv_by_wiphy_idx(wiphy_idx); | ||
84 | if (!drv) | ||
85 | return NULL; | ||
86 | return &drv->wiphy; | ||
87 | } | ||
88 | |||
89 | /* requires cfg80211_mutex to be held! */ | ||
55 | static struct cfg80211_registered_device * | 90 | static struct cfg80211_registered_device * |
56 | __cfg80211_drv_from_info(struct genl_info *info) | 91 | __cfg80211_drv_from_info(struct genl_info *info) |
57 | { | 92 | { |
58 | int ifindex; | 93 | int ifindex; |
59 | struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL; | 94 | struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; |
60 | struct net_device *dev; | 95 | struct net_device *dev; |
61 | int err = -EINVAL; | 96 | int err = -EINVAL; |
62 | 97 | ||
98 | assert_cfg80211_lock(); | ||
99 | |||
63 | if (info->attrs[NL80211_ATTR_WIPHY]) { | 100 | if (info->attrs[NL80211_ATTR_WIPHY]) { |
64 | bywiphy = cfg80211_drv_by_wiphy( | 101 | bywiphyidx = cfg80211_drv_by_wiphy_idx( |
65 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); | 102 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); |
66 | err = -ENODEV; | 103 | err = -ENODEV; |
67 | } | 104 | } |
@@ -78,14 +115,14 @@ __cfg80211_drv_from_info(struct genl_info *info) | |||
78 | err = -ENODEV; | 115 | err = -ENODEV; |
79 | } | 116 | } |
80 | 117 | ||
81 | if (bywiphy && byifidx) { | 118 | if (bywiphyidx && byifidx) { |
82 | if (bywiphy != byifidx) | 119 | if (bywiphyidx != byifidx) |
83 | return ERR_PTR(-EINVAL); | 120 | return ERR_PTR(-EINVAL); |
84 | else | 121 | else |
85 | return bywiphy; /* == byifidx */ | 122 | return bywiphyidx; /* == byifidx */ |
86 | } | 123 | } |
87 | if (bywiphy) | 124 | if (bywiphyidx) |
88 | return bywiphy; | 125 | return bywiphyidx; |
89 | 126 | ||
90 | if (byifidx) | 127 | if (byifidx) |
91 | return byifidx; | 128 | return byifidx; |
@@ -98,7 +135,7 @@ cfg80211_get_dev_from_info(struct genl_info *info) | |||
98 | { | 135 | { |
99 | struct cfg80211_registered_device *drv; | 136 | struct cfg80211_registered_device *drv; |
100 | 137 | ||
101 | mutex_lock(&cfg80211_drv_mutex); | 138 | mutex_lock(&cfg80211_mutex); |
102 | drv = __cfg80211_drv_from_info(info); | 139 | drv = __cfg80211_drv_from_info(info); |
103 | 140 | ||
104 | /* if it is not an error we grab the lock on | 141 | /* if it is not an error we grab the lock on |
@@ -107,7 +144,7 @@ cfg80211_get_dev_from_info(struct genl_info *info) | |||
107 | if (!IS_ERR(drv)) | 144 | if (!IS_ERR(drv)) |
108 | mutex_lock(&drv->mtx); | 145 | mutex_lock(&drv->mtx); |
109 | 146 | ||
110 | mutex_unlock(&cfg80211_drv_mutex); | 147 | mutex_unlock(&cfg80211_mutex); |
111 | 148 | ||
112 | return drv; | 149 | return drv; |
113 | } | 150 | } |
@@ -118,7 +155,7 @@ cfg80211_get_dev_from_ifindex(int ifindex) | |||
118 | struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV); | 155 | struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV); |
119 | struct net_device *dev; | 156 | struct net_device *dev; |
120 | 157 | ||
121 | mutex_lock(&cfg80211_drv_mutex); | 158 | mutex_lock(&cfg80211_mutex); |
122 | dev = dev_get_by_index(&init_net, ifindex); | 159 | dev = dev_get_by_index(&init_net, ifindex); |
123 | if (!dev) | 160 | if (!dev) |
124 | goto out; | 161 | goto out; |
@@ -129,7 +166,7 @@ cfg80211_get_dev_from_ifindex(int ifindex) | |||
129 | drv = ERR_PTR(-ENODEV); | 166 | drv = ERR_PTR(-ENODEV); |
130 | dev_put(dev); | 167 | dev_put(dev); |
131 | out: | 168 | out: |
132 | mutex_unlock(&cfg80211_drv_mutex); | 169 | mutex_unlock(&cfg80211_mutex); |
133 | return drv; | 170 | return drv; |
134 | } | 171 | } |
135 | 172 | ||
@@ -143,16 +180,16 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
143 | char *newname) | 180 | char *newname) |
144 | { | 181 | { |
145 | struct cfg80211_registered_device *drv; | 182 | struct cfg80211_registered_device *drv; |
146 | int idx, taken = -1, result, digits; | 183 | int wiphy_idx, taken = -1, result, digits; |
147 | 184 | ||
148 | mutex_lock(&cfg80211_drv_mutex); | 185 | mutex_lock(&cfg80211_mutex); |
149 | 186 | ||
150 | /* prohibit calling the thing phy%d when %d is not its number */ | 187 | /* prohibit calling the thing phy%d when %d is not its number */ |
151 | sscanf(newname, PHY_NAME "%d%n", &idx, &taken); | 188 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); |
152 | if (taken == strlen(newname) && idx != rdev->idx) { | 189 | if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { |
153 | /* count number of places needed to print idx */ | 190 | /* count number of places needed to print wiphy_idx */ |
154 | digits = 1; | 191 | digits = 1; |
155 | while (idx /= 10) | 192 | while (wiphy_idx /= 10) |
156 | digits++; | 193 | digits++; |
157 | /* | 194 | /* |
158 | * deny the name if it is phy<idx> where <idx> is printed | 195 | * deny the name if it is phy<idx> where <idx> is printed |
@@ -193,7 +230,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
193 | 230 | ||
194 | result = 0; | 231 | result = 0; |
195 | out_unlock: | 232 | out_unlock: |
196 | mutex_unlock(&cfg80211_drv_mutex); | 233 | mutex_unlock(&cfg80211_mutex); |
197 | if (result == 0) | 234 | if (result == 0) |
198 | nl80211_notify_dev_rename(rdev); | 235 | nl80211_notify_dev_rename(rdev); |
199 | 236 | ||
@@ -220,22 +257,22 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) | |||
220 | 257 | ||
221 | drv->ops = ops; | 258 | drv->ops = ops; |
222 | 259 | ||
223 | mutex_lock(&cfg80211_drv_mutex); | 260 | mutex_lock(&cfg80211_mutex); |
224 | 261 | ||
225 | drv->idx = wiphy_counter++; | 262 | drv->wiphy_idx = wiphy_counter++; |
226 | 263 | ||
227 | if (unlikely(drv->idx < 0)) { | 264 | if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) { |
228 | wiphy_counter--; | 265 | wiphy_counter--; |
229 | mutex_unlock(&cfg80211_drv_mutex); | 266 | mutex_unlock(&cfg80211_mutex); |
230 | /* ugh, wrapped! */ | 267 | /* ugh, wrapped! */ |
231 | kfree(drv); | 268 | kfree(drv); |
232 | return NULL; | 269 | return NULL; |
233 | } | 270 | } |
234 | 271 | ||
235 | mutex_unlock(&cfg80211_drv_mutex); | 272 | mutex_unlock(&cfg80211_mutex); |
236 | 273 | ||
237 | /* give it a proper name */ | 274 | /* give it a proper name */ |
238 | dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->idx); | 275 | dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx); |
239 | 276 | ||
240 | mutex_init(&drv->mtx); | 277 | mutex_init(&drv->mtx); |
241 | mutex_init(&drv->devlist_mtx); | 278 | mutex_init(&drv->devlist_mtx); |
@@ -310,7 +347,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
310 | /* check and set up bitrates */ | 347 | /* check and set up bitrates */ |
311 | ieee80211_set_bitrate_flags(wiphy); | 348 | ieee80211_set_bitrate_flags(wiphy); |
312 | 349 | ||
313 | mutex_lock(&cfg80211_drv_mutex); | 350 | mutex_lock(&cfg80211_mutex); |
314 | 351 | ||
315 | /* set up regulatory info */ | 352 | /* set up regulatory info */ |
316 | wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE); | 353 | wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE); |
@@ -330,7 +367,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
330 | 367 | ||
331 | res = 0; | 368 | res = 0; |
332 | out_unlock: | 369 | out_unlock: |
333 | mutex_unlock(&cfg80211_drv_mutex); | 370 | mutex_unlock(&cfg80211_mutex); |
334 | return res; | 371 | return res; |
335 | } | 372 | } |
336 | EXPORT_SYMBOL(wiphy_register); | 373 | EXPORT_SYMBOL(wiphy_register); |
@@ -340,7 +377,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
340 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); | 377 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); |
341 | 378 | ||
342 | /* protect the device list */ | 379 | /* protect the device list */ |
343 | mutex_lock(&cfg80211_drv_mutex); | 380 | mutex_lock(&cfg80211_mutex); |
344 | 381 | ||
345 | BUG_ON(!list_empty(&drv->netdev_list)); | 382 | BUG_ON(!list_empty(&drv->netdev_list)); |
346 | 383 | ||
@@ -366,7 +403,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
366 | device_del(&drv->wiphy.dev); | 403 | device_del(&drv->wiphy.dev); |
367 | debugfs_remove(drv->wiphy.debugfsdir); | 404 | debugfs_remove(drv->wiphy.debugfsdir); |
368 | 405 | ||
369 | mutex_unlock(&cfg80211_drv_mutex); | 406 | mutex_unlock(&cfg80211_mutex); |
370 | } | 407 | } |
371 | EXPORT_SYMBOL(wiphy_unregister); | 408 | EXPORT_SYMBOL(wiphy_unregister); |
372 | 409 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index e29ad4cd464f..f6c53f5807f4 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/netdevice.h> | 10 | #include <linux/netdevice.h> |
11 | #include <linux/kref.h> | 11 | #include <linux/kref.h> |
12 | #include <linux/rbtree.h> | 12 | #include <linux/rbtree.h> |
13 | #include <linux/mutex.h> | ||
13 | #include <net/genetlink.h> | 14 | #include <net/genetlink.h> |
14 | #include <net/wireless.h> | 15 | #include <net/wireless.h> |
15 | #include <net/cfg80211.h> | 16 | #include <net/cfg80211.h> |
@@ -37,7 +38,7 @@ struct cfg80211_registered_device { | |||
37 | enum environment_cap env; | 38 | enum environment_cap env; |
38 | 39 | ||
39 | /* wiphy index, internal only */ | 40 | /* wiphy index, internal only */ |
40 | int idx; | 41 | int wiphy_idx; |
41 | 42 | ||
42 | /* associate netdev list */ | 43 | /* associate netdev list */ |
43 | struct mutex devlist_mtx; | 44 | struct mutex devlist_mtx; |
@@ -49,6 +50,7 @@ struct cfg80211_registered_device { | |||
49 | struct rb_root bss_tree; | 50 | struct rb_root bss_tree; |
50 | u32 bss_generation; | 51 | u32 bss_generation; |
51 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | 52 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ |
53 | unsigned long suspend_at; | ||
52 | 54 | ||
53 | /* must be last because of the way we do wiphy_priv(), | 55 | /* must be last because of the way we do wiphy_priv(), |
54 | * and it should at least be aligned to NETDEV_ALIGN */ | 56 | * and it should at least be aligned to NETDEV_ALIGN */ |
@@ -62,9 +64,27 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) | |||
62 | return container_of(wiphy, struct cfg80211_registered_device, wiphy); | 64 | return container_of(wiphy, struct cfg80211_registered_device, wiphy); |
63 | } | 65 | } |
64 | 66 | ||
65 | extern struct mutex cfg80211_drv_mutex; | 67 | /* Note 0 is valid, hence phy0 */ |
68 | static inline | ||
69 | bool wiphy_idx_valid(int wiphy_idx) | ||
70 | { | ||
71 | return (wiphy_idx >= 0); | ||
72 | } | ||
73 | |||
74 | extern struct mutex cfg80211_mutex; | ||
66 | extern struct list_head cfg80211_drv_list; | 75 | extern struct list_head cfg80211_drv_list; |
67 | 76 | ||
77 | static inline void assert_cfg80211_lock(void) | ||
78 | { | ||
79 | WARN_ON(!mutex_is_locked(&cfg80211_mutex)); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * You can use this to mark a wiphy_idx as not having an associated wiphy. | ||
84 | * It guarantees cfg80211_drv_by_wiphy_idx(wiphy_idx) will return NULL | ||
85 | */ | ||
86 | #define WIPHY_IDX_STALE -1 | ||
87 | |||
68 | struct cfg80211_internal_bss { | 88 | struct cfg80211_internal_bss { |
69 | struct list_head list; | 89 | struct list_head list; |
70 | struct rb_node rbn; | 90 | struct rb_node rbn; |
@@ -74,6 +94,9 @@ struct cfg80211_internal_bss { | |||
74 | struct cfg80211_bss pub; | 94 | struct cfg80211_bss pub; |
75 | }; | 95 | }; |
76 | 96 | ||
97 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); | ||
98 | int get_wiphy_idx(struct wiphy *wiphy); | ||
99 | |||
77 | /* | 100 | /* |
78 | * This function returns a pointer to the driver | 101 | * This function returns a pointer to the driver |
79 | * that the genl_info item that is passed refers to. | 102 | * that the genl_info item that is passed refers to. |
@@ -81,13 +104,13 @@ struct cfg80211_internal_bss { | |||
81 | * the driver's mutex! | 104 | * the driver's mutex! |
82 | * | 105 | * |
83 | * This means that you need to call cfg80211_put_dev() | 106 | * This means that you need to call cfg80211_put_dev() |
84 | * before being allowed to acquire &cfg80211_drv_mutex! | 107 | * before being allowed to acquire &cfg80211_mutex! |
85 | * | 108 | * |
86 | * This is necessary because we need to lock the global | 109 | * This is necessary because we need to lock the global |
87 | * mutex to get an item off the list safely, and then | 110 | * mutex to get an item off the list safely, and then |
88 | * we lock the drv mutex so it doesn't go away under us. | 111 | * we lock the drv mutex so it doesn't go away under us. |
89 | * | 112 | * |
90 | * We don't want to keep cfg80211_drv_mutex locked | 113 | * We don't want to keep cfg80211_mutex locked |
91 | * for all the time in order to allow requests on | 114 | * for all the time in order to allow requests on |
92 | * other interfaces to go through at the same time. | 115 | * other interfaces to go through at the same time. |
93 | * | 116 | * |
@@ -97,6 +120,9 @@ struct cfg80211_internal_bss { | |||
97 | extern struct cfg80211_registered_device * | 120 | extern struct cfg80211_registered_device * |
98 | cfg80211_get_dev_from_info(struct genl_info *info); | 121 | cfg80211_get_dev_from_info(struct genl_info *info); |
99 | 122 | ||
123 | /* requires cfg80211_drv_mutex to be held! */ | ||
124 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); | ||
125 | |||
100 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ | 126 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ |
101 | extern struct cfg80211_registered_device * | 127 | extern struct cfg80211_registered_device * |
102 | cfg80211_get_dev_from_ifindex(int ifindex); | 128 | cfg80211_get_dev_from_ifindex(int ifindex); |
@@ -113,5 +139,7 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy); | |||
113 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby); | 139 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby); |
114 | 140 | ||
115 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev); | 141 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev); |
142 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, | ||
143 | unsigned long age_secs); | ||
116 | 144 | ||
117 | #endif /* __NET_WIRELESS_CORE_H */ | 145 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 298a4de59948..531bb67cf502 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
10 | #include <linux/mutex.h> | ||
11 | #include <linux/list.h> | 10 | #include <linux/list.h> |
12 | #include <linux/if_ether.h> | 11 | #include <linux/if_ether.h> |
13 | #include <linux/ieee80211.h> | 12 | #include <linux/ieee80211.h> |
@@ -142,7 +141,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
142 | if (!hdr) | 141 | if (!hdr) |
143 | return -1; | 142 | return -1; |
144 | 143 | ||
145 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); | 144 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
146 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 145 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
147 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 146 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
148 | dev->wiphy.max_scan_ssids); | 147 | dev->wiphy.max_scan_ssids); |
@@ -256,7 +255,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
256 | int start = cb->args[0]; | 255 | int start = cb->args[0]; |
257 | struct cfg80211_registered_device *dev; | 256 | struct cfg80211_registered_device *dev; |
258 | 257 | ||
259 | mutex_lock(&cfg80211_drv_mutex); | 258 | mutex_lock(&cfg80211_mutex); |
260 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 259 | list_for_each_entry(dev, &cfg80211_drv_list, list) { |
261 | if (++idx <= start) | 260 | if (++idx <= start) |
262 | continue; | 261 | continue; |
@@ -267,7 +266,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
267 | break; | 266 | break; |
268 | } | 267 | } |
269 | } | 268 | } |
270 | mutex_unlock(&cfg80211_drv_mutex); | 269 | mutex_unlock(&cfg80211_mutex); |
271 | 270 | ||
272 | cb->args[0] = idx; | 271 | cb->args[0] = idx; |
273 | 272 | ||
@@ -470,7 +469,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
470 | struct cfg80211_registered_device *dev; | 469 | struct cfg80211_registered_device *dev; |
471 | struct wireless_dev *wdev; | 470 | struct wireless_dev *wdev; |
472 | 471 | ||
473 | mutex_lock(&cfg80211_drv_mutex); | 472 | mutex_lock(&cfg80211_mutex); |
474 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 473 | list_for_each_entry(dev, &cfg80211_drv_list, list) { |
475 | if (wp_idx < wp_start) { | 474 | if (wp_idx < wp_start) { |
476 | wp_idx++; | 475 | wp_idx++; |
@@ -497,7 +496,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
497 | wp_idx++; | 496 | wp_idx++; |
498 | } | 497 | } |
499 | out: | 498 | out: |
500 | mutex_unlock(&cfg80211_drv_mutex); | 499 | mutex_unlock(&cfg80211_mutex); |
501 | 500 | ||
502 | cb->args[0] = wp_idx; | 501 | cb->args[0] = wp_idx; |
503 | cb->args[1] = if_idx; | 502 | cb->args[1] = if_idx; |
@@ -1206,6 +1205,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1206 | 1205 | ||
1207 | nla_nest_end(msg, txrate); | 1206 | nla_nest_end(msg, txrate); |
1208 | } | 1207 | } |
1208 | if (sinfo->filled & STATION_INFO_RX_PACKETS) | ||
1209 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS, | ||
1210 | sinfo->rx_packets); | ||
1211 | if (sinfo->filled & STATION_INFO_TX_PACKETS) | ||
1212 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, | ||
1213 | sinfo->tx_packets); | ||
1209 | nla_nest_end(msg, sinfoattr); | 1214 | nla_nest_end(msg, sinfoattr); |
1210 | 1215 | ||
1211 | return genlmsg_end(msg, hdr); | 1216 | return genlmsg_end(msg, hdr); |
@@ -1900,6 +1905,19 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
1900 | int r; | 1905 | int r; |
1901 | char *data = NULL; | 1906 | char *data = NULL; |
1902 | 1907 | ||
1908 | /* | ||
1909 | * You should only get this when cfg80211 hasn't yet initialized | ||
1910 | * completely when built-in to the kernel right between the time | ||
1911 | * window between nl80211_init() and regulatory_init(), if that is | ||
1912 | * even possible. | ||
1913 | */ | ||
1914 | mutex_lock(&cfg80211_mutex); | ||
1915 | if (unlikely(!cfg80211_regdomain)) { | ||
1916 | mutex_unlock(&cfg80211_mutex); | ||
1917 | return -EINPROGRESS; | ||
1918 | } | ||
1919 | mutex_unlock(&cfg80211_mutex); | ||
1920 | |||
1903 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 1921 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
1904 | return -EINVAL; | 1922 | return -EINVAL; |
1905 | 1923 | ||
@@ -1910,14 +1928,9 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
1910 | if (is_world_regdom(data)) | 1928 | if (is_world_regdom(data)) |
1911 | return -EINVAL; | 1929 | return -EINVAL; |
1912 | #endif | 1930 | #endif |
1913 | mutex_lock(&cfg80211_drv_mutex); | 1931 | |
1914 | r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); | 1932 | r = regulatory_hint_user(data); |
1915 | mutex_unlock(&cfg80211_drv_mutex); | 1933 | |
1916 | /* This means the regulatory domain was already set, however | ||
1917 | * we don't want to confuse userspace with a "successful error" | ||
1918 | * message so lets just treat it as a success */ | ||
1919 | if (r == -EALREADY) | ||
1920 | r = 0; | ||
1921 | return r; | 1934 | return r; |
1922 | } | 1935 | } |
1923 | 1936 | ||
@@ -2106,7 +2119,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
2106 | unsigned int i; | 2119 | unsigned int i; |
2107 | int err = -EINVAL; | 2120 | int err = -EINVAL; |
2108 | 2121 | ||
2109 | mutex_lock(&cfg80211_drv_mutex); | 2122 | mutex_lock(&cfg80211_mutex); |
2110 | 2123 | ||
2111 | if (!cfg80211_regdomain) | 2124 | if (!cfg80211_regdomain) |
2112 | goto out; | 2125 | goto out; |
@@ -2169,7 +2182,7 @@ nla_put_failure: | |||
2169 | genlmsg_cancel(msg, hdr); | 2182 | genlmsg_cancel(msg, hdr); |
2170 | err = -EMSGSIZE; | 2183 | err = -EMSGSIZE; |
2171 | out: | 2184 | out: |
2172 | mutex_unlock(&cfg80211_drv_mutex); | 2185 | mutex_unlock(&cfg80211_mutex); |
2173 | return err; | 2186 | return err; |
2174 | } | 2187 | } |
2175 | 2188 | ||
@@ -2228,9 +2241,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2228 | 2241 | ||
2229 | BUG_ON(rule_idx != num_rules); | 2242 | BUG_ON(rule_idx != num_rules); |
2230 | 2243 | ||
2231 | mutex_lock(&cfg80211_drv_mutex); | 2244 | mutex_lock(&cfg80211_mutex); |
2232 | r = set_regdom(rd); | 2245 | r = set_regdom(rd); |
2233 | mutex_unlock(&cfg80211_drv_mutex); | 2246 | mutex_unlock(&cfg80211_mutex); |
2234 | return r; | 2247 | return r; |
2235 | 2248 | ||
2236 | bad_reg: | 2249 | bad_reg: |
@@ -2286,6 +2299,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2286 | struct wiphy *wiphy; | 2299 | struct wiphy *wiphy; |
2287 | int err, tmp, n_ssids = 0, n_channels = 0, i; | 2300 | int err, tmp, n_ssids = 0, n_channels = 0, i; |
2288 | enum ieee80211_band band; | 2301 | enum ieee80211_band band; |
2302 | size_t ie_len; | ||
2289 | 2303 | ||
2290 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2304 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
2291 | if (err) | 2305 | if (err) |
@@ -2327,9 +2341,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2327 | goto out_unlock; | 2341 | goto out_unlock; |
2328 | } | 2342 | } |
2329 | 2343 | ||
2344 | if (info->attrs[NL80211_ATTR_IE]) | ||
2345 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2346 | else | ||
2347 | ie_len = 0; | ||
2348 | |||
2330 | request = kzalloc(sizeof(*request) | 2349 | request = kzalloc(sizeof(*request) |
2331 | + sizeof(*ssid) * n_ssids | 2350 | + sizeof(*ssid) * n_ssids |
2332 | + sizeof(channel) * n_channels, GFP_KERNEL); | 2351 | + sizeof(channel) * n_channels |
2352 | + ie_len, GFP_KERNEL); | ||
2333 | if (!request) { | 2353 | if (!request) { |
2334 | err = -ENOMEM; | 2354 | err = -ENOMEM; |
2335 | goto out_unlock; | 2355 | goto out_unlock; |
@@ -2340,6 +2360,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2340 | if (n_ssids) | 2360 | if (n_ssids) |
2341 | request->ssids = (void *)(request->channels + n_channels); | 2361 | request->ssids = (void *)(request->channels + n_channels); |
2342 | request->n_ssids = n_ssids; | 2362 | request->n_ssids = n_ssids; |
2363 | if (ie_len) { | ||
2364 | if (request->ssids) | ||
2365 | request->ie = (void *)(request->ssids + n_ssids); | ||
2366 | else | ||
2367 | request->ie = (void *)(request->channels + n_channels); | ||
2368 | } | ||
2343 | 2369 | ||
2344 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2370 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
2345 | /* user specified, bail out if channel not found */ | 2371 | /* user specified, bail out if channel not found */ |
@@ -2380,6 +2406,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2380 | } | 2406 | } |
2381 | } | 2407 | } |
2382 | 2408 | ||
2409 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2410 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2411 | memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), | ||
2412 | request->ie_len); | ||
2413 | } | ||
2414 | |||
2383 | request->ifidx = dev->ifindex; | 2415 | request->ifidx = dev->ifindex; |
2384 | request->wiphy = &drv->wiphy; | 2416 | request->wiphy = &drv->wiphy; |
2385 | 2417 | ||
@@ -2432,7 +2464,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
2432 | NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); | 2464 | NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); |
2433 | NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); | 2465 | NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); |
2434 | 2466 | ||
2435 | switch (res->signal_type) { | 2467 | switch (rdev->wiphy.signal_type) { |
2436 | case CFG80211_SIGNAL_TYPE_MBM: | 2468 | case CFG80211_SIGNAL_TYPE_MBM: |
2437 | NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal); | 2469 | NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal); |
2438 | break; | 2470 | break; |
@@ -2601,7 +2633,6 @@ static struct genl_ops nl80211_ops[] = { | |||
2601 | .doit = nl80211_get_station, | 2633 | .doit = nl80211_get_station, |
2602 | .dumpit = nl80211_dump_station, | 2634 | .dumpit = nl80211_dump_station, |
2603 | .policy = nl80211_policy, | 2635 | .policy = nl80211_policy, |
2604 | .flags = GENL_ADMIN_PERM, | ||
2605 | }, | 2636 | }, |
2606 | { | 2637 | { |
2607 | .cmd = NL80211_CMD_SET_STATION, | 2638 | .cmd = NL80211_CMD_SET_STATION, |
@@ -2739,7 +2770,7 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg, | |||
2739 | if (!hdr) | 2770 | if (!hdr) |
2740 | return -1; | 2771 | return -1; |
2741 | 2772 | ||
2742 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx); | 2773 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
2743 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 2774 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
2744 | 2775 | ||
2745 | /* XXX: we should probably bounce back the request? */ | 2776 | /* XXX: we should probably bounce back the request? */ |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b565a5f84e97..69787b621365 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -27,6 +27,10 @@ static inline void | |||
27 | nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 27 | nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
28 | struct net_device *netdev) | 28 | struct net_device *netdev) |
29 | {} | 29 | {} |
30 | static inline void nl80211_send_scan_aborted( | ||
31 | struct cfg80211_registered_device *rdev, | ||
32 | struct net_device *netdev) | ||
33 | {} | ||
30 | #endif /* CONFIG_NL80211 */ | 34 | #endif /* CONFIG_NL80211 */ |
31 | 35 | ||
32 | #endif /* __NET_WIRELESS_NL80211_H */ | 36 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2323644330cd..ce66bfdf57ec 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -54,22 +54,52 @@ static u32 supported_bandwidths[] = { | |||
54 | MHZ_TO_KHZ(20), | 54 | MHZ_TO_KHZ(20), |
55 | }; | 55 | }; |
56 | 56 | ||
57 | /* Central wireless core regulatory domains, we only need two, | 57 | /* |
58 | * Central wireless core regulatory domains, we only need two, | ||
58 | * the current one and a world regulatory domain in case we have no | 59 | * the current one and a world regulatory domain in case we have no |
59 | * information to give us an alpha2 */ | 60 | * information to give us an alpha2 |
61 | */ | ||
60 | const struct ieee80211_regdomain *cfg80211_regdomain; | 62 | const struct ieee80211_regdomain *cfg80211_regdomain; |
61 | 63 | ||
62 | /* We use this as a place for the rd structure built from the | 64 | /* |
65 | * We use this as a place for the rd structure built from the | ||
63 | * last parsed country IE to rest until CRDA gets back to us with | 66 | * last parsed country IE to rest until CRDA gets back to us with |
64 | * what it thinks should apply for the same country */ | 67 | * what it thinks should apply for the same country |
68 | */ | ||
65 | static const struct ieee80211_regdomain *country_ie_regdomain; | 69 | static const struct ieee80211_regdomain *country_ie_regdomain; |
66 | 70 | ||
71 | /* Used to queue up regulatory hints */ | ||
72 | static LIST_HEAD(reg_requests_list); | ||
73 | static spinlock_t reg_requests_lock; | ||
74 | |||
75 | /* Used to queue up beacon hints for review */ | ||
76 | static LIST_HEAD(reg_pending_beacons); | ||
77 | static spinlock_t reg_pending_beacons_lock; | ||
78 | |||
79 | /* Used to keep track of processed beacon hints */ | ||
80 | static LIST_HEAD(reg_beacon_list); | ||
81 | |||
82 | struct reg_beacon { | ||
83 | struct list_head list; | ||
84 | struct ieee80211_channel chan; | ||
85 | }; | ||
86 | |||
67 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 87 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
68 | static const struct ieee80211_regdomain world_regdom = { | 88 | static const struct ieee80211_regdomain world_regdom = { |
69 | .n_reg_rules = 1, | 89 | .n_reg_rules = 3, |
70 | .alpha2 = "00", | 90 | .alpha2 = "00", |
71 | .reg_rules = { | 91 | .reg_rules = { |
72 | REG_RULE(2412-10, 2462+10, 40, 6, 20, | 92 | /* IEEE 802.11b/g, channels 1..11 */ |
93 | REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), | ||
94 | /* IEEE 802.11a, channel 36..48 */ | ||
95 | REG_RULE(5180-10, 5240+10, 40, 6, 23, | ||
96 | NL80211_RRF_PASSIVE_SCAN | | ||
97 | NL80211_RRF_NO_IBSS), | ||
98 | |||
99 | /* NB: 5260 MHz - 5700 MHz requies DFS */ | ||
100 | |||
101 | /* IEEE 802.11a, channel 149..165 */ | ||
102 | REG_RULE(5745-10, 5825+10, 40, 6, 23, | ||
73 | NL80211_RRF_PASSIVE_SCAN | | 103 | NL80211_RRF_PASSIVE_SCAN | |
74 | NL80211_RRF_NO_IBSS), | 104 | NL80211_RRF_NO_IBSS), |
75 | } | 105 | } |
@@ -83,9 +113,11 @@ static char *ieee80211_regdom = "US"; | |||
83 | module_param(ieee80211_regdom, charp, 0444); | 113 | module_param(ieee80211_regdom, charp, 0444); |
84 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 114 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
85 | 115 | ||
86 | /* We assume 40 MHz bandwidth for the old regulatory work. | 116 | /* |
117 | * We assume 40 MHz bandwidth for the old regulatory work. | ||
87 | * We make emphasis we are using the exact same frequencies | 118 | * We make emphasis we are using the exact same frequencies |
88 | * as before */ | 119 | * as before |
120 | */ | ||
89 | 121 | ||
90 | static const struct ieee80211_regdomain us_regdom = { | 122 | static const struct ieee80211_regdomain us_regdom = { |
91 | .n_reg_rules = 6, | 123 | .n_reg_rules = 6, |
@@ -124,8 +156,10 @@ static const struct ieee80211_regdomain jp_regdom = { | |||
124 | 156 | ||
125 | static const struct ieee80211_regdomain eu_regdom = { | 157 | static const struct ieee80211_regdomain eu_regdom = { |
126 | .n_reg_rules = 6, | 158 | .n_reg_rules = 6, |
127 | /* This alpha2 is bogus, we leave it here just for stupid | 159 | /* |
128 | * backward compatibility */ | 160 | * This alpha2 is bogus, we leave it here just for stupid |
161 | * backward compatibility | ||
162 | */ | ||
129 | .alpha2 = "EU", | 163 | .alpha2 = "EU", |
130 | .reg_rules = { | 164 | .reg_rules = { |
131 | /* IEEE 802.11b/g, channels 1..13 */ | 165 | /* IEEE 802.11b/g, channels 1..13 */ |
@@ -194,8 +228,10 @@ static void reset_regdomains(void) | |||
194 | cfg80211_regdomain = NULL; | 228 | cfg80211_regdomain = NULL; |
195 | } | 229 | } |
196 | 230 | ||
197 | /* Dynamic world regulatory domain requested by the wireless | 231 | /* |
198 | * core upon initialization */ | 232 | * Dynamic world regulatory domain requested by the wireless |
233 | * core upon initialization | ||
234 | */ | ||
199 | static void update_world_regdomain(const struct ieee80211_regdomain *rd) | 235 | static void update_world_regdomain(const struct ieee80211_regdomain *rd) |
200 | { | 236 | { |
201 | BUG_ON(!last_request); | 237 | BUG_ON(!last_request); |
@@ -236,8 +272,10 @@ static bool is_unknown_alpha2(const char *alpha2) | |||
236 | { | 272 | { |
237 | if (!alpha2) | 273 | if (!alpha2) |
238 | return false; | 274 | return false; |
239 | /* Special case where regulatory domain was built by driver | 275 | /* |
240 | * but a specific alpha2 cannot be determined */ | 276 | * Special case where regulatory domain was built by driver |
277 | * but a specific alpha2 cannot be determined | ||
278 | */ | ||
241 | if (alpha2[0] == '9' && alpha2[1] == '9') | 279 | if (alpha2[0] == '9' && alpha2[1] == '9') |
242 | return true; | 280 | return true; |
243 | return false; | 281 | return false; |
@@ -247,9 +285,11 @@ static bool is_intersected_alpha2(const char *alpha2) | |||
247 | { | 285 | { |
248 | if (!alpha2) | 286 | if (!alpha2) |
249 | return false; | 287 | return false; |
250 | /* Special case where regulatory domain is the | 288 | /* |
289 | * Special case where regulatory domain is the | ||
251 | * result of an intersection between two regulatory domain | 290 | * result of an intersection between two regulatory domain |
252 | * structures */ | 291 | * structures |
292 | */ | ||
253 | if (alpha2[0] == '9' && alpha2[1] == '8') | 293 | if (alpha2[0] == '9' && alpha2[1] == '8') |
254 | return true; | 294 | return true; |
255 | return false; | 295 | return false; |
@@ -274,8 +314,10 @@ static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y) | |||
274 | return false; | 314 | return false; |
275 | } | 315 | } |
276 | 316 | ||
277 | static bool regdom_changed(const char *alpha2) | 317 | static bool regdom_changes(const char *alpha2) |
278 | { | 318 | { |
319 | assert_cfg80211_lock(); | ||
320 | |||
279 | if (!cfg80211_regdomain) | 321 | if (!cfg80211_regdomain) |
280 | return true; | 322 | return true; |
281 | if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) | 323 | if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) |
@@ -302,8 +344,10 @@ static bool country_ie_integrity_changes(u32 checksum) | |||
302 | return false; | 344 | return false; |
303 | } | 345 | } |
304 | 346 | ||
305 | /* This lets us keep regulatory code which is updated on a regulatory | 347 | /* |
306 | * basis in userspace. */ | 348 | * This lets us keep regulatory code which is updated on a regulatory |
349 | * basis in userspace. | ||
350 | */ | ||
307 | static int call_crda(const char *alpha2) | 351 | static int call_crda(const char *alpha2) |
308 | { | 352 | { |
309 | char country_env[9 + 2] = "COUNTRY="; | 353 | char country_env[9 + 2] = "COUNTRY="; |
@@ -414,10 +458,12 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
414 | #undef ONE_GHZ_IN_KHZ | 458 | #undef ONE_GHZ_IN_KHZ |
415 | } | 459 | } |
416 | 460 | ||
417 | /* Converts a country IE to a regulatory domain. A regulatory domain | 461 | /* |
462 | * Converts a country IE to a regulatory domain. A regulatory domain | ||
418 | * structure has a lot of information which the IE doesn't yet have, | 463 | * structure has a lot of information which the IE doesn't yet have, |
419 | * so for the other values we use upper max values as we will intersect | 464 | * so for the other values we use upper max values as we will intersect |
420 | * with our userspace regulatory agent to get lower bounds. */ | 465 | * with our userspace regulatory agent to get lower bounds. |
466 | */ | ||
421 | static struct ieee80211_regdomain *country_ie_2_rd( | 467 | static struct ieee80211_regdomain *country_ie_2_rd( |
422 | u8 *country_ie, | 468 | u8 *country_ie, |
423 | u8 country_ie_len, | 469 | u8 country_ie_len, |
@@ -462,9 +508,11 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
462 | 508 | ||
463 | *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8); | 509 | *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8); |
464 | 510 | ||
465 | /* We need to build a reg rule for each triplet, but first we must | 511 | /* |
512 | * We need to build a reg rule for each triplet, but first we must | ||
466 | * calculate the number of reg rules we will need. We will need one | 513 | * calculate the number of reg rules we will need. We will need one |
467 | * for each channel subband */ | 514 | * for each channel subband |
515 | */ | ||
468 | while (country_ie_len >= 3) { | 516 | while (country_ie_len >= 3) { |
469 | int end_channel = 0; | 517 | int end_channel = 0; |
470 | struct ieee80211_country_ie_triplet *triplet = | 518 | struct ieee80211_country_ie_triplet *triplet = |
@@ -502,9 +550,11 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
502 | if (cur_sub_max_channel < cur_channel) | 550 | if (cur_sub_max_channel < cur_channel) |
503 | return NULL; | 551 | return NULL; |
504 | 552 | ||
505 | /* Do not allow overlapping channels. Also channels | 553 | /* |
554 | * Do not allow overlapping channels. Also channels | ||
506 | * passed in each subband must be monotonically | 555 | * passed in each subband must be monotonically |
507 | * increasing */ | 556 | * increasing |
557 | */ | ||
508 | if (last_sub_max_channel) { | 558 | if (last_sub_max_channel) { |
509 | if (cur_channel <= last_sub_max_channel) | 559 | if (cur_channel <= last_sub_max_channel) |
510 | return NULL; | 560 | return NULL; |
@@ -512,10 +562,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
512 | return NULL; | 562 | return NULL; |
513 | } | 563 | } |
514 | 564 | ||
515 | /* When dot11RegulatoryClassesRequired is supported | 565 | /* |
566 | * When dot11RegulatoryClassesRequired is supported | ||
516 | * we can throw ext triplets as part of this soup, | 567 | * we can throw ext triplets as part of this soup, |
517 | * for now we don't care when those change as we | 568 | * for now we don't care when those change as we |
518 | * don't support them */ | 569 | * don't support them |
570 | */ | ||
519 | *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) | | 571 | *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) | |
520 | ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) | | 572 | ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) | |
521 | ((triplet->chans.max_power ^ cur_sub_max_channel) << 24); | 573 | ((triplet->chans.max_power ^ cur_sub_max_channel) << 24); |
@@ -526,8 +578,10 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
526 | country_ie_len -= 3; | 578 | country_ie_len -= 3; |
527 | num_rules++; | 579 | num_rules++; |
528 | 580 | ||
529 | /* Note: this is not a IEEE requirement but | 581 | /* |
530 | * simply a memory requirement */ | 582 | * Note: this is not a IEEE requirement but |
583 | * simply a memory requirement | ||
584 | */ | ||
531 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | 585 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) |
532 | return NULL; | 586 | return NULL; |
533 | } | 587 | } |
@@ -555,8 +609,10 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
555 | struct ieee80211_freq_range *freq_range = NULL; | 609 | struct ieee80211_freq_range *freq_range = NULL; |
556 | struct ieee80211_power_rule *power_rule = NULL; | 610 | struct ieee80211_power_rule *power_rule = NULL; |
557 | 611 | ||
558 | /* Must parse if dot11RegulatoryClassesRequired is true, | 612 | /* |
559 | * we don't support this yet */ | 613 | * Must parse if dot11RegulatoryClassesRequired is true, |
614 | * we don't support this yet | ||
615 | */ | ||
560 | if (triplet->ext.reg_extension_id >= | 616 | if (triplet->ext.reg_extension_id >= |
561 | IEEE80211_COUNTRY_EXTENSION_ID) { | 617 | IEEE80211_COUNTRY_EXTENSION_ID) { |
562 | country_ie += 3; | 618 | country_ie += 3; |
@@ -578,10 +634,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
578 | end_channel = triplet->chans.first_channel + | 634 | end_channel = triplet->chans.first_channel + |
579 | (4 * (triplet->chans.num_channels - 1)); | 635 | (4 * (triplet->chans.num_channels - 1)); |
580 | 636 | ||
581 | /* The +10 is since the regulatory domain expects | 637 | /* |
638 | * The +10 is since the regulatory domain expects | ||
582 | * the actual band edge, not the center of freq for | 639 | * the actual band edge, not the center of freq for |
583 | * its start and end freqs, assuming 20 MHz bandwidth on | 640 | * its start and end freqs, assuming 20 MHz bandwidth on |
584 | * the channels passed */ | 641 | * the channels passed |
642 | */ | ||
585 | freq_range->start_freq_khz = | 643 | freq_range->start_freq_khz = |
586 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( | 644 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( |
587 | triplet->chans.first_channel) - 10); | 645 | triplet->chans.first_channel) - 10); |
@@ -589,9 +647,11 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
589 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( | 647 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( |
590 | end_channel) + 10); | 648 | end_channel) + 10); |
591 | 649 | ||
592 | /* Large arbitrary values, we intersect later */ | 650 | /* |
593 | /* Increment this if we ever support >= 40 MHz channels | 651 | * These are large arbitrary values we use to intersect later. |
594 | * in IEEE 802.11 */ | 652 | * Increment this if we ever support >= 40 MHz channels |
653 | * in IEEE 802.11 | ||
654 | */ | ||
595 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); | 655 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); |
596 | power_rule->max_antenna_gain = DBI_TO_MBI(100); | 656 | power_rule->max_antenna_gain = DBI_TO_MBI(100); |
597 | power_rule->max_eirp = DBM_TO_MBM(100); | 657 | power_rule->max_eirp = DBM_TO_MBM(100); |
@@ -607,8 +667,10 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
607 | } | 667 | } |
608 | 668 | ||
609 | 669 | ||
610 | /* Helper for regdom_intersect(), this does the real | 670 | /* |
611 | * mathematical intersection fun */ | 671 | * Helper for regdom_intersect(), this does the real |
672 | * mathematical intersection fun | ||
673 | */ | ||
612 | static int reg_rules_intersect( | 674 | static int reg_rules_intersect( |
613 | const struct ieee80211_reg_rule *rule1, | 675 | const struct ieee80211_reg_rule *rule1, |
614 | const struct ieee80211_reg_rule *rule2, | 676 | const struct ieee80211_reg_rule *rule2, |
@@ -686,11 +748,13 @@ static struct ieee80211_regdomain *regdom_intersect( | |||
686 | if (!rd1 || !rd2) | 748 | if (!rd1 || !rd2) |
687 | return NULL; | 749 | return NULL; |
688 | 750 | ||
689 | /* First we get a count of the rules we'll need, then we actually | 751 | /* |
752 | * First we get a count of the rules we'll need, then we actually | ||
690 | * build them. This is to so we can malloc() and free() a | 753 | * build them. This is to so we can malloc() and free() a |
691 | * regdomain once. The reason we use reg_rules_intersect() here | 754 | * regdomain once. The reason we use reg_rules_intersect() here |
692 | * is it will return -EINVAL if the rule computed makes no sense. | 755 | * is it will return -EINVAL if the rule computed makes no sense. |
693 | * All rules that do check out OK are valid. */ | 756 | * All rules that do check out OK are valid. |
757 | */ | ||
694 | 758 | ||
695 | for (x = 0; x < rd1->n_reg_rules; x++) { | 759 | for (x = 0; x < rd1->n_reg_rules; x++) { |
696 | rule1 = &rd1->reg_rules[x]; | 760 | rule1 = &rd1->reg_rules[x]; |
@@ -718,14 +782,18 @@ static struct ieee80211_regdomain *regdom_intersect( | |||
718 | rule1 = &rd1->reg_rules[x]; | 782 | rule1 = &rd1->reg_rules[x]; |
719 | for (y = 0; y < rd2->n_reg_rules; y++) { | 783 | for (y = 0; y < rd2->n_reg_rules; y++) { |
720 | rule2 = &rd2->reg_rules[y]; | 784 | rule2 = &rd2->reg_rules[y]; |
721 | /* This time around instead of using the stack lets | 785 | /* |
786 | * This time around instead of using the stack lets | ||
722 | * write to the target rule directly saving ourselves | 787 | * write to the target rule directly saving ourselves |
723 | * a memcpy() */ | 788 | * a memcpy() |
789 | */ | ||
724 | intersected_rule = &rd->reg_rules[rule_idx]; | 790 | intersected_rule = &rd->reg_rules[rule_idx]; |
725 | r = reg_rules_intersect(rule1, rule2, | 791 | r = reg_rules_intersect(rule1, rule2, |
726 | intersected_rule); | 792 | intersected_rule); |
727 | /* No need to memset here the intersected rule here as | 793 | /* |
728 | * we're not using the stack anymore */ | 794 | * No need to memset here the intersected rule here as |
795 | * we're not using the stack anymore | ||
796 | */ | ||
729 | if (r) | 797 | if (r) |
730 | continue; | 798 | continue; |
731 | rule_idx++; | 799 | rule_idx++; |
@@ -744,8 +812,10 @@ static struct ieee80211_regdomain *regdom_intersect( | |||
744 | return rd; | 812 | return rd; |
745 | } | 813 | } |
746 | 814 | ||
747 | /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may | 815 | /* |
748 | * want to just have the channel structure use these */ | 816 | * XXX: add support for the rest of enum nl80211_reg_rule_flags, we may |
817 | * want to just have the channel structure use these | ||
818 | */ | ||
749 | static u32 map_regdom_flags(u32 rd_flags) | 819 | static u32 map_regdom_flags(u32 rd_flags) |
750 | { | 820 | { |
751 | u32 channel_flags = 0; | 821 | u32 channel_flags = 0; |
@@ -771,8 +841,10 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
771 | 841 | ||
772 | regd = custom_regd ? custom_regd : cfg80211_regdomain; | 842 | regd = custom_regd ? custom_regd : cfg80211_regdomain; |
773 | 843 | ||
774 | /* Follow the driver's regulatory domain, if present, unless a country | 844 | /* |
775 | * IE has been processed or a user wants to help complaince further */ | 845 | * Follow the driver's regulatory domain, if present, unless a country |
846 | * IE has been processed or a user wants to help complaince further | ||
847 | */ | ||
776 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE && | 848 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE && |
777 | last_request->initiator != REGDOM_SET_BY_USER && | 849 | last_request->initiator != REGDOM_SET_BY_USER && |
778 | wiphy->regd) | 850 | wiphy->regd) |
@@ -790,9 +862,11 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
790 | fr = &rr->freq_range; | 862 | fr = &rr->freq_range; |
791 | pr = &rr->power_rule; | 863 | pr = &rr->power_rule; |
792 | 864 | ||
793 | /* We only need to know if one frequency rule was | 865 | /* |
866 | * We only need to know if one frequency rule was | ||
794 | * was in center_freq's band, that's enough, so lets | 867 | * was in center_freq's band, that's enough, so lets |
795 | * not overwrite it once found */ | 868 | * not overwrite it once found |
869 | */ | ||
796 | if (!band_rule_found) | 870 | if (!band_rule_found) |
797 | band_rule_found = freq_in_rule_band(fr, center_freq); | 871 | band_rule_found = freq_in_rule_band(fr, center_freq); |
798 | 872 | ||
@@ -829,6 +903,11 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
829 | const struct ieee80211_power_rule *power_rule = NULL; | 903 | const struct ieee80211_power_rule *power_rule = NULL; |
830 | struct ieee80211_supported_band *sband; | 904 | struct ieee80211_supported_band *sband; |
831 | struct ieee80211_channel *chan; | 905 | struct ieee80211_channel *chan; |
906 | struct wiphy *request_wiphy = NULL; | ||
907 | |||
908 | assert_cfg80211_lock(); | ||
909 | |||
910 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
832 | 911 | ||
833 | sband = wiphy->bands[band]; | 912 | sband = wiphy->bands[band]; |
834 | BUG_ON(chan_idx >= sband->n_channels); | 913 | BUG_ON(chan_idx >= sband->n_channels); |
@@ -840,7 +919,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
840 | &max_bandwidth, ®_rule); | 919 | &max_bandwidth, ®_rule); |
841 | 920 | ||
842 | if (r) { | 921 | if (r) { |
843 | /* This means no regulatory rule was found in the country IE | 922 | /* |
923 | * This means no regulatory rule was found in the country IE | ||
844 | * with a frequency range on the center_freq's band, since | 924 | * with a frequency range on the center_freq's band, since |
845 | * IEEE-802.11 allows for a country IE to have a subset of the | 925 | * IEEE-802.11 allows for a country IE to have a subset of the |
846 | * regulatory information provided in a country we ignore | 926 | * regulatory information provided in a country we ignore |
@@ -859,8 +939,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
859 | chan->center_freq, wiphy_name(wiphy)); | 939 | chan->center_freq, wiphy_name(wiphy)); |
860 | #endif | 940 | #endif |
861 | } else { | 941 | } else { |
862 | /* In this case we know the country IE has at least one reg rule | 942 | /* |
863 | * for the band so we respect its band definitions */ | 943 | * In this case we know the country IE has at least one reg rule |
944 | * for the band so we respect its band definitions | ||
945 | */ | ||
864 | #ifdef CONFIG_CFG80211_REG_DEBUG | 946 | #ifdef CONFIG_CFG80211_REG_DEBUG |
865 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) | 947 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) |
866 | printk(KERN_DEBUG "cfg80211: Disabling " | 948 | printk(KERN_DEBUG "cfg80211: Disabling " |
@@ -877,11 +959,13 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
877 | power_rule = ®_rule->power_rule; | 959 | power_rule = ®_rule->power_rule; |
878 | 960 | ||
879 | if (last_request->initiator == REGDOM_SET_BY_DRIVER && | 961 | if (last_request->initiator == REGDOM_SET_BY_DRIVER && |
880 | last_request->wiphy && last_request->wiphy == wiphy && | 962 | request_wiphy && request_wiphy == wiphy && |
881 | last_request->wiphy->strict_regulatory) { | 963 | request_wiphy->strict_regulatory) { |
882 | /* This gaurantees the driver's requested regulatory domain | 964 | /* |
965 | * This gaurantees the driver's requested regulatory domain | ||
883 | * will always be used as a base for further regulatory | 966 | * will always be used as a base for further regulatory |
884 | * settings */ | 967 | * settings |
968 | */ | ||
885 | chan->flags = chan->orig_flags = | 969 | chan->flags = chan->orig_flags = |
886 | map_regdom_flags(reg_rule->flags); | 970 | map_regdom_flags(reg_rule->flags); |
887 | chan->max_antenna_gain = chan->orig_mag = | 971 | chan->max_antenna_gain = chan->orig_mag = |
@@ -922,8 +1006,10 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby) | |||
922 | if (setby == REGDOM_SET_BY_CORE && | 1006 | if (setby == REGDOM_SET_BY_CORE && |
923 | wiphy->custom_regulatory) | 1007 | wiphy->custom_regulatory) |
924 | return true; | 1008 | return true; |
925 | /* wiphy->regd will be set once the device has its own | 1009 | /* |
926 | * desired regulatory domain set */ | 1010 | * wiphy->regd will be set once the device has its own |
1011 | * desired regulatory domain set | ||
1012 | */ | ||
927 | if (wiphy->strict_regulatory && !wiphy->regd && | 1013 | if (wiphy->strict_regulatory && !wiphy->regd && |
928 | !is_world_regdom(last_request->alpha2)) | 1014 | !is_world_regdom(last_request->alpha2)) |
929 | return true; | 1015 | return true; |
@@ -938,16 +1024,120 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby) | |||
938 | wiphy_update_regulatory(&drv->wiphy, setby); | 1024 | wiphy_update_regulatory(&drv->wiphy, setby); |
939 | } | 1025 | } |
940 | 1026 | ||
1027 | static void handle_reg_beacon(struct wiphy *wiphy, | ||
1028 | unsigned int chan_idx, | ||
1029 | struct reg_beacon *reg_beacon) | ||
1030 | { | ||
1031 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
1032 | #define REG_DEBUG_BEACON_FLAG(desc) \ | ||
1033 | printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \ | ||
1034 | "frequency: %d MHz (Ch %d) on %s\n", \ | ||
1035 | reg_beacon->chan.center_freq, \ | ||
1036 | ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \ | ||
1037 | wiphy_name(wiphy)); | ||
1038 | #else | ||
1039 | #define REG_DEBUG_BEACON_FLAG(desc) do {} while (0) | ||
1040 | #endif | ||
1041 | struct ieee80211_supported_band *sband; | ||
1042 | struct ieee80211_channel *chan; | ||
1043 | |||
1044 | assert_cfg80211_lock(); | ||
1045 | |||
1046 | sband = wiphy->bands[reg_beacon->chan.band]; | ||
1047 | chan = &sband->channels[chan_idx]; | ||
1048 | |||
1049 | if (likely(chan->center_freq != reg_beacon->chan.center_freq)) | ||
1050 | return; | ||
1051 | |||
1052 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { | ||
1053 | chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; | ||
1054 | REG_DEBUG_BEACON_FLAG("active scanning"); | ||
1055 | } | ||
1056 | |||
1057 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) { | ||
1058 | chan->flags &= ~IEEE80211_CHAN_NO_IBSS; | ||
1059 | REG_DEBUG_BEACON_FLAG("beaconing"); | ||
1060 | } | ||
1061 | |||
1062 | chan->beacon_found = true; | ||
1063 | #undef REG_DEBUG_BEACON_FLAG | ||
1064 | } | ||
1065 | |||
1066 | /* | ||
1067 | * Called when a scan on a wiphy finds a beacon on | ||
1068 | * new channel | ||
1069 | */ | ||
1070 | static void wiphy_update_new_beacon(struct wiphy *wiphy, | ||
1071 | struct reg_beacon *reg_beacon) | ||
1072 | { | ||
1073 | unsigned int i; | ||
1074 | struct ieee80211_supported_band *sband; | ||
1075 | |||
1076 | assert_cfg80211_lock(); | ||
1077 | |||
1078 | if (!wiphy->bands[reg_beacon->chan.band]) | ||
1079 | return; | ||
1080 | |||
1081 | sband = wiphy->bands[reg_beacon->chan.band]; | ||
1082 | |||
1083 | for (i = 0; i < sband->n_channels; i++) | ||
1084 | handle_reg_beacon(wiphy, i, reg_beacon); | ||
1085 | } | ||
1086 | |||
1087 | /* | ||
1088 | * Called upon reg changes or a new wiphy is added | ||
1089 | */ | ||
1090 | static void wiphy_update_beacon_reg(struct wiphy *wiphy) | ||
1091 | { | ||
1092 | unsigned int i; | ||
1093 | struct ieee80211_supported_band *sband; | ||
1094 | struct reg_beacon *reg_beacon; | ||
1095 | |||
1096 | assert_cfg80211_lock(); | ||
1097 | |||
1098 | if (list_empty(®_beacon_list)) | ||
1099 | return; | ||
1100 | |||
1101 | list_for_each_entry(reg_beacon, ®_beacon_list, list) { | ||
1102 | if (!wiphy->bands[reg_beacon->chan.band]) | ||
1103 | continue; | ||
1104 | sband = wiphy->bands[reg_beacon->chan.band]; | ||
1105 | for (i = 0; i < sband->n_channels; i++) | ||
1106 | handle_reg_beacon(wiphy, i, reg_beacon); | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | static bool reg_is_world_roaming(struct wiphy *wiphy) | ||
1111 | { | ||
1112 | if (is_world_regdom(cfg80211_regdomain->alpha2) || | ||
1113 | (wiphy->regd && is_world_regdom(wiphy->regd->alpha2))) | ||
1114 | return true; | ||
1115 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE && | ||
1116 | wiphy->custom_regulatory) | ||
1117 | return true; | ||
1118 | return false; | ||
1119 | } | ||
1120 | |||
1121 | /* Reap the advantages of previously found beacons */ | ||
1122 | static void reg_process_beacons(struct wiphy *wiphy) | ||
1123 | { | ||
1124 | if (!reg_is_world_roaming(wiphy)) | ||
1125 | return; | ||
1126 | wiphy_update_beacon_reg(wiphy); | ||
1127 | } | ||
1128 | |||
941 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) | 1129 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) |
942 | { | 1130 | { |
943 | enum ieee80211_band band; | 1131 | enum ieee80211_band band; |
944 | 1132 | ||
945 | if (ignore_reg_update(wiphy, setby)) | 1133 | if (ignore_reg_update(wiphy, setby)) |
946 | return; | 1134 | goto out; |
947 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1135 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
948 | if (wiphy->bands[band]) | 1136 | if (wiphy->bands[band]) |
949 | handle_band(wiphy, band); | 1137 | handle_band(wiphy, band); |
950 | } | 1138 | } |
1139 | out: | ||
1140 | reg_process_beacons(wiphy); | ||
951 | if (wiphy->reg_notifier) | 1141 | if (wiphy->reg_notifier) |
952 | wiphy->reg_notifier(wiphy, last_request); | 1142 | wiphy->reg_notifier(wiphy, last_request); |
953 | } | 1143 | } |
@@ -1033,48 +1223,53 @@ static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, | |||
1033 | return 0; | 1223 | return 0; |
1034 | } | 1224 | } |
1035 | 1225 | ||
1036 | /* Return value which can be used by ignore_request() to indicate | 1226 | /* |
1037 | * it has been determined we should intersect two regulatory domains */ | 1227 | * Return value which can be used by ignore_request() to indicate |
1228 | * it has been determined we should intersect two regulatory domains | ||
1229 | */ | ||
1038 | #define REG_INTERSECT 1 | 1230 | #define REG_INTERSECT 1 |
1039 | 1231 | ||
1040 | /* This has the logic which determines when a new request | 1232 | /* This has the logic which determines when a new request |
1041 | * should be ignored. */ | 1233 | * should be ignored. */ |
1042 | static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | 1234 | static int ignore_request(struct wiphy *wiphy, |
1043 | const char *alpha2) | 1235 | struct regulatory_request *pending_request) |
1044 | { | 1236 | { |
1237 | struct wiphy *last_wiphy = NULL; | ||
1238 | |||
1239 | assert_cfg80211_lock(); | ||
1240 | |||
1045 | /* All initial requests are respected */ | 1241 | /* All initial requests are respected */ |
1046 | if (!last_request) | 1242 | if (!last_request) |
1047 | return 0; | 1243 | return 0; |
1048 | 1244 | ||
1049 | switch (set_by) { | 1245 | switch (pending_request->initiator) { |
1050 | case REGDOM_SET_BY_INIT: | 1246 | case REGDOM_SET_BY_INIT: |
1051 | return -EINVAL; | 1247 | return -EINVAL; |
1052 | case REGDOM_SET_BY_CORE: | 1248 | case REGDOM_SET_BY_CORE: |
1053 | /* | 1249 | return -EINVAL; |
1054 | * Always respect new wireless core hints, should only happen | ||
1055 | * when updating the world regulatory domain at init. | ||
1056 | */ | ||
1057 | return 0; | ||
1058 | case REGDOM_SET_BY_COUNTRY_IE: | 1250 | case REGDOM_SET_BY_COUNTRY_IE: |
1059 | if (unlikely(!is_an_alpha2(alpha2))) | 1251 | |
1252 | last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
1253 | |||
1254 | if (unlikely(!is_an_alpha2(pending_request->alpha2))) | ||
1060 | return -EINVAL; | 1255 | return -EINVAL; |
1061 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { | 1256 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { |
1062 | if (last_request->wiphy != wiphy) { | 1257 | if (last_wiphy != wiphy) { |
1063 | /* | 1258 | /* |
1064 | * Two cards with two APs claiming different | 1259 | * Two cards with two APs claiming different |
1065 | * different Country IE alpha2s. We could | 1260 | * different Country IE alpha2s. We could |
1066 | * intersect them, but that seems unlikely | 1261 | * intersect them, but that seems unlikely |
1067 | * to be correct. Reject second one for now. | 1262 | * to be correct. Reject second one for now. |
1068 | */ | 1263 | */ |
1069 | if (!alpha2_equal(alpha2, | 1264 | if (regdom_changes(pending_request->alpha2)) |
1070 | cfg80211_regdomain->alpha2)) | ||
1071 | return -EOPNOTSUPP; | 1265 | return -EOPNOTSUPP; |
1072 | return -EALREADY; | 1266 | return -EALREADY; |
1073 | } | 1267 | } |
1074 | /* Two consecutive Country IE hints on the same wiphy. | 1268 | /* |
1075 | * This should be picked up early by the driver/stack */ | 1269 | * Two consecutive Country IE hints on the same wiphy. |
1076 | if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2, | 1270 | * This should be picked up early by the driver/stack |
1077 | alpha2))) | 1271 | */ |
1272 | if (WARN_ON(regdom_changes(pending_request->alpha2))) | ||
1078 | return 0; | 1273 | return 0; |
1079 | return -EALREADY; | 1274 | return -EALREADY; |
1080 | } | 1275 | } |
@@ -1083,31 +1278,44 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1083 | if (last_request->initiator == REGDOM_SET_BY_CORE) { | 1278 | if (last_request->initiator == REGDOM_SET_BY_CORE) { |
1084 | if (is_old_static_regdom(cfg80211_regdomain)) | 1279 | if (is_old_static_regdom(cfg80211_regdomain)) |
1085 | return 0; | 1280 | return 0; |
1086 | if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) | 1281 | if (regdom_changes(pending_request->alpha2)) |
1087 | return 0; | 1282 | return 0; |
1088 | return -EALREADY; | 1283 | return -EALREADY; |
1089 | } | 1284 | } |
1285 | |||
1286 | /* | ||
1287 | * This would happen if you unplug and plug your card | ||
1288 | * back in or if you add a new device for which the previously | ||
1289 | * loaded card also agrees on the regulatory domain. | ||
1290 | */ | ||
1291 | if (last_request->initiator == REGDOM_SET_BY_DRIVER && | ||
1292 | !regdom_changes(pending_request->alpha2)) | ||
1293 | return -EALREADY; | ||
1294 | |||
1090 | return REG_INTERSECT; | 1295 | return REG_INTERSECT; |
1091 | case REGDOM_SET_BY_USER: | 1296 | case REGDOM_SET_BY_USER: |
1092 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) | 1297 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) |
1093 | return REG_INTERSECT; | 1298 | return REG_INTERSECT; |
1094 | /* If the user knows better the user should set the regdom | 1299 | /* |
1095 | * to their country before the IE is picked up */ | 1300 | * If the user knows better the user should set the regdom |
1301 | * to their country before the IE is picked up | ||
1302 | */ | ||
1096 | if (last_request->initiator == REGDOM_SET_BY_USER && | 1303 | if (last_request->initiator == REGDOM_SET_BY_USER && |
1097 | last_request->intersect) | 1304 | last_request->intersect) |
1098 | return -EOPNOTSUPP; | 1305 | return -EOPNOTSUPP; |
1099 | /* Process user requests only after previous user/driver/core | 1306 | /* |
1100 | * requests have been processed */ | 1307 | * Process user requests only after previous user/driver/core |
1308 | * requests have been processed | ||
1309 | */ | ||
1101 | if (last_request->initiator == REGDOM_SET_BY_CORE || | 1310 | if (last_request->initiator == REGDOM_SET_BY_CORE || |
1102 | last_request->initiator == REGDOM_SET_BY_DRIVER || | 1311 | last_request->initiator == REGDOM_SET_BY_DRIVER || |
1103 | last_request->initiator == REGDOM_SET_BY_USER) { | 1312 | last_request->initiator == REGDOM_SET_BY_USER) { |
1104 | if (!alpha2_equal(last_request->alpha2, | 1313 | if (regdom_changes(last_request->alpha2)) |
1105 | cfg80211_regdomain->alpha2)) | ||
1106 | return -EAGAIN; | 1314 | return -EAGAIN; |
1107 | } | 1315 | } |
1108 | 1316 | ||
1109 | if (!is_old_static_regdom(cfg80211_regdomain) && | 1317 | if (!is_old_static_regdom(cfg80211_regdomain) && |
1110 | alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) | 1318 | !regdom_changes(pending_request->alpha2)) |
1111 | return -EALREADY; | 1319 | return -EALREADY; |
1112 | 1320 | ||
1113 | return 0; | 1321 | return 0; |
@@ -1116,55 +1324,66 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1116 | return -EINVAL; | 1324 | return -EINVAL; |
1117 | } | 1325 | } |
1118 | 1326 | ||
1119 | /* Caller must hold &cfg80211_drv_mutex */ | 1327 | /** |
1120 | int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | 1328 | * __regulatory_hint - hint to the wireless core a regulatory domain |
1121 | const char *alpha2, | 1329 | * @wiphy: if the hint comes from country information from an AP, this |
1122 | u32 country_ie_checksum, | 1330 | * is required to be set to the wiphy that received the information |
1123 | enum environment_cap env) | 1331 | * @pending_request: the regulatory request currently being processed |
1332 | * | ||
1333 | * The Wireless subsystem can use this function to hint to the wireless core | ||
1334 | * what it believes should be the current regulatory domain. | ||
1335 | * | ||
1336 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had | ||
1337 | * already been set or other standard error codes. | ||
1338 | * | ||
1339 | * Caller must hold &cfg80211_mutex | ||
1340 | */ | ||
1341 | static int __regulatory_hint(struct wiphy *wiphy, | ||
1342 | struct regulatory_request *pending_request) | ||
1124 | { | 1343 | { |
1125 | struct regulatory_request *request; | ||
1126 | bool intersect = false; | 1344 | bool intersect = false; |
1127 | int r = 0; | 1345 | int r = 0; |
1128 | 1346 | ||
1129 | r = ignore_request(wiphy, set_by, alpha2); | 1347 | assert_cfg80211_lock(); |
1348 | |||
1349 | r = ignore_request(wiphy, pending_request); | ||
1130 | 1350 | ||
1131 | if (r == REG_INTERSECT) { | 1351 | if (r == REG_INTERSECT) { |
1132 | if (set_by == REGDOM_SET_BY_DRIVER) { | 1352 | if (pending_request->initiator == REGDOM_SET_BY_DRIVER) { |
1133 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); | 1353 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); |
1134 | if (r) | 1354 | if (r) { |
1355 | kfree(pending_request); | ||
1135 | return r; | 1356 | return r; |
1357 | } | ||
1136 | } | 1358 | } |
1137 | intersect = true; | 1359 | intersect = true; |
1138 | } else if (r) { | 1360 | } else if (r) { |
1139 | /* If the regulatory domain being requested by the | 1361 | /* |
1362 | * If the regulatory domain being requested by the | ||
1140 | * driver has already been set just copy it to the | 1363 | * driver has already been set just copy it to the |
1141 | * wiphy */ | 1364 | * wiphy |
1142 | if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) { | 1365 | */ |
1366 | if (r == -EALREADY && | ||
1367 | pending_request->initiator == REGDOM_SET_BY_DRIVER) { | ||
1143 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); | 1368 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); |
1144 | if (r) | 1369 | if (r) { |
1370 | kfree(pending_request); | ||
1145 | return r; | 1371 | return r; |
1372 | } | ||
1146 | r = -EALREADY; | 1373 | r = -EALREADY; |
1147 | goto new_request; | 1374 | goto new_request; |
1148 | } | 1375 | } |
1376 | kfree(pending_request); | ||
1149 | return r; | 1377 | return r; |
1150 | } | 1378 | } |
1151 | 1379 | ||
1152 | new_request: | 1380 | new_request: |
1153 | request = kzalloc(sizeof(struct regulatory_request), | 1381 | kfree(last_request); |
1154 | GFP_KERNEL); | ||
1155 | if (!request) | ||
1156 | return -ENOMEM; | ||
1157 | 1382 | ||
1158 | request->alpha2[0] = alpha2[0]; | 1383 | last_request = pending_request; |
1159 | request->alpha2[1] = alpha2[1]; | 1384 | last_request->intersect = intersect; |
1160 | request->initiator = set_by; | ||
1161 | request->wiphy = wiphy; | ||
1162 | request->intersect = intersect; | ||
1163 | request->country_ie_checksum = country_ie_checksum; | ||
1164 | request->country_ie_env = env; | ||
1165 | 1385 | ||
1166 | kfree(last_request); | 1386 | pending_request = NULL; |
1167 | last_request = request; | ||
1168 | 1387 | ||
1169 | /* When r == REG_INTERSECT we do need to call CRDA */ | 1388 | /* When r == REG_INTERSECT we do need to call CRDA */ |
1170 | if (r < 0) | 1389 | if (r < 0) |
@@ -1180,34 +1399,194 @@ new_request: | |||
1180 | * | 1399 | * |
1181 | * to intersect with the static rd | 1400 | * to intersect with the static rd |
1182 | */ | 1401 | */ |
1183 | return call_crda(alpha2); | 1402 | return call_crda(last_request->alpha2); |
1184 | } | 1403 | } |
1185 | 1404 | ||
1186 | void regulatory_hint(struct wiphy *wiphy, const char *alpha2) | 1405 | /* This currently only processes user and driver regulatory hints */ |
1406 | static void reg_process_hint(struct regulatory_request *reg_request) | ||
1187 | { | 1407 | { |
1188 | int r; | 1408 | int r = 0; |
1189 | BUG_ON(!alpha2); | 1409 | struct wiphy *wiphy = NULL; |
1410 | |||
1411 | BUG_ON(!reg_request->alpha2); | ||
1412 | |||
1413 | mutex_lock(&cfg80211_mutex); | ||
1414 | |||
1415 | if (wiphy_idx_valid(reg_request->wiphy_idx)) | ||
1416 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | ||
1417 | |||
1418 | if (reg_request->initiator == REGDOM_SET_BY_DRIVER && | ||
1419 | !wiphy) { | ||
1420 | kfree(reg_request); | ||
1421 | goto out; | ||
1422 | } | ||
1190 | 1423 | ||
1191 | mutex_lock(&cfg80211_drv_mutex); | 1424 | r = __regulatory_hint(wiphy, reg_request); |
1192 | r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, | ||
1193 | alpha2, 0, ENVIRON_ANY); | ||
1194 | /* This is required so that the orig_* parameters are saved */ | 1425 | /* This is required so that the orig_* parameters are saved */ |
1195 | if (r == -EALREADY && wiphy->strict_regulatory) | 1426 | if (r == -EALREADY && wiphy && wiphy->strict_regulatory) |
1196 | wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER); | 1427 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
1197 | mutex_unlock(&cfg80211_drv_mutex); | 1428 | out: |
1429 | mutex_unlock(&cfg80211_mutex); | ||
1430 | } | ||
1431 | |||
1432 | /* Processes regulatory hints, this is all the REGDOM_SET_BY_* */ | ||
1433 | static void reg_process_pending_hints(void) | ||
1434 | { | ||
1435 | struct regulatory_request *reg_request; | ||
1436 | |||
1437 | spin_lock(®_requests_lock); | ||
1438 | while (!list_empty(®_requests_list)) { | ||
1439 | reg_request = list_first_entry(®_requests_list, | ||
1440 | struct regulatory_request, | ||
1441 | list); | ||
1442 | list_del_init(®_request->list); | ||
1443 | |||
1444 | spin_unlock(®_requests_lock); | ||
1445 | reg_process_hint(reg_request); | ||
1446 | spin_lock(®_requests_lock); | ||
1447 | } | ||
1448 | spin_unlock(®_requests_lock); | ||
1449 | } | ||
1450 | |||
1451 | /* Processes beacon hints -- this has nothing to do with country IEs */ | ||
1452 | static void reg_process_pending_beacon_hints(void) | ||
1453 | { | ||
1454 | struct cfg80211_registered_device *drv; | ||
1455 | struct reg_beacon *pending_beacon, *tmp; | ||
1456 | |||
1457 | mutex_lock(&cfg80211_mutex); | ||
1458 | |||
1459 | /* This goes through the _pending_ beacon list */ | ||
1460 | spin_lock_bh(®_pending_beacons_lock); | ||
1461 | |||
1462 | if (list_empty(®_pending_beacons)) { | ||
1463 | spin_unlock_bh(®_pending_beacons_lock); | ||
1464 | goto out; | ||
1465 | } | ||
1466 | |||
1467 | list_for_each_entry_safe(pending_beacon, tmp, | ||
1468 | ®_pending_beacons, list) { | ||
1469 | |||
1470 | list_del_init(&pending_beacon->list); | ||
1471 | |||
1472 | /* Applies the beacon hint to current wiphys */ | ||
1473 | list_for_each_entry(drv, &cfg80211_drv_list, list) | ||
1474 | wiphy_update_new_beacon(&drv->wiphy, pending_beacon); | ||
1475 | |||
1476 | /* Remembers the beacon hint for new wiphys or reg changes */ | ||
1477 | list_add_tail(&pending_beacon->list, ®_beacon_list); | ||
1478 | } | ||
1479 | |||
1480 | spin_unlock_bh(®_pending_beacons_lock); | ||
1481 | out: | ||
1482 | mutex_unlock(&cfg80211_mutex); | ||
1483 | } | ||
1484 | |||
1485 | static void reg_todo(struct work_struct *work) | ||
1486 | { | ||
1487 | reg_process_pending_hints(); | ||
1488 | reg_process_pending_beacon_hints(); | ||
1489 | } | ||
1490 | |||
1491 | static DECLARE_WORK(reg_work, reg_todo); | ||
1492 | |||
1493 | static void queue_regulatory_request(struct regulatory_request *request) | ||
1494 | { | ||
1495 | spin_lock(®_requests_lock); | ||
1496 | list_add_tail(&request->list, ®_requests_list); | ||
1497 | spin_unlock(®_requests_lock); | ||
1498 | |||
1499 | schedule_work(®_work); | ||
1500 | } | ||
1501 | |||
1502 | /* Core regulatory hint -- happens once during cfg80211_init() */ | ||
1503 | static int regulatory_hint_core(const char *alpha2) | ||
1504 | { | ||
1505 | struct regulatory_request *request; | ||
1506 | |||
1507 | BUG_ON(last_request); | ||
1508 | |||
1509 | request = kzalloc(sizeof(struct regulatory_request), | ||
1510 | GFP_KERNEL); | ||
1511 | if (!request) | ||
1512 | return -ENOMEM; | ||
1513 | |||
1514 | request->alpha2[0] = alpha2[0]; | ||
1515 | request->alpha2[1] = alpha2[1]; | ||
1516 | request->initiator = REGDOM_SET_BY_CORE; | ||
1517 | |||
1518 | queue_regulatory_request(request); | ||
1519 | |||
1520 | return 0; | ||
1521 | } | ||
1522 | |||
1523 | /* User hints */ | ||
1524 | int regulatory_hint_user(const char *alpha2) | ||
1525 | { | ||
1526 | struct regulatory_request *request; | ||
1527 | |||
1528 | BUG_ON(!alpha2); | ||
1529 | |||
1530 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | ||
1531 | if (!request) | ||
1532 | return -ENOMEM; | ||
1533 | |||
1534 | request->wiphy_idx = WIPHY_IDX_STALE; | ||
1535 | request->alpha2[0] = alpha2[0]; | ||
1536 | request->alpha2[1] = alpha2[1]; | ||
1537 | request->initiator = REGDOM_SET_BY_USER, | ||
1538 | |||
1539 | queue_regulatory_request(request); | ||
1540 | |||
1541 | return 0; | ||
1542 | } | ||
1543 | |||
1544 | /* Driver hints */ | ||
1545 | int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | ||
1546 | { | ||
1547 | struct regulatory_request *request; | ||
1548 | |||
1549 | BUG_ON(!alpha2); | ||
1550 | BUG_ON(!wiphy); | ||
1551 | |||
1552 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | ||
1553 | if (!request) | ||
1554 | return -ENOMEM; | ||
1555 | |||
1556 | request->wiphy_idx = get_wiphy_idx(wiphy); | ||
1557 | |||
1558 | /* Must have registered wiphy first */ | ||
1559 | BUG_ON(!wiphy_idx_valid(request->wiphy_idx)); | ||
1560 | |||
1561 | request->alpha2[0] = alpha2[0]; | ||
1562 | request->alpha2[1] = alpha2[1]; | ||
1563 | request->initiator = REGDOM_SET_BY_DRIVER; | ||
1564 | |||
1565 | queue_regulatory_request(request); | ||
1566 | |||
1567 | return 0; | ||
1198 | } | 1568 | } |
1199 | EXPORT_SYMBOL(regulatory_hint); | 1569 | EXPORT_SYMBOL(regulatory_hint); |
1200 | 1570 | ||
1201 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, | 1571 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, |
1202 | u32 country_ie_checksum) | 1572 | u32 country_ie_checksum) |
1203 | { | 1573 | { |
1204 | if (!last_request->wiphy) | 1574 | struct wiphy *request_wiphy; |
1575 | |||
1576 | assert_cfg80211_lock(); | ||
1577 | |||
1578 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
1579 | |||
1580 | if (!request_wiphy) | ||
1205 | return false; | 1581 | return false; |
1206 | if (likely(last_request->wiphy != wiphy)) | 1582 | |
1583 | if (likely(request_wiphy != wiphy)) | ||
1207 | return !country_ie_integrity_changes(country_ie_checksum); | 1584 | return !country_ie_integrity_changes(country_ie_checksum); |
1208 | /* We should not have let these through at this point, they | 1585 | /* |
1586 | * We should not have let these through at this point, they | ||
1209 | * should have been picked up earlier by the first alpha2 check | 1587 | * should have been picked up earlier by the first alpha2 check |
1210 | * on the device */ | 1588 | * on the device |
1589 | */ | ||
1211 | if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) | 1590 | if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) |
1212 | return true; | 1591 | return true; |
1213 | return false; | 1592 | return false; |
@@ -1221,11 +1600,14 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1221 | char alpha2[2]; | 1600 | char alpha2[2]; |
1222 | u32 checksum = 0; | 1601 | u32 checksum = 0; |
1223 | enum environment_cap env = ENVIRON_ANY; | 1602 | enum environment_cap env = ENVIRON_ANY; |
1603 | struct regulatory_request *request; | ||
1224 | 1604 | ||
1225 | if (!last_request) | 1605 | mutex_lock(&cfg80211_mutex); |
1226 | return; | ||
1227 | 1606 | ||
1228 | mutex_lock(&cfg80211_drv_mutex); | 1607 | if (unlikely(!last_request)) { |
1608 | mutex_unlock(&cfg80211_mutex); | ||
1609 | return; | ||
1610 | } | ||
1229 | 1611 | ||
1230 | /* IE len must be evenly divisible by 2 */ | 1612 | /* IE len must be evenly divisible by 2 */ |
1231 | if (country_ie_len & 0x01) | 1613 | if (country_ie_len & 0x01) |
@@ -1234,9 +1616,11 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1234 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 1616 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
1235 | goto out; | 1617 | goto out; |
1236 | 1618 | ||
1237 | /* Pending country IE processing, this can happen after we | 1619 | /* |
1620 | * Pending country IE processing, this can happen after we | ||
1238 | * call CRDA and wait for a response if a beacon was received before | 1621 | * call CRDA and wait for a response if a beacon was received before |
1239 | * we were able to process the last regulatory_hint_11d() call */ | 1622 | * we were able to process the last regulatory_hint_11d() call |
1623 | */ | ||
1240 | if (country_ie_regdomain) | 1624 | if (country_ie_regdomain) |
1241 | goto out; | 1625 | goto out; |
1242 | 1626 | ||
@@ -1248,33 +1632,44 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1248 | else if (country_ie[2] == 'O') | 1632 | else if (country_ie[2] == 'O') |
1249 | env = ENVIRON_OUTDOOR; | 1633 | env = ENVIRON_OUTDOOR; |
1250 | 1634 | ||
1251 | /* We will run this for *every* beacon processed for the BSSID, so | 1635 | /* |
1636 | * We will run this for *every* beacon processed for the BSSID, so | ||
1252 | * we optimize an early check to exit out early if we don't have to | 1637 | * we optimize an early check to exit out early if we don't have to |
1253 | * do anything */ | 1638 | * do anything |
1254 | if (likely(last_request->wiphy)) { | 1639 | */ |
1640 | if (likely(wiphy_idx_valid(last_request->wiphy_idx))) { | ||
1255 | struct cfg80211_registered_device *drv_last_ie; | 1641 | struct cfg80211_registered_device *drv_last_ie; |
1256 | 1642 | ||
1257 | drv_last_ie = wiphy_to_dev(last_request->wiphy); | 1643 | drv_last_ie = |
1644 | cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx); | ||
1258 | 1645 | ||
1259 | /* Lets keep this simple -- we trust the first AP | 1646 | /* |
1260 | * after we intersect with CRDA */ | 1647 | * Lets keep this simple -- we trust the first AP |
1261 | if (likely(last_request->wiphy == wiphy)) { | 1648 | * after we intersect with CRDA |
1262 | /* Ignore IEs coming in on this wiphy with | 1649 | */ |
1263 | * the same alpha2 and environment cap */ | 1650 | if (likely(&drv_last_ie->wiphy == wiphy)) { |
1651 | /* | ||
1652 | * Ignore IEs coming in on this wiphy with | ||
1653 | * the same alpha2 and environment cap | ||
1654 | */ | ||
1264 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, | 1655 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, |
1265 | alpha2) && | 1656 | alpha2) && |
1266 | env == drv_last_ie->env)) { | 1657 | env == drv_last_ie->env)) { |
1267 | goto out; | 1658 | goto out; |
1268 | } | 1659 | } |
1269 | /* the wiphy moved on to another BSSID or the AP | 1660 | /* |
1661 | * the wiphy moved on to another BSSID or the AP | ||
1270 | * was reconfigured. XXX: We need to deal with the | 1662 | * was reconfigured. XXX: We need to deal with the |
1271 | * case where the user suspends and goes to goes | 1663 | * case where the user suspends and goes to goes |
1272 | * to another country, and then gets IEs from an | 1664 | * to another country, and then gets IEs from an |
1273 | * AP with different settings */ | 1665 | * AP with different settings |
1666 | */ | ||
1274 | goto out; | 1667 | goto out; |
1275 | } else { | 1668 | } else { |
1276 | /* Ignore IEs coming in on two separate wiphys with | 1669 | /* |
1277 | * the same alpha2 and environment cap */ | 1670 | * Ignore IEs coming in on two separate wiphys with |
1671 | * the same alpha2 and environment cap | ||
1672 | */ | ||
1278 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, | 1673 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, |
1279 | alpha2) && | 1674 | alpha2) && |
1280 | env == drv_last_ie->env)) { | 1675 | env == drv_last_ie->env)) { |
@@ -1289,28 +1684,97 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1289 | if (!rd) | 1684 | if (!rd) |
1290 | goto out; | 1685 | goto out; |
1291 | 1686 | ||
1292 | /* This will not happen right now but we leave it here for the | 1687 | /* |
1688 | * This will not happen right now but we leave it here for the | ||
1293 | * the future when we want to add suspend/resume support and having | 1689 | * the future when we want to add suspend/resume support and having |
1294 | * the user move to another country after doing so, or having the user | 1690 | * the user move to another country after doing so, or having the user |
1295 | * move to another AP. Right now we just trust the first AP. This is why | 1691 | * move to another AP. Right now we just trust the first AP. |
1296 | * this is marked as likley(). If we hit this before we add this support | 1692 | * |
1297 | * we want to be informed of it as it would indicate a mistake in the | 1693 | * If we hit this before we add this support we want to be informed of |
1298 | * current design */ | 1694 | * it as it would indicate a mistake in the current design |
1299 | if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))) | 1695 | */ |
1300 | goto out; | 1696 | if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum))) |
1697 | goto free_rd_out; | ||
1698 | |||
1699 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | ||
1700 | if (!request) | ||
1701 | goto free_rd_out; | ||
1301 | 1702 | ||
1302 | /* We keep this around for when CRDA comes back with a response so | 1703 | /* |
1303 | * we can intersect with that */ | 1704 | * We keep this around for when CRDA comes back with a response so |
1705 | * we can intersect with that | ||
1706 | */ | ||
1304 | country_ie_regdomain = rd; | 1707 | country_ie_regdomain = rd; |
1305 | 1708 | ||
1306 | __regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE, | 1709 | request->wiphy_idx = get_wiphy_idx(wiphy); |
1307 | country_ie_regdomain->alpha2, checksum, env); | 1710 | request->alpha2[0] = rd->alpha2[0]; |
1711 | request->alpha2[1] = rd->alpha2[1]; | ||
1712 | request->initiator = REGDOM_SET_BY_COUNTRY_IE; | ||
1713 | request->country_ie_checksum = checksum; | ||
1714 | request->country_ie_env = env; | ||
1715 | |||
1716 | mutex_unlock(&cfg80211_mutex); | ||
1717 | |||
1718 | queue_regulatory_request(request); | ||
1308 | 1719 | ||
1720 | return; | ||
1721 | |||
1722 | free_rd_out: | ||
1723 | kfree(rd); | ||
1309 | out: | 1724 | out: |
1310 | mutex_unlock(&cfg80211_drv_mutex); | 1725 | mutex_unlock(&cfg80211_mutex); |
1311 | } | 1726 | } |
1312 | EXPORT_SYMBOL(regulatory_hint_11d); | 1727 | EXPORT_SYMBOL(regulatory_hint_11d); |
1313 | 1728 | ||
1729 | static bool freq_is_chan_12_13_14(u16 freq) | ||
1730 | { | ||
1731 | if (freq == ieee80211_channel_to_frequency(12) || | ||
1732 | freq == ieee80211_channel_to_frequency(13) || | ||
1733 | freq == ieee80211_channel_to_frequency(14)) | ||
1734 | return true; | ||
1735 | return false; | ||
1736 | } | ||
1737 | |||
1738 | int regulatory_hint_found_beacon(struct wiphy *wiphy, | ||
1739 | struct ieee80211_channel *beacon_chan, | ||
1740 | gfp_t gfp) | ||
1741 | { | ||
1742 | struct reg_beacon *reg_beacon; | ||
1743 | |||
1744 | if (likely((beacon_chan->beacon_found || | ||
1745 | (beacon_chan->flags & IEEE80211_CHAN_RADAR) || | ||
1746 | (beacon_chan->band == IEEE80211_BAND_2GHZ && | ||
1747 | !freq_is_chan_12_13_14(beacon_chan->center_freq))))) | ||
1748 | return 0; | ||
1749 | |||
1750 | reg_beacon = kzalloc(sizeof(struct reg_beacon), gfp); | ||
1751 | if (!reg_beacon) | ||
1752 | return -ENOMEM; | ||
1753 | |||
1754 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
1755 | printk(KERN_DEBUG "cfg80211: Found new beacon on " | ||
1756 | "frequency: %d MHz (Ch %d) on %s\n", | ||
1757 | beacon_chan->center_freq, | ||
1758 | ieee80211_frequency_to_channel(beacon_chan->center_freq), | ||
1759 | wiphy_name(wiphy)); | ||
1760 | #endif | ||
1761 | memcpy(®_beacon->chan, beacon_chan, | ||
1762 | sizeof(struct ieee80211_channel)); | ||
1763 | |||
1764 | |||
1765 | /* | ||
1766 | * Since we can be called from BH or and non-BH context | ||
1767 | * we must use spin_lock_bh() | ||
1768 | */ | ||
1769 | spin_lock_bh(®_pending_beacons_lock); | ||
1770 | list_add_tail(®_beacon->list, ®_pending_beacons); | ||
1771 | spin_unlock_bh(®_pending_beacons_lock); | ||
1772 | |||
1773 | schedule_work(®_work); | ||
1774 | |||
1775 | return 0; | ||
1776 | } | ||
1777 | |||
1314 | static void print_rd_rules(const struct ieee80211_regdomain *rd) | 1778 | static void print_rd_rules(const struct ieee80211_regdomain *rd) |
1315 | { | 1779 | { |
1316 | unsigned int i; | 1780 | unsigned int i; |
@@ -1326,8 +1790,10 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
1326 | freq_range = ®_rule->freq_range; | 1790 | freq_range = ®_rule->freq_range; |
1327 | power_rule = ®_rule->power_rule; | 1791 | power_rule = ®_rule->power_rule; |
1328 | 1792 | ||
1329 | /* There may not be documentation for max antenna gain | 1793 | /* |
1330 | * in certain regions */ | 1794 | * There may not be documentation for max antenna gain |
1795 | * in certain regions | ||
1796 | */ | ||
1331 | if (power_rule->max_antenna_gain) | 1797 | if (power_rule->max_antenna_gain) |
1332 | printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " | 1798 | printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " |
1333 | "(%d mBi, %d mBm)\n", | 1799 | "(%d mBi, %d mBm)\n", |
@@ -1350,13 +1816,12 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1350 | { | 1816 | { |
1351 | 1817 | ||
1352 | if (is_intersected_alpha2(rd->alpha2)) { | 1818 | if (is_intersected_alpha2(rd->alpha2)) { |
1353 | struct wiphy *wiphy = NULL; | ||
1354 | struct cfg80211_registered_device *drv; | ||
1355 | 1819 | ||
1356 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { | 1820 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { |
1357 | if (last_request->wiphy) { | 1821 | struct cfg80211_registered_device *drv; |
1358 | wiphy = last_request->wiphy; | 1822 | drv = cfg80211_drv_by_wiphy_idx( |
1359 | drv = wiphy_to_dev(wiphy); | 1823 | last_request->wiphy_idx); |
1824 | if (drv) { | ||
1360 | printk(KERN_INFO "cfg80211: Current regulatory " | 1825 | printk(KERN_INFO "cfg80211: Current regulatory " |
1361 | "domain updated by AP to: %c%c\n", | 1826 | "domain updated by AP to: %c%c\n", |
1362 | drv->country_ie_alpha2[0], | 1827 | drv->country_ie_alpha2[0], |
@@ -1422,7 +1887,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1422 | { | 1887 | { |
1423 | const struct ieee80211_regdomain *intersected_rd = NULL; | 1888 | const struct ieee80211_regdomain *intersected_rd = NULL; |
1424 | struct cfg80211_registered_device *drv = NULL; | 1889 | struct cfg80211_registered_device *drv = NULL; |
1425 | struct wiphy *wiphy = NULL; | 1890 | struct wiphy *request_wiphy; |
1426 | /* Some basic sanity checks first */ | 1891 | /* Some basic sanity checks first */ |
1427 | 1892 | ||
1428 | if (is_world_regdom(rd->alpha2)) { | 1893 | if (is_world_regdom(rd->alpha2)) { |
@@ -1439,23 +1904,27 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1439 | if (!last_request) | 1904 | if (!last_request) |
1440 | return -EINVAL; | 1905 | return -EINVAL; |
1441 | 1906 | ||
1442 | /* Lets only bother proceeding on the same alpha2 if the current | 1907 | /* |
1908 | * Lets only bother proceeding on the same alpha2 if the current | ||
1443 | * rd is non static (it means CRDA was present and was used last) | 1909 | * rd is non static (it means CRDA was present and was used last) |
1444 | * and the pending request came in from a country IE */ | 1910 | * and the pending request came in from a country IE |
1911 | */ | ||
1445 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) { | 1912 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) { |
1446 | /* If someone else asked us to change the rd lets only bother | 1913 | /* |
1447 | * checking if the alpha2 changes if CRDA was already called */ | 1914 | * If someone else asked us to change the rd lets only bother |
1915 | * checking if the alpha2 changes if CRDA was already called | ||
1916 | */ | ||
1448 | if (!is_old_static_regdom(cfg80211_regdomain) && | 1917 | if (!is_old_static_regdom(cfg80211_regdomain) && |
1449 | !regdom_changed(rd->alpha2)) | 1918 | !regdom_changes(rd->alpha2)) |
1450 | return -EINVAL; | 1919 | return -EINVAL; |
1451 | } | 1920 | } |
1452 | 1921 | ||
1453 | wiphy = last_request->wiphy; | 1922 | /* |
1454 | 1923 | * Now lets set the regulatory domain, update all driver channels | |
1455 | /* Now lets set the regulatory domain, update all driver channels | ||
1456 | * and finally inform them of what we have done, in case they want | 1924 | * and finally inform them of what we have done, in case they want |
1457 | * to review or adjust their own settings based on their own | 1925 | * to review or adjust their own settings based on their own |
1458 | * internal EEPROM data */ | 1926 | * internal EEPROM data |
1927 | */ | ||
1459 | 1928 | ||
1460 | if (WARN_ON(!reg_is_valid_request(rd->alpha2))) | 1929 | if (WARN_ON(!reg_is_valid_request(rd->alpha2))) |
1461 | return -EINVAL; | 1930 | return -EINVAL; |
@@ -1467,6 +1936,8 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1467 | return -EINVAL; | 1936 | return -EINVAL; |
1468 | } | 1937 | } |
1469 | 1938 | ||
1939 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
1940 | |||
1470 | if (!last_request->intersect) { | 1941 | if (!last_request->intersect) { |
1471 | int r; | 1942 | int r; |
1472 | 1943 | ||
@@ -1476,12 +1947,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1476 | return 0; | 1947 | return 0; |
1477 | } | 1948 | } |
1478 | 1949 | ||
1479 | /* For a driver hint, lets copy the regulatory domain the | 1950 | /* |
1480 | * driver wanted to the wiphy to deal with conflicts */ | 1951 | * For a driver hint, lets copy the regulatory domain the |
1952 | * driver wanted to the wiphy to deal with conflicts | ||
1953 | */ | ||
1481 | 1954 | ||
1482 | BUG_ON(last_request->wiphy->regd); | 1955 | BUG_ON(request_wiphy->regd); |
1483 | 1956 | ||
1484 | r = reg_copy_regd(&last_request->wiphy->regd, rd); | 1957 | r = reg_copy_regd(&request_wiphy->regd, rd); |
1485 | if (r) | 1958 | if (r) |
1486 | return r; | 1959 | return r; |
1487 | 1960 | ||
@@ -1498,11 +1971,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1498 | if (!intersected_rd) | 1971 | if (!intersected_rd) |
1499 | return -EINVAL; | 1972 | return -EINVAL; |
1500 | 1973 | ||
1501 | /* We can trash what CRDA provided now. | 1974 | /* |
1975 | * We can trash what CRDA provided now. | ||
1502 | * However if a driver requested this specific regulatory | 1976 | * However if a driver requested this specific regulatory |
1503 | * domain we keep it for its private use */ | 1977 | * domain we keep it for its private use |
1978 | */ | ||
1504 | if (last_request->initiator == REGDOM_SET_BY_DRIVER) | 1979 | if (last_request->initiator == REGDOM_SET_BY_DRIVER) |
1505 | last_request->wiphy->regd = rd; | 1980 | request_wiphy->regd = rd; |
1506 | else | 1981 | else |
1507 | kfree(rd); | 1982 | kfree(rd); |
1508 | 1983 | ||
@@ -1522,8 +1997,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1522 | BUG_ON(!country_ie_regdomain); | 1997 | BUG_ON(!country_ie_regdomain); |
1523 | 1998 | ||
1524 | if (rd != country_ie_regdomain) { | 1999 | if (rd != country_ie_regdomain) { |
1525 | /* Intersect what CRDA returned and our what we | 2000 | /* |
1526 | * had built from the Country IE received */ | 2001 | * Intersect what CRDA returned and our what we |
2002 | * had built from the Country IE received | ||
2003 | */ | ||
1527 | 2004 | ||
1528 | intersected_rd = regdom_intersect(rd, country_ie_regdomain); | 2005 | intersected_rd = regdom_intersect(rd, country_ie_regdomain); |
1529 | 2006 | ||
@@ -1533,16 +2010,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1533 | kfree(country_ie_regdomain); | 2010 | kfree(country_ie_regdomain); |
1534 | country_ie_regdomain = NULL; | 2011 | country_ie_regdomain = NULL; |
1535 | } else { | 2012 | } else { |
1536 | /* This would happen when CRDA was not present and | 2013 | /* |
2014 | * This would happen when CRDA was not present and | ||
1537 | * OLD_REGULATORY was enabled. We intersect our Country | 2015 | * OLD_REGULATORY was enabled. We intersect our Country |
1538 | * IE rd and what was set on cfg80211 originally */ | 2016 | * IE rd and what was set on cfg80211 originally |
2017 | */ | ||
1539 | intersected_rd = regdom_intersect(rd, cfg80211_regdomain); | 2018 | intersected_rd = regdom_intersect(rd, cfg80211_regdomain); |
1540 | } | 2019 | } |
1541 | 2020 | ||
1542 | if (!intersected_rd) | 2021 | if (!intersected_rd) |
1543 | return -EINVAL; | 2022 | return -EINVAL; |
1544 | 2023 | ||
1545 | drv = wiphy_to_dev(wiphy); | 2024 | drv = wiphy_to_dev(request_wiphy); |
1546 | 2025 | ||
1547 | drv->country_ie_alpha2[0] = rd->alpha2[0]; | 2026 | drv->country_ie_alpha2[0] = rd->alpha2[0]; |
1548 | drv->country_ie_alpha2[1] = rd->alpha2[1]; | 2027 | drv->country_ie_alpha2[1] = rd->alpha2[1]; |
@@ -1560,13 +2039,17 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1560 | } | 2039 | } |
1561 | 2040 | ||
1562 | 2041 | ||
1563 | /* Use this call to set the current regulatory domain. Conflicts with | 2042 | /* |
2043 | * Use this call to set the current regulatory domain. Conflicts with | ||
1564 | * multiple drivers can be ironed out later. Caller must've already | 2044 | * multiple drivers can be ironed out later. Caller must've already |
1565 | * kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */ | 2045 | * kmalloc'd the rd structure. Caller must hold cfg80211_mutex |
2046 | */ | ||
1566 | int set_regdom(const struct ieee80211_regdomain *rd) | 2047 | int set_regdom(const struct ieee80211_regdomain *rd) |
1567 | { | 2048 | { |
1568 | int r; | 2049 | int r; |
1569 | 2050 | ||
2051 | assert_cfg80211_lock(); | ||
2052 | |||
1570 | /* Note that this doesn't update the wiphys, this is done below */ | 2053 | /* Note that this doesn't update the wiphys, this is done below */ |
1571 | r = __set_regdom(rd); | 2054 | r = __set_regdom(rd); |
1572 | if (r) { | 2055 | if (r) { |
@@ -1586,54 +2069,82 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
1586 | return r; | 2069 | return r; |
1587 | } | 2070 | } |
1588 | 2071 | ||
1589 | /* Caller must hold cfg80211_drv_mutex */ | 2072 | /* Caller must hold cfg80211_mutex */ |
1590 | void reg_device_remove(struct wiphy *wiphy) | 2073 | void reg_device_remove(struct wiphy *wiphy) |
1591 | { | 2074 | { |
2075 | struct wiphy *request_wiphy; | ||
2076 | |||
2077 | assert_cfg80211_lock(); | ||
2078 | |||
2079 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
2080 | |||
1592 | kfree(wiphy->regd); | 2081 | kfree(wiphy->regd); |
1593 | if (!last_request || !last_request->wiphy) | 2082 | if (!last_request || !request_wiphy) |
1594 | return; | 2083 | return; |
1595 | if (last_request->wiphy != wiphy) | 2084 | if (request_wiphy != wiphy) |
1596 | return; | 2085 | return; |
1597 | last_request->wiphy = NULL; | 2086 | last_request->wiphy_idx = WIPHY_IDX_STALE; |
1598 | last_request->country_ie_env = ENVIRON_ANY; | 2087 | last_request->country_ie_env = ENVIRON_ANY; |
1599 | } | 2088 | } |
1600 | 2089 | ||
1601 | int regulatory_init(void) | 2090 | int regulatory_init(void) |
1602 | { | 2091 | { |
1603 | int err; | 2092 | int err = 0; |
1604 | 2093 | ||
1605 | reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); | 2094 | reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); |
1606 | if (IS_ERR(reg_pdev)) | 2095 | if (IS_ERR(reg_pdev)) |
1607 | return PTR_ERR(reg_pdev); | 2096 | return PTR_ERR(reg_pdev); |
1608 | 2097 | ||
2098 | spin_lock_init(®_requests_lock); | ||
2099 | spin_lock_init(®_pending_beacons_lock); | ||
2100 | |||
1609 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | 2101 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY |
1610 | cfg80211_regdomain = static_regdom(ieee80211_regdom); | 2102 | cfg80211_regdomain = static_regdom(ieee80211_regdom); |
1611 | 2103 | ||
1612 | printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); | 2104 | printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); |
1613 | print_regdomain_info(cfg80211_regdomain); | 2105 | print_regdomain_info(cfg80211_regdomain); |
1614 | /* The old code still requests for a new regdomain and if | 2106 | /* |
2107 | * The old code still requests for a new regdomain and if | ||
1615 | * you have CRDA you get it updated, otherwise you get | 2108 | * you have CRDA you get it updated, otherwise you get |
1616 | * stuck with the static values. We ignore "EU" code as | 2109 | * stuck with the static values. We ignore "EU" code as |
1617 | * that is not a valid ISO / IEC 3166 alpha2 */ | 2110 | * that is not a valid ISO / IEC 3166 alpha2 |
2111 | */ | ||
1618 | if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U') | 2112 | if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U') |
1619 | err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, | 2113 | err = regulatory_hint_core(ieee80211_regdom); |
1620 | ieee80211_regdom, 0, ENVIRON_ANY); | ||
1621 | #else | 2114 | #else |
1622 | cfg80211_regdomain = cfg80211_world_regdom; | 2115 | cfg80211_regdomain = cfg80211_world_regdom; |
1623 | 2116 | ||
1624 | err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY); | 2117 | err = regulatory_hint_core("00"); |
1625 | if (err) | ||
1626 | printk(KERN_ERR "cfg80211: calling CRDA failed - " | ||
1627 | "unable to update world regulatory domain, " | ||
1628 | "using static definition\n"); | ||
1629 | #endif | 2118 | #endif |
2119 | if (err) { | ||
2120 | if (err == -ENOMEM) | ||
2121 | return err; | ||
2122 | /* | ||
2123 | * N.B. kobject_uevent_env() can fail mainly for when we're out | ||
2124 | * memory which is handled and propagated appropriately above | ||
2125 | * but it can also fail during a netlink_broadcast() or during | ||
2126 | * early boot for call_usermodehelper(). For now treat these | ||
2127 | * errors as non-fatal. | ||
2128 | */ | ||
2129 | printk(KERN_ERR "cfg80211: kobject_uevent_env() was unable " | ||
2130 | "to call CRDA during init"); | ||
2131 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
2132 | /* We want to find out exactly why when debugging */ | ||
2133 | WARN_ON(err); | ||
2134 | #endif | ||
2135 | } | ||
1630 | 2136 | ||
1631 | return 0; | 2137 | return 0; |
1632 | } | 2138 | } |
1633 | 2139 | ||
1634 | void regulatory_exit(void) | 2140 | void regulatory_exit(void) |
1635 | { | 2141 | { |
1636 | mutex_lock(&cfg80211_drv_mutex); | 2142 | struct regulatory_request *reg_request, *tmp; |
2143 | struct reg_beacon *reg_beacon, *btmp; | ||
2144 | |||
2145 | cancel_work_sync(®_work); | ||
2146 | |||
2147 | mutex_lock(&cfg80211_mutex); | ||
1637 | 2148 | ||
1638 | reset_regdomains(); | 2149 | reset_regdomains(); |
1639 | 2150 | ||
@@ -1644,5 +2155,33 @@ void regulatory_exit(void) | |||
1644 | 2155 | ||
1645 | platform_device_unregister(reg_pdev); | 2156 | platform_device_unregister(reg_pdev); |
1646 | 2157 | ||
1647 | mutex_unlock(&cfg80211_drv_mutex); | 2158 | spin_lock_bh(®_pending_beacons_lock); |
2159 | if (!list_empty(®_pending_beacons)) { | ||
2160 | list_for_each_entry_safe(reg_beacon, btmp, | ||
2161 | ®_pending_beacons, list) { | ||
2162 | list_del(®_beacon->list); | ||
2163 | kfree(reg_beacon); | ||
2164 | } | ||
2165 | } | ||
2166 | spin_unlock_bh(®_pending_beacons_lock); | ||
2167 | |||
2168 | if (!list_empty(®_beacon_list)) { | ||
2169 | list_for_each_entry_safe(reg_beacon, btmp, | ||
2170 | ®_beacon_list, list) { | ||
2171 | list_del(®_beacon->list); | ||
2172 | kfree(reg_beacon); | ||
2173 | } | ||
2174 | } | ||
2175 | |||
2176 | spin_lock(®_requests_lock); | ||
2177 | if (!list_empty(®_requests_list)) { | ||
2178 | list_for_each_entry_safe(reg_request, tmp, | ||
2179 | ®_requests_list, list) { | ||
2180 | list_del(®_request->list); | ||
2181 | kfree(reg_request); | ||
2182 | } | ||
2183 | } | ||
2184 | spin_unlock(®_requests_lock); | ||
2185 | |||
2186 | mutex_unlock(&cfg80211_mutex); | ||
1648 | } | 2187 | } |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index fe8c83f34fb7..e37829a49dc4 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -6,6 +6,8 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain; | |||
6 | bool is_world_regdom(const char *alpha2); | 6 | bool is_world_regdom(const char *alpha2); |
7 | bool reg_is_valid_request(const char *alpha2); | 7 | bool reg_is_valid_request(const char *alpha2); |
8 | 8 | ||
9 | int regulatory_hint_user(const char *alpha2); | ||
10 | |||
9 | void reg_device_remove(struct wiphy *wiphy); | 11 | void reg_device_remove(struct wiphy *wiphy); |
10 | 12 | ||
11 | int regulatory_init(void); | 13 | int regulatory_init(void); |
@@ -14,26 +16,24 @@ void regulatory_exit(void); | |||
14 | int set_regdom(const struct ieee80211_regdomain *rd); | 16 | int set_regdom(const struct ieee80211_regdomain *rd); |
15 | 17 | ||
16 | /** | 18 | /** |
17 | * __regulatory_hint - hint to the wireless core a regulatory domain | 19 | * regulatory_hint_found_beacon - hints a beacon was found on a channel |
18 | * @wiphy: if the hint comes from country information from an AP, this | 20 | * @wiphy: the wireless device where the beacon was found on |
19 | * is required to be set to the wiphy that received the information | 21 | * @beacon_chan: the channel on which the beacon was found on |
20 | * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain | 22 | * @gfp: context flags |
21 | * should be in. | ||
22 | * @country_ie_checksum: checksum of processed country IE, set this to 0 | ||
23 | * if the hint did not come from a country IE | ||
24 | * @country_ie_env: the environment the IE told us we are in, %ENVIRON_* | ||
25 | * | ||
26 | * The Wireless subsystem can use this function to hint to the wireless core | ||
27 | * what it believes should be the current regulatory domain by giving it an | ||
28 | * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be | ||
29 | * in. | ||
30 | * | 23 | * |
31 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had | 24 | * This informs the wireless core that a beacon from an AP was found on |
32 | * already been set or other standard error codes. | 25 | * the channel provided. This allows the wireless core to make educated |
26 | * guesses on regulatory to help with world roaming. This is only used for | ||
27 | * world roaming -- when we do not know our current location. This is | ||
28 | * only useful on channels 12, 13 and 14 on the 2 GHz band as channels | ||
29 | * 1-11 are already enabled by the world regulatory domain; and on | ||
30 | * non-radar 5 GHz channels. | ||
33 | * | 31 | * |
32 | * Drivers do not need to call this, cfg80211 will do it for after a scan | ||
33 | * on a newly found BSS. | ||
34 | */ | 34 | */ |
35 | extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | 35 | int regulatory_hint_found_beacon(struct wiphy *wiphy, |
36 | const char *alpha2, u32 country_ie_checksum, | 36 | struct ieee80211_channel *beacon_chan, |
37 | enum environment_cap country_ie_env); | 37 | gfp_t gfp); |
38 | 38 | ||
39 | #endif /* __NET_WIRELESS_REG_H */ | 39 | #endif /* __NET_WIRELESS_REG_H */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index b1893c863b97..280dbcd02c15 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -62,6 +62,18 @@ static void bss_release(struct kref *ref) | |||
62 | } | 62 | } |
63 | 63 | ||
64 | /* must hold dev->bss_lock! */ | 64 | /* must hold dev->bss_lock! */ |
65 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, | ||
66 | unsigned long age_secs) | ||
67 | { | ||
68 | struct cfg80211_internal_bss *bss; | ||
69 | unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); | ||
70 | |||
71 | list_for_each_entry(bss, &dev->bss_list, list) { | ||
72 | bss->ts -= age_jiffies; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /* must hold dev->bss_lock! */ | ||
65 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | 77 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) |
66 | { | 78 | { |
67 | struct cfg80211_internal_bss *bss, *tmp; | 79 | struct cfg80211_internal_bss *bss, *tmp; |
@@ -358,7 +370,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
358 | found->pub.beacon_interval = res->pub.beacon_interval; | 370 | found->pub.beacon_interval = res->pub.beacon_interval; |
359 | found->pub.tsf = res->pub.tsf; | 371 | found->pub.tsf = res->pub.tsf; |
360 | found->pub.signal = res->pub.signal; | 372 | found->pub.signal = res->pub.signal; |
361 | found->pub.signal_type = res->pub.signal_type; | ||
362 | found->pub.capability = res->pub.capability; | 373 | found->pub.capability = res->pub.capability; |
363 | found->ts = res->ts; | 374 | found->ts = res->ts; |
364 | kref_put(&res->ref, bss_release); | 375 | kref_put(&res->ref, bss_release); |
@@ -380,8 +391,7 @@ struct cfg80211_bss * | |||
380 | cfg80211_inform_bss_frame(struct wiphy *wiphy, | 391 | cfg80211_inform_bss_frame(struct wiphy *wiphy, |
381 | struct ieee80211_channel *channel, | 392 | struct ieee80211_channel *channel, |
382 | struct ieee80211_mgmt *mgmt, size_t len, | 393 | struct ieee80211_mgmt *mgmt, size_t len, |
383 | s32 signal, enum cfg80211_signal_type sigtype, | 394 | s32 signal, gfp_t gfp) |
384 | gfp_t gfp) | ||
385 | { | 395 | { |
386 | struct cfg80211_internal_bss *res; | 396 | struct cfg80211_internal_bss *res; |
387 | size_t ielen = len - offsetof(struct ieee80211_mgmt, | 397 | size_t ielen = len - offsetof(struct ieee80211_mgmt, |
@@ -389,7 +399,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
389 | bool overwrite; | 399 | bool overwrite; |
390 | size_t privsz = wiphy->bss_priv_size; | 400 | size_t privsz = wiphy->bss_priv_size; |
391 | 401 | ||
392 | if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC && | 402 | if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && |
393 | (signal < 0 || signal > 100))) | 403 | (signal < 0 || signal > 100))) |
394 | return NULL; | 404 | return NULL; |
395 | 405 | ||
@@ -403,7 +413,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
403 | 413 | ||
404 | memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); | 414 | memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); |
405 | res->pub.channel = channel; | 415 | res->pub.channel = channel; |
406 | res->pub.signal_type = sigtype; | ||
407 | res->pub.signal = signal; | 416 | res->pub.signal = signal; |
408 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); | 417 | 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); | 418 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); |
@@ -421,6 +430,9 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
421 | if (!res) | 430 | if (!res) |
422 | return NULL; | 431 | return NULL; |
423 | 432 | ||
433 | if (res->pub.capability & WLAN_CAPABILITY_ESS) | ||
434 | regulatory_hint_found_beacon(wiphy, channel, gfp); | ||
435 | |||
424 | /* cfg80211_bss_update gives us a referenced result */ | 436 | /* cfg80211_bss_update gives us a referenced result */ |
425 | return &res->pub; | 437 | return &res->pub; |
426 | } | 438 | } |
@@ -584,16 +596,25 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, | |||
584 | } | 596 | } |
585 | } | 597 | } |
586 | 598 | ||
599 | static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | ||
600 | { | ||
601 | unsigned long end = jiffies; | ||
602 | |||
603 | if (end >= start) | ||
604 | return jiffies_to_msecs(end - start); | ||
605 | |||
606 | return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); | ||
607 | } | ||
587 | 608 | ||
588 | static char * | 609 | static char * |
589 | ieee80211_bss(struct iw_request_info *info, | 610 | ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, |
590 | struct cfg80211_internal_bss *bss, | 611 | struct cfg80211_internal_bss *bss, char *current_ev, |
591 | char *current_ev, char *end_buf) | 612 | char *end_buf) |
592 | { | 613 | { |
593 | struct iw_event iwe; | 614 | struct iw_event iwe; |
594 | u8 *buf, *cfg, *p; | 615 | u8 *buf, *cfg, *p; |
595 | u8 *ie = bss->pub.information_elements; | 616 | u8 *ie = bss->pub.information_elements; |
596 | int rem = bss->pub.len_information_elements, i; | 617 | int rem = bss->pub.len_information_elements, i, sig; |
597 | bool ismesh = false; | 618 | bool ismesh = false; |
598 | 619 | ||
599 | memset(&iwe, 0, sizeof(iwe)); | 620 | memset(&iwe, 0, sizeof(iwe)); |
@@ -617,19 +638,28 @@ ieee80211_bss(struct iw_request_info *info, | |||
617 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | 638 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
618 | IW_EV_FREQ_LEN); | 639 | IW_EV_FREQ_LEN); |
619 | 640 | ||
620 | if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) { | 641 | if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { |
621 | memset(&iwe, 0, sizeof(iwe)); | 642 | memset(&iwe, 0, sizeof(iwe)); |
622 | iwe.cmd = IWEVQUAL; | 643 | iwe.cmd = IWEVQUAL; |
623 | iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED | | 644 | iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED | |
624 | IW_QUAL_NOISE_INVALID | | 645 | IW_QUAL_NOISE_INVALID | |
625 | IW_QUAL_QUAL_INVALID; | 646 | IW_QUAL_QUAL_UPDATED; |
626 | switch (bss->pub.signal_type) { | 647 | switch (wiphy->signal_type) { |
627 | case CFG80211_SIGNAL_TYPE_MBM: | 648 | case CFG80211_SIGNAL_TYPE_MBM: |
628 | iwe.u.qual.level = bss->pub.signal / 100; | 649 | sig = bss->pub.signal / 100; |
650 | iwe.u.qual.level = sig; | ||
629 | iwe.u.qual.updated |= IW_QUAL_DBM; | 651 | iwe.u.qual.updated |= IW_QUAL_DBM; |
652 | if (sig < -110) /* rather bad */ | ||
653 | sig = -110; | ||
654 | else if (sig > -40) /* perfect */ | ||
655 | sig = -40; | ||
656 | /* will give a range of 0 .. 70 */ | ||
657 | iwe.u.qual.qual = sig + 110; | ||
630 | break; | 658 | break; |
631 | case CFG80211_SIGNAL_TYPE_UNSPEC: | 659 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
632 | iwe.u.qual.level = bss->pub.signal; | 660 | iwe.u.qual.level = bss->pub.signal; |
661 | /* will give range 0 .. 100 */ | ||
662 | iwe.u.qual.qual = bss->pub.signal; | ||
633 | break; | 663 | break; |
634 | default: | 664 | default: |
635 | /* not reached */ | 665 | /* not reached */ |
@@ -763,8 +793,8 @@ ieee80211_bss(struct iw_request_info *info, | |||
763 | &iwe, buf); | 793 | &iwe, buf); |
764 | memset(&iwe, 0, sizeof(iwe)); | 794 | memset(&iwe, 0, sizeof(iwe)); |
765 | iwe.cmd = IWEVCUSTOM; | 795 | iwe.cmd = IWEVCUSTOM; |
766 | sprintf(buf, " Last beacon: %dms ago", | 796 | sprintf(buf, " Last beacon: %ums ago", |
767 | jiffies_to_msecs(jiffies - bss->ts)); | 797 | elapsed_jiffies_msecs(bss->ts)); |
768 | iwe.u.data.length = strlen(buf); | 798 | iwe.u.data.length = strlen(buf); |
769 | current_ev = iwe_stream_add_point(info, current_ev, | 799 | current_ev = iwe_stream_add_point(info, current_ev, |
770 | end_buf, &iwe, buf); | 800 | end_buf, &iwe, buf); |
@@ -793,8 +823,8 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *dev, | |||
793 | spin_unlock_bh(&dev->bss_lock); | 823 | spin_unlock_bh(&dev->bss_lock); |
794 | return -E2BIG; | 824 | return -E2BIG; |
795 | } | 825 | } |
796 | current_ev = ieee80211_bss(info, bss, | 826 | current_ev = ieee80211_bss(&dev->wiphy, info, bss, |
797 | current_ev, end_buf); | 827 | current_ev, end_buf); |
798 | } | 828 | } |
799 | spin_unlock_bh(&dev->bss_lock); | 829 | spin_unlock_bh(&dev->bss_lock); |
800 | return current_ev - buf; | 830 | return current_ev - buf; |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 26a72b0797a0..efe3c5c92b2d 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -31,7 +31,7 @@ static ssize_t name ## _show(struct device *dev, \ | |||
31 | return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ | 31 | return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ |
32 | } | 32 | } |
33 | 33 | ||
34 | SHOW_FMT(index, "%d", idx); | 34 | SHOW_FMT(index, "%d", wiphy_idx); |
35 | SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); | 35 | SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); |
36 | 36 | ||
37 | static struct device_attribute ieee80211_dev_attrs[] = { | 37 | static struct device_attribute ieee80211_dev_attrs[] = { |
@@ -60,6 +60,8 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) | |||
60 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | 60 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); |
61 | int ret = 0; | 61 | int ret = 0; |
62 | 62 | ||
63 | rdev->suspend_at = get_seconds(); | ||
64 | |||
63 | if (rdev->ops->suspend) { | 65 | if (rdev->ops->suspend) { |
64 | rtnl_lock(); | 66 | rtnl_lock(); |
65 | ret = rdev->ops->suspend(&rdev->wiphy); | 67 | ret = rdev->ops->suspend(&rdev->wiphy); |
@@ -74,6 +76,11 @@ static int wiphy_resume(struct device *dev) | |||
74 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | 76 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); |
75 | int ret = 0; | 77 | int ret = 0; |
76 | 78 | ||
79 | /* Age scan results with time spent in suspend */ | ||
80 | spin_lock_bh(&rdev->bss_lock); | ||
81 | cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); | ||
82 | spin_unlock_bh(&rdev->bss_lock); | ||
83 | |||
77 | if (rdev->ops->resume) { | 84 | if (rdev->ops->resume) { |
78 | rtnl_lock(); | 85 | rtnl_lock(); |
79 | ret = rdev->ops->resume(&rdev->wiphy); | 86 | ret = rdev->ops->resume(&rdev->wiphy); |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 58e489fd4aed..b84a9b4fe96a 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -137,3 +137,100 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, | |||
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
139 | EXPORT_SYMBOL(cfg80211_wext_giwmode); | 139 | EXPORT_SYMBOL(cfg80211_wext_giwmode); |
140 | |||
141 | |||
142 | int cfg80211_wext_giwrange(struct net_device *dev, | ||
143 | struct iw_request_info *info, | ||
144 | struct iw_point *data, char *extra) | ||
145 | { | ||
146 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
147 | struct iw_range *range = (struct iw_range *) extra; | ||
148 | enum ieee80211_band band; | ||
149 | int c = 0; | ||
150 | |||
151 | if (!wdev) | ||
152 | return -EOPNOTSUPP; | ||
153 | |||
154 | data->length = sizeof(struct iw_range); | ||
155 | memset(range, 0, sizeof(struct iw_range)); | ||
156 | |||
157 | range->we_version_compiled = WIRELESS_EXT; | ||
158 | range->we_version_source = 21; | ||
159 | range->retry_capa = IW_RETRY_LIMIT; | ||
160 | range->retry_flags = IW_RETRY_LIMIT; | ||
161 | range->min_retry = 0; | ||
162 | range->max_retry = 255; | ||
163 | range->min_rts = 0; | ||
164 | range->max_rts = 2347; | ||
165 | range->min_frag = 256; | ||
166 | range->max_frag = 2346; | ||
167 | |||
168 | range->encoding_size[0] = 5; | ||
169 | range->encoding_size[1] = 13; | ||
170 | range->num_encoding_sizes = 2; | ||
171 | range->max_encoding_tokens = 4; | ||
172 | |||
173 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; | ||
174 | |||
175 | switch (wdev->wiphy->signal_type) { | ||
176 | case CFG80211_SIGNAL_TYPE_NONE: | ||
177 | break; | ||
178 | case CFG80211_SIGNAL_TYPE_MBM: | ||
179 | range->max_qual.level = -110; | ||
180 | range->max_qual.qual = 70; | ||
181 | range->avg_qual.qual = 35; | ||
182 | range->max_qual.updated |= IW_QUAL_DBM; | ||
183 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; | ||
184 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; | ||
185 | break; | ||
186 | case CFG80211_SIGNAL_TYPE_UNSPEC: | ||
187 | range->max_qual.level = 100; | ||
188 | range->max_qual.qual = 100; | ||
189 | range->avg_qual.qual = 50; | ||
190 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; | ||
191 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | range->avg_qual.level = range->max_qual.level / 2; | ||
196 | range->avg_qual.noise = range->max_qual.noise / 2; | ||
197 | range->avg_qual.updated = range->max_qual.updated; | ||
198 | |||
199 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
200 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | ||
201 | |||
202 | |||
203 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { | ||
204 | int i; | ||
205 | struct ieee80211_supported_band *sband; | ||
206 | |||
207 | sband = wdev->wiphy->bands[band]; | ||
208 | |||
209 | if (!sband) | ||
210 | continue; | ||
211 | |||
212 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { | ||
213 | struct ieee80211_channel *chan = &sband->channels[i]; | ||
214 | |||
215 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { | ||
216 | range->freq[c].i = | ||
217 | ieee80211_frequency_to_channel( | ||
218 | chan->center_freq); | ||
219 | range->freq[c].m = chan->center_freq; | ||
220 | range->freq[c].e = 6; | ||
221 | c++; | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | range->num_channels = c; | ||
226 | range->num_frequency = c; | ||
227 | |||
228 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | ||
229 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | ||
230 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | ||
231 | |||
232 | range->scan_capa |= IW_SCAN_CAPA_ESSID; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | EXPORT_SYMBOL(cfg80211_wext_giwrange); | ||