diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-10-15 11:20:54 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-10-15 11:20:54 -0400 |
commit | df9b42963f2d010ae3163a894ce22cf6b27cd344 (patch) | |
tree | f42f826d9bb975766c1a79986c39e64c9a900908 /net/mac80211/mlme.c | |
parent | 33766368f6532313571534f9112b1796d6651bbe (diff) | |
parent | c3e7724b6bc2f25e46c38dbe68f09d71fafeafb8 (diff) |
Merge remote-tracking branch 'wireless/master' into mac80211
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 443 |
1 files changed, 270 insertions, 173 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f76b83341cf9..e714ed8bb198 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -88,8 +88,6 @@ MODULE_PARM_DESC(probe_wait_ms, | |||
88 | #define TMR_RUNNING_TIMER 0 | 88 | #define TMR_RUNNING_TIMER 0 |
89 | #define TMR_RUNNING_CHANSW 1 | 89 | #define TMR_RUNNING_CHANSW 1 |
90 | 90 | ||
91 | #define DEAUTH_DISASSOC_LEN (24 /* hdr */ + 2 /* reason */) | ||
92 | |||
93 | /* | 91 | /* |
94 | * All cfg80211 functions have to be called outside a locked | 92 | * All cfg80211 functions have to be called outside a locked |
95 | * section so that they can acquire a lock themselves... This | 93 | * section so that they can acquire a lock themselves... This |
@@ -146,6 +144,9 @@ void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) | |||
146 | if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) | 144 | if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) |
147 | return; | 145 | return; |
148 | 146 | ||
147 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
148 | return; | ||
149 | |||
149 | mod_timer(&sdata->u.mgd.bcn_mon_timer, | 150 | mod_timer(&sdata->u.mgd.bcn_mon_timer, |
150 | round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); | 151 | round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); |
151 | } | 152 | } |
@@ -182,15 +183,15 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, | |||
182 | u16 ht_opmode; | 183 | u16 ht_opmode; |
183 | bool disable_40 = false; | 184 | bool disable_40 = false; |
184 | 185 | ||
185 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 186 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
186 | 187 | ||
187 | switch (sdata->vif.bss_conf.channel_type) { | 188 | switch (sdata->vif.bss_conf.channel_type) { |
188 | case NL80211_CHAN_HT40PLUS: | 189 | case NL80211_CHAN_HT40PLUS: |
189 | if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40PLUS) | 190 | if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS) |
190 | disable_40 = true; | 191 | disable_40 = true; |
191 | break; | 192 | break; |
192 | case NL80211_CHAN_HT40MINUS: | 193 | case NL80211_CHAN_HT40MINUS: |
193 | if (local->hw.conf.channel->flags & IEEE80211_CHAN_NO_HT40MINUS) | 194 | if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS) |
194 | disable_40 = true; | 195 | disable_40 = true; |
195 | break; | 196 | break; |
196 | default: | 197 | default: |
@@ -326,6 +327,26 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | |||
326 | ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); | 327 | ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); |
327 | } | 328 | } |
328 | 329 | ||
330 | static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | ||
331 | struct sk_buff *skb, | ||
332 | struct ieee80211_supported_band *sband) | ||
333 | { | ||
334 | u8 *pos; | ||
335 | u32 cap; | ||
336 | struct ieee80211_sta_vht_cap vht_cap; | ||
337 | |||
338 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); | ||
339 | |||
340 | memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); | ||
341 | |||
342 | /* determine capability flags */ | ||
343 | cap = vht_cap.cap; | ||
344 | |||
345 | /* reserve and fill IE */ | ||
346 | pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2); | ||
347 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); | ||
348 | } | ||
349 | |||
329 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | 350 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) |
330 | { | 351 | { |
331 | struct ieee80211_local *local = sdata->local; | 352 | struct ieee80211_local *local = sdata->local; |
@@ -371,6 +392,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
371 | 4 + /* power capability */ | 392 | 4 + /* power capability */ |
372 | 2 + 2 * sband->n_channels + /* supported channels */ | 393 | 2 + 2 * sband->n_channels + /* supported channels */ |
373 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | 394 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ |
395 | 2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */ | ||
374 | assoc_data->ie_len + /* extra IEs */ | 396 | assoc_data->ie_len + /* extra IEs */ |
375 | 9, /* WMM */ | 397 | 9, /* WMM */ |
376 | GFP_KERNEL); | 398 | GFP_KERNEL); |
@@ -503,6 +525,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
503 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, | 525 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, |
504 | sband, local->oper_channel, ifmgd->ap_smps); | 526 | sband, local->oper_channel, ifmgd->ap_smps); |
505 | 527 | ||
528 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | ||
529 | ieee80211_add_vht_ie(sdata, skb, sband); | ||
530 | |||
506 | /* if present, add any custom non-vendor IEs that go after HT */ | 531 | /* if present, add any custom non-vendor IEs that go after HT */ |
507 | if (assoc_data->ie_len && assoc_data->ie) { | 532 | if (assoc_data->ie_len && assoc_data->ie) { |
508 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, | 533 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, |
@@ -547,48 +572,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
547 | ieee80211_tx_skb(sdata, skb); | 572 | ieee80211_tx_skb(sdata, skb); |
548 | } | 573 | } |
549 | 574 | ||
550 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | ||
551 | const u8 *bssid, u16 stype, | ||
552 | u16 reason, bool send_frame, | ||
553 | u8 *frame_buf) | ||
554 | { | ||
555 | struct ieee80211_local *local = sdata->local; | ||
556 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
557 | struct sk_buff *skb; | ||
558 | struct ieee80211_mgmt *mgmt = (void *)frame_buf; | ||
559 | |||
560 | /* build frame */ | ||
561 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | ||
562 | mgmt->duration = 0; /* initialize only */ | ||
563 | mgmt->seq_ctrl = 0; /* initialize only */ | ||
564 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
565 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
566 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
567 | /* u.deauth.reason_code == u.disassoc.reason_code */ | ||
568 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | ||
569 | |||
570 | if (send_frame) { | ||
571 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
572 | DEAUTH_DISASSOC_LEN); | ||
573 | if (!skb) | ||
574 | return; | ||
575 | |||
576 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
577 | |||
578 | /* copy in frame */ | ||
579 | memcpy(skb_put(skb, DEAUTH_DISASSOC_LEN), | ||
580 | mgmt, DEAUTH_DISASSOC_LEN); | ||
581 | |||
582 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) | ||
583 | IEEE80211_SKB_CB(skb)->flags |= | ||
584 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
585 | |||
586 | drv_mgd_prepare_tx(local, sdata); | ||
587 | |||
588 | ieee80211_tx_skb(sdata, skb); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 575 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
593 | struct ieee80211_sub_if_data *sdata) | 576 | struct ieee80211_sub_if_data *sdata) |
594 | { | 577 | { |
@@ -687,6 +670,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
687 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 670 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
688 | ifmgd->associated->channel = sdata->local->oper_channel; | 671 | ifmgd->associated->channel = sdata->local->oper_channel; |
689 | 672 | ||
673 | /* XXX: wait for a beacon first? */ | ||
690 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 674 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
691 | IEEE80211_QUEUE_STOP_REASON_CSA); | 675 | IEEE80211_QUEUE_STOP_REASON_CSA); |
692 | out: | 676 | out: |
@@ -704,16 +688,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | |||
704 | 688 | ||
705 | trace_api_chswitch_done(sdata, success); | 689 | trace_api_chswitch_done(sdata, success); |
706 | if (!success) { | 690 | if (!success) { |
707 | /* | 691 | sdata_info(sdata, |
708 | * If the channel switch was not successful, stay | 692 | "driver channel switch failed, disconnecting\n"); |
709 | * around on the old channel. We currently lack | 693 | ieee80211_queue_work(&sdata->local->hw, |
710 | * good handling of this situation, possibly we | 694 | &ifmgd->csa_connection_drop_work); |
711 | * should just drop the association. | 695 | } else { |
712 | */ | 696 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
713 | sdata->local->csa_channel = sdata->local->oper_channel; | ||
714 | } | 697 | } |
715 | |||
716 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||
717 | } | 698 | } |
718 | EXPORT_SYMBOL(ieee80211_chswitch_done); | 699 | EXPORT_SYMBOL(ieee80211_chswitch_done); |
719 | 700 | ||
@@ -758,61 +739,111 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
758 | return; | 739 | return; |
759 | 740 | ||
760 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | 741 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); |
761 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | 742 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { |
743 | sdata_info(sdata, | ||
744 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
745 | ifmgd->associated->bssid, new_freq); | ||
746 | ieee80211_queue_work(&sdata->local->hw, | ||
747 | &ifmgd->csa_connection_drop_work); | ||
762 | return; | 748 | return; |
749 | } | ||
763 | 750 | ||
764 | sdata->local->csa_channel = new_ch; | 751 | sdata->local->csa_channel = new_ch; |
765 | 752 | ||
753 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
754 | |||
755 | if (sw_elem->mode) | ||
756 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
757 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
758 | |||
766 | if (sdata->local->ops->channel_switch) { | 759 | if (sdata->local->ops->channel_switch) { |
767 | /* use driver's channel switch callback */ | 760 | /* use driver's channel switch callback */ |
768 | struct ieee80211_channel_switch ch_switch; | 761 | struct ieee80211_channel_switch ch_switch = { |
769 | memset(&ch_switch, 0, sizeof(ch_switch)); | 762 | .timestamp = timestamp, |
770 | ch_switch.timestamp = timestamp; | 763 | .block_tx = sw_elem->mode, |
771 | if (sw_elem->mode) { | 764 | .channel = new_ch, |
772 | ch_switch.block_tx = true; | 765 | .count = sw_elem->count, |
773 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | 766 | }; |
774 | IEEE80211_QUEUE_STOP_REASON_CSA); | 767 | |
775 | } | ||
776 | ch_switch.channel = new_ch; | ||
777 | ch_switch.count = sw_elem->count; | ||
778 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
779 | drv_channel_switch(sdata->local, &ch_switch); | 768 | drv_channel_switch(sdata->local, &ch_switch); |
780 | return; | 769 | return; |
781 | } | 770 | } |
782 | 771 | ||
783 | /* channel switch handled in software */ | 772 | /* channel switch handled in software */ |
784 | if (sw_elem->count <= 1) { | 773 | if (sw_elem->count <= 1) |
785 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | 774 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
786 | } else { | 775 | else |
787 | if (sw_elem->mode) | ||
788 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
789 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
790 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
791 | mod_timer(&ifmgd->chswitch_timer, | 776 | mod_timer(&ifmgd->chswitch_timer, |
792 | jiffies + | 777 | TU_TO_EXP_TIME(sw_elem->count * |
793 | msecs_to_jiffies(sw_elem->count * | 778 | cbss->beacon_interval)); |
794 | cbss->beacon_interval)); | ||
795 | } | ||
796 | } | 779 | } |
797 | 780 | ||
798 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | 781 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, |
799 | u16 capab_info, u8 *pwr_constr_elem, | 782 | struct ieee80211_channel *channel, |
800 | u8 pwr_constr_elem_len) | 783 | const u8 *country_ie, u8 country_ie_len, |
784 | const u8 *pwr_constr_elem) | ||
801 | { | 785 | { |
802 | struct ieee80211_conf *conf = &sdata->local->hw.conf; | 786 | struct ieee80211_country_ie_triplet *triplet; |
787 | int chan = ieee80211_frequency_to_channel(channel->center_freq); | ||
788 | int i, chan_pwr, chan_increment, new_ap_level; | ||
789 | bool have_chan_pwr = false; | ||
803 | 790 | ||
804 | if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) | 791 | /* Invalid IE */ |
792 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | ||
805 | return; | 793 | return; |
806 | 794 | ||
807 | /* Power constraint IE length should be 1 octet */ | 795 | triplet = (void *)(country_ie + 3); |
808 | if (pwr_constr_elem_len != 1) | 796 | country_ie_len -= 3; |
809 | return; | 797 | |
798 | switch (channel->band) { | ||
799 | default: | ||
800 | WARN_ON_ONCE(1); | ||
801 | /* fall through */ | ||
802 | case IEEE80211_BAND_2GHZ: | ||
803 | case IEEE80211_BAND_60GHZ: | ||
804 | chan_increment = 1; | ||
805 | break; | ||
806 | case IEEE80211_BAND_5GHZ: | ||
807 | chan_increment = 4; | ||
808 | break; | ||
809 | } | ||
810 | |||
811 | /* find channel */ | ||
812 | while (country_ie_len >= 3) { | ||
813 | u8 first_channel = triplet->chans.first_channel; | ||
810 | 814 | ||
811 | if ((*pwr_constr_elem <= conf->channel->max_reg_power) && | 815 | if (first_channel >= IEEE80211_COUNTRY_EXTENSION_ID) |
812 | (*pwr_constr_elem != sdata->local->power_constr_level)) { | 816 | goto next; |
813 | sdata->local->power_constr_level = *pwr_constr_elem; | 817 | |
814 | ieee80211_hw_config(sdata->local, 0); | 818 | for (i = 0; i < triplet->chans.num_channels; i++) { |
819 | if (first_channel + i * chan_increment == chan) { | ||
820 | have_chan_pwr = true; | ||
821 | chan_pwr = triplet->chans.max_power; | ||
822 | break; | ||
823 | } | ||
824 | } | ||
825 | if (have_chan_pwr) | ||
826 | break; | ||
827 | |||
828 | next: | ||
829 | triplet++; | ||
830 | country_ie_len -= 3; | ||
815 | } | 831 | } |
832 | |||
833 | if (!have_chan_pwr) | ||
834 | return; | ||
835 | |||
836 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); | ||
837 | |||
838 | if (sdata->local->ap_power_level == new_ap_level) | ||
839 | return; | ||
840 | |||
841 | sdata_info(sdata, | ||
842 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", | ||
843 | new_ap_level, chan_pwr, *pwr_constr_elem, | ||
844 | sdata->u.mgd.bssid); | ||
845 | sdata->local->ap_power_level = new_ap_level; | ||
846 | ieee80211_hw_config(sdata->local, 0); | ||
816 | } | 847 | } |
817 | 848 | ||
818 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | 849 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) |
@@ -1007,6 +1038,16 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
1007 | ieee80211_change_ps(local); | 1038 | ieee80211_change_ps(local); |
1008 | } | 1039 | } |
1009 | 1040 | ||
1041 | void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata) | ||
1042 | { | ||
1043 | bool ps_allowed = ieee80211_powersave_allowed(sdata); | ||
1044 | |||
1045 | if (sdata->vif.bss_conf.ps != ps_allowed) { | ||
1046 | sdata->vif.bss_conf.ps = ps_allowed; | ||
1047 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_PS); | ||
1048 | } | ||
1049 | } | ||
1050 | |||
1010 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | 1051 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work) |
1011 | { | 1052 | { |
1012 | struct ieee80211_local *local = | 1053 | struct ieee80211_local *local = |
@@ -1239,7 +1280,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
1239 | } | 1280 | } |
1240 | 1281 | ||
1241 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | 1282 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); |
1242 | if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) | 1283 | if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) |
1243 | use_short_slot = true; | 1284 | use_short_slot = true; |
1244 | 1285 | ||
1245 | if (use_protection != bss_conf->use_cts_prot) { | 1286 | if (use_protection != bss_conf->use_cts_prot) { |
@@ -1307,9 +1348,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1307 | 1348 | ||
1308 | mutex_lock(&local->iflist_mtx); | 1349 | mutex_lock(&local->iflist_mtx); |
1309 | ieee80211_recalc_ps(local, -1); | 1350 | ieee80211_recalc_ps(local, -1); |
1310 | ieee80211_recalc_smps(local); | ||
1311 | mutex_unlock(&local->iflist_mtx); | 1351 | mutex_unlock(&local->iflist_mtx); |
1312 | 1352 | ||
1353 | ieee80211_recalc_smps(local); | ||
1354 | ieee80211_recalc_ps_vif(sdata); | ||
1355 | |||
1313 | netif_tx_start_all_queues(sdata->dev); | 1356 | netif_tx_start_all_queues(sdata->dev); |
1314 | netif_carrier_on(sdata->dev); | 1357 | netif_carrier_on(sdata->dev); |
1315 | } | 1358 | } |
@@ -1356,7 +1399,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1356 | sta = sta_info_get(sdata, ifmgd->bssid); | 1399 | sta = sta_info_get(sdata, ifmgd->bssid); |
1357 | if (sta) { | 1400 | if (sta) { |
1358 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | 1401 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
1359 | ieee80211_sta_tear_down_BA_sessions(sta, tx); | 1402 | ieee80211_sta_tear_down_BA_sessions(sta, false); |
1360 | } | 1403 | } |
1361 | mutex_unlock(&local->sta_mtx); | 1404 | mutex_unlock(&local->sta_mtx); |
1362 | 1405 | ||
@@ -1371,6 +1414,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1371 | } | 1414 | } |
1372 | local->ps_sdata = NULL; | 1415 | local->ps_sdata = NULL; |
1373 | 1416 | ||
1417 | /* disable per-vif ps */ | ||
1418 | ieee80211_recalc_ps_vif(sdata); | ||
1419 | |||
1374 | /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ | 1420 | /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ |
1375 | if (tx) | 1421 | if (tx) |
1376 | drv_flush(local, false); | 1422 | drv_flush(local, false); |
@@ -1401,7 +1447,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1401 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1447 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
1402 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1448 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
1403 | 1449 | ||
1404 | local->power_constr_level = 0; | 1450 | local->ap_power_level = 0; |
1405 | 1451 | ||
1406 | del_timer_sync(&local->dynamic_ps_timer); | 1452 | del_timer_sync(&local->dynamic_ps_timer); |
1407 | cancel_work_sync(&local->dynamic_ps_enable_work); | 1453 | cancel_work_sync(&local->dynamic_ps_enable_work); |
@@ -1542,7 +1588,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1542 | ssid_len = ssid[1]; | 1588 | ssid_len = ssid[1]; |
1543 | 1589 | ||
1544 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | 1590 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, |
1545 | 0, (u32) -1, true, false); | 1591 | 0, (u32) -1, true, false, |
1592 | ifmgd->associated->channel); | ||
1546 | } | 1593 | } |
1547 | 1594 | ||
1548 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 1595 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
@@ -1645,19 +1692,21 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1645 | ssid_len = ssid[1]; | 1692 | ssid_len = ssid[1]; |
1646 | 1693 | ||
1647 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, | 1694 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, |
1648 | (u32) -1, ssid + 2, ssid_len, | 1695 | (u32) -1, |
1696 | sdata->local->oper_channel, | ||
1697 | ssid + 2, ssid_len, | ||
1649 | NULL, 0, true); | 1698 | NULL, 0, true); |
1650 | 1699 | ||
1651 | return skb; | 1700 | return skb; |
1652 | } | 1701 | } |
1653 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | 1702 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); |
1654 | 1703 | ||
1655 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | 1704 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, |
1705 | bool transmit_frame) | ||
1656 | { | 1706 | { |
1657 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1707 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1658 | struct ieee80211_local *local = sdata->local; | 1708 | struct ieee80211_local *local = sdata->local; |
1659 | u8 bssid[ETH_ALEN]; | 1709 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
1660 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | ||
1661 | 1710 | ||
1662 | mutex_lock(&ifmgd->mtx); | 1711 | mutex_lock(&ifmgd->mtx); |
1663 | if (!ifmgd->associated) { | 1712 | if (!ifmgd->associated) { |
@@ -1665,27 +1714,24 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1665 | return; | 1714 | return; |
1666 | } | 1715 | } |
1667 | 1716 | ||
1668 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | ||
1669 | |||
1670 | sdata_info(sdata, "Connection to AP %pM lost\n", bssid); | ||
1671 | |||
1672 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 1717 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
1673 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 1718 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
1674 | false, frame_buf); | 1719 | transmit_frame, frame_buf); |
1720 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
1675 | mutex_unlock(&ifmgd->mtx); | 1721 | mutex_unlock(&ifmgd->mtx); |
1676 | 1722 | ||
1677 | /* | 1723 | /* |
1678 | * must be outside lock due to cfg80211, | 1724 | * must be outside lock due to cfg80211, |
1679 | * but that's not a problem. | 1725 | * but that's not a problem. |
1680 | */ | 1726 | */ |
1681 | cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 1727 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
1682 | 1728 | ||
1683 | mutex_lock(&local->mtx); | 1729 | mutex_lock(&local->mtx); |
1684 | ieee80211_recalc_idle(local); | 1730 | ieee80211_recalc_idle(local); |
1685 | mutex_unlock(&local->mtx); | 1731 | mutex_unlock(&local->mtx); |
1686 | } | 1732 | } |
1687 | 1733 | ||
1688 | void ieee80211_beacon_connection_loss_work(struct work_struct *work) | 1734 | static void ieee80211_beacon_connection_loss_work(struct work_struct *work) |
1689 | { | 1735 | { |
1690 | struct ieee80211_sub_if_data *sdata = | 1736 | struct ieee80211_sub_if_data *sdata = |
1691 | container_of(work, struct ieee80211_sub_if_data, | 1737 | container_of(work, struct ieee80211_sub_if_data, |
@@ -1701,10 +1747,24 @@ void ieee80211_beacon_connection_loss_work(struct work_struct *work) | |||
1701 | rcu_read_unlock(); | 1747 | rcu_read_unlock(); |
1702 | } | 1748 | } |
1703 | 1749 | ||
1704 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 1750 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) { |
1705 | __ieee80211_connection_loss(sdata); | 1751 | sdata_info(sdata, "Connection to AP %pM lost\n", |
1706 | else | 1752 | ifmgd->bssid); |
1753 | __ieee80211_disconnect(sdata, false); | ||
1754 | } else { | ||
1707 | ieee80211_mgd_probe_ap(sdata, true); | 1755 | ieee80211_mgd_probe_ap(sdata, true); |
1756 | } | ||
1757 | } | ||
1758 | |||
1759 | static void ieee80211_csa_connection_drop_work(struct work_struct *work) | ||
1760 | { | ||
1761 | struct ieee80211_sub_if_data *sdata = | ||
1762 | container_of(work, struct ieee80211_sub_if_data, | ||
1763 | u.mgd.csa_connection_drop_work); | ||
1764 | |||
1765 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
1766 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1767 | __ieee80211_disconnect(sdata, true); | ||
1708 | } | 1768 | } |
1709 | 1769 | ||
1710 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 1770 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
@@ -2232,14 +2292,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2232 | mutex_unlock(&local->iflist_mtx); | 2292 | mutex_unlock(&local->iflist_mtx); |
2233 | } | 2293 | } |
2234 | 2294 | ||
2235 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | 2295 | if (elems->ch_switch_ie && |
2236 | (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, | 2296 | memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0) |
2237 | ETH_ALEN) == 0)) { | 2297 | ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie, |
2238 | struct ieee80211_channel_sw_ie *sw_elem = | ||
2239 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | ||
2240 | ieee80211_sta_process_chanswitch(sdata, sw_elem, | ||
2241 | bss, rx_status->mactime); | 2298 | bss, rx_status->mactime); |
2242 | } | ||
2243 | } | 2299 | } |
2244 | 2300 | ||
2245 | 2301 | ||
@@ -2326,7 +2382,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2326 | if (baselen > len) | 2382 | if (baselen > len) |
2327 | return; | 2383 | return; |
2328 | 2384 | ||
2329 | if (rx_status->freq != local->hw.conf.channel->center_freq) | 2385 | if (rx_status->freq != local->oper_channel->center_freq) |
2330 | return; | 2386 | return; |
2331 | 2387 | ||
2332 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && | 2388 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && |
@@ -2490,21 +2546,19 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2490 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { | 2546 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { |
2491 | struct ieee80211_supported_band *sband; | 2547 | struct ieee80211_supported_band *sband; |
2492 | 2548 | ||
2493 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 2549 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
2494 | 2550 | ||
2495 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | 2551 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, |
2496 | bssid, true); | 2552 | bssid, true); |
2497 | } | 2553 | } |
2498 | 2554 | ||
2499 | /* Note: country IE parsing is done for us by cfg80211 */ | 2555 | if (elems.country_elem && elems.pwr_constr_elem && |
2500 | if (elems.country_elem) { | 2556 | mgmt->u.probe_resp.capab_info & |
2501 | /* TODO: IBSS also needs this */ | 2557 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) |
2502 | if (elems.pwr_constr_elem) | 2558 | ieee80211_handle_pwr_constr(sdata, local->oper_channel, |
2503 | ieee80211_handle_pwr_constr(sdata, | 2559 | elems.country_elem, |
2504 | le16_to_cpu(mgmt->u.probe_resp.capab_info), | 2560 | elems.country_elem_len, |
2505 | elems.pwr_constr_elem, | 2561 | elems.pwr_constr_elem); |
2506 | elems.pwr_constr_elem_len); | ||
2507 | } | ||
2508 | 2562 | ||
2509 | ieee80211_bss_info_change_notify(sdata, changed); | 2563 | ieee80211_bss_info_change_notify(sdata, changed); |
2510 | } | 2564 | } |
@@ -2601,7 +2655,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2601 | { | 2655 | { |
2602 | struct ieee80211_local *local = sdata->local; | 2656 | struct ieee80211_local *local = sdata->local; |
2603 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2657 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2604 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 2658 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
2605 | 2659 | ||
2606 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, | 2660 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, |
2607 | false, frame_buf); | 2661 | false, frame_buf); |
@@ -2611,7 +2665,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2611 | * must be outside lock due to cfg80211, | 2665 | * must be outside lock due to cfg80211, |
2612 | * but that's not a problem. | 2666 | * but that's not a problem. |
2613 | */ | 2667 | */ |
2614 | cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 2668 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
2615 | 2669 | ||
2616 | mutex_lock(&local->mtx); | 2670 | mutex_lock(&local->mtx); |
2617 | ieee80211_recalc_idle(local); | 2671 | ieee80211_recalc_idle(local); |
@@ -2673,7 +2727,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
2673 | * will not answer to direct packet in unassociated state. | 2727 | * will not answer to direct packet in unassociated state. |
2674 | */ | 2728 | */ |
2675 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | 2729 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], |
2676 | NULL, 0, (u32) -1, true, false); | 2730 | NULL, 0, (u32) -1, true, false, |
2731 | auth_data->bss->channel); | ||
2677 | } | 2732 | } |
2678 | 2733 | ||
2679 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 2734 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
@@ -2894,6 +2949,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
2894 | 2949 | ||
2895 | cancel_work_sync(&ifmgd->monitor_work); | 2950 | cancel_work_sync(&ifmgd->monitor_work); |
2896 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 2951 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
2952 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | ||
2897 | if (del_timer_sync(&ifmgd->timer)) | 2953 | if (del_timer_sync(&ifmgd->timer)) |
2898 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 2954 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
2899 | 2955 | ||
@@ -2950,6 +3006,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2950 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 3006 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
2951 | INIT_WORK(&ifmgd->beacon_connection_loss_work, | 3007 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
2952 | ieee80211_beacon_connection_loss_work); | 3008 | ieee80211_beacon_connection_loss_work); |
3009 | INIT_WORK(&ifmgd->csa_connection_drop_work, | ||
3010 | ieee80211_csa_connection_drop_work); | ||
2953 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); | 3011 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); |
2954 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 3012 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
2955 | (unsigned long) sdata); | 3013 | (unsigned long) sdata); |
@@ -3000,41 +3058,17 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
3000 | return 0; | 3058 | return 0; |
3001 | } | 3059 | } |
3002 | 3060 | ||
3003 | static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | 3061 | static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, |
3004 | struct cfg80211_bss *cbss, bool assoc) | 3062 | struct cfg80211_bss *cbss) |
3005 | { | 3063 | { |
3006 | struct ieee80211_local *local = sdata->local; | 3064 | struct ieee80211_local *local = sdata->local; |
3007 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3065 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3008 | struct ieee80211_bss *bss = (void *)cbss->priv; | ||
3009 | struct sta_info *sta = NULL; | ||
3010 | bool have_sta = false; | ||
3011 | int err; | ||
3012 | int ht_cfreq; | 3066 | int ht_cfreq; |
3013 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 3067 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
3014 | const u8 *ht_oper_ie; | 3068 | const u8 *ht_oper_ie; |
3015 | const struct ieee80211_ht_operation *ht_oper = NULL; | 3069 | const struct ieee80211_ht_operation *ht_oper = NULL; |
3016 | struct ieee80211_supported_band *sband; | 3070 | struct ieee80211_supported_band *sband; |
3017 | 3071 | ||
3018 | if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) | ||
3019 | return -EINVAL; | ||
3020 | |||
3021 | if (assoc) { | ||
3022 | rcu_read_lock(); | ||
3023 | have_sta = sta_info_get(sdata, cbss->bssid); | ||
3024 | rcu_read_unlock(); | ||
3025 | } | ||
3026 | |||
3027 | if (!have_sta) { | ||
3028 | sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); | ||
3029 | if (!sta) | ||
3030 | return -ENOMEM; | ||
3031 | } | ||
3032 | |||
3033 | mutex_lock(&local->mtx); | ||
3034 | ieee80211_recalc_idle(sdata->local); | ||
3035 | mutex_unlock(&local->mtx); | ||
3036 | |||
3037 | /* switch to the right channel */ | ||
3038 | sband = local->hw.wiphy->bands[cbss->channel->band]; | 3072 | sband = local->hw.wiphy->bands[cbss->channel->band]; |
3039 | 3073 | ||
3040 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; | 3074 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; |
@@ -3097,10 +3131,51 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3097 | local->oper_channel = cbss->channel; | 3131 | local->oper_channel = cbss->channel; |
3098 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 3132 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
3099 | 3133 | ||
3100 | if (sta) { | 3134 | return 0; |
3135 | } | ||
3136 | |||
3137 | static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | ||
3138 | struct cfg80211_bss *cbss, bool assoc) | ||
3139 | { | ||
3140 | struct ieee80211_local *local = sdata->local; | ||
3141 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3142 | struct ieee80211_bss *bss = (void *)cbss->priv; | ||
3143 | struct sta_info *new_sta = NULL; | ||
3144 | bool have_sta = false; | ||
3145 | int err; | ||
3146 | |||
3147 | if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) | ||
3148 | return -EINVAL; | ||
3149 | |||
3150 | if (assoc) { | ||
3151 | rcu_read_lock(); | ||
3152 | have_sta = sta_info_get(sdata, cbss->bssid); | ||
3153 | rcu_read_unlock(); | ||
3154 | } | ||
3155 | |||
3156 | if (!have_sta) { | ||
3157 | new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); | ||
3158 | if (!new_sta) | ||
3159 | return -ENOMEM; | ||
3160 | } | ||
3161 | |||
3162 | mutex_lock(&local->mtx); | ||
3163 | ieee80211_recalc_idle(sdata->local); | ||
3164 | mutex_unlock(&local->mtx); | ||
3165 | |||
3166 | if (new_sta) { | ||
3101 | u32 rates = 0, basic_rates = 0; | 3167 | u32 rates = 0, basic_rates = 0; |
3102 | bool have_higher_than_11mbit; | 3168 | bool have_higher_than_11mbit; |
3103 | int min_rate = INT_MAX, min_rate_index = -1; | 3169 | int min_rate = INT_MAX, min_rate_index = -1; |
3170 | struct ieee80211_supported_band *sband; | ||
3171 | |||
3172 | sband = local->hw.wiphy->bands[cbss->channel->band]; | ||
3173 | |||
3174 | err = ieee80211_prep_channel(sdata, cbss); | ||
3175 | if (err) { | ||
3176 | sta_info_free(local, new_sta); | ||
3177 | return err; | ||
3178 | } | ||
3104 | 3179 | ||
3105 | ieee80211_get_rates(sband, bss->supp_rates, | 3180 | ieee80211_get_rates(sband, bss->supp_rates, |
3106 | bss->supp_rates_len, | 3181 | bss->supp_rates_len, |
@@ -3122,7 +3197,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3122 | basic_rates = BIT(min_rate_index); | 3197 | basic_rates = BIT(min_rate_index); |
3123 | } | 3198 | } |
3124 | 3199 | ||
3125 | sta->sta.supp_rates[cbss->channel->band] = rates; | 3200 | new_sta->sta.supp_rates[cbss->channel->band] = rates; |
3126 | sdata->vif.bss_conf.basic_rates = basic_rates; | 3201 | sdata->vif.bss_conf.basic_rates = basic_rates; |
3127 | 3202 | ||
3128 | /* cf. IEEE 802.11 9.2.12 */ | 3203 | /* cf. IEEE 802.11 9.2.12 */ |
@@ -3145,10 +3220,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3145 | BSS_CHANGED_BEACON_INT); | 3220 | BSS_CHANGED_BEACON_INT); |
3146 | 3221 | ||
3147 | if (assoc) | 3222 | if (assoc) |
3148 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | 3223 | sta_info_pre_move_state(new_sta, IEEE80211_STA_AUTH); |
3149 | 3224 | ||
3150 | err = sta_info_insert(sta); | 3225 | err = sta_info_insert(new_sta); |
3151 | sta = NULL; | 3226 | new_sta = NULL; |
3152 | if (err) { | 3227 | if (err) { |
3153 | sdata_info(sdata, | 3228 | sdata_info(sdata, |
3154 | "failed to insert STA entry for the AP (error %d)\n", | 3229 | "failed to insert STA entry for the AP (error %d)\n", |
@@ -3302,9 +3377,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
3302 | } | 3377 | } |
3303 | 3378 | ||
3304 | /* prepare assoc data */ | 3379 | /* prepare assoc data */ |
3305 | 3380 | ||
3306 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 3381 | /* |
3307 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 3382 | * keep only the 40 MHz disable bit set as it might have |
3383 | * been set during authentication already, all other bits | ||
3384 | * should be reset for a new connection | ||
3385 | */ | ||
3386 | ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ; | ||
3308 | 3387 | ||
3309 | ifmgd->beacon_crc_valid = false; | 3388 | ifmgd->beacon_crc_valid = false; |
3310 | 3389 | ||
@@ -3320,21 +3399,34 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
3320 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | 3399 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || |
3321 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { | 3400 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { |
3322 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3401 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
3402 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
3323 | netdev_info(sdata->dev, | 3403 | netdev_info(sdata->dev, |
3324 | "disabling HT due to WEP/TKIP use\n"); | 3404 | "disabling HT/VHT due to WEP/TKIP use\n"); |
3325 | } | 3405 | } |
3326 | } | 3406 | } |
3327 | 3407 | ||
3328 | if (req->flags & ASSOC_REQ_DISABLE_HT) | 3408 | if (req->flags & ASSOC_REQ_DISABLE_HT) { |
3329 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3409 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
3410 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
3411 | } | ||
3330 | 3412 | ||
3331 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ | 3413 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ |
3332 | sband = local->hw.wiphy->bands[req->bss->channel->band]; | 3414 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
3333 | if (!sband->ht_cap.ht_supported || | 3415 | if (!sband->ht_cap.ht_supported || |
3334 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | 3416 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { |
3335 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3417 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
3336 | netdev_info(sdata->dev, | 3418 | if (!bss->wmm_used) |
3337 | "disabling HT as WMM/QoS is not supported\n"); | 3419 | netdev_info(sdata->dev, |
3420 | "disabling HT as WMM/QoS is not supported by the AP\n"); | ||
3421 | } | ||
3422 | |||
3423 | /* disable VHT if we don't support it or the AP doesn't use WMM */ | ||
3424 | if (!sband->vht_cap.vht_supported || | ||
3425 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | ||
3426 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
3427 | if (!bss->wmm_used) | ||
3428 | netdev_info(sdata->dev, | ||
3429 | "disabling VHT as WMM/QoS is not supported by the AP\n"); | ||
3338 | } | 3430 | } |
3339 | 3431 | ||
3340 | memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); | 3432 | memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); |
@@ -3456,7 +3548,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
3456 | struct cfg80211_deauth_request *req) | 3548 | struct cfg80211_deauth_request *req) |
3457 | { | 3549 | { |
3458 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3550 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3459 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 3551 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
3460 | 3552 | ||
3461 | mutex_lock(&ifmgd->mtx); | 3553 | mutex_lock(&ifmgd->mtx); |
3462 | 3554 | ||
@@ -3471,17 +3563,21 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
3471 | req->bssid, req->reason_code); | 3563 | req->bssid, req->reason_code); |
3472 | 3564 | ||
3473 | if (ifmgd->associated && | 3565 | if (ifmgd->associated && |
3474 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) | 3566 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { |
3475 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 3567 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
3476 | req->reason_code, true, frame_buf); | 3568 | req->reason_code, true, frame_buf); |
3477 | else | 3569 | } else { |
3570 | drv_mgd_prepare_tx(sdata->local, sdata); | ||
3478 | ieee80211_send_deauth_disassoc(sdata, req->bssid, | 3571 | ieee80211_send_deauth_disassoc(sdata, req->bssid, |
3479 | IEEE80211_STYPE_DEAUTH, | 3572 | IEEE80211_STYPE_DEAUTH, |
3480 | req->reason_code, true, | 3573 | req->reason_code, true, |
3481 | frame_buf); | 3574 | frame_buf); |
3575 | } | ||
3576 | |||
3482 | mutex_unlock(&ifmgd->mtx); | 3577 | mutex_unlock(&ifmgd->mtx); |
3483 | 3578 | ||
3484 | __cfg80211_send_deauth(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 3579 | __cfg80211_send_deauth(sdata->dev, frame_buf, |
3580 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3485 | 3581 | ||
3486 | mutex_lock(&sdata->local->mtx); | 3582 | mutex_lock(&sdata->local->mtx); |
3487 | ieee80211_recalc_idle(sdata->local); | 3583 | ieee80211_recalc_idle(sdata->local); |
@@ -3495,7 +3591,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
3495 | { | 3591 | { |
3496 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3592 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3497 | u8 bssid[ETH_ALEN]; | 3593 | u8 bssid[ETH_ALEN]; |
3498 | u8 frame_buf[DEAUTH_DISASSOC_LEN]; | 3594 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
3499 | 3595 | ||
3500 | mutex_lock(&ifmgd->mtx); | 3596 | mutex_lock(&ifmgd->mtx); |
3501 | 3597 | ||
@@ -3520,7 +3616,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
3520 | frame_buf); | 3616 | frame_buf); |
3521 | mutex_unlock(&ifmgd->mtx); | 3617 | mutex_unlock(&ifmgd->mtx); |
3522 | 3618 | ||
3523 | __cfg80211_send_disassoc(sdata->dev, frame_buf, DEAUTH_DISASSOC_LEN); | 3619 | __cfg80211_send_disassoc(sdata->dev, frame_buf, |
3620 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3524 | 3621 | ||
3525 | mutex_lock(&sdata->local->mtx); | 3622 | mutex_lock(&sdata->local->mtx); |
3526 | ieee80211_recalc_idle(sdata->local); | 3623 | ieee80211_recalc_idle(sdata->local); |