diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 1081 |
1 files changed, 220 insertions, 861 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2f9ed8b9c3f0..72920ee07885 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -77,12 +77,6 @@ enum rx_mgmt_action { | |||
77 | 77 | ||
78 | /* caller must tell cfg80211 about internal error */ | 78 | /* caller must tell cfg80211 about internal error */ |
79 | RX_MGMT_CFG80211_ASSOC_ERROR, | 79 | RX_MGMT_CFG80211_ASSOC_ERROR, |
80 | |||
81 | /* caller must call cfg80211_auth_timeout() & free work */ | ||
82 | RX_MGMT_CFG80211_AUTH_TO, | ||
83 | |||
84 | /* caller must call cfg80211_assoc_timeout() & free work */ | ||
85 | RX_MGMT_CFG80211_ASSOC_TO, | ||
86 | }; | 80 | }; |
87 | 81 | ||
88 | /* utils */ | 82 | /* utils */ |
@@ -125,27 +119,6 @@ static int ecw2cw(int ecw) | |||
125 | return (1 << ecw) - 1; | 119 | return (1 << ecw) - 1; |
126 | } | 120 | } |
127 | 121 | ||
128 | static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | ||
129 | struct ieee80211_supported_band *sband, | ||
130 | u32 *rates) | ||
131 | { | ||
132 | int i, j, count; | ||
133 | *rates = 0; | ||
134 | count = 0; | ||
135 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
136 | int rate = (bss->supp_rates[i] & 0x7F) * 5; | ||
137 | |||
138 | for (j = 0; j < sband->n_bitrates; j++) | ||
139 | if (sband->bitrates[j].bitrate == rate) { | ||
140 | *rates |= BIT(j); | ||
141 | count++; | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return count; | ||
147 | } | ||
148 | |||
149 | /* | 122 | /* |
150 | * ieee80211_enable_ht should be called only after the operating band | 123 | * ieee80211_enable_ht should be called only after the operating band |
151 | * has been determined as ht configuration depends on the hw's | 124 | * has been determined as ht configuration depends on the hw's |
@@ -231,264 +204,6 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
231 | 204 | ||
232 | /* frame sending functions */ | 205 | /* frame sending functions */ |
233 | 206 | ||
234 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
235 | struct ieee80211_mgd_work *wk) | ||
236 | { | ||
237 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
238 | struct ieee80211_local *local = sdata->local; | ||
239 | struct sk_buff *skb; | ||
240 | struct ieee80211_mgmt *mgmt; | ||
241 | u8 *pos; | ||
242 | const u8 *ies, *ht_ie; | ||
243 | int i, len, count, rates_len, supp_rates_len; | ||
244 | u16 capab; | ||
245 | int wmm = 0; | ||
246 | struct ieee80211_supported_band *sband; | ||
247 | u32 rates = 0; | ||
248 | |||
249 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
250 | sizeof(*mgmt) + 200 + wk->ie_len + | ||
251 | wk->ssid_len); | ||
252 | if (!skb) { | ||
253 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | ||
254 | "frame\n", sdata->name); | ||
255 | return; | ||
256 | } | ||
257 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
258 | |||
259 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
260 | |||
261 | capab = ifmgd->capab; | ||
262 | |||
263 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
264 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
265 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
266 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
267 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
268 | } | ||
269 | |||
270 | if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) | ||
271 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
272 | if (wk->bss->wmm_used) | ||
273 | wmm = 1; | ||
274 | |||
275 | /* get all rates supported by the device and the AP as | ||
276 | * some APs don't like getting a superset of their rates | ||
277 | * in the association request (e.g. D-Link DAP 1353 in | ||
278 | * b-only mode) */ | ||
279 | rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates); | ||
280 | |||
281 | if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
282 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
283 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
284 | |||
285 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
286 | memset(mgmt, 0, 24); | ||
287 | memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); | ||
288 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
289 | memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); | ||
290 | |||
291 | if (!is_zero_ether_addr(wk->prev_bssid)) { | ||
292 | skb_put(skb, 10); | ||
293 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
294 | IEEE80211_STYPE_REASSOC_REQ); | ||
295 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
296 | mgmt->u.reassoc_req.listen_interval = | ||
297 | cpu_to_le16(local->hw.conf.listen_interval); | ||
298 | memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid, | ||
299 | ETH_ALEN); | ||
300 | } else { | ||
301 | skb_put(skb, 4); | ||
302 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
303 | IEEE80211_STYPE_ASSOC_REQ); | ||
304 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
305 | mgmt->u.assoc_req.listen_interval = | ||
306 | cpu_to_le16(local->hw.conf.listen_interval); | ||
307 | } | ||
308 | |||
309 | /* SSID */ | ||
310 | ies = pos = skb_put(skb, 2 + wk->ssid_len); | ||
311 | *pos++ = WLAN_EID_SSID; | ||
312 | *pos++ = wk->ssid_len; | ||
313 | memcpy(pos, wk->ssid, wk->ssid_len); | ||
314 | |||
315 | /* add all rates which were marked to be used above */ | ||
316 | supp_rates_len = rates_len; | ||
317 | if (supp_rates_len > 8) | ||
318 | supp_rates_len = 8; | ||
319 | |||
320 | len = sband->n_bitrates; | ||
321 | pos = skb_put(skb, supp_rates_len + 2); | ||
322 | *pos++ = WLAN_EID_SUPP_RATES; | ||
323 | *pos++ = supp_rates_len; | ||
324 | |||
325 | count = 0; | ||
326 | for (i = 0; i < sband->n_bitrates; i++) { | ||
327 | if (BIT(i) & rates) { | ||
328 | int rate = sband->bitrates[i].bitrate; | ||
329 | *pos++ = (u8) (rate / 5); | ||
330 | if (++count == 8) | ||
331 | break; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | if (rates_len > count) { | ||
336 | pos = skb_put(skb, rates_len - count + 2); | ||
337 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
338 | *pos++ = rates_len - count; | ||
339 | |||
340 | for (i++; i < sband->n_bitrates; i++) { | ||
341 | if (BIT(i) & rates) { | ||
342 | int rate = sband->bitrates[i].bitrate; | ||
343 | *pos++ = (u8) (rate / 5); | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
349 | /* 1. power capabilities */ | ||
350 | pos = skb_put(skb, 4); | ||
351 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
352 | *pos++ = 2; | ||
353 | *pos++ = 0; /* min tx power */ | ||
354 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | ||
355 | |||
356 | /* 2. supported channels */ | ||
357 | /* TODO: get this in reg domain format */ | ||
358 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
359 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
360 | *pos++ = 2 * sband->n_channels; | ||
361 | for (i = 0; i < sband->n_channels; i++) { | ||
362 | *pos++ = ieee80211_frequency_to_channel( | ||
363 | sband->channels[i].center_freq); | ||
364 | *pos++ = 1; /* one channel in the subband*/ | ||
365 | } | ||
366 | } | ||
367 | |||
368 | if (wk->ie_len && wk->ie) { | ||
369 | pos = skb_put(skb, wk->ie_len); | ||
370 | memcpy(pos, wk->ie, wk->ie_len); | ||
371 | } | ||
372 | |||
373 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { | ||
374 | pos = skb_put(skb, 9); | ||
375 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
376 | *pos++ = 7; /* len */ | ||
377 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
378 | *pos++ = 0x50; | ||
379 | *pos++ = 0xf2; | ||
380 | *pos++ = 2; /* WME */ | ||
381 | *pos++ = 0; /* WME info */ | ||
382 | *pos++ = 1; /* WME ver */ | ||
383 | *pos++ = 0; | ||
384 | } | ||
385 | |||
386 | /* wmm support is a must to HT */ | ||
387 | /* | ||
388 | * IEEE802.11n does not allow TKIP/WEP as pairwise | ||
389 | * ciphers in HT mode. We still associate in non-ht | ||
390 | * mode (11a/b/g) if any one of these ciphers is | ||
391 | * configured as pairwise. | ||
392 | */ | ||
393 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | ||
394 | sband->ht_cap.ht_supported && | ||
395 | (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) && | ||
396 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && | ||
397 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { | ||
398 | struct ieee80211_ht_info *ht_info = | ||
399 | (struct ieee80211_ht_info *)(ht_ie + 2); | ||
400 | u16 cap = sband->ht_cap.cap; | ||
401 | __le16 tmp; | ||
402 | u32 flags = local->hw.conf.channel->flags; | ||
403 | |||
404 | /* determine capability flags */ | ||
405 | |||
406 | if (ieee80211_disable_40mhz_24ghz && | ||
407 | sband->band == IEEE80211_BAND_2GHZ) { | ||
408 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
409 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
410 | } | ||
411 | |||
412 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
413 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
414 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
415 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
416 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
417 | } | ||
418 | break; | ||
419 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
420 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
421 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
422 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
423 | } | ||
424 | break; | ||
425 | } | ||
426 | |||
427 | /* set SM PS mode properly */ | ||
428 | cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
429 | /* new association always uses requested smps mode */ | ||
430 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { | ||
431 | if (ifmgd->powersave) | ||
432 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; | ||
433 | else | ||
434 | ifmgd->ap_smps = IEEE80211_SMPS_OFF; | ||
435 | } else | ||
436 | ifmgd->ap_smps = ifmgd->req_smps; | ||
437 | |||
438 | switch (ifmgd->ap_smps) { | ||
439 | case IEEE80211_SMPS_AUTOMATIC: | ||
440 | case IEEE80211_SMPS_NUM_MODES: | ||
441 | WARN_ON(1); | ||
442 | case IEEE80211_SMPS_OFF: | ||
443 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << | ||
444 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
445 | break; | ||
446 | case IEEE80211_SMPS_STATIC: | ||
447 | cap |= WLAN_HT_CAP_SM_PS_STATIC << | ||
448 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
449 | break; | ||
450 | case IEEE80211_SMPS_DYNAMIC: | ||
451 | cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << | ||
452 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
453 | break; | ||
454 | } | ||
455 | |||
456 | /* reserve and fill IE */ | ||
457 | |||
458 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
459 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
460 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
461 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
462 | |||
463 | /* capability flags */ | ||
464 | tmp = cpu_to_le16(cap); | ||
465 | memcpy(pos, &tmp, sizeof(u16)); | ||
466 | pos += sizeof(u16); | ||
467 | |||
468 | /* AMPDU parameters */ | ||
469 | *pos++ = sband->ht_cap.ampdu_factor | | ||
470 | (sband->ht_cap.ampdu_density << | ||
471 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | ||
472 | |||
473 | /* MCS set */ | ||
474 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | ||
475 | pos += sizeof(sband->ht_cap.mcs); | ||
476 | |||
477 | /* extended capabilities */ | ||
478 | pos += sizeof(__le16); | ||
479 | |||
480 | /* BF capabilities */ | ||
481 | pos += sizeof(__le32); | ||
482 | |||
483 | /* antenna selection */ | ||
484 | pos += sizeof(u8); | ||
485 | } | ||
486 | |||
487 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
488 | ieee80211_tx_skb(sdata, skb); | ||
489 | } | ||
490 | |||
491 | |||
492 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 207 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
493 | const u8 *bssid, u16 stype, u16 reason, | 208 | const u8 *bssid, u16 stype, u16 reason, |
494 | void *cookie) | 209 | void *cookie) |
@@ -604,7 +319,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
604 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 319 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
605 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 320 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
606 | 321 | ||
607 | if (!netif_running(sdata->dev)) | 322 | if (!ieee80211_sdata_running(sdata)) |
608 | return; | 323 | return; |
609 | 324 | ||
610 | mutex_lock(&ifmgd->mtx); | 325 | mutex_lock(&ifmgd->mtx); |
@@ -615,7 +330,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
615 | ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); | 330 | ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); |
616 | 331 | ||
617 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 332 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
618 | ifmgd->associated->cbss.channel = sdata->local->oper_channel; | 333 | ifmgd->associated->channel = sdata->local->oper_channel; |
619 | 334 | ||
620 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 335 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
621 | IEEE80211_QUEUE_STOP_REASON_CSA); | 336 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -642,6 +357,8 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
642 | struct ieee80211_channel_sw_ie *sw_elem, | 357 | struct ieee80211_channel_sw_ie *sw_elem, |
643 | struct ieee80211_bss *bss) | 358 | struct ieee80211_bss *bss) |
644 | { | 359 | { |
360 | struct cfg80211_bss *cbss = | ||
361 | container_of((void *)bss, struct cfg80211_bss, priv); | ||
645 | struct ieee80211_channel *new_ch; | 362 | struct ieee80211_channel *new_ch; |
646 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 363 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
647 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | 364 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); |
@@ -675,7 +392,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
675 | mod_timer(&ifmgd->chswitch_timer, | 392 | mod_timer(&ifmgd->chswitch_timer, |
676 | jiffies + | 393 | jiffies + |
677 | msecs_to_jiffies(sw_elem->count * | 394 | msecs_to_jiffies(sw_elem->count * |
678 | bss->cbss.beacon_interval)); | 395 | cbss->beacon_interval)); |
679 | } | 396 | } |
680 | } | 397 | } |
681 | 398 | ||
@@ -749,8 +466,13 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
749 | return; | 466 | return; |
750 | } | 467 | } |
751 | 468 | ||
469 | if (!list_empty(&local->work_list)) { | ||
470 | local->ps_sdata = NULL; | ||
471 | goto change; | ||
472 | } | ||
473 | |||
752 | list_for_each_entry(sdata, &local->interfaces, list) { | 474 | list_for_each_entry(sdata, &local->interfaces, list) { |
753 | if (!netif_running(sdata->dev)) | 475 | if (!ieee80211_sdata_running(sdata)) |
754 | continue; | 476 | continue; |
755 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 477 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
756 | continue; | 478 | continue; |
@@ -759,7 +481,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
759 | } | 481 | } |
760 | 482 | ||
761 | if (count == 1 && found->u.mgd.powersave && | 483 | if (count == 1 && found->u.mgd.powersave && |
762 | found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && | 484 | found->u.mgd.associated && |
763 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | 485 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | |
764 | IEEE80211_STA_CONNECTION_POLL))) { | 486 | IEEE80211_STA_CONNECTION_POLL))) { |
765 | s32 beaconint_us; | 487 | s32 beaconint_us; |
@@ -787,6 +509,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
787 | local->ps_sdata = NULL; | 509 | local->ps_sdata = NULL; |
788 | } | 510 | } |
789 | 511 | ||
512 | change: | ||
790 | ieee80211_change_ps(local); | 513 | ieee80211_change_ps(local); |
791 | } | 514 | } |
792 | 515 | ||
@@ -846,7 +569,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
846 | int count; | 569 | int count; |
847 | u8 *pos; | 570 | u8 *pos; |
848 | 571 | ||
849 | if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) | 572 | if (local->hw.queues < 4) |
850 | return; | 573 | return; |
851 | 574 | ||
852 | if (!wmm_param) | 575 | if (!wmm_param) |
@@ -949,25 +672,24 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
949 | } | 672 | } |
950 | 673 | ||
951 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 674 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
952 | struct ieee80211_mgd_work *wk, | 675 | struct cfg80211_bss *cbss, |
953 | u32 bss_info_changed) | 676 | u32 bss_info_changed) |
954 | { | 677 | { |
678 | struct ieee80211_bss *bss = (void *)cbss->priv; | ||
955 | struct ieee80211_local *local = sdata->local; | 679 | struct ieee80211_local *local = sdata->local; |
956 | struct ieee80211_bss *bss = wk->bss; | ||
957 | 680 | ||
958 | bss_info_changed |= BSS_CHANGED_ASSOC; | 681 | bss_info_changed |= BSS_CHANGED_ASSOC; |
959 | /* set timing information */ | 682 | /* set timing information */ |
960 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; | 683 | sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; |
961 | sdata->vif.bss_conf.timestamp = bss->cbss.tsf; | 684 | sdata->vif.bss_conf.timestamp = cbss->tsf; |
962 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | 685 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; |
963 | 686 | ||
964 | bss_info_changed |= BSS_CHANGED_BEACON_INT; | 687 | bss_info_changed |= BSS_CHANGED_BEACON_INT; |
965 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 688 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
966 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 689 | cbss->capability, bss->has_erp_value, bss->erp_value); |
967 | 690 | ||
968 | sdata->u.mgd.associated = bss; | 691 | sdata->u.mgd.associated = cbss; |
969 | sdata->u.mgd.old_associate_work = wk; | 692 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); |
970 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); | ||
971 | 693 | ||
972 | /* just to be sure */ | 694 | /* just to be sure */ |
973 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | | 695 | sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
@@ -1005,93 +727,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1005 | netif_carrier_on(sdata->dev); | 727 | netif_carrier_on(sdata->dev); |
1006 | } | 728 | } |
1007 | 729 | ||
1008 | static enum rx_mgmt_action __must_check | 730 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) |
1009 | ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | ||
1010 | struct ieee80211_mgd_work *wk) | ||
1011 | { | ||
1012 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1013 | struct ieee80211_local *local = sdata->local; | ||
1014 | |||
1015 | wk->tries++; | ||
1016 | if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { | ||
1017 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | ||
1018 | sdata->name, wk->bss->cbss.bssid); | ||
1019 | |||
1020 | /* | ||
1021 | * Most likely AP is not in the range so remove the | ||
1022 | * bss struct for that AP. | ||
1023 | */ | ||
1024 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); | ||
1025 | |||
1026 | /* | ||
1027 | * We might have a pending scan which had no chance to run yet | ||
1028 | * due to work needing to be done. Hence, queue the STAs work | ||
1029 | * again for that. | ||
1030 | */ | ||
1031 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
1032 | return RX_MGMT_CFG80211_AUTH_TO; | ||
1033 | } | ||
1034 | |||
1035 | printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", | ||
1036 | sdata->name, wk->bss->cbss.bssid, | ||
1037 | wk->tries); | ||
1038 | |||
1039 | /* | ||
1040 | * Direct probe is sent to broadcast address as some APs | ||
1041 | * will not answer to direct packet in unassociated state. | ||
1042 | */ | ||
1043 | ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); | ||
1044 | |||
1045 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
1046 | run_again(ifmgd, wk->timeout); | ||
1047 | |||
1048 | return RX_MGMT_NONE; | ||
1049 | } | ||
1050 | |||
1051 | |||
1052 | static enum rx_mgmt_action __must_check | ||
1053 | ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | ||
1054 | struct ieee80211_mgd_work *wk) | ||
1055 | { | ||
1056 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1057 | struct ieee80211_local *local = sdata->local; | ||
1058 | |||
1059 | wk->tries++; | ||
1060 | if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { | ||
1061 | printk(KERN_DEBUG "%s: authentication with AP %pM" | ||
1062 | " timed out\n", | ||
1063 | sdata->name, wk->bss->cbss.bssid); | ||
1064 | |||
1065 | /* | ||
1066 | * Most likely AP is not in the range so remove the | ||
1067 | * bss struct for that AP. | ||
1068 | */ | ||
1069 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); | ||
1070 | |||
1071 | /* | ||
1072 | * We might have a pending scan which had no chance to run yet | ||
1073 | * due to work needing to be done. Hence, queue the STAs work | ||
1074 | * again for that. | ||
1075 | */ | ||
1076 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
1077 | return RX_MGMT_CFG80211_AUTH_TO; | ||
1078 | } | ||
1079 | |||
1080 | printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", | ||
1081 | sdata->name, wk->bss->cbss.bssid, wk->tries); | ||
1082 | |||
1083 | ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, | ||
1084 | wk->bss->cbss.bssid, NULL, 0, 0); | ||
1085 | wk->auth_transaction = 2; | ||
1086 | |||
1087 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
1088 | run_again(ifmgd, wk->timeout); | ||
1089 | |||
1090 | return RX_MGMT_NONE; | ||
1091 | } | ||
1092 | |||
1093 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | ||
1094 | bool deauth) | ||
1095 | { | 731 | { |
1096 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 732 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1097 | struct ieee80211_local *local = sdata->local; | 733 | struct ieee80211_local *local = sdata->local; |
@@ -1104,21 +740,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1104 | if (WARN_ON(!ifmgd->associated)) | 740 | if (WARN_ON(!ifmgd->associated)) |
1105 | return; | 741 | return; |
1106 | 742 | ||
1107 | memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); | 743 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
1108 | 744 | ||
1109 | ifmgd->associated = NULL; | 745 | ifmgd->associated = NULL; |
1110 | memset(ifmgd->bssid, 0, ETH_ALEN); | 746 | memset(ifmgd->bssid, 0, ETH_ALEN); |
1111 | 747 | ||
1112 | if (deauth) { | ||
1113 | kfree(ifmgd->old_associate_work); | ||
1114 | ifmgd->old_associate_work = NULL; | ||
1115 | } else { | ||
1116 | struct ieee80211_mgd_work *wk = ifmgd->old_associate_work; | ||
1117 | |||
1118 | wk->state = IEEE80211_MGD_STATE_IDLE; | ||
1119 | list_add(&wk->list, &ifmgd->work_list); | ||
1120 | } | ||
1121 | |||
1122 | /* | 748 | /* |
1123 | * we need to commit the associated = NULL change because the | 749 | * we need to commit the associated = NULL change because the |
1124 | * scan code uses that to determine whether this iface should | 750 | * scan code uses that to determine whether this iface should |
@@ -1187,44 +813,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1187 | sta_info_destroy(sta); | 813 | sta_info_destroy(sta); |
1188 | } | 814 | } |
1189 | 815 | ||
1190 | static enum rx_mgmt_action __must_check | ||
1191 | ieee80211_associate(struct ieee80211_sub_if_data *sdata, | ||
1192 | struct ieee80211_mgd_work *wk) | ||
1193 | { | ||
1194 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1195 | struct ieee80211_local *local = sdata->local; | ||
1196 | |||
1197 | wk->tries++; | ||
1198 | if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
1199 | printk(KERN_DEBUG "%s: association with AP %pM" | ||
1200 | " timed out\n", | ||
1201 | sdata->name, wk->bss->cbss.bssid); | ||
1202 | |||
1203 | /* | ||
1204 | * Most likely AP is not in the range so remove the | ||
1205 | * bss struct for that AP. | ||
1206 | */ | ||
1207 | cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); | ||
1208 | |||
1209 | /* | ||
1210 | * We might have a pending scan which had no chance to run yet | ||
1211 | * due to work needing to be done. Hence, queue the STAs work | ||
1212 | * again for that. | ||
1213 | */ | ||
1214 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
1215 | return RX_MGMT_CFG80211_ASSOC_TO; | ||
1216 | } | ||
1217 | |||
1218 | printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", | ||
1219 | sdata->name, wk->bss->cbss.bssid, wk->tries); | ||
1220 | ieee80211_send_assoc(sdata, wk); | ||
1221 | |||
1222 | wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | ||
1223 | run_again(ifmgd, wk->timeout); | ||
1224 | |||
1225 | return RX_MGMT_NONE; | ||
1226 | } | ||
1227 | |||
1228 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 816 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1229 | struct ieee80211_hdr *hdr) | 817 | struct ieee80211_hdr *hdr) |
1230 | { | 818 | { |
@@ -1248,8 +836,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1248 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 836 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1249 | const u8 *ssid; | 837 | const u8 *ssid; |
1250 | 838 | ||
1251 | ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); | 839 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
1252 | ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, | 840 | ieee80211_send_probe_req(sdata, ifmgd->associated->bssid, |
1253 | ssid + 2, ssid[1], NULL, 0); | 841 | ssid + 2, ssid[1], NULL, 0); |
1254 | 842 | ||
1255 | ifmgd->probe_send_count++; | 843 | ifmgd->probe_send_count++; |
@@ -1263,12 +851,15 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
1263 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 851 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1264 | bool already = false; | 852 | bool already = false; |
1265 | 853 | ||
1266 | if (!netif_running(sdata->dev)) | 854 | if (!ieee80211_sdata_running(sdata)) |
1267 | return; | 855 | return; |
1268 | 856 | ||
1269 | if (sdata->local->scanning) | 857 | if (sdata->local->scanning) |
1270 | return; | 858 | return; |
1271 | 859 | ||
860 | if (sdata->local->tmp_channel) | ||
861 | return; | ||
862 | |||
1272 | mutex_lock(&ifmgd->mtx); | 863 | mutex_lock(&ifmgd->mtx); |
1273 | 864 | ||
1274 | if (!ifmgd->associated) | 865 | if (!ifmgd->associated) |
@@ -1330,88 +921,8 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) | |||
1330 | } | 921 | } |
1331 | EXPORT_SYMBOL(ieee80211_beacon_loss); | 922 | EXPORT_SYMBOL(ieee80211_beacon_loss); |
1332 | 923 | ||
1333 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | ||
1334 | struct ieee80211_mgd_work *wk) | ||
1335 | { | ||
1336 | wk->state = IEEE80211_MGD_STATE_IDLE; | ||
1337 | printk(KERN_DEBUG "%s: authenticated\n", sdata->name); | ||
1338 | } | ||
1339 | |||
1340 | |||
1341 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | ||
1342 | struct ieee80211_mgd_work *wk, | ||
1343 | struct ieee80211_mgmt *mgmt, | ||
1344 | size_t len) | ||
1345 | { | ||
1346 | u8 *pos; | ||
1347 | struct ieee802_11_elems elems; | ||
1348 | |||
1349 | pos = mgmt->u.auth.variable; | ||
1350 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1351 | if (!elems.challenge) | ||
1352 | return; | ||
1353 | ieee80211_send_auth(sdata, 3, wk->auth_alg, | ||
1354 | elems.challenge - 2, elems.challenge_len + 2, | ||
1355 | wk->bss->cbss.bssid, | ||
1356 | wk->key, wk->key_len, wk->key_idx); | ||
1357 | wk->auth_transaction = 4; | ||
1358 | } | ||
1359 | |||
1360 | static enum rx_mgmt_action __must_check | ||
1361 | ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | ||
1362 | struct ieee80211_mgd_work *wk, | ||
1363 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1364 | { | ||
1365 | u16 auth_alg, auth_transaction, status_code; | ||
1366 | |||
1367 | if (wk->state != IEEE80211_MGD_STATE_AUTH) | ||
1368 | return RX_MGMT_NONE; | ||
1369 | |||
1370 | if (len < 24 + 6) | ||
1371 | return RX_MGMT_NONE; | ||
1372 | |||
1373 | if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) | ||
1374 | return RX_MGMT_NONE; | ||
1375 | |||
1376 | if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1377 | return RX_MGMT_NONE; | ||
1378 | |||
1379 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
1380 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
1381 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
1382 | |||
1383 | if (auth_alg != wk->auth_alg || | ||
1384 | auth_transaction != wk->auth_transaction) | ||
1385 | return RX_MGMT_NONE; | ||
1386 | |||
1387 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
1388 | list_del(&wk->list); | ||
1389 | kfree(wk); | ||
1390 | return RX_MGMT_CFG80211_AUTH; | ||
1391 | } | ||
1392 | |||
1393 | switch (wk->auth_alg) { | ||
1394 | case WLAN_AUTH_OPEN: | ||
1395 | case WLAN_AUTH_LEAP: | ||
1396 | case WLAN_AUTH_FT: | ||
1397 | ieee80211_auth_completed(sdata, wk); | ||
1398 | return RX_MGMT_CFG80211_AUTH; | ||
1399 | case WLAN_AUTH_SHARED_KEY: | ||
1400 | if (wk->auth_transaction == 4) { | ||
1401 | ieee80211_auth_completed(sdata, wk); | ||
1402 | return RX_MGMT_CFG80211_AUTH; | ||
1403 | } else | ||
1404 | ieee80211_auth_challenge(sdata, wk, mgmt, len); | ||
1405 | break; | ||
1406 | } | ||
1407 | |||
1408 | return RX_MGMT_NONE; | ||
1409 | } | ||
1410 | |||
1411 | |||
1412 | static enum rx_mgmt_action __must_check | 924 | static enum rx_mgmt_action __must_check |
1413 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 925 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1414 | struct ieee80211_mgd_work *wk, | ||
1415 | struct ieee80211_mgmt *mgmt, size_t len) | 926 | struct ieee80211_mgmt *mgmt, size_t len) |
1416 | { | 927 | { |
1417 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 928 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1423,23 +934,15 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1423 | 934 | ||
1424 | ASSERT_MGD_MTX(ifmgd); | 935 | ASSERT_MGD_MTX(ifmgd); |
1425 | 936 | ||
1426 | if (wk) | 937 | bssid = ifmgd->associated->bssid; |
1427 | bssid = wk->bss->cbss.bssid; | ||
1428 | else | ||
1429 | bssid = ifmgd->associated->cbss.bssid; | ||
1430 | 938 | ||
1431 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 939 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
1432 | 940 | ||
1433 | printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", | 941 | printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", |
1434 | sdata->name, bssid, reason_code); | 942 | sdata->name, bssid, reason_code); |
1435 | 943 | ||
1436 | if (!wk) { | 944 | ieee80211_set_disassoc(sdata); |
1437 | ieee80211_set_disassoc(sdata, true); | 945 | ieee80211_recalc_idle(sdata->local); |
1438 | ieee80211_recalc_idle(sdata->local); | ||
1439 | } else { | ||
1440 | list_del(&wk->list); | ||
1441 | kfree(wk); | ||
1442 | } | ||
1443 | 946 | ||
1444 | return RX_MGMT_CFG80211_DEAUTH; | 947 | return RX_MGMT_CFG80211_DEAUTH; |
1445 | } | 948 | } |
@@ -1460,7 +963,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1460 | if (WARN_ON(!ifmgd->associated)) | 963 | if (WARN_ON(!ifmgd->associated)) |
1461 | return RX_MGMT_NONE; | 964 | return RX_MGMT_NONE; |
1462 | 965 | ||
1463 | if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN))) | 966 | if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN))) |
1464 | return RX_MGMT_NONE; | 967 | return RX_MGMT_NONE; |
1465 | 968 | ||
1466 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 969 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
@@ -1468,96 +971,57 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1468 | printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", | 971 | printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", |
1469 | sdata->name, mgmt->sa, reason_code); | 972 | sdata->name, mgmt->sa, reason_code); |
1470 | 973 | ||
1471 | ieee80211_set_disassoc(sdata, false); | 974 | ieee80211_set_disassoc(sdata); |
1472 | ieee80211_recalc_idle(sdata->local); | 975 | ieee80211_recalc_idle(sdata->local); |
1473 | return RX_MGMT_CFG80211_DISASSOC; | 976 | return RX_MGMT_CFG80211_DISASSOC; |
1474 | } | 977 | } |
1475 | 978 | ||
1476 | 979 | ||
1477 | static enum rx_mgmt_action __must_check | 980 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, |
1478 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 981 | struct ieee80211_mgmt *mgmt, size_t len) |
1479 | struct ieee80211_mgd_work *wk, | ||
1480 | struct ieee80211_mgmt *mgmt, size_t len, | ||
1481 | bool reassoc) | ||
1482 | { | 982 | { |
983 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
1483 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 984 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1484 | struct ieee80211_local *local = sdata->local; | 985 | struct ieee80211_local *local = sdata->local; |
1485 | struct ieee80211_supported_band *sband; | 986 | struct ieee80211_supported_band *sband; |
1486 | struct sta_info *sta; | 987 | struct sta_info *sta; |
988 | struct cfg80211_bss *cbss = wk->assoc.bss; | ||
989 | u8 *pos; | ||
1487 | u32 rates, basic_rates; | 990 | u32 rates, basic_rates; |
1488 | u16 capab_info, status_code, aid; | 991 | u16 capab_info, aid; |
1489 | struct ieee802_11_elems elems; | 992 | struct ieee802_11_elems elems; |
1490 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 993 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
1491 | u8 *pos; | ||
1492 | u32 changed = 0; | 994 | u32 changed = 0; |
1493 | int i, j, err; | 995 | int i, j, err; |
1494 | bool have_higher_than_11mbit = false; | 996 | bool have_higher_than_11mbit = false; |
1495 | u16 ap_ht_cap_flags; | 997 | u16 ap_ht_cap_flags; |
1496 | 998 | ||
1497 | /* | 999 | /* AssocResp and ReassocResp have identical structure */ |
1498 | * AssocResp and ReassocResp have identical structure, so process both | ||
1499 | * of them in this function. | ||
1500 | */ | ||
1501 | |||
1502 | if (len < 24 + 6) | ||
1503 | return RX_MGMT_NONE; | ||
1504 | 1000 | ||
1505 | if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) | ||
1506 | return RX_MGMT_NONE; | ||
1507 | |||
1508 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | ||
1509 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
1510 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | 1001 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); |
1511 | 1002 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | |
1512 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " | ||
1513 | "status=%d aid=%d)\n", | ||
1514 | sdata->name, reassoc ? "Rea" : "A", mgmt->sa, | ||
1515 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | ||
1516 | |||
1517 | pos = mgmt->u.assoc_resp.variable; | ||
1518 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1519 | |||
1520 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
1521 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
1522 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
1523 | u32 tu, ms; | ||
1524 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
1525 | ms = tu * 1024 / 1000; | ||
1526 | printk(KERN_DEBUG "%s: AP rejected association temporarily; " | ||
1527 | "comeback duration %u TU (%u ms)\n", | ||
1528 | sdata->name, tu, ms); | ||
1529 | wk->timeout = jiffies + msecs_to_jiffies(ms); | ||
1530 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
1531 | run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); | ||
1532 | return RX_MGMT_NONE; | ||
1533 | } | ||
1534 | |||
1535 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
1536 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", | ||
1537 | sdata->name, status_code); | ||
1538 | wk->state = IEEE80211_MGD_STATE_IDLE; | ||
1539 | return RX_MGMT_CFG80211_ASSOC; | ||
1540 | } | ||
1541 | 1003 | ||
1542 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) | 1004 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) |
1543 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " | 1005 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " |
1544 | "set\n", sdata->name, aid); | 1006 | "set\n", sdata->name, aid); |
1545 | aid &= ~(BIT(15) | BIT(14)); | 1007 | aid &= ~(BIT(15) | BIT(14)); |
1546 | 1008 | ||
1009 | pos = mgmt->u.assoc_resp.variable; | ||
1010 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1011 | |||
1547 | if (!elems.supp_rates) { | 1012 | if (!elems.supp_rates) { |
1548 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", | 1013 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", |
1549 | sdata->name); | 1014 | sdata->name); |
1550 | return RX_MGMT_NONE; | 1015 | return false; |
1551 | } | 1016 | } |
1552 | 1017 | ||
1553 | printk(KERN_DEBUG "%s: associated\n", sdata->name); | ||
1554 | ifmgd->aid = aid; | 1018 | ifmgd->aid = aid; |
1555 | 1019 | ||
1556 | sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); | 1020 | sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); |
1557 | if (!sta) { | 1021 | if (!sta) { |
1558 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | 1022 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" |
1559 | " the AP\n", sdata->name); | 1023 | " the AP\n", sdata->name); |
1560 | return RX_MGMT_CFG80211_ASSOC_ERROR; | 1024 | return false; |
1561 | } | 1025 | } |
1562 | 1026 | ||
1563 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | | 1027 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | |
@@ -1641,22 +1105,19 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1641 | else | 1105 | else |
1642 | ieee80211_set_wmm_default(sdata); | 1106 | ieee80211_set_wmm_default(sdata); |
1643 | 1107 | ||
1108 | local->oper_channel = wk->chan; | ||
1109 | |||
1644 | if (elems.ht_info_elem && elems.wmm_param && | 1110 | if (elems.ht_info_elem && elems.wmm_param && |
1645 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | 1111 | (sdata->local->hw.queues >= 4) && |
1646 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 1112 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
1647 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1113 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1648 | wk->bss->cbss.bssid, | 1114 | cbss->bssid, ap_ht_cap_flags); |
1649 | ap_ht_cap_flags); | ||
1650 | |||
1651 | /* delete work item -- must be before set_associated for PS */ | ||
1652 | list_del(&wk->list); | ||
1653 | 1115 | ||
1654 | /* set AID and assoc capability, | 1116 | /* set AID and assoc capability, |
1655 | * ieee80211_set_associated() will tell the driver */ | 1117 | * ieee80211_set_associated() will tell the driver */ |
1656 | bss_conf->aid = aid; | 1118 | bss_conf->aid = aid; |
1657 | bss_conf->assoc_capability = capab_info; | 1119 | bss_conf->assoc_capability = capab_info; |
1658 | /* this will take ownership of wk */ | 1120 | ieee80211_set_associated(sdata, cbss, changed); |
1659 | ieee80211_set_associated(sdata, wk, changed); | ||
1660 | 1121 | ||
1661 | /* | 1122 | /* |
1662 | * Start timer to probe the connection to the AP now. | 1123 | * Start timer to probe the connection to the AP now. |
@@ -1665,7 +1126,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1665 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 1126 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1666 | mod_beacon_timer(sdata); | 1127 | mod_beacon_timer(sdata); |
1667 | 1128 | ||
1668 | return RX_MGMT_CFG80211_ASSOC; | 1129 | return true; |
1669 | } | 1130 | } |
1670 | 1131 | ||
1671 | 1132 | ||
@@ -1700,7 +1161,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1700 | return; | 1161 | return; |
1701 | 1162 | ||
1702 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | 1163 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && |
1703 | (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid, | 1164 | (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, |
1704 | ETH_ALEN) == 0)) { | 1165 | ETH_ALEN) == 0)) { |
1705 | struct ieee80211_channel_sw_ie *sw_elem = | 1166 | struct ieee80211_channel_sw_ie *sw_elem = |
1706 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | 1167 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
@@ -1710,12 +1171,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1710 | 1171 | ||
1711 | 1172 | ||
1712 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | 1173 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, |
1713 | struct ieee80211_mgd_work *wk, | 1174 | struct sk_buff *skb) |
1714 | struct ieee80211_mgmt *mgmt, size_t len, | ||
1715 | struct ieee80211_rx_status *rx_status) | ||
1716 | { | 1175 | { |
1176 | struct ieee80211_mgmt *mgmt = (void *)skb->data; | ||
1717 | struct ieee80211_if_managed *ifmgd; | 1177 | struct ieee80211_if_managed *ifmgd; |
1718 | size_t baselen; | 1178 | struct ieee80211_rx_status *rx_status = (void *) skb->cb; |
1179 | size_t baselen, len = skb->len; | ||
1719 | struct ieee802_11_elems elems; | 1180 | struct ieee802_11_elems elems; |
1720 | 1181 | ||
1721 | ifmgd = &sdata->u.mgd; | 1182 | ifmgd = &sdata->u.mgd; |
@@ -1734,17 +1195,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1734 | 1195 | ||
1735 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 1196 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
1736 | 1197 | ||
1737 | /* direct probe may be part of the association flow */ | ||
1738 | if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { | ||
1739 | printk(KERN_DEBUG "%s: direct probe responded\n", | ||
1740 | sdata->name); | ||
1741 | wk->tries = 0; | ||
1742 | wk->state = IEEE80211_MGD_STATE_AUTH; | ||
1743 | WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); | ||
1744 | } | ||
1745 | |||
1746 | if (ifmgd->associated && | 1198 | if (ifmgd->associated && |
1747 | memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && | 1199 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && |
1748 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1200 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
1749 | IEEE80211_STA_CONNECTION_POLL)) { | 1201 | IEEE80211_STA_CONNECTION_POLL)) { |
1750 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | 1202 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
@@ -1817,7 +1269,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1817 | if (!ifmgd->associated) | 1269 | if (!ifmgd->associated) |
1818 | return; | 1270 | return; |
1819 | 1271 | ||
1820 | bssid = ifmgd->associated->cbss.bssid; | 1272 | bssid = ifmgd->associated->bssid; |
1821 | 1273 | ||
1822 | /* | 1274 | /* |
1823 | * And in theory even frames from a different AP we were just | 1275 | * And in theory even frames from a different AP we were just |
@@ -1956,9 +1408,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1956 | switch (fc & IEEE80211_FCTL_STYPE) { | 1408 | switch (fc & IEEE80211_FCTL_STYPE) { |
1957 | case IEEE80211_STYPE_PROBE_RESP: | 1409 | case IEEE80211_STYPE_PROBE_RESP: |
1958 | case IEEE80211_STYPE_BEACON: | 1410 | case IEEE80211_STYPE_BEACON: |
1959 | case IEEE80211_STYPE_AUTH: | ||
1960 | case IEEE80211_STYPE_ASSOC_RESP: | ||
1961 | case IEEE80211_STYPE_REASSOC_RESP: | ||
1962 | case IEEE80211_STYPE_DEAUTH: | 1411 | case IEEE80211_STYPE_DEAUTH: |
1963 | case IEEE80211_STYPE_DISASSOC: | 1412 | case IEEE80211_STYPE_DISASSOC: |
1964 | case IEEE80211_STYPE_ACTION: | 1413 | case IEEE80211_STYPE_ACTION: |
@@ -1976,7 +1425,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1976 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1425 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1977 | struct ieee80211_rx_status *rx_status; | 1426 | struct ieee80211_rx_status *rx_status; |
1978 | struct ieee80211_mgmt *mgmt; | 1427 | struct ieee80211_mgmt *mgmt; |
1979 | struct ieee80211_mgd_work *wk; | ||
1980 | enum rx_mgmt_action rma = RX_MGMT_NONE; | 1428 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
1981 | u16 fc; | 1429 | u16 fc; |
1982 | 1430 | ||
@@ -1987,20 +1435,17 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1987 | mutex_lock(&ifmgd->mtx); | 1435 | mutex_lock(&ifmgd->mtx); |
1988 | 1436 | ||
1989 | if (ifmgd->associated && | 1437 | if (ifmgd->associated && |
1990 | memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid, | 1438 | memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) { |
1991 | ETH_ALEN) == 0) { | ||
1992 | switch (fc & IEEE80211_FCTL_STYPE) { | 1439 | switch (fc & IEEE80211_FCTL_STYPE) { |
1993 | case IEEE80211_STYPE_BEACON: | 1440 | case IEEE80211_STYPE_BEACON: |
1994 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 1441 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
1995 | rx_status); | 1442 | rx_status); |
1996 | break; | 1443 | break; |
1997 | case IEEE80211_STYPE_PROBE_RESP: | 1444 | case IEEE80211_STYPE_PROBE_RESP: |
1998 | ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt, | 1445 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
1999 | skb->len, rx_status); | ||
2000 | break; | 1446 | break; |
2001 | case IEEE80211_STYPE_DEAUTH: | 1447 | case IEEE80211_STYPE_DEAUTH: |
2002 | rma = ieee80211_rx_mgmt_deauth(sdata, NULL, | 1448 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
2003 | mgmt, skb->len); | ||
2004 | break; | 1449 | break; |
2005 | case IEEE80211_STYPE_DISASSOC: | 1450 | case IEEE80211_STYPE_DISASSOC: |
2006 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); | 1451 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
@@ -2009,7 +1454,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2009 | /* XXX: differentiate, can only happen for CSA now! */ | 1454 | /* XXX: differentiate, can only happen for CSA now! */ |
2010 | ieee80211_sta_process_chanswitch(sdata, | 1455 | ieee80211_sta_process_chanswitch(sdata, |
2011 | &mgmt->u.action.u.chan_switch.sw_elem, | 1456 | &mgmt->u.action.u.chan_switch.sw_elem, |
2012 | ifmgd->associated); | 1457 | (void *)ifmgd->associated->priv); |
2013 | break; | 1458 | break; |
2014 | } | 1459 | } |
2015 | mutex_unlock(&ifmgd->mtx); | 1460 | mutex_unlock(&ifmgd->mtx); |
@@ -2030,62 +1475,11 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2030 | goto out; | 1475 | goto out; |
2031 | } | 1476 | } |
2032 | 1477 | ||
2033 | list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
2034 | if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
2035 | continue; | ||
2036 | |||
2037 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
2038 | case IEEE80211_STYPE_PROBE_RESP: | ||
2039 | ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len, | ||
2040 | rx_status); | ||
2041 | break; | ||
2042 | case IEEE80211_STYPE_AUTH: | ||
2043 | rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len); | ||
2044 | break; | ||
2045 | case IEEE80211_STYPE_ASSOC_RESP: | ||
2046 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, | ||
2047 | skb->len, false); | ||
2048 | break; | ||
2049 | case IEEE80211_STYPE_REASSOC_RESP: | ||
2050 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, | ||
2051 | skb->len, true); | ||
2052 | break; | ||
2053 | case IEEE80211_STYPE_DEAUTH: | ||
2054 | rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt, | ||
2055 | skb->len); | ||
2056 | break; | ||
2057 | } | ||
2058 | /* | ||
2059 | * We've processed this frame for that work, so it can't | ||
2060 | * belong to another work struct. | ||
2061 | * NB: this is also required for correctness because the | ||
2062 | * called functions can free 'wk', and for 'rma'! | ||
2063 | */ | ||
2064 | break; | ||
2065 | } | ||
2066 | |||
2067 | mutex_unlock(&ifmgd->mtx); | 1478 | mutex_unlock(&ifmgd->mtx); |
2068 | 1479 | ||
2069 | switch (rma) { | 1480 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && |
2070 | case RX_MGMT_NONE: | 1481 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) |
2071 | /* no action */ | ||
2072 | break; | ||
2073 | case RX_MGMT_CFG80211_AUTH: | ||
2074 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len); | ||
2075 | break; | ||
2076 | case RX_MGMT_CFG80211_ASSOC: | ||
2077 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); | ||
2078 | break; | ||
2079 | case RX_MGMT_CFG80211_DEAUTH: | ||
2080 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 1482 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); |
2081 | break; | ||
2082 | case RX_MGMT_CFG80211_ASSOC_ERROR: | ||
2083 | /* an internal error -- pretend timeout for now */ | ||
2084 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); | ||
2085 | break; | ||
2086 | default: | ||
2087 | WARN(1, "unexpected: %d", rma); | ||
2088 | } | ||
2089 | 1483 | ||
2090 | out: | 1484 | out: |
2091 | kfree_skb(skb); | 1485 | kfree_skb(skb); |
@@ -2113,12 +1507,8 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2113 | struct ieee80211_local *local = sdata->local; | 1507 | struct ieee80211_local *local = sdata->local; |
2114 | struct ieee80211_if_managed *ifmgd; | 1508 | struct ieee80211_if_managed *ifmgd; |
2115 | struct sk_buff *skb; | 1509 | struct sk_buff *skb; |
2116 | struct ieee80211_mgd_work *wk, *tmp; | ||
2117 | LIST_HEAD(free_work); | ||
2118 | enum rx_mgmt_action rma; | ||
2119 | bool anybusy = false; | ||
2120 | 1510 | ||
2121 | if (!netif_running(sdata->dev)) | 1511 | if (!ieee80211_sdata_running(sdata)) |
2122 | return; | 1512 | return; |
2123 | 1513 | ||
2124 | if (local->scanning) | 1514 | if (local->scanning) |
@@ -2149,7 +1539,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2149 | ifmgd->associated) { | 1539 | ifmgd->associated) { |
2150 | u8 bssid[ETH_ALEN]; | 1540 | u8 bssid[ETH_ALEN]; |
2151 | 1541 | ||
2152 | memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); | 1542 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
2153 | if (time_is_after_jiffies(ifmgd->probe_timeout)) | 1543 | if (time_is_after_jiffies(ifmgd->probe_timeout)) |
2154 | run_again(ifmgd, ifmgd->probe_timeout); | 1544 | run_again(ifmgd, ifmgd->probe_timeout); |
2155 | 1545 | ||
@@ -2171,7 +1561,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2171 | printk(KERN_DEBUG "No probe response from AP %pM" | 1561 | printk(KERN_DEBUG "No probe response from AP %pM" |
2172 | " after %dms, disconnecting.\n", | 1562 | " after %dms, disconnecting.\n", |
2173 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 1563 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
2174 | ieee80211_set_disassoc(sdata, true); | 1564 | ieee80211_set_disassoc(sdata); |
2175 | ieee80211_recalc_idle(local); | 1565 | ieee80211_recalc_idle(local); |
2176 | mutex_unlock(&ifmgd->mtx); | 1566 | mutex_unlock(&ifmgd->mtx); |
2177 | /* | 1567 | /* |
@@ -2186,87 +1576,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2186 | } | 1576 | } |
2187 | } | 1577 | } |
2188 | 1578 | ||
2189 | |||
2190 | ieee80211_recalc_idle(local); | ||
2191 | |||
2192 | list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { | ||
2193 | if (time_is_after_jiffies(wk->timeout)) { | ||
2194 | /* | ||
2195 | * This work item isn't supposed to be worked on | ||
2196 | * right now, but take care to adjust the timer | ||
2197 | * properly. | ||
2198 | */ | ||
2199 | run_again(ifmgd, wk->timeout); | ||
2200 | continue; | ||
2201 | } | ||
2202 | |||
2203 | switch (wk->state) { | ||
2204 | default: | ||
2205 | WARN_ON(1); | ||
2206 | /* fall through */ | ||
2207 | case IEEE80211_MGD_STATE_IDLE: | ||
2208 | /* nothing */ | ||
2209 | rma = RX_MGMT_NONE; | ||
2210 | break; | ||
2211 | case IEEE80211_MGD_STATE_PROBE: | ||
2212 | rma = ieee80211_direct_probe(sdata, wk); | ||
2213 | break; | ||
2214 | case IEEE80211_MGD_STATE_AUTH: | ||
2215 | rma = ieee80211_authenticate(sdata, wk); | ||
2216 | break; | ||
2217 | case IEEE80211_MGD_STATE_ASSOC: | ||
2218 | rma = ieee80211_associate(sdata, wk); | ||
2219 | break; | ||
2220 | } | ||
2221 | |||
2222 | switch (rma) { | ||
2223 | case RX_MGMT_NONE: | ||
2224 | /* no action required */ | ||
2225 | break; | ||
2226 | case RX_MGMT_CFG80211_AUTH_TO: | ||
2227 | case RX_MGMT_CFG80211_ASSOC_TO: | ||
2228 | list_del(&wk->list); | ||
2229 | list_add(&wk->list, &free_work); | ||
2230 | wk->tries = rma; /* small abuse but only local */ | ||
2231 | break; | ||
2232 | default: | ||
2233 | WARN(1, "unexpected: %d", rma); | ||
2234 | } | ||
2235 | } | ||
2236 | |||
2237 | list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
2238 | if (wk->state != IEEE80211_MGD_STATE_IDLE) { | ||
2239 | anybusy = true; | ||
2240 | break; | ||
2241 | } | ||
2242 | } | ||
2243 | if (!anybusy && | ||
2244 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) | ||
2245 | ieee80211_queue_delayed_work(&local->hw, | ||
2246 | &local->scan_work, | ||
2247 | round_jiffies_relative(0)); | ||
2248 | |||
2249 | mutex_unlock(&ifmgd->mtx); | 1579 | mutex_unlock(&ifmgd->mtx); |
2250 | |||
2251 | list_for_each_entry_safe(wk, tmp, &free_work, list) { | ||
2252 | switch (wk->tries) { | ||
2253 | case RX_MGMT_CFG80211_AUTH_TO: | ||
2254 | cfg80211_send_auth_timeout(sdata->dev, | ||
2255 | wk->bss->cbss.bssid); | ||
2256 | break; | ||
2257 | case RX_MGMT_CFG80211_ASSOC_TO: | ||
2258 | cfg80211_send_assoc_timeout(sdata->dev, | ||
2259 | wk->bss->cbss.bssid); | ||
2260 | break; | ||
2261 | default: | ||
2262 | WARN(1, "unexpected: %d", wk->tries); | ||
2263 | } | ||
2264 | |||
2265 | list_del(&wk->list); | ||
2266 | kfree(wk); | ||
2267 | } | ||
2268 | |||
2269 | ieee80211_recalc_idle(local); | ||
2270 | } | 1580 | } |
2271 | 1581 | ||
2272 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) | 1582 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) |
@@ -2375,12 +1685,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2375 | (unsigned long) sdata); | 1685 | (unsigned long) sdata); |
2376 | skb_queue_head_init(&ifmgd->skb_queue); | 1686 | skb_queue_head_init(&ifmgd->skb_queue); |
2377 | 1687 | ||
2378 | INIT_LIST_HEAD(&ifmgd->work_list); | ||
2379 | |||
2380 | ifmgd->capab = WLAN_CAPABILITY_ESS; | ||
2381 | ifmgd->flags = 0; | 1688 | ifmgd->flags = 0; |
2382 | if (sdata->local->hw.queues >= 4) | ||
2383 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; | ||
2384 | 1689 | ||
2385 | mutex_init(&ifmgd->mtx); | 1690 | mutex_init(&ifmgd->mtx); |
2386 | 1691 | ||
@@ -2418,12 +1723,34 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
2418 | } | 1723 | } |
2419 | 1724 | ||
2420 | /* config hooks */ | 1725 | /* config hooks */ |
1726 | static enum work_done_result | ||
1727 | ieee80211_probe_auth_done(struct ieee80211_work *wk, | ||
1728 | struct sk_buff *skb) | ||
1729 | { | ||
1730 | if (!skb) { | ||
1731 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); | ||
1732 | return WORK_DONE_DESTROY; | ||
1733 | } | ||
1734 | |||
1735 | if (wk->type == IEEE80211_WORK_AUTH) { | ||
1736 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); | ||
1737 | return WORK_DONE_DESTROY; | ||
1738 | } | ||
1739 | |||
1740 | mutex_lock(&wk->sdata->u.mgd.mtx); | ||
1741 | ieee80211_rx_mgmt_probe_resp(wk->sdata, skb); | ||
1742 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
1743 | |||
1744 | wk->type = IEEE80211_WORK_AUTH; | ||
1745 | wk->probe_auth.tries = 0; | ||
1746 | return WORK_DONE_REQUEUE; | ||
1747 | } | ||
1748 | |||
2421 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | 1749 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
2422 | struct cfg80211_auth_request *req) | 1750 | struct cfg80211_auth_request *req) |
2423 | { | 1751 | { |
2424 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2425 | const u8 *ssid; | 1752 | const u8 *ssid; |
2426 | struct ieee80211_mgd_work *wk; | 1753 | struct ieee80211_work *wk; |
2427 | u16 auth_alg; | 1754 | u16 auth_alg; |
2428 | 1755 | ||
2429 | switch (req->auth_type) { | 1756 | switch (req->auth_type) { |
@@ -2447,7 +1774,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2447 | if (!wk) | 1774 | if (!wk) |
2448 | return -ENOMEM; | 1775 | return -ENOMEM; |
2449 | 1776 | ||
2450 | wk->bss = (void *)req->bss; | 1777 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);; |
2451 | 1778 | ||
2452 | if (req->ie && req->ie_len) { | 1779 | if (req->ie && req->ie_len) { |
2453 | memcpy(wk->ie, req->ie, req->ie_len); | 1780 | memcpy(wk->ie, req->ie, req->ie_len); |
@@ -2455,66 +1782,76 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2455 | } | 1782 | } |
2456 | 1783 | ||
2457 | if (req->key && req->key_len) { | 1784 | if (req->key && req->key_len) { |
2458 | wk->key_len = req->key_len; | 1785 | wk->probe_auth.key_len = req->key_len; |
2459 | wk->key_idx = req->key_idx; | 1786 | wk->probe_auth.key_idx = req->key_idx; |
2460 | memcpy(wk->key, req->key, req->key_len); | 1787 | memcpy(wk->probe_auth.key, req->key, req->key_len); |
2461 | } | 1788 | } |
2462 | 1789 | ||
2463 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 1790 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); |
2464 | memcpy(wk->ssid, ssid + 2, ssid[1]); | 1791 | memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]); |
2465 | wk->ssid_len = ssid[1]; | 1792 | wk->probe_auth.ssid_len = ssid[1]; |
2466 | 1793 | ||
2467 | wk->state = IEEE80211_MGD_STATE_PROBE; | 1794 | wk->probe_auth.algorithm = auth_alg; |
2468 | wk->auth_alg = auth_alg; | 1795 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; |
2469 | wk->timeout = jiffies; /* run right away */ | ||
2470 | 1796 | ||
2471 | /* | 1797 | wk->type = IEEE80211_WORK_DIRECT_PROBE; |
2472 | * XXX: if still associated need to tell AP that we're going | 1798 | wk->chan = req->bss->channel; |
2473 | * to sleep and then change channel etc. | 1799 | wk->sdata = sdata; |
2474 | */ | 1800 | wk->done = ieee80211_probe_auth_done; |
2475 | sdata->local->oper_channel = req->bss->channel; | ||
2476 | ieee80211_hw_config(sdata->local, 0); | ||
2477 | 1801 | ||
2478 | mutex_lock(&ifmgd->mtx); | 1802 | ieee80211_add_work(wk); |
2479 | list_add(&wk->list, &sdata->u.mgd.work_list); | ||
2480 | mutex_unlock(&ifmgd->mtx); | ||
2481 | |||
2482 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); | ||
2483 | return 0; | 1803 | return 0; |
2484 | } | 1804 | } |
2485 | 1805 | ||
2486 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | 1806 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, |
2487 | struct cfg80211_assoc_request *req) | 1807 | struct sk_buff *skb) |
2488 | { | 1808 | { |
2489 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1809 | struct ieee80211_mgmt *mgmt; |
2490 | struct ieee80211_mgd_work *wk, *found = NULL; | 1810 | u16 status; |
2491 | int i, err; | ||
2492 | 1811 | ||
2493 | mutex_lock(&ifmgd->mtx); | 1812 | if (!skb) { |
1813 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); | ||
1814 | return WORK_DONE_DESTROY; | ||
1815 | } | ||
2494 | 1816 | ||
2495 | list_for_each_entry(wk, &ifmgd->work_list, list) { | 1817 | mgmt = (void *)skb->data; |
2496 | if (&wk->bss->cbss == req->bss && | 1818 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
2497 | wk->state == IEEE80211_MGD_STATE_IDLE) { | 1819 | |
2498 | found = wk; | 1820 | if (status == WLAN_STATUS_SUCCESS) { |
2499 | break; | 1821 | mutex_lock(&wk->sdata->u.mgd.mtx); |
1822 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { | ||
1823 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
1824 | /* oops -- internal error -- send timeout for now */ | ||
1825 | cfg80211_send_assoc_timeout(wk->sdata->dev, | ||
1826 | wk->filter_ta); | ||
1827 | return WORK_DONE_DESTROY; | ||
2500 | } | 1828 | } |
1829 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
2501 | } | 1830 | } |
2502 | 1831 | ||
2503 | if (!found) { | 1832 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); |
2504 | err = -ENOLINK; | 1833 | return WORK_DONE_DESTROY; |
2505 | goto out; | 1834 | } |
2506 | } | ||
2507 | 1835 | ||
2508 | list_del(&found->list); | 1836 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, |
1837 | struct cfg80211_assoc_request *req) | ||
1838 | { | ||
1839 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1840 | struct ieee80211_bss *bss = (void *)req->bss->priv; | ||
1841 | struct ieee80211_work *wk; | ||
1842 | const u8 *ssid; | ||
1843 | int i; | ||
2509 | 1844 | ||
2510 | wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL); | 1845 | mutex_lock(&ifmgd->mtx); |
2511 | if (!wk) { | 1846 | if (ifmgd->associated) { |
2512 | list_add(&found->list, &ifmgd->work_list); | 1847 | mutex_unlock(&ifmgd->mtx); |
2513 | err = -ENOMEM; | 1848 | return -EALREADY; |
2514 | goto out; | ||
2515 | } | 1849 | } |
1850 | mutex_unlock(&ifmgd->mtx); | ||
2516 | 1851 | ||
2517 | list_add(&wk->list, &ifmgd->work_list); | 1852 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); |
1853 | if (!wk) | ||
1854 | return -ENOMEM; | ||
2518 | 1855 | ||
2519 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 1856 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
2520 | 1857 | ||
@@ -2524,8 +1861,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2524 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) | 1861 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) |
2525 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 1862 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
2526 | 1863 | ||
2527 | sdata->local->oper_channel = req->bss->channel; | ||
2528 | ieee80211_hw_config(sdata->local, 0); | ||
2529 | 1864 | ||
2530 | if (req->ie && req->ie_len) { | 1865 | if (req->ie && req->ie_len) { |
2531 | memcpy(wk->ie, req->ie, req->ie_len); | 1866 | memcpy(wk->ie, req->ie, req->ie_len); |
@@ -2533,12 +1868,46 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2533 | } else | 1868 | } else |
2534 | wk->ie_len = 0; | 1869 | wk->ie_len = 0; |
2535 | 1870 | ||
1871 | wk->assoc.bss = req->bss; | ||
1872 | |||
1873 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); | ||
1874 | |||
1875 | /* new association always uses requested smps mode */ | ||
1876 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { | ||
1877 | if (ifmgd->powersave) | ||
1878 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; | ||
1879 | else | ||
1880 | ifmgd->ap_smps = IEEE80211_SMPS_OFF; | ||
1881 | } else | ||
1882 | ifmgd->ap_smps = ifmgd->req_smps; | ||
1883 | |||
1884 | wk->assoc.smps = ifmgd->ap_smps; | ||
1885 | /* | ||
1886 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. | ||
1887 | * We still associate in non-HT mode (11a/b/g) if any one of these | ||
1888 | * ciphers is configured as pairwise. | ||
1889 | * We can set this to true for non-11n hardware, that'll be checked | ||
1890 | * separately along with the peer capabilities. | ||
1891 | */ | ||
1892 | wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); | ||
1893 | wk->assoc.capability = req->bss->capability; | ||
1894 | wk->assoc.wmm_used = bss->wmm_used; | ||
1895 | wk->assoc.supp_rates = bss->supp_rates; | ||
1896 | wk->assoc.supp_rates_len = bss->supp_rates_len; | ||
1897 | wk->assoc.ht_information_ie = | ||
1898 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); | ||
1899 | |||
1900 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | ||
1901 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); | ||
1902 | wk->assoc.ssid_len = ssid[1]; | ||
1903 | |||
2536 | if (req->prev_bssid) | 1904 | if (req->prev_bssid) |
2537 | memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); | 1905 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); |
2538 | 1906 | ||
2539 | wk->state = IEEE80211_MGD_STATE_ASSOC; | 1907 | wk->type = IEEE80211_WORK_ASSOC; |
2540 | wk->tries = 0; | 1908 | wk->chan = req->bss->channel; |
2541 | wk->timeout = jiffies; /* run right away */ | 1909 | wk->sdata = sdata; |
1910 | wk->done = ieee80211_assoc_done; | ||
2542 | 1911 | ||
2543 | if (req->use_mfp) { | 1912 | if (req->use_mfp) { |
2544 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; | 1913 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; |
@@ -2553,67 +1922,57 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2553 | else | 1922 | else |
2554 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; | 1923 | ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; |
2555 | 1924 | ||
2556 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); | 1925 | ieee80211_add_work(wk); |
2557 | 1926 | return 0; | |
2558 | err = 0; | ||
2559 | |||
2560 | out: | ||
2561 | mutex_unlock(&ifmgd->mtx); | ||
2562 | return err; | ||
2563 | } | 1927 | } |
2564 | 1928 | ||
2565 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | 1929 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, |
2566 | struct cfg80211_deauth_request *req, | 1930 | struct cfg80211_deauth_request *req, |
2567 | void *cookie) | 1931 | void *cookie) |
2568 | { | 1932 | { |
1933 | struct ieee80211_local *local = sdata->local; | ||
2569 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1934 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2570 | struct ieee80211_mgd_work *wk; | 1935 | struct ieee80211_work *wk; |
2571 | const u8 *bssid = NULL; | 1936 | const u8 *bssid = req->bss->bssid; |
2572 | bool not_auth_yet = false; | ||
2573 | 1937 | ||
2574 | mutex_lock(&ifmgd->mtx); | 1938 | mutex_lock(&ifmgd->mtx); |
2575 | 1939 | ||
2576 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { | 1940 | if (ifmgd->associated == req->bss) { |
2577 | bssid = req->bss->bssid; | 1941 | bssid = req->bss->bssid; |
2578 | ieee80211_set_disassoc(sdata, true); | 1942 | ieee80211_set_disassoc(sdata); |
2579 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { | 1943 | mutex_unlock(&ifmgd->mtx); |
2580 | if (&wk->bss->cbss == req->bss) { | 1944 | } else { |
2581 | bssid = req->bss->bssid; | 1945 | bool not_auth_yet = false; |
2582 | if (wk->state == IEEE80211_MGD_STATE_PROBE) | 1946 | |
2583 | not_auth_yet = true; | 1947 | mutex_unlock(&ifmgd->mtx); |
1948 | |||
1949 | mutex_lock(&local->work_mtx); | ||
1950 | list_for_each_entry(wk, &local->work_list, list) { | ||
1951 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE) | ||
1952 | continue; | ||
1953 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) | ||
1954 | continue; | ||
1955 | not_auth_yet = true; | ||
2584 | list_del(&wk->list); | 1956 | list_del(&wk->list); |
2585 | kfree(wk); | 1957 | free_work(wk); |
2586 | break; | 1958 | break; |
2587 | } | 1959 | } |
2588 | } | 1960 | mutex_unlock(&local->work_mtx); |
2589 | 1961 | ||
2590 | /* | 1962 | /* |
2591 | * If somebody requests authentication and we haven't | 1963 | * If somebody requests authentication and we haven't |
2592 | * sent out an auth frame yet there's no need to send | 1964 | * sent out an auth frame yet there's no need to send |
2593 | * out a deauth frame either. If the state was PROBE, | 1965 | * out a deauth frame either. If the state was PROBE, |
2594 | * then this is the case. If it's AUTH we have sent a | 1966 | * then this is the case. If it's AUTH we have sent a |
2595 | * frame, and if it's IDLE we have completed the auth | 1967 | * frame, and if it's IDLE we have completed the auth |
2596 | * process already. | 1968 | * process already. |
2597 | */ | 1969 | */ |
2598 | if (not_auth_yet) { | 1970 | if (not_auth_yet) { |
2599 | mutex_unlock(&ifmgd->mtx); | 1971 | __cfg80211_auth_canceled(sdata->dev, bssid); |
2600 | __cfg80211_auth_canceled(sdata->dev, bssid); | 1972 | return 0; |
2601 | return 0; | 1973 | } |
2602 | } | ||
2603 | |||
2604 | /* | ||
2605 | * cfg80211 should catch this ... but it's racy since | ||
2606 | * we can receive a deauth frame, process it, hand it | ||
2607 | * to cfg80211 while that's in a locked section already | ||
2608 | * trying to tell us that the user wants to disconnect. | ||
2609 | */ | ||
2610 | if (!bssid) { | ||
2611 | mutex_unlock(&ifmgd->mtx); | ||
2612 | return -ENOLINK; | ||
2613 | } | 1974 | } |
2614 | 1975 | ||
2615 | mutex_unlock(&ifmgd->mtx); | ||
2616 | |||
2617 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", | 1976 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", |
2618 | sdata->name, bssid, req->reason_code); | 1977 | sdata->name, bssid, req->reason_code); |
2619 | 1978 | ||
@@ -2640,7 +1999,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2640 | * to cfg80211 while that's in a locked section already | 1999 | * to cfg80211 while that's in a locked section already |
2641 | * trying to tell us that the user wants to disconnect. | 2000 | * trying to tell us that the user wants to disconnect. |
2642 | */ | 2001 | */ |
2643 | if (&ifmgd->associated->cbss != req->bss) { | 2002 | if (ifmgd->associated != req->bss) { |
2644 | mutex_unlock(&ifmgd->mtx); | 2003 | mutex_unlock(&ifmgd->mtx); |
2645 | return -ENOLINK; | 2004 | return -ENOLINK; |
2646 | } | 2005 | } |
@@ -2648,7 +2007,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2648 | printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", | 2007 | printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", |
2649 | sdata->name, req->bss->bssid, req->reason_code); | 2008 | sdata->name, req->bss->bssid, req->reason_code); |
2650 | 2009 | ||
2651 | ieee80211_set_disassoc(sdata, false); | 2010 | ieee80211_set_disassoc(sdata); |
2652 | 2011 | ||
2653 | mutex_unlock(&ifmgd->mtx); | 2012 | mutex_unlock(&ifmgd->mtx); |
2654 | 2013 | ||