diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 88 |
1 files changed, 67 insertions, 21 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b3a3ce316656..245dce969b31 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -222,6 +222,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
222 | switch (vht_oper->chan_width) { | 222 | switch (vht_oper->chan_width) { |
223 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | 223 | case IEEE80211_VHT_CHANWIDTH_USE_HT: |
224 | vht_chandef.width = chandef->width; | 224 | vht_chandef.width = chandef->width; |
225 | vht_chandef.center_freq1 = chandef->center_freq1; | ||
225 | break; | 226 | break; |
226 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | 227 | case IEEE80211_VHT_CHANWIDTH_80MHZ: |
227 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | 228 | vht_chandef.width = NL80211_CHAN_WIDTH_80; |
@@ -271,6 +272,28 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
271 | ret = 0; | 272 | ret = 0; |
272 | 273 | ||
273 | out: | 274 | out: |
275 | /* | ||
276 | * When tracking the current AP, don't do any further checks if the | ||
277 | * new chandef is identical to the one we're currently using for the | ||
278 | * connection. This keeps us from playing ping-pong with regulatory, | ||
279 | * without it the following can happen (for example): | ||
280 | * - connect to an AP with 80 MHz, world regdom allows 80 MHz | ||
281 | * - AP advertises regdom US | ||
282 | * - CRDA loads regdom US with 80 MHz prohibited (old database) | ||
283 | * - the code below detects an unsupported channel, downgrades, and | ||
284 | * we disconnect from the AP in the caller | ||
285 | * - disconnect causes CRDA to reload world regdomain and the game | ||
286 | * starts anew. | ||
287 | * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881) | ||
288 | * | ||
289 | * It seems possible that there are still scenarios with CSA or real | ||
290 | * bandwidth changes where a this could happen, but those cases are | ||
291 | * less common and wouldn't completely prevent using the AP. | ||
292 | */ | ||
293 | if (tracking && | ||
294 | cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) | ||
295 | return ret; | ||
296 | |||
274 | /* don't print the message below for VHT mismatch if VHT is disabled */ | 297 | /* don't print the message below for VHT mismatch if VHT is disabled */ |
275 | if (ret & IEEE80211_STA_DISABLE_VHT) | 298 | if (ret & IEEE80211_STA_DISABLE_VHT) |
276 | vht_chandef = *chandef; | 299 | vht_chandef = *chandef; |
@@ -330,6 +353,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
330 | if (WARN_ON_ONCE(!sta)) | 353 | if (WARN_ON_ONCE(!sta)) |
331 | return -EINVAL; | 354 | return -EINVAL; |
332 | 355 | ||
356 | /* | ||
357 | * if bss configuration changed store the new one - | ||
358 | * this may be applicable even if channel is identical | ||
359 | */ | ||
360 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); | ||
361 | if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { | ||
362 | *changed |= BSS_CHANGED_HT; | ||
363 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | ||
364 | } | ||
365 | |||
333 | chan = sdata->vif.bss_conf.chandef.chan; | 366 | chan = sdata->vif.bss_conf.chandef.chan; |
334 | sband = local->hw.wiphy->bands[chan->band]; | 367 | sband = local->hw.wiphy->bands[chan->band]; |
335 | 368 | ||
@@ -416,14 +449,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
416 | IEEE80211_RC_BW_CHANGED); | 449 | IEEE80211_RC_BW_CHANGED); |
417 | } | 450 | } |
418 | 451 | ||
419 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); | ||
420 | |||
421 | /* if bss configuration changed store the new one */ | ||
422 | if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { | ||
423 | *changed |= BSS_CHANGED_HT; | ||
424 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | ||
425 | } | ||
426 | |||
427 | return 0; | 452 | return 0; |
428 | } | 453 | } |
429 | 454 | ||
@@ -714,7 +739,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
714 | } | 739 | } |
715 | 740 | ||
716 | /* if present, add any custom IEs that go before HT */ | 741 | /* if present, add any custom IEs that go before HT */ |
717 | if (assoc_data->ie_len && assoc_data->ie) { | 742 | if (assoc_data->ie_len) { |
718 | static const u8 before_ht[] = { | 743 | static const u8 before_ht[] = { |
719 | WLAN_EID_SSID, | 744 | WLAN_EID_SSID, |
720 | WLAN_EID_SUPP_RATES, | 745 | WLAN_EID_SUPP_RATES, |
@@ -748,7 +773,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
748 | &assoc_data->ap_vht_cap); | 773 | &assoc_data->ap_vht_cap); |
749 | 774 | ||
750 | /* if present, add any custom non-vendor IEs that go after HT */ | 775 | /* if present, add any custom non-vendor IEs that go after HT */ |
751 | if (assoc_data->ie_len && assoc_data->ie) { | 776 | if (assoc_data->ie_len) { |
752 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, | 777 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, |
753 | assoc_data->ie_len, | 778 | assoc_data->ie_len, |
754 | offset); | 779 | offset); |
@@ -779,7 +804,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
779 | } | 804 | } |
780 | 805 | ||
781 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 806 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
782 | if (assoc_data->ie_len && assoc_data->ie) { | 807 | if (assoc_data->ie_len) { |
783 | noffset = assoc_data->ie_len; | 808 | noffset = assoc_data->ie_len; |
784 | pos = skb_put(skb, noffset - offset); | 809 | pos = skb_put(skb, noffset - offset); |
785 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 810 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
@@ -886,8 +911,9 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
886 | if (!ifmgd->associated) | 911 | if (!ifmgd->associated) |
887 | goto out; | 912 | goto out; |
888 | 913 | ||
889 | ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef, | 914 | mutex_lock(&local->mtx); |
890 | &changed); | 915 | ret = ieee80211_vif_change_channel(sdata, &changed); |
916 | mutex_unlock(&local->mtx); | ||
891 | if (ret) { | 917 | if (ret) { |
892 | sdata_info(sdata, | 918 | sdata_info(sdata, |
893 | "vif channel switch failed, disconnecting\n"); | 919 | "vif channel switch failed, disconnecting\n"); |
@@ -897,7 +923,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
897 | } | 923 | } |
898 | 924 | ||
899 | if (!local->use_chanctx) { | 925 | if (!local->use_chanctx) { |
900 | local->_oper_chandef = local->csa_chandef; | 926 | local->_oper_chandef = sdata->csa_chandef; |
901 | /* Call "hw_config" only if doing sw channel switch. | 927 | /* Call "hw_config" only if doing sw channel switch. |
902 | * Otherwise update the channel directly | 928 | * Otherwise update the channel directly |
903 | */ | 929 | */ |
@@ -908,7 +934,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
908 | } | 934 | } |
909 | 935 | ||
910 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 936 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
911 | ifmgd->associated->channel = local->csa_chandef.chan; | 937 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
912 | 938 | ||
913 | /* XXX: wait for a beacon first? */ | 939 | /* XXX: wait for a beacon first? */ |
914 | ieee80211_wake_queues_by_reason(&local->hw, | 940 | ieee80211_wake_queues_by_reason(&local->hw, |
@@ -1035,7 +1061,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1035 | } | 1061 | } |
1036 | mutex_unlock(&local->chanctx_mtx); | 1062 | mutex_unlock(&local->chanctx_mtx); |
1037 | 1063 | ||
1038 | local->csa_chandef = csa_ie.chandef; | 1064 | sdata->csa_chandef = csa_ie.chandef; |
1039 | 1065 | ||
1040 | if (csa_ie.mode) | 1066 | if (csa_ie.mode) |
1041 | ieee80211_stop_queues_by_reason(&local->hw, | 1067 | ieee80211_stop_queues_by_reason(&local->hw, |
@@ -1398,10 +1424,16 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) | |||
1398 | struct ieee80211_sub_if_data *sdata = | 1424 | struct ieee80211_sub_if_data *sdata = |
1399 | container_of(delayed_work, struct ieee80211_sub_if_data, | 1425 | container_of(delayed_work, struct ieee80211_sub_if_data, |
1400 | dfs_cac_timer_work); | 1426 | dfs_cac_timer_work); |
1427 | struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef; | ||
1401 | 1428 | ||
1402 | ieee80211_vif_release_channel(sdata); | 1429 | mutex_lock(&sdata->local->mtx); |
1403 | 1430 | if (sdata->wdev.cac_started) { | |
1404 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); | 1431 | ieee80211_vif_release_channel(sdata); |
1432 | cfg80211_cac_event(sdata->dev, &chandef, | ||
1433 | NL80211_RADAR_CAC_FINISHED, | ||
1434 | GFP_KERNEL); | ||
1435 | } | ||
1436 | mutex_unlock(&sdata->local->mtx); | ||
1405 | } | 1437 | } |
1406 | 1438 | ||
1407 | /* MLME */ | 1439 | /* MLME */ |
@@ -1695,7 +1727,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1695 | memset(ifmgd->bssid, 0, ETH_ALEN); | 1727 | memset(ifmgd->bssid, 0, ETH_ALEN); |
1696 | 1728 | ||
1697 | /* remove AP and TDLS peers */ | 1729 | /* remove AP and TDLS peers */ |
1698 | sta_info_flush_defer(sdata); | 1730 | sta_info_flush(sdata); |
1699 | 1731 | ||
1700 | /* finally reset all BSS / config parameters */ | 1732 | /* finally reset all BSS / config parameters */ |
1701 | changed |= ieee80211_reset_erp_info(sdata); | 1733 | changed |= ieee80211_reset_erp_info(sdata); |
@@ -1744,7 +1776,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1744 | ifmgd->have_beacon = false; | 1776 | ifmgd->have_beacon = false; |
1745 | 1777 | ||
1746 | ifmgd->flags = 0; | 1778 | ifmgd->flags = 0; |
1779 | mutex_lock(&local->mtx); | ||
1747 | ieee80211_vif_release_channel(sdata); | 1780 | ieee80211_vif_release_channel(sdata); |
1781 | mutex_unlock(&local->mtx); | ||
1782 | |||
1783 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
1748 | } | 1784 | } |
1749 | 1785 | ||
1750 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1786 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -2065,7 +2101,9 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | |||
2065 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 2101 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
2066 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 2102 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
2067 | sdata->u.mgd.flags = 0; | 2103 | sdata->u.mgd.flags = 0; |
2104 | mutex_lock(&sdata->local->mtx); | ||
2068 | ieee80211_vif_release_channel(sdata); | 2105 | ieee80211_vif_release_channel(sdata); |
2106 | mutex_unlock(&sdata->local->mtx); | ||
2069 | } | 2107 | } |
2070 | 2108 | ||
2071 | cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss); | 2109 | cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss); |
@@ -2314,7 +2352,9 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, | |||
2314 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 2352 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
2315 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 2353 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
2316 | sdata->u.mgd.flags = 0; | 2354 | sdata->u.mgd.flags = 0; |
2355 | mutex_lock(&sdata->local->mtx); | ||
2317 | ieee80211_vif_release_channel(sdata); | 2356 | ieee80211_vif_release_channel(sdata); |
2357 | mutex_unlock(&sdata->local->mtx); | ||
2318 | } | 2358 | } |
2319 | 2359 | ||
2320 | kfree(assoc_data); | 2360 | kfree(assoc_data); |
@@ -3665,6 +3705,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3665 | /* will change later if needed */ | 3705 | /* will change later if needed */ |
3666 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 3706 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
3667 | 3707 | ||
3708 | mutex_lock(&local->mtx); | ||
3668 | /* | 3709 | /* |
3669 | * If this fails (possibly due to channel context sharing | 3710 | * If this fails (possibly due to channel context sharing |
3670 | * on incompatible channels, e.g. 80+80 and 160 sharing the | 3711 | * on incompatible channels, e.g. 80+80 and 160 sharing the |
@@ -3676,13 +3717,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3676 | /* don't downgrade for 5 and 10 MHz channels, though. */ | 3717 | /* don't downgrade for 5 and 10 MHz channels, though. */ |
3677 | if (chandef.width == NL80211_CHAN_WIDTH_5 || | 3718 | if (chandef.width == NL80211_CHAN_WIDTH_5 || |
3678 | chandef.width == NL80211_CHAN_WIDTH_10) | 3719 | chandef.width == NL80211_CHAN_WIDTH_10) |
3679 | return ret; | 3720 | goto out; |
3680 | 3721 | ||
3681 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { | 3722 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) { |
3682 | ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); | 3723 | ifmgd->flags |= ieee80211_chandef_downgrade(&chandef); |
3683 | ret = ieee80211_vif_use_channel(sdata, &chandef, | 3724 | ret = ieee80211_vif_use_channel(sdata, &chandef, |
3684 | IEEE80211_CHANCTX_SHARED); | 3725 | IEEE80211_CHANCTX_SHARED); |
3685 | } | 3726 | } |
3727 | out: | ||
3728 | mutex_unlock(&local->mtx); | ||
3686 | return ret; | 3729 | return ret; |
3687 | } | 3730 | } |
3688 | 3731 | ||
@@ -3733,6 +3776,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3733 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 3776 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
3734 | if (WARN_ON(!chanctx_conf)) { | 3777 | if (WARN_ON(!chanctx_conf)) { |
3735 | rcu_read_unlock(); | 3778 | rcu_read_unlock(); |
3779 | sta_info_free(local, new_sta); | ||
3736 | return -EINVAL; | 3780 | return -EINVAL; |
3737 | } | 3781 | } |
3738 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); | 3782 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); |
@@ -4191,6 +4235,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4191 | 4235 | ||
4192 | sdata->control_port_protocol = req->crypto.control_port_ethertype; | 4236 | sdata->control_port_protocol = req->crypto.control_port_ethertype; |
4193 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; | 4237 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; |
4238 | sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto, | ||
4239 | sdata->vif.type); | ||
4194 | 4240 | ||
4195 | /* kick off associate process */ | 4241 | /* kick off associate process */ |
4196 | 4242 | ||