diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 352 |
1 files changed, 262 insertions, 90 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 245dce969b31..b82a12a9f0f1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -131,13 +131,13 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) | |||
131 | if (unlikely(!sdata->u.mgd.associated)) | 131 | if (unlikely(!sdata->u.mgd.associated)) |
132 | return; | 132 | return; |
133 | 133 | ||
134 | ifmgd->probe_send_count = 0; | ||
135 | |||
134 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 136 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
135 | return; | 137 | return; |
136 | 138 | ||
137 | mod_timer(&sdata->u.mgd.conn_mon_timer, | 139 | mod_timer(&sdata->u.mgd.conn_mon_timer, |
138 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | 140 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); |
139 | |||
140 | ifmgd->probe_send_count = 0; | ||
141 | } | 141 | } |
142 | 142 | ||
143 | static int ecw2cw(int ecw) | 143 | static int ecw2cw(int ecw) |
@@ -531,6 +531,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
531 | u8 *pos; | 531 | u8 *pos; |
532 | u32 cap; | 532 | u32 cap; |
533 | struct ieee80211_sta_vht_cap vht_cap; | 533 | struct ieee80211_sta_vht_cap vht_cap; |
534 | u32 mask, ap_bf_sts, our_bf_sts; | ||
534 | 535 | ||
535 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); | 536 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); |
536 | 537 | ||
@@ -558,6 +559,16 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
558 | cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) | 559 | cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) |
559 | cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; | 560 | cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; |
560 | 561 | ||
562 | mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; | ||
563 | |||
564 | ap_bf_sts = le32_to_cpu(ap_vht_cap->vht_cap_info) & mask; | ||
565 | our_bf_sts = cap & mask; | ||
566 | |||
567 | if (ap_bf_sts < our_bf_sts) { | ||
568 | cap &= ~mask; | ||
569 | cap |= ap_bf_sts; | ||
570 | } | ||
571 | |||
561 | /* reserve and fill IE */ | 572 | /* reserve and fill IE */ |
562 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); | 573 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); |
563 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); | 574 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); |
@@ -768,6 +779,34 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
768 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, | 779 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, |
769 | sband, chan, sdata->smps_mode); | 780 | sband, chan, sdata->smps_mode); |
770 | 781 | ||
782 | /* if present, add any custom IEs that go before VHT */ | ||
783 | if (assoc_data->ie_len) { | ||
784 | static const u8 before_vht[] = { | ||
785 | WLAN_EID_SSID, | ||
786 | WLAN_EID_SUPP_RATES, | ||
787 | WLAN_EID_EXT_SUPP_RATES, | ||
788 | WLAN_EID_PWR_CAPABILITY, | ||
789 | WLAN_EID_SUPPORTED_CHANNELS, | ||
790 | WLAN_EID_RSN, | ||
791 | WLAN_EID_QOS_CAPA, | ||
792 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | ||
793 | WLAN_EID_MOBILITY_DOMAIN, | ||
794 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
795 | WLAN_EID_HT_CAPABILITY, | ||
796 | WLAN_EID_BSS_COEX_2040, | ||
797 | WLAN_EID_EXT_CAPABILITY, | ||
798 | WLAN_EID_QOS_TRAFFIC_CAPA, | ||
799 | WLAN_EID_TIM_BCAST_REQ, | ||
800 | WLAN_EID_INTERWORKING, | ||
801 | }; | ||
802 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | ||
803 | before_vht, ARRAY_SIZE(before_vht), | ||
804 | offset); | ||
805 | pos = skb_put(skb, noffset - offset); | ||
806 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | ||
807 | offset = noffset; | ||
808 | } | ||
809 | |||
771 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | 810 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
772 | ieee80211_add_vht_ie(sdata, skb, sband, | 811 | ieee80211_add_vht_ie(sdata, skb, sband, |
773 | &assoc_data->ap_vht_cap); | 812 | &assoc_data->ap_vht_cap); |
@@ -791,16 +830,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
791 | qos_info = 0; | 830 | qos_info = 0; |
792 | } | 831 | } |
793 | 832 | ||
794 | pos = skb_put(skb, 9); | 833 | pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); |
795 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
796 | *pos++ = 7; /* len */ | ||
797 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
798 | *pos++ = 0x50; | ||
799 | *pos++ = 0xf2; | ||
800 | *pos++ = 2; /* WME */ | ||
801 | *pos++ = 0; /* WME info */ | ||
802 | *pos++ = 1; /* WME ver */ | ||
803 | *pos++ = qos_info; | ||
804 | } | 834 | } |
805 | 835 | ||
806 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 836 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
@@ -901,51 +931,77 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
901 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | 931 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
902 | struct ieee80211_local *local = sdata->local; | 932 | struct ieee80211_local *local = sdata->local; |
903 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 933 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
904 | u32 changed = 0; | ||
905 | int ret; | 934 | int ret; |
906 | 935 | ||
907 | if (!ieee80211_sdata_running(sdata)) | 936 | if (!ieee80211_sdata_running(sdata)) |
908 | return; | 937 | return; |
909 | 938 | ||
910 | sdata_lock(sdata); | 939 | sdata_lock(sdata); |
940 | mutex_lock(&local->mtx); | ||
941 | mutex_lock(&local->chanctx_mtx); | ||
942 | |||
911 | if (!ifmgd->associated) | 943 | if (!ifmgd->associated) |
912 | goto out; | 944 | goto out; |
913 | 945 | ||
914 | mutex_lock(&local->mtx); | 946 | if (!sdata->vif.csa_active) |
915 | ret = ieee80211_vif_change_channel(sdata, &changed); | 947 | goto out; |
916 | mutex_unlock(&local->mtx); | 948 | |
917 | if (ret) { | 949 | /* |
950 | * using reservation isn't immediate as it may be deferred until later | ||
951 | * with multi-vif. once reservation is complete it will re-schedule the | ||
952 | * work with no reserved_chanctx so verify chandef to check if it | ||
953 | * completed successfully | ||
954 | */ | ||
955 | |||
956 | if (sdata->reserved_chanctx) { | ||
957 | /* | ||
958 | * with multi-vif csa driver may call ieee80211_csa_finish() | ||
959 | * many times while waiting for other interfaces to use their | ||
960 | * reservations | ||
961 | */ | ||
962 | if (sdata->reserved_ready) | ||
963 | goto out; | ||
964 | |||
965 | ret = ieee80211_vif_use_reserved_context(sdata); | ||
966 | if (ret) { | ||
967 | sdata_info(sdata, | ||
968 | "failed to use reserved channel context, disconnecting (err=%d)\n", | ||
969 | ret); | ||
970 | ieee80211_queue_work(&sdata->local->hw, | ||
971 | &ifmgd->csa_connection_drop_work); | ||
972 | goto out; | ||
973 | } | ||
974 | |||
975 | goto out; | ||
976 | } | ||
977 | |||
978 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | ||
979 | &sdata->csa_chandef)) { | ||
918 | sdata_info(sdata, | 980 | sdata_info(sdata, |
919 | "vif channel switch failed, disconnecting\n"); | 981 | "failed to finalize channel switch, disconnecting\n"); |
920 | ieee80211_queue_work(&sdata->local->hw, | 982 | ieee80211_queue_work(&sdata->local->hw, |
921 | &ifmgd->csa_connection_drop_work); | 983 | &ifmgd->csa_connection_drop_work); |
922 | goto out; | 984 | goto out; |
923 | } | 985 | } |
924 | 986 | ||
925 | if (!local->use_chanctx) { | ||
926 | local->_oper_chandef = sdata->csa_chandef; | ||
927 | /* Call "hw_config" only if doing sw channel switch. | ||
928 | * Otherwise update the channel directly | ||
929 | */ | ||
930 | if (!local->ops->channel_switch) | ||
931 | ieee80211_hw_config(local, 0); | ||
932 | else | ||
933 | local->hw.conf.chandef = local->_oper_chandef; | ||
934 | } | ||
935 | |||
936 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 987 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
937 | ifmgd->associated->channel = sdata->csa_chandef.chan; | 988 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
938 | 989 | ||
990 | sdata->vif.csa_active = false; | ||
991 | |||
939 | /* XXX: wait for a beacon first? */ | 992 | /* XXX: wait for a beacon first? */ |
940 | ieee80211_wake_queues_by_reason(&local->hw, | 993 | if (sdata->csa_block_tx) { |
941 | IEEE80211_MAX_QUEUE_MAP, | 994 | ieee80211_wake_vif_queues(local, sdata, |
942 | IEEE80211_QUEUE_STOP_REASON_CSA); | 995 | IEEE80211_QUEUE_STOP_REASON_CSA); |
996 | sdata->csa_block_tx = false; | ||
997 | } | ||
943 | 998 | ||
944 | ieee80211_bss_info_change_notify(sdata, changed); | 999 | ieee80211_sta_reset_beacon_monitor(sdata); |
1000 | ieee80211_sta_reset_conn_monitor(sdata); | ||
945 | 1001 | ||
946 | out: | 1002 | out: |
947 | sdata->vif.csa_active = false; | 1003 | mutex_unlock(&local->chanctx_mtx); |
948 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 1004 | mutex_unlock(&local->mtx); |
949 | sdata_unlock(sdata); | 1005 | sdata_unlock(sdata); |
950 | } | 1006 | } |
951 | 1007 | ||
@@ -982,6 +1038,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
982 | struct ieee80211_local *local = sdata->local; | 1038 | struct ieee80211_local *local = sdata->local; |
983 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1039 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
984 | struct cfg80211_bss *cbss = ifmgd->associated; | 1040 | struct cfg80211_bss *cbss = ifmgd->associated; |
1041 | struct ieee80211_chanctx_conf *conf; | ||
985 | struct ieee80211_chanctx *chanctx; | 1042 | struct ieee80211_chanctx *chanctx; |
986 | enum ieee80211_band current_band; | 1043 | enum ieee80211_band current_band; |
987 | struct ieee80211_csa_ie csa_ie; | 1044 | struct ieee80211_csa_ie csa_ie; |
@@ -996,7 +1053,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
996 | return; | 1053 | return; |
997 | 1054 | ||
998 | /* disregard subsequent announcements if we are already processing */ | 1055 | /* disregard subsequent announcements if we are already processing */ |
999 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | 1056 | if (sdata->vif.csa_active) |
1000 | return; | 1057 | return; |
1001 | 1058 | ||
1002 | current_band = cbss->channel->band; | 1059 | current_band = cbss->channel->band; |
@@ -1023,10 +1080,22 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1023 | return; | 1080 | return; |
1024 | } | 1081 | } |
1025 | 1082 | ||
1026 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1083 | mutex_lock(&local->mtx); |
1027 | sdata->vif.csa_active = true; | ||
1028 | |||
1029 | mutex_lock(&local->chanctx_mtx); | 1084 | mutex_lock(&local->chanctx_mtx); |
1085 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1086 | lockdep_is_held(&local->chanctx_mtx)); | ||
1087 | if (!conf) { | ||
1088 | sdata_info(sdata, | ||
1089 | "no channel context assigned to vif?, disconnecting\n"); | ||
1090 | ieee80211_queue_work(&local->hw, | ||
1091 | &ifmgd->csa_connection_drop_work); | ||
1092 | mutex_unlock(&local->chanctx_mtx); | ||
1093 | mutex_unlock(&local->mtx); | ||
1094 | return; | ||
1095 | } | ||
1096 | |||
1097 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
1098 | |||
1030 | if (local->use_chanctx) { | 1099 | if (local->use_chanctx) { |
1031 | u32 num_chanctx = 0; | 1100 | u32 num_chanctx = 0; |
1032 | list_for_each_entry(chanctx, &local->chanctx_list, list) | 1101 | list_for_each_entry(chanctx, &local->chanctx_list, list) |
@@ -1039,34 +1108,33 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1039 | ieee80211_queue_work(&local->hw, | 1108 | ieee80211_queue_work(&local->hw, |
1040 | &ifmgd->csa_connection_drop_work); | 1109 | &ifmgd->csa_connection_drop_work); |
1041 | mutex_unlock(&local->chanctx_mtx); | 1110 | mutex_unlock(&local->chanctx_mtx); |
1111 | mutex_unlock(&local->mtx); | ||
1042 | return; | 1112 | return; |
1043 | } | 1113 | } |
1044 | } | 1114 | } |
1045 | 1115 | ||
1046 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { | 1116 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
1047 | ieee80211_queue_work(&local->hw, | 1117 | chanctx->mode, false); |
1048 | &ifmgd->csa_connection_drop_work); | 1118 | if (res) { |
1049 | mutex_unlock(&local->chanctx_mtx); | ||
1050 | return; | ||
1051 | } | ||
1052 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), | ||
1053 | struct ieee80211_chanctx, conf); | ||
1054 | if (chanctx->refcount > 1) { | ||
1055 | sdata_info(sdata, | 1119 | sdata_info(sdata, |
1056 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); | 1120 | "failed to reserve channel context for channel switch, disconnecting (err=%d)\n", |
1121 | res); | ||
1057 | ieee80211_queue_work(&local->hw, | 1122 | ieee80211_queue_work(&local->hw, |
1058 | &ifmgd->csa_connection_drop_work); | 1123 | &ifmgd->csa_connection_drop_work); |
1059 | mutex_unlock(&local->chanctx_mtx); | 1124 | mutex_unlock(&local->chanctx_mtx); |
1125 | mutex_unlock(&local->mtx); | ||
1060 | return; | 1126 | return; |
1061 | } | 1127 | } |
1062 | mutex_unlock(&local->chanctx_mtx); | 1128 | mutex_unlock(&local->chanctx_mtx); |
1063 | 1129 | ||
1130 | sdata->vif.csa_active = true; | ||
1064 | sdata->csa_chandef = csa_ie.chandef; | 1131 | sdata->csa_chandef = csa_ie.chandef; |
1132 | sdata->csa_block_tx = csa_ie.mode; | ||
1065 | 1133 | ||
1066 | if (csa_ie.mode) | 1134 | if (sdata->csa_block_tx) |
1067 | ieee80211_stop_queues_by_reason(&local->hw, | 1135 | ieee80211_stop_vif_queues(local, sdata, |
1068 | IEEE80211_MAX_QUEUE_MAP, | 1136 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1069 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1137 | mutex_unlock(&local->mtx); |
1070 | 1138 | ||
1071 | if (local->ops->channel_switch) { | 1139 | if (local->ops->channel_switch) { |
1072 | /* use driver's channel switch callback */ | 1140 | /* use driver's channel switch callback */ |
@@ -1335,7 +1403,8 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work) | |||
1335 | 1403 | ||
1336 | ieee80211_wake_queues_by_reason(&local->hw, | 1404 | ieee80211_wake_queues_by_reason(&local->hw, |
1337 | IEEE80211_MAX_QUEUE_MAP, | 1405 | IEEE80211_MAX_QUEUE_MAP, |
1338 | IEEE80211_QUEUE_STOP_REASON_PS); | 1406 | IEEE80211_QUEUE_STOP_REASON_PS, |
1407 | false); | ||
1339 | } | 1408 | } |
1340 | 1409 | ||
1341 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | 1410 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work) |
@@ -1778,6 +1847,13 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1778 | ifmgd->flags = 0; | 1847 | ifmgd->flags = 0; |
1779 | mutex_lock(&local->mtx); | 1848 | mutex_lock(&local->mtx); |
1780 | ieee80211_vif_release_channel(sdata); | 1849 | ieee80211_vif_release_channel(sdata); |
1850 | |||
1851 | sdata->vif.csa_active = false; | ||
1852 | if (sdata->csa_block_tx) { | ||
1853 | ieee80211_wake_vif_queues(local, sdata, | ||
1854 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1855 | sdata->csa_block_tx = false; | ||
1856 | } | ||
1781 | mutex_unlock(&local->mtx); | 1857 | mutex_unlock(&local->mtx); |
1782 | 1858 | ||
1783 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | 1859 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
@@ -2006,6 +2082,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get); | |||
2006 | 2082 | ||
2007 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | 2083 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) |
2008 | { | 2084 | { |
2085 | struct ieee80211_local *local = sdata->local; | ||
2009 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2086 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2010 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 2087 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
2011 | 2088 | ||
@@ -2018,11 +2095,14 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2018 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 2095 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
2019 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 2096 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
2020 | true, frame_buf); | 2097 | true, frame_buf); |
2021 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 2098 | mutex_lock(&local->mtx); |
2022 | sdata->vif.csa_active = false; | 2099 | sdata->vif.csa_active = false; |
2023 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 2100 | if (sdata->csa_block_tx) { |
2024 | IEEE80211_MAX_QUEUE_MAP, | 2101 | ieee80211_wake_vif_queues(local, sdata, |
2025 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2102 | IEEE80211_QUEUE_STOP_REASON_CSA); |
2103 | sdata->csa_block_tx = false; | ||
2104 | } | ||
2105 | mutex_unlock(&local->mtx); | ||
2026 | 2106 | ||
2027 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 2107 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
2028 | IEEE80211_DEAUTH_FRAME_LEN); | 2108 | IEEE80211_DEAUTH_FRAME_LEN); |
@@ -2233,6 +2313,62 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2233 | /* ignore frame -- wait for timeout */ | 2313 | /* ignore frame -- wait for timeout */ |
2234 | } | 2314 | } |
2235 | 2315 | ||
2316 | #define case_WLAN(type) \ | ||
2317 | case WLAN_REASON_##type: return #type | ||
2318 | |||
2319 | static const char *ieee80211_get_reason_code_string(u16 reason_code) | ||
2320 | { | ||
2321 | switch (reason_code) { | ||
2322 | case_WLAN(UNSPECIFIED); | ||
2323 | case_WLAN(PREV_AUTH_NOT_VALID); | ||
2324 | case_WLAN(DEAUTH_LEAVING); | ||
2325 | case_WLAN(DISASSOC_DUE_TO_INACTIVITY); | ||
2326 | case_WLAN(DISASSOC_AP_BUSY); | ||
2327 | case_WLAN(CLASS2_FRAME_FROM_NONAUTH_STA); | ||
2328 | case_WLAN(CLASS3_FRAME_FROM_NONASSOC_STA); | ||
2329 | case_WLAN(DISASSOC_STA_HAS_LEFT); | ||
2330 | case_WLAN(STA_REQ_ASSOC_WITHOUT_AUTH); | ||
2331 | case_WLAN(DISASSOC_BAD_POWER); | ||
2332 | case_WLAN(DISASSOC_BAD_SUPP_CHAN); | ||
2333 | case_WLAN(INVALID_IE); | ||
2334 | case_WLAN(MIC_FAILURE); | ||
2335 | case_WLAN(4WAY_HANDSHAKE_TIMEOUT); | ||
2336 | case_WLAN(GROUP_KEY_HANDSHAKE_TIMEOUT); | ||
2337 | case_WLAN(IE_DIFFERENT); | ||
2338 | case_WLAN(INVALID_GROUP_CIPHER); | ||
2339 | case_WLAN(INVALID_PAIRWISE_CIPHER); | ||
2340 | case_WLAN(INVALID_AKMP); | ||
2341 | case_WLAN(UNSUPP_RSN_VERSION); | ||
2342 | case_WLAN(INVALID_RSN_IE_CAP); | ||
2343 | case_WLAN(IEEE8021X_FAILED); | ||
2344 | case_WLAN(CIPHER_SUITE_REJECTED); | ||
2345 | case_WLAN(DISASSOC_UNSPECIFIED_QOS); | ||
2346 | case_WLAN(DISASSOC_QAP_NO_BANDWIDTH); | ||
2347 | case_WLAN(DISASSOC_LOW_ACK); | ||
2348 | case_WLAN(DISASSOC_QAP_EXCEED_TXOP); | ||
2349 | case_WLAN(QSTA_LEAVE_QBSS); | ||
2350 | case_WLAN(QSTA_NOT_USE); | ||
2351 | case_WLAN(QSTA_REQUIRE_SETUP); | ||
2352 | case_WLAN(QSTA_TIMEOUT); | ||
2353 | case_WLAN(QSTA_CIPHER_NOT_SUPP); | ||
2354 | case_WLAN(MESH_PEER_CANCELED); | ||
2355 | case_WLAN(MESH_MAX_PEERS); | ||
2356 | case_WLAN(MESH_CONFIG); | ||
2357 | case_WLAN(MESH_CLOSE); | ||
2358 | case_WLAN(MESH_MAX_RETRIES); | ||
2359 | case_WLAN(MESH_CONFIRM_TIMEOUT); | ||
2360 | case_WLAN(MESH_INVALID_GTK); | ||
2361 | case_WLAN(MESH_INCONSISTENT_PARAM); | ||
2362 | case_WLAN(MESH_INVALID_SECURITY); | ||
2363 | case_WLAN(MESH_PATH_ERROR); | ||
2364 | case_WLAN(MESH_PATH_NOFORWARD); | ||
2365 | case_WLAN(MESH_PATH_DEST_UNREACHABLE); | ||
2366 | case_WLAN(MAC_EXISTS_IN_MBSS); | ||
2367 | case_WLAN(MESH_CHAN_REGULATORY); | ||
2368 | case_WLAN(MESH_CHAN); | ||
2369 | default: return "<unknown>"; | ||
2370 | } | ||
2371 | } | ||
2236 | 2372 | ||
2237 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 2373 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
2238 | struct ieee80211_mgmt *mgmt, size_t len) | 2374 | struct ieee80211_mgmt *mgmt, size_t len) |
@@ -2254,8 +2390,8 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
2254 | 2390 | ||
2255 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 2391 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
2256 | 2392 | ||
2257 | sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n", | 2393 | sdata_info(sdata, "deauthenticated from %pM (Reason: %u=%s)\n", |
2258 | bssid, reason_code); | 2394 | bssid, reason_code, ieee80211_get_reason_code_string(reason_code)); |
2259 | 2395 | ||
2260 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2396 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2261 | 2397 | ||
@@ -2688,28 +2824,20 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2688 | struct ieee802_11_elems *elems) | 2824 | struct ieee802_11_elems *elems) |
2689 | { | 2825 | { |
2690 | struct ieee80211_local *local = sdata->local; | 2826 | struct ieee80211_local *local = sdata->local; |
2691 | int freq; | ||
2692 | struct ieee80211_bss *bss; | 2827 | struct ieee80211_bss *bss; |
2693 | struct ieee80211_channel *channel; | 2828 | struct ieee80211_channel *channel; |
2694 | 2829 | ||
2695 | sdata_assert_lock(sdata); | 2830 | sdata_assert_lock(sdata); |
2696 | 2831 | ||
2697 | if (elems->ds_params) | 2832 | channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); |
2698 | freq = ieee80211_channel_to_frequency(elems->ds_params[0], | 2833 | if (!channel) |
2699 | rx_status->band); | ||
2700 | else | ||
2701 | freq = rx_status->freq; | ||
2702 | |||
2703 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
2704 | |||
2705 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
2706 | return; | 2834 | return; |
2707 | 2835 | ||
2708 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 2836 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
2709 | channel); | 2837 | channel); |
2710 | if (bss) { | 2838 | if (bss) { |
2711 | ieee80211_rx_bss_put(local, bss); | ||
2712 | sdata->vif.bss_conf.beacon_rate = bss->beacon_rate; | 2839 | sdata->vif.bss_conf.beacon_rate = bss->beacon_rate; |
2840 | ieee80211_rx_bss_put(local, bss); | ||
2713 | } | 2841 | } |
2714 | } | 2842 | } |
2715 | 2843 | ||
@@ -3459,6 +3587,9 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
3459 | if (local->quiescing) | 3587 | if (local->quiescing) |
3460 | return; | 3588 | return; |
3461 | 3589 | ||
3590 | if (sdata->vif.csa_active) | ||
3591 | return; | ||
3592 | |||
3462 | sdata->u.mgd.connection_loss = false; | 3593 | sdata->u.mgd.connection_loss = false; |
3463 | ieee80211_queue_work(&sdata->local->hw, | 3594 | ieee80211_queue_work(&sdata->local->hw, |
3464 | &sdata->u.mgd.beacon_connection_loss_work); | 3595 | &sdata->u.mgd.beacon_connection_loss_work); |
@@ -3474,6 +3605,9 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) | |||
3474 | if (local->quiescing) | 3605 | if (local->quiescing) |
3475 | return; | 3606 | return; |
3476 | 3607 | ||
3608 | if (sdata->vif.csa_active) | ||
3609 | return; | ||
3610 | |||
3477 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); | 3611 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); |
3478 | } | 3612 | } |
3479 | 3613 | ||
@@ -3504,6 +3638,38 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
3504 | } | 3638 | } |
3505 | 3639 | ||
3506 | #ifdef CONFIG_PM | 3640 | #ifdef CONFIG_PM |
3641 | void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) | ||
3642 | { | ||
3643 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3644 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||
3645 | |||
3646 | sdata_lock(sdata); | ||
3647 | |||
3648 | if (ifmgd->auth_data || ifmgd->assoc_data) { | ||
3649 | const u8 *bssid = ifmgd->auth_data ? | ||
3650 | ifmgd->auth_data->bss->bssid : | ||
3651 | ifmgd->assoc_data->bss->bssid; | ||
3652 | |||
3653 | /* | ||
3654 | * If we are trying to authenticate / associate while suspending, | ||
3655 | * cfg80211 won't know and won't actually abort those attempts, | ||
3656 | * thus we need to do that ourselves. | ||
3657 | */ | ||
3658 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
3659 | IEEE80211_STYPE_DEAUTH, | ||
3660 | WLAN_REASON_DEAUTH_LEAVING, | ||
3661 | false, frame_buf); | ||
3662 | if (ifmgd->assoc_data) | ||
3663 | ieee80211_destroy_assoc_data(sdata, false); | ||
3664 | if (ifmgd->auth_data) | ||
3665 | ieee80211_destroy_auth_data(sdata, false); | ||
3666 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | ||
3667 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3668 | } | ||
3669 | |||
3670 | sdata_unlock(sdata); | ||
3671 | } | ||
3672 | |||
3507 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | 3673 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) |
3508 | { | 3674 | { |
3509 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3675 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -3541,6 +3707,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3541 | INIT_WORK(&ifmgd->csa_connection_drop_work, | 3707 | INIT_WORK(&ifmgd->csa_connection_drop_work, |
3542 | ieee80211_csa_connection_drop_work); | 3708 | ieee80211_csa_connection_drop_work); |
3543 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); | 3709 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work); |
3710 | INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work, | ||
3711 | ieee80211_tdls_peer_del_work); | ||
3544 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 3712 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
3545 | (unsigned long) sdata); | 3713 | (unsigned long) sdata); |
3546 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | 3714 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, |
@@ -3588,7 +3756,7 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
3588 | ieee80211_recalc_ps(local, latency_usec); | 3756 | ieee80211_recalc_ps(local, latency_usec); |
3589 | mutex_unlock(&local->iflist_mtx); | 3757 | mutex_unlock(&local->iflist_mtx); |
3590 | 3758 | ||
3591 | return 0; | 3759 | return NOTIFY_OK; |
3592 | } | 3760 | } |
3593 | 3761 | ||
3594 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, | 3762 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, |
@@ -4208,8 +4376,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4208 | rcu_read_unlock(); | 4376 | rcu_read_unlock(); |
4209 | 4377 | ||
4210 | if (bss->wmm_used && bss->uapsd_supported && | 4378 | if (bss->wmm_used && bss->uapsd_supported && |
4211 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) && | 4379 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { |
4212 | sdata->wmm_acm != 0xff) { | ||
4213 | assoc_data->uapsd = true; | 4380 | assoc_data->uapsd = true; |
4214 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; | 4381 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; |
4215 | } else { | 4382 | } else { |
@@ -4322,37 +4489,41 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4322 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 4489 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
4323 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 4490 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
4324 | bool tx = !req->local_state_change; | 4491 | bool tx = !req->local_state_change; |
4325 | bool report_frame = false; | ||
4326 | 4492 | ||
4327 | sdata_info(sdata, | 4493 | if (ifmgd->auth_data && |
4328 | "deauthenticating from %pM by local choice (reason=%d)\n", | 4494 | ether_addr_equal(ifmgd->auth_data->bss->bssid, req->bssid)) { |
4329 | req->bssid, req->reason_code); | 4495 | sdata_info(sdata, |
4496 | "aborting authentication with %pM by local choice (Reason: %u=%s)\n", | ||
4497 | req->bssid, req->reason_code, | ||
4498 | ieee80211_get_reason_code_string(req->reason_code)); | ||
4330 | 4499 | ||
4331 | if (ifmgd->auth_data) { | ||
4332 | drv_mgd_prepare_tx(sdata->local, sdata); | 4500 | drv_mgd_prepare_tx(sdata->local, sdata); |
4333 | ieee80211_send_deauth_disassoc(sdata, req->bssid, | 4501 | ieee80211_send_deauth_disassoc(sdata, req->bssid, |
4334 | IEEE80211_STYPE_DEAUTH, | 4502 | IEEE80211_STYPE_DEAUTH, |
4335 | req->reason_code, tx, | 4503 | req->reason_code, tx, |
4336 | frame_buf); | 4504 | frame_buf); |
4337 | ieee80211_destroy_auth_data(sdata, false); | 4505 | ieee80211_destroy_auth_data(sdata, false); |
4506 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | ||
4507 | IEEE80211_DEAUTH_FRAME_LEN); | ||
4338 | 4508 | ||
4339 | report_frame = true; | 4509 | return 0; |
4340 | goto out; | ||
4341 | } | 4510 | } |
4342 | 4511 | ||
4343 | if (ifmgd->associated && | 4512 | if (ifmgd->associated && |
4344 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | 4513 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { |
4514 | sdata_info(sdata, | ||
4515 | "deauthenticating from %pM by local choice (Reason: %u=%s)\n", | ||
4516 | req->bssid, req->reason_code, | ||
4517 | ieee80211_get_reason_code_string(req->reason_code)); | ||
4518 | |||
4345 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 4519 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
4346 | req->reason_code, tx, frame_buf); | 4520 | req->reason_code, tx, frame_buf); |
4347 | report_frame = true; | ||
4348 | } | ||
4349 | |||
4350 | out: | ||
4351 | if (report_frame) | ||
4352 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, | 4521 | cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, |
4353 | IEEE80211_DEAUTH_FRAME_LEN); | 4522 | IEEE80211_DEAUTH_FRAME_LEN); |
4523 | return 0; | ||
4524 | } | ||
4354 | 4525 | ||
4355 | return 0; | 4526 | return -ENOTCONN; |
4356 | } | 4527 | } |
4357 | 4528 | ||
4358 | int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | 4529 | int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, |
@@ -4372,8 +4543,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
4372 | return -ENOLINK; | 4543 | return -ENOLINK; |
4373 | 4544 | ||
4374 | sdata_info(sdata, | 4545 | sdata_info(sdata, |
4375 | "disassociating from %pM by local choice (reason=%d)\n", | 4546 | "disassociating from %pM by local choice (Reason: %u=%s)\n", |
4376 | req->bss->bssid, req->reason_code); | 4547 | req->bss->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code)); |
4377 | 4548 | ||
4378 | memcpy(bssid, req->bss->bssid, ETH_ALEN); | 4549 | memcpy(bssid, req->bss->bssid, ETH_ALEN); |
4379 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, | 4550 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, |
@@ -4400,6 +4571,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4400 | cancel_work_sync(&ifmgd->request_smps_work); | 4571 | cancel_work_sync(&ifmgd->request_smps_work); |
4401 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | 4572 | cancel_work_sync(&ifmgd->csa_connection_drop_work); |
4402 | cancel_work_sync(&ifmgd->chswitch_work); | 4573 | cancel_work_sync(&ifmgd->chswitch_work); |
4574 | cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work); | ||
4403 | 4575 | ||
4404 | sdata_lock(sdata); | 4576 | sdata_lock(sdata); |
4405 | if (ifmgd->assoc_data) { | 4577 | if (ifmgd->assoc_data) { |