diff options
Diffstat (limited to 'net')
46 files changed, 2460 insertions, 1092 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 95667b088c5b..754069cbb756 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
133 | struct key_params *params) | 133 | struct key_params *params) |
134 | { | 134 | { |
135 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 135 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
136 | struct ieee80211_local *local = sdata->local; | ||
136 | struct sta_info *sta = NULL; | 137 | struct sta_info *sta = NULL; |
138 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
137 | struct ieee80211_key *key; | 139 | struct ieee80211_key *key; |
138 | int err; | 140 | int err; |
139 | 141 | ||
@@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
145 | case WLAN_CIPHER_SUITE_WEP40: | 147 | case WLAN_CIPHER_SUITE_WEP40: |
146 | case WLAN_CIPHER_SUITE_TKIP: | 148 | case WLAN_CIPHER_SUITE_TKIP: |
147 | case WLAN_CIPHER_SUITE_WEP104: | 149 | case WLAN_CIPHER_SUITE_WEP104: |
148 | if (IS_ERR(sdata->local->wep_tx_tfm)) | 150 | if (IS_ERR(local->wep_tx_tfm)) |
149 | return -EINVAL; | 151 | return -EINVAL; |
150 | break; | 152 | break; |
153 | case WLAN_CIPHER_SUITE_CCMP: | ||
154 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
155 | case WLAN_CIPHER_SUITE_GCMP: | ||
156 | break; | ||
151 | default: | 157 | default: |
158 | cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type); | ||
152 | break; | 159 | break; |
153 | } | 160 | } |
154 | 161 | ||
155 | key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, | 162 | key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, |
156 | params->key, params->seq_len, params->seq); | 163 | params->key, params->seq_len, params->seq, |
164 | cs); | ||
157 | if (IS_ERR(key)) | 165 | if (IS_ERR(key)) |
158 | return PTR_ERR(key); | 166 | return PTR_ERR(key); |
159 | 167 | ||
160 | if (pairwise) | 168 | if (pairwise) |
161 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | 169 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; |
162 | 170 | ||
163 | mutex_lock(&sdata->local->sta_mtx); | 171 | mutex_lock(&local->sta_mtx); |
164 | 172 | ||
165 | if (mac_addr) { | 173 | if (mac_addr) { |
166 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 174 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
@@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
216 | break; | 224 | break; |
217 | } | 225 | } |
218 | 226 | ||
227 | if (sta) | ||
228 | sta->cipher_scheme = cs; | ||
229 | |||
219 | err = ieee80211_key_link(key, sdata, sta); | 230 | err = ieee80211_key_link(key, sdata, sta); |
220 | 231 | ||
221 | out_unlock: | 232 | out_unlock: |
222 | mutex_unlock(&sdata->local->sta_mtx); | 233 | mutex_unlock(&local->sta_mtx); |
223 | 234 | ||
224 | return err; | 235 | return err; |
225 | } | 236 | } |
@@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
244 | goto out_unlock; | 255 | goto out_unlock; |
245 | 256 | ||
246 | if (pairwise) | 257 | if (pairwise) |
247 | key = key_mtx_dereference(local, sta->ptk); | 258 | key = key_mtx_dereference(local, sta->ptk[key_idx]); |
248 | else | 259 | else |
249 | key = key_mtx_dereference(local, sta->gtk[key_idx]); | 260 | key = key_mtx_dereference(local, sta->gtk[key_idx]); |
250 | } else | 261 | } else |
@@ -291,7 +302,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
291 | goto out; | 302 | goto out; |
292 | 303 | ||
293 | if (pairwise) | 304 | if (pairwise) |
294 | key = rcu_dereference(sta->ptk); | 305 | key = rcu_dereference(sta->ptk[key_idx]); |
295 | else if (key_idx < NUM_DEFAULT_KEYS) | 306 | else if (key_idx < NUM_DEFAULT_KEYS) |
296 | key = rcu_dereference(sta->gtk[key_idx]); | 307 | key = rcu_dereference(sta->gtk[key_idx]); |
297 | } else | 308 | } else |
@@ -521,8 +532,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
521 | STATION_INFO_PEER_PM | | 532 | STATION_INFO_PEER_PM | |
522 | STATION_INFO_NONPEER_PM; | 533 | STATION_INFO_NONPEER_PM; |
523 | 534 | ||
524 | sinfo->llid = le16_to_cpu(sta->llid); | 535 | sinfo->llid = sta->llid; |
525 | sinfo->plid = le16_to_cpu(sta->plid); | 536 | sinfo->plid = sta->plid; |
526 | sinfo->plink_state = sta->plink_state; | 537 | sinfo->plink_state = sta->plink_state; |
527 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | 538 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { |
528 | sinfo->filled |= STATION_INFO_T_OFFSET; | 539 | sinfo->filled |= STATION_INFO_T_OFFSET; |
@@ -846,7 +857,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
846 | if (!resp || !resp_len) | 857 | if (!resp || !resp_len) |
847 | return 1; | 858 | return 1; |
848 | 859 | ||
849 | old = rtnl_dereference(sdata->u.ap.probe_resp); | 860 | old = sdata_dereference(sdata->u.ap.probe_resp, sdata); |
850 | 861 | ||
851 | new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL); | 862 | new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL); |
852 | if (!new) | 863 | if (!new) |
@@ -870,7 +881,8 @@ int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | |||
870 | int size, err; | 881 | int size, err; |
871 | u32 changed = BSS_CHANGED_BEACON; | 882 | u32 changed = BSS_CHANGED_BEACON; |
872 | 883 | ||
873 | old = rtnl_dereference(sdata->u.ap.beacon); | 884 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
885 | |||
874 | 886 | ||
875 | /* Need to have a beacon head if we don't have one yet */ | 887 | /* Need to have a beacon head if we don't have one yet */ |
876 | if (!params->head && !old) | 888 | if (!params->head && !old) |
@@ -947,7 +959,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
947 | BSS_CHANGED_P2P_PS; | 959 | BSS_CHANGED_P2P_PS; |
948 | int err; | 960 | int err; |
949 | 961 | ||
950 | old = rtnl_dereference(sdata->u.ap.beacon); | 962 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
951 | if (old) | 963 | if (old) |
952 | return -EALREADY; | 964 | return -EALREADY; |
953 | 965 | ||
@@ -968,11 +980,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
968 | */ | 980 | */ |
969 | sdata->control_port_protocol = params->crypto.control_port_ethertype; | 981 | sdata->control_port_protocol = params->crypto.control_port_ethertype; |
970 | sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; | 982 | sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; |
983 | sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local, | ||
984 | ¶ms->crypto, | ||
985 | sdata->vif.type); | ||
986 | |||
971 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { | 987 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { |
972 | vlan->control_port_protocol = | 988 | vlan->control_port_protocol = |
973 | params->crypto.control_port_ethertype; | 989 | params->crypto.control_port_ethertype; |
974 | vlan->control_port_no_encrypt = | 990 | vlan->control_port_no_encrypt = |
975 | params->crypto.control_port_no_encrypt; | 991 | params->crypto.control_port_no_encrypt; |
992 | vlan->encrypt_headroom = | ||
993 | ieee80211_cs_headroom(sdata->local, | ||
994 | ¶ms->crypto, | ||
995 | vlan->vif.type); | ||
976 | } | 996 | } |
977 | 997 | ||
978 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | 998 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; |
@@ -1001,7 +1021,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
1001 | 1021 | ||
1002 | err = drv_start_ap(sdata->local, sdata); | 1022 | err = drv_start_ap(sdata->local, sdata); |
1003 | if (err) { | 1023 | if (err) { |
1004 | old = rtnl_dereference(sdata->u.ap.beacon); | 1024 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
1025 | |||
1005 | if (old) | 1026 | if (old) |
1006 | kfree_rcu(old, rcu_head); | 1027 | kfree_rcu(old, rcu_head); |
1007 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | 1028 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); |
@@ -1032,7 +1053,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
1032 | if (sdata->vif.csa_active) | 1053 | if (sdata->vif.csa_active) |
1033 | return -EBUSY; | 1054 | return -EBUSY; |
1034 | 1055 | ||
1035 | old = rtnl_dereference(sdata->u.ap.beacon); | 1056 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
1036 | if (!old) | 1057 | if (!old) |
1037 | return -ENOENT; | 1058 | return -ENOENT; |
1038 | 1059 | ||
@@ -1050,15 +1071,18 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1050 | struct ieee80211_local *local = sdata->local; | 1071 | struct ieee80211_local *local = sdata->local; |
1051 | struct beacon_data *old_beacon; | 1072 | struct beacon_data *old_beacon; |
1052 | struct probe_resp *old_probe_resp; | 1073 | struct probe_resp *old_probe_resp; |
1074 | struct cfg80211_chan_def chandef; | ||
1053 | 1075 | ||
1054 | old_beacon = rtnl_dereference(sdata->u.ap.beacon); | 1076 | old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata); |
1055 | if (!old_beacon) | 1077 | if (!old_beacon) |
1056 | return -ENOENT; | 1078 | return -ENOENT; |
1057 | old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); | 1079 | old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata); |
1058 | 1080 | ||
1059 | /* abort any running channel switch */ | 1081 | /* abort any running channel switch */ |
1060 | sdata->vif.csa_active = false; | 1082 | sdata->vif.csa_active = false; |
1061 | cancel_work_sync(&sdata->csa_finalize_work); | 1083 | kfree(sdata->u.ap.next_beacon); |
1084 | sdata->u.ap.next_beacon = NULL; | ||
1085 | |||
1062 | cancel_work_sync(&sdata->u.ap.request_smps_work); | 1086 | cancel_work_sync(&sdata->u.ap.request_smps_work); |
1063 | 1087 | ||
1064 | /* turn off carrier for this interface and dependent VLANs */ | 1088 | /* turn off carrier for this interface and dependent VLANs */ |
@@ -1091,8 +1115,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1091 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 1115 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
1092 | 1116 | ||
1093 | if (sdata->wdev.cac_started) { | 1117 | if (sdata->wdev.cac_started) { |
1118 | chandef = sdata->vif.bss_conf.chandef; | ||
1094 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 1119 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); |
1095 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, | 1120 | cfg80211_cac_event(sdata->dev, &chandef, |
1121 | NL80211_RADAR_CAC_ABORTED, | ||
1096 | GFP_KERNEL); | 1122 | GFP_KERNEL); |
1097 | } | 1123 | } |
1098 | 1124 | ||
@@ -1953,7 +1979,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1953 | enum ieee80211_band band; | 1979 | enum ieee80211_band band; |
1954 | u32 changed = 0; | 1980 | u32 changed = 0; |
1955 | 1981 | ||
1956 | if (!rtnl_dereference(sdata->u.ap.beacon)) | 1982 | if (!sdata_dereference(sdata->u.ap.beacon, sdata)) |
1957 | return -ENOENT; | 1983 | return -ENOENT; |
1958 | 1984 | ||
1959 | band = ieee80211_get_sdata_band(sdata); | 1985 | band = ieee80211_get_sdata_band(sdata); |
@@ -2964,27 +2990,33 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
2964 | struct ieee80211_local *local = sdata->local; | 2990 | struct ieee80211_local *local = sdata->local; |
2965 | int err, changed = 0; | 2991 | int err, changed = 0; |
2966 | 2992 | ||
2993 | sdata_lock(sdata); | ||
2994 | /* AP might have been stopped while waiting for the lock. */ | ||
2995 | if (!sdata->vif.csa_active) | ||
2996 | goto unlock; | ||
2997 | |||
2967 | if (!ieee80211_sdata_running(sdata)) | 2998 | if (!ieee80211_sdata_running(sdata)) |
2968 | return; | 2999 | goto unlock; |
2969 | 3000 | ||
2970 | sdata->radar_required = sdata->csa_radar_required; | 3001 | sdata->radar_required = sdata->csa_radar_required; |
2971 | err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, | 3002 | err = ieee80211_vif_change_channel(sdata, &changed); |
2972 | &changed); | ||
2973 | if (WARN_ON(err < 0)) | 3003 | if (WARN_ON(err < 0)) |
2974 | return; | 3004 | goto unlock; |
2975 | 3005 | ||
2976 | if (!local->use_chanctx) { | 3006 | if (!local->use_chanctx) { |
2977 | local->_oper_chandef = local->csa_chandef; | 3007 | local->_oper_chandef = sdata->csa_chandef; |
2978 | ieee80211_hw_config(local, 0); | 3008 | ieee80211_hw_config(local, 0); |
2979 | } | 3009 | } |
2980 | 3010 | ||
2981 | ieee80211_bss_info_change_notify(sdata, changed); | 3011 | ieee80211_bss_info_change_notify(sdata, changed); |
2982 | 3012 | ||
3013 | sdata->vif.csa_active = false; | ||
2983 | switch (sdata->vif.type) { | 3014 | switch (sdata->vif.type) { |
2984 | case NL80211_IFTYPE_AP: | 3015 | case NL80211_IFTYPE_AP: |
2985 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 3016 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); |
2986 | if (err < 0) | 3017 | if (err < 0) |
2987 | return; | 3018 | goto unlock; |
3019 | |||
2988 | changed |= err; | 3020 | changed |= err; |
2989 | kfree(sdata->u.ap.next_beacon); | 3021 | kfree(sdata->u.ap.next_beacon); |
2990 | sdata->u.ap.next_beacon = NULL; | 3022 | sdata->u.ap.next_beacon = NULL; |
@@ -2998,20 +3030,22 @@ void ieee80211_csa_finalize_work(struct work_struct *work) | |||
2998 | case NL80211_IFTYPE_MESH_POINT: | 3030 | case NL80211_IFTYPE_MESH_POINT: |
2999 | err = ieee80211_mesh_finish_csa(sdata); | 3031 | err = ieee80211_mesh_finish_csa(sdata); |
3000 | if (err < 0) | 3032 | if (err < 0) |
3001 | return; | 3033 | goto unlock; |
3002 | break; | 3034 | break; |
3003 | #endif | 3035 | #endif |
3004 | default: | 3036 | default: |
3005 | WARN_ON(1); | 3037 | WARN_ON(1); |
3006 | return; | 3038 | goto unlock; |
3007 | } | 3039 | } |
3008 | sdata->vif.csa_active = false; | ||
3009 | 3040 | ||
3010 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 3041 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
3011 | IEEE80211_MAX_QUEUE_MAP, | 3042 | IEEE80211_MAX_QUEUE_MAP, |
3012 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3043 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3013 | 3044 | ||
3014 | cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); | 3045 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); |
3046 | |||
3047 | unlock: | ||
3048 | sdata_unlock(sdata); | ||
3015 | } | 3049 | } |
3016 | 3050 | ||
3017 | static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | 3051 | static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, |
@@ -3024,6 +3058,8 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3024 | struct ieee80211_if_mesh __maybe_unused *ifmsh; | 3058 | struct ieee80211_if_mesh __maybe_unused *ifmsh; |
3025 | int err, num_chanctx; | 3059 | int err, num_chanctx; |
3026 | 3060 | ||
3061 | lockdep_assert_held(&sdata->wdev.mtx); | ||
3062 | |||
3027 | if (!list_empty(&local->roc_list) || local->scanning) | 3063 | if (!list_empty(&local->roc_list) || local->scanning) |
3028 | return -EBUSY; | 3064 | return -EBUSY; |
3029 | 3065 | ||
@@ -3136,7 +3172,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3136 | IEEE80211_MAX_QUEUE_MAP, | 3172 | IEEE80211_MAX_QUEUE_MAP, |
3137 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3173 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3138 | 3174 | ||
3139 | local->csa_chandef = params->chandef; | 3175 | sdata->csa_chandef = params->chandef; |
3140 | sdata->vif.csa_active = true; | 3176 | sdata->vif.csa_active = true; |
3141 | 3177 | ||
3142 | ieee80211_bss_info_change_notify(sdata, err); | 3178 | ieee80211_bss_info_change_notify(sdata, err); |
@@ -3146,26 +3182,25 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3146 | } | 3182 | } |
3147 | 3183 | ||
3148 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | 3184 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
3149 | struct ieee80211_channel *chan, bool offchan, | 3185 | struct cfg80211_mgmt_tx_params *params, |
3150 | unsigned int wait, const u8 *buf, size_t len, | 3186 | u64 *cookie) |
3151 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
3152 | { | 3187 | { |
3153 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 3188 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
3154 | struct ieee80211_local *local = sdata->local; | 3189 | struct ieee80211_local *local = sdata->local; |
3155 | struct sk_buff *skb; | 3190 | struct sk_buff *skb; |
3156 | struct sta_info *sta; | 3191 | struct sta_info *sta; |
3157 | const struct ieee80211_mgmt *mgmt = (void *)buf; | 3192 | const struct ieee80211_mgmt *mgmt = (void *)params->buf; |
3158 | bool need_offchan = false; | 3193 | bool need_offchan = false; |
3159 | u32 flags; | 3194 | u32 flags; |
3160 | int ret; | 3195 | int ret; |
3161 | 3196 | ||
3162 | if (dont_wait_for_ack) | 3197 | if (params->dont_wait_for_ack) |
3163 | flags = IEEE80211_TX_CTL_NO_ACK; | 3198 | flags = IEEE80211_TX_CTL_NO_ACK; |
3164 | else | 3199 | else |
3165 | flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | | 3200 | flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | |
3166 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 3201 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
3167 | 3202 | ||
3168 | if (no_cck) | 3203 | if (params->no_cck) |
3169 | flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | 3204 | flags |= IEEE80211_TX_CTL_NO_CCK_RATE; |
3170 | 3205 | ||
3171 | switch (sdata->vif.type) { | 3206 | switch (sdata->vif.type) { |
@@ -3213,7 +3248,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
3213 | /* configurations requiring offchan cannot work if no channel has been | 3248 | /* configurations requiring offchan cannot work if no channel has been |
3214 | * specified | 3249 | * specified |
3215 | */ | 3250 | */ |
3216 | if (need_offchan && !chan) | 3251 | if (need_offchan && !params->chan) |
3217 | return -EINVAL; | 3252 | return -EINVAL; |
3218 | 3253 | ||
3219 | mutex_lock(&local->mtx); | 3254 | mutex_lock(&local->mtx); |
@@ -3226,8 +3261,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
3226 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 3261 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
3227 | 3262 | ||
3228 | if (chanctx_conf) { | 3263 | if (chanctx_conf) { |
3229 | need_offchan = chan && (chan != chanctx_conf->def.chan); | 3264 | need_offchan = params->chan && |
3230 | } else if (!chan) { | 3265 | (params->chan != |
3266 | chanctx_conf->def.chan); | ||
3267 | } else if (!params->chan) { | ||
3231 | ret = -EINVAL; | 3268 | ret = -EINVAL; |
3232 | rcu_read_unlock(); | 3269 | rcu_read_unlock(); |
3233 | goto out_unlock; | 3270 | goto out_unlock; |
@@ -3237,19 +3274,19 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
3237 | rcu_read_unlock(); | 3274 | rcu_read_unlock(); |
3238 | } | 3275 | } |
3239 | 3276 | ||
3240 | if (need_offchan && !offchan) { | 3277 | if (need_offchan && !params->offchan) { |
3241 | ret = -EBUSY; | 3278 | ret = -EBUSY; |
3242 | goto out_unlock; | 3279 | goto out_unlock; |
3243 | } | 3280 | } |
3244 | 3281 | ||
3245 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); | 3282 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len); |
3246 | if (!skb) { | 3283 | if (!skb) { |
3247 | ret = -ENOMEM; | 3284 | ret = -ENOMEM; |
3248 | goto out_unlock; | 3285 | goto out_unlock; |
3249 | } | 3286 | } |
3250 | skb_reserve(skb, local->hw.extra_tx_headroom); | 3287 | skb_reserve(skb, local->hw.extra_tx_headroom); |
3251 | 3288 | ||
3252 | memcpy(skb_put(skb, len), buf, len); | 3289 | memcpy(skb_put(skb, params->len), params->buf, params->len); |
3253 | 3290 | ||
3254 | IEEE80211_SKB_CB(skb)->flags = flags; | 3291 | IEEE80211_SKB_CB(skb)->flags = flags; |
3255 | 3292 | ||
@@ -3269,8 +3306,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
3269 | local->hw.offchannel_tx_hw_queue; | 3306 | local->hw.offchannel_tx_hw_queue; |
3270 | 3307 | ||
3271 | /* This will handle all kinds of coalescing and immediate TX */ | 3308 | /* This will handle all kinds of coalescing and immediate TX */ |
3272 | ret = ieee80211_start_roc_work(local, sdata, chan, | 3309 | ret = ieee80211_start_roc_work(local, sdata, params->chan, |
3273 | wait, cookie, skb, | 3310 | params->wait, cookie, skb, |
3274 | IEEE80211_ROC_TYPE_MGMT_TX); | 3311 | IEEE80211_ROC_TYPE_MGMT_TX); |
3275 | if (ret) | 3312 | if (ret) |
3276 | kfree_skb(skb); | 3313 | kfree_skb(skb); |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 03ba6b5c5373..a57d5d9466bc 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -9,6 +9,140 @@ | |||
9 | #include "ieee80211_i.h" | 9 | #include "ieee80211_i.h" |
10 | #include "driver-ops.h" | 10 | #include "driver-ops.h" |
11 | 11 | ||
12 | static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) | ||
13 | { | ||
14 | switch (sta->bandwidth) { | ||
15 | case IEEE80211_STA_RX_BW_20: | ||
16 | if (sta->ht_cap.ht_supported) | ||
17 | return NL80211_CHAN_WIDTH_20; | ||
18 | else | ||
19 | return NL80211_CHAN_WIDTH_20_NOHT; | ||
20 | case IEEE80211_STA_RX_BW_40: | ||
21 | return NL80211_CHAN_WIDTH_40; | ||
22 | case IEEE80211_STA_RX_BW_80: | ||
23 | return NL80211_CHAN_WIDTH_80; | ||
24 | case IEEE80211_STA_RX_BW_160: | ||
25 | /* | ||
26 | * This applied for both 160 and 80+80. since we use | ||
27 | * the returned value to consider degradation of | ||
28 | * ctx->conf.min_def, we have to make sure to take | ||
29 | * the bigger one (NL80211_CHAN_WIDTH_160). | ||
30 | * Otherwise we might try degrading even when not | ||
31 | * needed, as the max required sta_bw returned (80+80) | ||
32 | * might be smaller than the configured bw (160). | ||
33 | */ | ||
34 | return NL80211_CHAN_WIDTH_160; | ||
35 | default: | ||
36 | WARN_ON(1); | ||
37 | return NL80211_CHAN_WIDTH_20; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | static enum nl80211_chan_width | ||
42 | ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) | ||
43 | { | ||
44 | enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; | ||
45 | struct sta_info *sta; | ||
46 | |||
47 | rcu_read_lock(); | ||
48 | list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { | ||
49 | if (sdata != sta->sdata && | ||
50 | !(sta->sdata->bss && sta->sdata->bss == sdata->bss)) | ||
51 | continue; | ||
52 | |||
53 | if (!sta->uploaded) | ||
54 | continue; | ||
55 | |||
56 | max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta)); | ||
57 | } | ||
58 | rcu_read_unlock(); | ||
59 | |||
60 | return max_bw; | ||
61 | } | ||
62 | |||
63 | static enum nl80211_chan_width | ||
64 | ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, | ||
65 | struct ieee80211_chanctx_conf *conf) | ||
66 | { | ||
67 | struct ieee80211_sub_if_data *sdata; | ||
68 | enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; | ||
69 | |||
70 | rcu_read_lock(); | ||
71 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
72 | struct ieee80211_vif *vif = &sdata->vif; | ||
73 | enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; | ||
74 | |||
75 | if (!ieee80211_sdata_running(sdata)) | ||
76 | continue; | ||
77 | |||
78 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) | ||
79 | continue; | ||
80 | |||
81 | switch (vif->type) { | ||
82 | case NL80211_IFTYPE_AP: | ||
83 | case NL80211_IFTYPE_AP_VLAN: | ||
84 | width = ieee80211_get_max_required_bw(sdata); | ||
85 | break; | ||
86 | case NL80211_IFTYPE_P2P_DEVICE: | ||
87 | continue; | ||
88 | case NL80211_IFTYPE_STATION: | ||
89 | case NL80211_IFTYPE_ADHOC: | ||
90 | case NL80211_IFTYPE_WDS: | ||
91 | case NL80211_IFTYPE_MESH_POINT: | ||
92 | width = vif->bss_conf.chandef.width; | ||
93 | break; | ||
94 | case NL80211_IFTYPE_UNSPECIFIED: | ||
95 | case NUM_NL80211_IFTYPES: | ||
96 | case NL80211_IFTYPE_MONITOR: | ||
97 | case NL80211_IFTYPE_P2P_CLIENT: | ||
98 | case NL80211_IFTYPE_P2P_GO: | ||
99 | WARN_ON_ONCE(1); | ||
100 | } | ||
101 | max_bw = max(max_bw, width); | ||
102 | } | ||
103 | rcu_read_unlock(); | ||
104 | |||
105 | return max_bw; | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * recalc the min required chan width of the channel context, which is | ||
110 | * the max of min required widths of all the interfaces bound to this | ||
111 | * channel context. | ||
112 | */ | ||
113 | void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, | ||
114 | struct ieee80211_chanctx *ctx) | ||
115 | { | ||
116 | enum nl80211_chan_width max_bw; | ||
117 | struct cfg80211_chan_def min_def; | ||
118 | |||
119 | lockdep_assert_held(&local->chanctx_mtx); | ||
120 | |||
121 | /* don't optimize 5MHz, 10MHz, and radar_enabled confs */ | ||
122 | if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 || | ||
123 | ctx->conf.def.width == NL80211_CHAN_WIDTH_10 || | ||
124 | ctx->conf.radar_enabled) { | ||
125 | ctx->conf.min_def = ctx->conf.def; | ||
126 | return; | ||
127 | } | ||
128 | |||
129 | max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf); | ||
130 | |||
131 | /* downgrade chandef up to max_bw */ | ||
132 | min_def = ctx->conf.def; | ||
133 | while (min_def.width > max_bw) | ||
134 | ieee80211_chandef_downgrade(&min_def); | ||
135 | |||
136 | if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def)) | ||
137 | return; | ||
138 | |||
139 | ctx->conf.min_def = min_def; | ||
140 | if (!ctx->driver_present) | ||
141 | return; | ||
142 | |||
143 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH); | ||
144 | } | ||
145 | |||
12 | static void ieee80211_change_chanctx(struct ieee80211_local *local, | 146 | static void ieee80211_change_chanctx(struct ieee80211_local *local, |
13 | struct ieee80211_chanctx *ctx, | 147 | struct ieee80211_chanctx *ctx, |
14 | const struct cfg80211_chan_def *chandef) | 148 | const struct cfg80211_chan_def *chandef) |
@@ -20,6 +154,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local, | |||
20 | 154 | ||
21 | ctx->conf.def = *chandef; | 155 | ctx->conf.def = *chandef; |
22 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); | 156 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); |
157 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
23 | 158 | ||
24 | if (!local->use_chanctx) { | 159 | if (!local->use_chanctx) { |
25 | local->_oper_chandef = *chandef; | 160 | local->_oper_chandef = *chandef; |
@@ -93,6 +228,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
93 | ctx->conf.rx_chains_dynamic = 1; | 228 | ctx->conf.rx_chains_dynamic = 1; |
94 | ctx->mode = mode; | 229 | ctx->mode = mode; |
95 | ctx->conf.radar_enabled = ieee80211_is_radar_required(local); | 230 | ctx->conf.radar_enabled = ieee80211_is_radar_required(local); |
231 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
96 | if (!local->use_chanctx) | 232 | if (!local->use_chanctx) |
97 | local->hw.conf.radar_enabled = ctx->conf.radar_enabled; | 233 | local->hw.conf.radar_enabled = ctx->conf.radar_enabled; |
98 | 234 | ||
@@ -179,6 +315,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
179 | ctx->refcount++; | 315 | ctx->refcount++; |
180 | 316 | ||
181 | ieee80211_recalc_txpower(sdata); | 317 | ieee80211_recalc_txpower(sdata); |
318 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
182 | sdata->vif.bss_conf.idle = false; | 319 | sdata->vif.bss_conf.idle = false; |
183 | 320 | ||
184 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && | 321 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && |
@@ -243,6 +380,7 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
243 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); | 380 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); |
244 | ieee80211_recalc_smps_chanctx(local, ctx); | 381 | ieee80211_recalc_smps_chanctx(local, ctx); |
245 | ieee80211_recalc_radar_chanctx(local, ctx); | 382 | ieee80211_recalc_radar_chanctx(local, ctx); |
383 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
246 | } | 384 | } |
247 | } | 385 | } |
248 | 386 | ||
@@ -411,12 +549,12 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
411 | } | 549 | } |
412 | 550 | ||
413 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | 551 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, |
414 | const struct cfg80211_chan_def *chandef, | ||
415 | u32 *changed) | 552 | u32 *changed) |
416 | { | 553 | { |
417 | struct ieee80211_local *local = sdata->local; | 554 | struct ieee80211_local *local = sdata->local; |
418 | struct ieee80211_chanctx_conf *conf; | 555 | struct ieee80211_chanctx_conf *conf; |
419 | struct ieee80211_chanctx *ctx; | 556 | struct ieee80211_chanctx *ctx; |
557 | const struct cfg80211_chan_def *chandef = &sdata->csa_chandef; | ||
420 | int ret; | 558 | int ret; |
421 | u32 chanctx_changed = 0; | 559 | u32 chanctx_changed = 0; |
422 | 560 | ||
@@ -456,6 +594,7 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | |||
456 | ieee80211_recalc_chanctx_chantype(local, ctx); | 594 | ieee80211_recalc_chanctx_chantype(local, ctx); |
457 | ieee80211_recalc_smps_chanctx(local, ctx); | 595 | ieee80211_recalc_smps_chanctx(local, ctx); |
458 | ieee80211_recalc_radar_chanctx(local, ctx); | 596 | ieee80211_recalc_radar_chanctx(local, ctx); |
597 | ieee80211_recalc_chanctx_min_def(local, ctx); | ||
459 | 598 | ||
460 | ret = 0; | 599 | ret = 0; |
461 | out: | 600 | out: |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 5c090e41d9bb..fa16e54980a1 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -17,6 +17,172 @@ | |||
17 | 17 | ||
18 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 | 18 | #define DEBUGFS_FORMAT_BUFFER_SIZE 100 |
19 | 19 | ||
20 | #define TX_LATENCY_BIN_DELIMTER_C ',' | ||
21 | #define TX_LATENCY_BIN_DELIMTER_S "," | ||
22 | #define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n" | ||
23 | #define TX_LATENCY_DISABLED "disable\n" | ||
24 | |||
25 | |||
26 | /* | ||
27 | * Display if Tx latency statistics & bins are enabled/disabled | ||
28 | */ | ||
29 | static ssize_t sta_tx_latency_stat_read(struct file *file, | ||
30 | char __user *userbuf, | ||
31 | size_t count, loff_t *ppos) | ||
32 | { | ||
33 | struct ieee80211_local *local = file->private_data; | ||
34 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
35 | char *buf; | ||
36 | int bufsz, i, ret; | ||
37 | int pos = 0; | ||
38 | |||
39 | rcu_read_lock(); | ||
40 | |||
41 | tx_latency = rcu_dereference(local->tx_latency); | ||
42 | |||
43 | if (tx_latency && tx_latency->n_ranges) { | ||
44 | bufsz = tx_latency->n_ranges * 15; | ||
45 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
46 | if (!buf) | ||
47 | goto err; | ||
48 | |||
49 | for (i = 0; i < tx_latency->n_ranges; i++) | ||
50 | pos += scnprintf(buf + pos, bufsz - pos, "%d,", | ||
51 | tx_latency->ranges[i]); | ||
52 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
53 | } else if (tx_latency) { | ||
54 | bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1; | ||
55 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
56 | if (!buf) | ||
57 | goto err; | ||
58 | |||
59 | pos += scnprintf(buf + pos, bufsz - pos, "%s\n", | ||
60 | TX_LATENCY_BINS_DISABLED); | ||
61 | } else { | ||
62 | bufsz = sizeof(TX_LATENCY_DISABLED) + 1; | ||
63 | buf = kzalloc(bufsz, GFP_ATOMIC); | ||
64 | if (!buf) | ||
65 | goto err; | ||
66 | |||
67 | pos += scnprintf(buf + pos, bufsz - pos, "%s\n", | ||
68 | TX_LATENCY_DISABLED); | ||
69 | } | ||
70 | |||
71 | rcu_read_unlock(); | ||
72 | |||
73 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
74 | kfree(buf); | ||
75 | |||
76 | return ret; | ||
77 | err: | ||
78 | rcu_read_unlock(); | ||
79 | return -ENOMEM; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Receive input from user regarding Tx latency statistics | ||
84 | * The input should indicate if Tx latency statistics and bins are | ||
85 | * enabled/disabled. | ||
86 | * If bins are enabled input should indicate the amount of different bins and | ||
87 | * their ranges. Each bin will count how many Tx frames transmitted within the | ||
88 | * appropriate latency. | ||
89 | * Legal input is: | ||
90 | * a) "enable(bins disabled)" - to enable only general statistics | ||
91 | * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are | ||
92 | * numbers and a < b < c < d.. < z | ||
93 | * c) "disable" - disable all statistics | ||
94 | * NOTE: must configure Tx latency statistics bins before stations connected. | ||
95 | */ | ||
96 | |||
97 | static ssize_t sta_tx_latency_stat_write(struct file *file, | ||
98 | const char __user *userbuf, | ||
99 | size_t count, loff_t *ppos) | ||
100 | { | ||
101 | struct ieee80211_local *local = file->private_data; | ||
102 | char buf[128] = {}; | ||
103 | char *bins = buf; | ||
104 | char *token; | ||
105 | int buf_size, i, alloc_size; | ||
106 | int prev_bin = 0; | ||
107 | int n_ranges = 0; | ||
108 | int ret = count; | ||
109 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
110 | |||
111 | if (sizeof(buf) <= count) | ||
112 | return -EINVAL; | ||
113 | buf_size = count; | ||
114 | if (copy_from_user(buf, userbuf, buf_size)) | ||
115 | return -EFAULT; | ||
116 | |||
117 | mutex_lock(&local->sta_mtx); | ||
118 | |||
119 | /* cannot change config once we have stations */ | ||
120 | if (local->num_sta) | ||
121 | goto unlock; | ||
122 | |||
123 | tx_latency = | ||
124 | rcu_dereference_protected(local->tx_latency, | ||
125 | lockdep_is_held(&local->sta_mtx)); | ||
126 | |||
127 | /* disable Tx statistics */ | ||
128 | if (!strcmp(buf, TX_LATENCY_DISABLED)) { | ||
129 | if (!tx_latency) | ||
130 | goto unlock; | ||
131 | rcu_assign_pointer(local->tx_latency, NULL); | ||
132 | synchronize_rcu(); | ||
133 | kfree(tx_latency); | ||
134 | goto unlock; | ||
135 | } | ||
136 | |||
137 | /* Tx latency already enabled */ | ||
138 | if (tx_latency) | ||
139 | goto unlock; | ||
140 | |||
141 | if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) { | ||
142 | /* check how many bins and between what ranges user requested */ | ||
143 | token = buf; | ||
144 | while (*token != '\0') { | ||
145 | if (*token == TX_LATENCY_BIN_DELIMTER_C) | ||
146 | n_ranges++; | ||
147 | token++; | ||
148 | } | ||
149 | n_ranges++; | ||
150 | } | ||
151 | |||
152 | alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) + | ||
153 | n_ranges * sizeof(u32); | ||
154 | tx_latency = kzalloc(alloc_size, GFP_ATOMIC); | ||
155 | if (!tx_latency) { | ||
156 | ret = -ENOMEM; | ||
157 | goto unlock; | ||
158 | } | ||
159 | tx_latency->n_ranges = n_ranges; | ||
160 | for (i = 0; i < n_ranges; i++) { /* setting bin ranges */ | ||
161 | token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S); | ||
162 | sscanf(token, "%d", &tx_latency->ranges[i]); | ||
163 | /* bins values should be in ascending order */ | ||
164 | if (prev_bin >= tx_latency->ranges[i]) { | ||
165 | ret = -EINVAL; | ||
166 | kfree(tx_latency); | ||
167 | goto unlock; | ||
168 | } | ||
169 | prev_bin = tx_latency->ranges[i]; | ||
170 | } | ||
171 | rcu_assign_pointer(local->tx_latency, tx_latency); | ||
172 | |||
173 | unlock: | ||
174 | mutex_unlock(&local->sta_mtx); | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static const struct file_operations stats_tx_latency_ops = { | ||
180 | .write = sta_tx_latency_stat_write, | ||
181 | .read = sta_tx_latency_stat_read, | ||
182 | .open = simple_open, | ||
183 | .llseek = generic_file_llseek, | ||
184 | }; | ||
185 | |||
20 | int mac80211_format_buffer(char __user *userbuf, size_t count, | 186 | int mac80211_format_buffer(char __user *userbuf, size_t count, |
21 | loff_t *ppos, char *fmt, ...) | 187 | loff_t *ppos, char *fmt, ...) |
22 | { | 188 | { |
@@ -315,4 +481,6 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
315 | DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); | 481 | DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); |
316 | DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); | 482 | DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); |
317 | DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); | 483 | DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); |
484 | |||
485 | DEBUGFS_DEVSTATS_ADD(tx_latency); | ||
318 | } | 486 | } |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 19c54a44ed47..80194b557a0c 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -38,6 +38,13 @@ static const struct file_operations sta_ ##name## _ops = { \ | |||
38 | .llseek = generic_file_llseek, \ | 38 | .llseek = generic_file_llseek, \ |
39 | } | 39 | } |
40 | 40 | ||
41 | #define STA_OPS_W(name) \ | ||
42 | static const struct file_operations sta_ ##name## _ops = { \ | ||
43 | .write = sta_##name##_write, \ | ||
44 | .open = simple_open, \ | ||
45 | .llseek = generic_file_llseek, \ | ||
46 | } | ||
47 | |||
41 | #define STA_OPS_RW(name) \ | 48 | #define STA_OPS_RW(name) \ |
42 | static const struct file_operations sta_ ##name## _ops = { \ | 49 | static const struct file_operations sta_ ##name## _ops = { \ |
43 | .read = sta_##name##_read, \ | 50 | .read = sta_##name##_read, \ |
@@ -388,6 +395,131 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf, | |||
388 | } | 395 | } |
389 | STA_OPS(last_rx_rate); | 396 | STA_OPS(last_rx_rate); |
390 | 397 | ||
398 | static int | ||
399 | sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency, | ||
400 | char *buf, int pos, int bufsz) | ||
401 | { | ||
402 | int i; | ||
403 | int range_count = tx_latency->n_ranges; | ||
404 | u32 *bin_ranges = tx_latency->ranges; | ||
405 | |||
406 | pos += scnprintf(buf + pos, bufsz - pos, | ||
407 | "Station\t\t\tTID\tMax\tAvg"); | ||
408 | if (range_count) { | ||
409 | pos += scnprintf(buf + pos, bufsz - pos, | ||
410 | "\t<=%d", bin_ranges[0]); | ||
411 | for (i = 0; i < range_count - 1; i++) | ||
412 | pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d", | ||
413 | bin_ranges[i], bin_ranges[i+1]); | ||
414 | pos += scnprintf(buf + pos, bufsz - pos, | ||
415 | "\t%d<", bin_ranges[range_count - 1]); | ||
416 | } | ||
417 | |||
418 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
419 | |||
420 | return pos; | ||
421 | } | ||
422 | |||
423 | static int | ||
424 | sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range, | ||
425 | struct ieee80211_tx_latency_stat *tx_lat, | ||
426 | char *buf, int pos, int bufsz, int tid) | ||
427 | { | ||
428 | u32 avg = 0; | ||
429 | int j; | ||
430 | int bin_count = tx_lat->bin_count; | ||
431 | |||
432 | pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid); | ||
433 | /* make sure you don't divide in 0 */ | ||
434 | if (tx_lat->counter) | ||
435 | avg = tx_lat->sum / tx_lat->counter; | ||
436 | |||
437 | pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d", | ||
438 | tx_lat->max, avg); | ||
439 | |||
440 | if (tx_lat_range->n_ranges && tx_lat->bins) | ||
441 | for (j = 0; j < bin_count; j++) | ||
442 | pos += scnprintf(buf + pos, bufsz - pos, | ||
443 | "\t%d", tx_lat->bins[j]); | ||
444 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | ||
445 | |||
446 | return pos; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * Output Tx latency statistics station && restart all statistics information | ||
451 | */ | ||
452 | static ssize_t sta_tx_latency_stat_read(struct file *file, | ||
453 | char __user *userbuf, | ||
454 | size_t count, loff_t *ppos) | ||
455 | { | ||
456 | struct sta_info *sta = file->private_data; | ||
457 | struct ieee80211_local *local = sta->local; | ||
458 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
459 | char *buf; | ||
460 | int bufsz, ret, i; | ||
461 | int pos = 0; | ||
462 | |||
463 | bufsz = 20 * IEEE80211_NUM_TIDS * | ||
464 | sizeof(struct ieee80211_tx_latency_stat); | ||
465 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
466 | if (!buf) | ||
467 | return -ENOMEM; | ||
468 | |||
469 | rcu_read_lock(); | ||
470 | |||
471 | tx_latency = rcu_dereference(local->tx_latency); | ||
472 | |||
473 | if (!sta->tx_lat) { | ||
474 | pos += scnprintf(buf + pos, bufsz - pos, | ||
475 | "Tx latency statistics are not enabled\n"); | ||
476 | goto unlock; | ||
477 | } | ||
478 | |||
479 | pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz); | ||
480 | |||
481 | pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr); | ||
482 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | ||
483 | pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i], | ||
484 | buf, pos, bufsz, i); | ||
485 | unlock: | ||
486 | rcu_read_unlock(); | ||
487 | |||
488 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
489 | kfree(buf); | ||
490 | |||
491 | return ret; | ||
492 | } | ||
493 | STA_OPS(tx_latency_stat); | ||
494 | |||
495 | static ssize_t sta_tx_latency_stat_reset_write(struct file *file, | ||
496 | const char __user *userbuf, | ||
497 | size_t count, loff_t *ppos) | ||
498 | { | ||
499 | u32 *bins; | ||
500 | int bin_count; | ||
501 | struct sta_info *sta = file->private_data; | ||
502 | int i; | ||
503 | |||
504 | if (!sta->tx_lat) | ||
505 | return -EINVAL; | ||
506 | |||
507 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | ||
508 | bins = sta->tx_lat[i].bins; | ||
509 | bin_count = sta->tx_lat[i].bin_count; | ||
510 | |||
511 | sta->tx_lat[i].max = 0; | ||
512 | sta->tx_lat[i].sum = 0; | ||
513 | sta->tx_lat[i].counter = 0; | ||
514 | |||
515 | if (bin_count) | ||
516 | memset(bins, 0, bin_count * sizeof(u32)); | ||
517 | } | ||
518 | |||
519 | return count; | ||
520 | } | ||
521 | STA_OPS_W(tx_latency_stat_reset); | ||
522 | |||
391 | #define DEBUGFS_ADD(name) \ | 523 | #define DEBUGFS_ADD(name) \ |
392 | debugfs_create_file(#name, 0400, \ | 524 | debugfs_create_file(#name, 0400, \ |
393 | sta->debugfs.dir, sta, &sta_ ##name## _ops); | 525 | sta->debugfs.dir, sta, &sta_ ##name## _ops); |
@@ -441,6 +573,8 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
441 | DEBUGFS_ADD(last_ack_signal); | 573 | DEBUGFS_ADD(last_ack_signal); |
442 | DEBUGFS_ADD(current_tx_rate); | 574 | DEBUGFS_ADD(current_tx_rate); |
443 | DEBUGFS_ADD(last_rx_rate); | 575 | DEBUGFS_ADD(last_rx_rate); |
576 | DEBUGFS_ADD(tx_latency_stat); | ||
577 | DEBUGFS_ADD(tx_latency_stat_reset); | ||
444 | 578 | ||
445 | DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); | 579 | DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); |
446 | DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); | 580 | DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 531be040b9ae..0f1fb5db4bdb 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -550,12 +550,12 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
550 | capability); | 550 | capability); |
551 | /* XXX: should not really modify cfg80211 data */ | 551 | /* XXX: should not really modify cfg80211 data */ |
552 | if (cbss) { | 552 | if (cbss) { |
553 | cbss->channel = sdata->local->csa_chandef.chan; | 553 | cbss->channel = sdata->csa_chandef.chan; |
554 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | 554 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); |
555 | } | 555 | } |
556 | } | 556 | } |
557 | 557 | ||
558 | ifibss->chandef = sdata->local->csa_chandef; | 558 | ifibss->chandef = sdata->csa_chandef; |
559 | 559 | ||
560 | /* generate the beacon */ | 560 | /* generate the beacon */ |
561 | err = ieee80211_ibss_csa_beacon(sdata, NULL); | 561 | err = ieee80211_ibss_csa_beacon(sdata, NULL); |
@@ -922,7 +922,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
922 | IEEE80211_MAX_QUEUE_MAP, | 922 | IEEE80211_MAX_QUEUE_MAP, |
923 | IEEE80211_QUEUE_STOP_REASON_CSA); | 923 | IEEE80211_QUEUE_STOP_REASON_CSA); |
924 | 924 | ||
925 | sdata->local->csa_chandef = params.chandef; | 925 | sdata->csa_chandef = params.chandef; |
926 | sdata->vif.csa_active = true; | 926 | sdata->vif.csa_active = true; |
927 | 927 | ||
928 | ieee80211_bss_info_change_notify(sdata, err); | 928 | ieee80211_bss_info_change_notify(sdata, err); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 29dc505be125..32bae218d6e5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -728,6 +728,7 @@ struct ieee80211_sub_if_data { | |||
728 | u16 sequence_number; | 728 | u16 sequence_number; |
729 | __be16 control_port_protocol; | 729 | __be16 control_port_protocol; |
730 | bool control_port_no_encrypt; | 730 | bool control_port_no_encrypt; |
731 | int encrypt_headroom; | ||
731 | 732 | ||
732 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; | 733 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; |
733 | 734 | ||
@@ -735,6 +736,7 @@ struct ieee80211_sub_if_data { | |||
735 | int csa_counter_offset_beacon; | 736 | int csa_counter_offset_beacon; |
736 | int csa_counter_offset_presp; | 737 | int csa_counter_offset_presp; |
737 | bool csa_radar_required; | 738 | bool csa_radar_required; |
739 | struct cfg80211_chan_def csa_chandef; | ||
738 | 740 | ||
739 | /* used to reconfigure hardware SM PS */ | 741 | /* used to reconfigure hardware SM PS */ |
740 | struct work_struct recalc_smps; | 742 | struct work_struct recalc_smps; |
@@ -811,6 +813,9 @@ static inline void sdata_unlock(struct ieee80211_sub_if_data *sdata) | |||
811 | __release(&sdata->wdev.mtx); | 813 | __release(&sdata->wdev.mtx); |
812 | } | 814 | } |
813 | 815 | ||
816 | #define sdata_dereference(p, sdata) \ | ||
817 | rcu_dereference_protected(p, lockdep_is_held(&sdata->wdev.mtx)) | ||
818 | |||
814 | static inline void | 819 | static inline void |
815 | sdata_assert_lock(struct ieee80211_sub_if_data *sdata) | 820 | sdata_assert_lock(struct ieee80211_sub_if_data *sdata) |
816 | { | 821 | { |
@@ -896,6 +901,24 @@ struct tpt_led_trigger { | |||
896 | }; | 901 | }; |
897 | #endif | 902 | #endif |
898 | 903 | ||
904 | /* | ||
905 | * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges | ||
906 | * | ||
907 | * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a | ||
908 | * certain latency range (in Milliseconds). Each station that uses these | ||
909 | * ranges will have bins to count the amount of frames received in that range. | ||
910 | * The user can configure the ranges via debugfs. | ||
911 | * If ranges is NULL then Tx latency statistics bins are disabled for all | ||
912 | * stations. | ||
913 | * | ||
914 | * @n_ranges: number of ranges that are taken in account | ||
915 | * @ranges: the ranges that the user requested or NULL if disabled. | ||
916 | */ | ||
917 | struct ieee80211_tx_latency_bin_ranges { | ||
918 | int n_ranges; | ||
919 | u32 ranges[]; | ||
920 | }; | ||
921 | |||
899 | /** | 922 | /** |
900 | * mac80211 scan flags - currently active scan mode | 923 | * mac80211 scan flags - currently active scan mode |
901 | * | 924 | * |
@@ -1048,6 +1071,12 @@ struct ieee80211_local { | |||
1048 | struct timer_list sta_cleanup; | 1071 | struct timer_list sta_cleanup; |
1049 | int sta_generation; | 1072 | int sta_generation; |
1050 | 1073 | ||
1074 | /* | ||
1075 | * Tx latency statistics parameters for all stations. | ||
1076 | * Can enable via debugfs (NULL when disabled). | ||
1077 | */ | ||
1078 | struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency; | ||
1079 | |||
1051 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 1080 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
1052 | struct tasklet_struct tx_pending_tasklet; | 1081 | struct tasklet_struct tx_pending_tasklet; |
1053 | 1082 | ||
@@ -1093,7 +1122,6 @@ struct ieee80211_local { | |||
1093 | enum mac80211_scan_state next_scan_state; | 1122 | enum mac80211_scan_state next_scan_state; |
1094 | struct delayed_work scan_work; | 1123 | struct delayed_work scan_work; |
1095 | struct ieee80211_sub_if_data __rcu *scan_sdata; | 1124 | struct ieee80211_sub_if_data __rcu *scan_sdata; |
1096 | struct cfg80211_chan_def csa_chandef; | ||
1097 | /* For backward compatibility only -- do not use */ | 1125 | /* For backward compatibility only -- do not use */ |
1098 | struct cfg80211_chan_def _oper_chandef; | 1126 | struct cfg80211_chan_def _oper_chandef; |
1099 | 1127 | ||
@@ -1692,6 +1720,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, | |||
1692 | int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, | 1720 | int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, |
1693 | enum ieee80211_smps_mode smps_mode); | 1721 | enum ieee80211_smps_mode smps_mode); |
1694 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); | 1722 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); |
1723 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); | ||
1695 | 1724 | ||
1696 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1725 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, |
1697 | const u8 *ids, int n_ids, size_t offset); | 1726 | const u8 *ids, int n_ids, size_t offset); |
@@ -1730,7 +1759,6 @@ ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
1730 | /* NOTE: only use ieee80211_vif_change_channel() for channel switch */ | 1759 | /* NOTE: only use ieee80211_vif_change_channel() for channel switch */ |
1731 | int __must_check | 1760 | int __must_check |
1732 | ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | 1761 | ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, |
1733 | const struct cfg80211_chan_def *chandef, | ||
1734 | u32 *changed); | 1762 | u32 *changed); |
1735 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1763 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
1736 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1764 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
@@ -1741,6 +1769,8 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | |||
1741 | struct ieee80211_chanctx *chanctx); | 1769 | struct ieee80211_chanctx *chanctx); |
1742 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | 1770 | void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, |
1743 | struct ieee80211_chanctx *chanctx); | 1771 | struct ieee80211_chanctx *chanctx); |
1772 | void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, | ||
1773 | struct ieee80211_chanctx *ctx); | ||
1744 | 1774 | ||
1745 | void ieee80211_dfs_cac_timer(unsigned long data); | 1775 | void ieee80211_dfs_cac_timer(unsigned long data); |
1746 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); | 1776 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); |
@@ -1749,6 +1779,15 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work); | |||
1749 | int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | 1779 | int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, |
1750 | struct cfg80211_csa_settings *csa_settings); | 1780 | struct cfg80211_csa_settings *csa_settings); |
1751 | 1781 | ||
1782 | bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs); | ||
1783 | bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n); | ||
1784 | const struct ieee80211_cipher_scheme * | ||
1785 | ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, | ||
1786 | enum nl80211_iftype iftype); | ||
1787 | int ieee80211_cs_headroom(struct ieee80211_local *local, | ||
1788 | struct cfg80211_crypto_settings *crypto, | ||
1789 | enum nl80211_iftype iftype); | ||
1790 | |||
1752 | #ifdef CONFIG_MAC80211_NOINLINE | 1791 | #ifdef CONFIG_MAC80211_NOINLINE |
1753 | #define debug_noinline noinline | 1792 | #define debug_noinline noinline |
1754 | #else | 1793 | #else |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ff101ea1d9ae..d226751ba63a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
401 | snprintf(sdata->name, IFNAMSIZ, "%s-monitor", | 401 | snprintf(sdata->name, IFNAMSIZ, "%s-monitor", |
402 | wiphy_name(local->hw.wiphy)); | 402 | wiphy_name(local->hw.wiphy)); |
403 | 403 | ||
404 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
405 | |||
404 | ieee80211_set_default_queues(sdata); | 406 | ieee80211_set_default_queues(sdata); |
405 | 407 | ||
406 | ret = drv_add_interface(local, sdata); | 408 | ret = drv_add_interface(local, sdata); |
@@ -749,6 +751,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
749 | u32 hw_reconf_flags = 0; | 751 | u32 hw_reconf_flags = 0; |
750 | int i, flushed; | 752 | int i, flushed; |
751 | struct ps_data *ps; | 753 | struct ps_data *ps; |
754 | struct cfg80211_chan_def chandef; | ||
752 | 755 | ||
753 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 756 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
754 | 757 | ||
@@ -823,11 +826,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
823 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 826 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); |
824 | 827 | ||
825 | if (sdata->wdev.cac_started) { | 828 | if (sdata->wdev.cac_started) { |
829 | chandef = sdata->vif.bss_conf.chandef; | ||
826 | WARN_ON(local->suspended); | 830 | WARN_ON(local->suspended); |
827 | mutex_lock(&local->iflist_mtx); | 831 | mutex_lock(&local->iflist_mtx); |
828 | ieee80211_vif_release_channel(sdata); | 832 | ieee80211_vif_release_channel(sdata); |
829 | mutex_unlock(&local->iflist_mtx); | 833 | mutex_unlock(&local->iflist_mtx); |
830 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED, | 834 | cfg80211_cac_event(sdata->dev, &chandef, |
835 | NL80211_RADAR_CAC_ABORTED, | ||
831 | GFP_KERNEL); | 836 | GFP_KERNEL); |
832 | } | 837 | } |
833 | 838 | ||
@@ -1036,7 +1041,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
1036 | */ | 1041 | */ |
1037 | static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | 1042 | static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) |
1038 | { | 1043 | { |
1039 | int flushed; | ||
1040 | int i; | 1044 | int i; |
1041 | 1045 | ||
1042 | /* free extra data */ | 1046 | /* free extra data */ |
@@ -1050,9 +1054,6 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) | |||
1050 | 1054 | ||
1051 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 1055 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
1052 | mesh_rmc_free(sdata); | 1056 | mesh_rmc_free(sdata); |
1053 | |||
1054 | flushed = sta_info_flush(sdata); | ||
1055 | WARN_ON(flushed); | ||
1056 | } | 1057 | } |
1057 | 1058 | ||
1058 | static void ieee80211_uninit(struct net_device *dev) | 1059 | static void ieee80211_uninit(struct net_device *dev) |
@@ -1270,6 +1271,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1270 | 1271 | ||
1271 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); | 1272 | sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); |
1272 | sdata->control_port_no_encrypt = false; | 1273 | sdata->control_port_no_encrypt = false; |
1274 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
1273 | 1275 | ||
1274 | sdata->noack_map = 0; | 1276 | sdata->noack_map = 0; |
1275 | 1277 | ||
@@ -1686,6 +1688,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1686 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | 1688 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
1687 | sdata->user_power_level = local->user_power_level; | 1689 | sdata->user_power_level = local->user_power_level; |
1688 | 1690 | ||
1691 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
1692 | |||
1689 | /* setup type-dependent data */ | 1693 | /* setup type-dependent data */ |
1690 | ieee80211_setup_sdata(sdata, type); | 1694 | ieee80211_setup_sdata(sdata, type); |
1691 | 1695 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 3e51dd7d98b3..e568d98167d0 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -260,25 +260,29 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
260 | int idx; | 260 | int idx; |
261 | bool defunikey, defmultikey, defmgmtkey; | 261 | bool defunikey, defmultikey, defmgmtkey; |
262 | 262 | ||
263 | /* caller must provide at least one old/new */ | ||
264 | if (WARN_ON(!new && !old)) | ||
265 | return; | ||
266 | |||
263 | if (new) | 267 | if (new) |
264 | list_add_tail(&new->list, &sdata->key_list); | 268 | list_add_tail(&new->list, &sdata->key_list); |
265 | 269 | ||
266 | if (sta && pairwise) { | 270 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); |
267 | rcu_assign_pointer(sta->ptk, new); | ||
268 | } else if (sta) { | ||
269 | if (old) | ||
270 | idx = old->conf.keyidx; | ||
271 | else | ||
272 | idx = new->conf.keyidx; | ||
273 | rcu_assign_pointer(sta->gtk[idx], new); | ||
274 | } else { | ||
275 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | ||
276 | 271 | ||
277 | if (old) | 272 | if (old) |
278 | idx = old->conf.keyidx; | 273 | idx = old->conf.keyidx; |
279 | else | 274 | else |
280 | idx = new->conf.keyidx; | 275 | idx = new->conf.keyidx; |
281 | 276 | ||
277 | if (sta) { | ||
278 | if (pairwise) { | ||
279 | rcu_assign_pointer(sta->ptk[idx], new); | ||
280 | sta->ptk_idx = idx; | ||
281 | } else { | ||
282 | rcu_assign_pointer(sta->gtk[idx], new); | ||
283 | sta->gtk_idx = idx; | ||
284 | } | ||
285 | } else { | ||
282 | defunikey = old && | 286 | defunikey = old && |
283 | old == key_mtx_dereference(sdata->local, | 287 | old == key_mtx_dereference(sdata->local, |
284 | sdata->default_unicast_key); | 288 | sdata->default_unicast_key); |
@@ -312,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
312 | list_del(&old->list); | 316 | list_del(&old->list); |
313 | } | 317 | } |
314 | 318 | ||
315 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 319 | struct ieee80211_key * |
316 | const u8 *key_data, | 320 | ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
317 | size_t seq_len, const u8 *seq) | 321 | const u8 *key_data, |
322 | size_t seq_len, const u8 *seq, | ||
323 | const struct ieee80211_cipher_scheme *cs) | ||
318 | { | 324 | { |
319 | struct ieee80211_key *key; | 325 | struct ieee80211_key *key; |
320 | int i, j, err; | 326 | int i, j, err; |
@@ -393,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
393 | return ERR_PTR(err); | 399 | return ERR_PTR(err); |
394 | } | 400 | } |
395 | break; | 401 | break; |
402 | default: | ||
403 | if (cs) { | ||
404 | size_t len = (seq_len > MAX_PN_LEN) ? | ||
405 | MAX_PN_LEN : seq_len; | ||
406 | |||
407 | key->conf.iv_len = cs->hdr_len; | ||
408 | key->conf.icv_len = cs->mic_len; | ||
409 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) | ||
410 | for (j = 0; j < len; j++) | ||
411 | key->u.gen.rx_pn[i][j] = | ||
412 | seq[len - j - 1]; | ||
413 | } | ||
396 | } | 414 | } |
397 | memcpy(key->conf.key, key_data, key_len); | 415 | memcpy(key->conf.key, key_data, key_len); |
398 | INIT_LIST_HEAD(&key->list); | 416 | INIT_LIST_HEAD(&key->list); |
@@ -475,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
475 | mutex_lock(&sdata->local->key_mtx); | 493 | mutex_lock(&sdata->local->key_mtx); |
476 | 494 | ||
477 | if (sta && pairwise) | 495 | if (sta && pairwise) |
478 | old_key = key_mtx_dereference(sdata->local, sta->ptk); | 496 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); |
479 | else if (sta) | 497 | else if (sta) |
480 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); | 498 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
481 | else | 499 | else |
@@ -625,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, | |||
625 | list_add(&key->list, &keys); | 643 | list_add(&key->list, &keys); |
626 | } | 644 | } |
627 | 645 | ||
628 | key = key_mtx_dereference(local, sta->ptk); | 646 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) { |
629 | if (key) { | 647 | key = key_mtx_dereference(local, sta->ptk[i]); |
648 | if (!key) | ||
649 | continue; | ||
630 | ieee80211_key_replace(key->sdata, key->sta, | 650 | ieee80211_key_replace(key->sdata, key->sta, |
631 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 651 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
632 | key, NULL); | 652 | key, NULL); |
@@ -877,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, | |||
877 | 897 | ||
878 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, | 898 | key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, |
879 | keyconf->keylen, keyconf->key, | 899 | keyconf->keylen, keyconf->key, |
880 | 0, NULL); | 900 | 0, NULL, NULL); |
881 | if (IS_ERR(key)) | 901 | if (IS_ERR(key)) |
882 | return ERR_CAST(key); | 902 | return ERR_CAST(key); |
883 | 903 | ||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index aaae0ed37004..0aebb889caba 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #define NUM_DEFAULT_KEYS 4 | 19 | #define NUM_DEFAULT_KEYS 4 |
20 | #define NUM_DEFAULT_MGMT_KEYS 2 | 20 | #define NUM_DEFAULT_MGMT_KEYS 2 |
21 | #define MAX_PN_LEN 16 | ||
21 | 22 | ||
22 | struct ieee80211_local; | 23 | struct ieee80211_local; |
23 | struct ieee80211_sub_if_data; | 24 | struct ieee80211_sub_if_data; |
@@ -93,6 +94,10 @@ struct ieee80211_key { | |||
93 | u32 replays; /* dot11RSNAStatsCMACReplays */ | 94 | u32 replays; /* dot11RSNAStatsCMACReplays */ |
94 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ | 95 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ |
95 | } aes_cmac; | 96 | } aes_cmac; |
97 | struct { | ||
98 | /* generic cipher scheme */ | ||
99 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN]; | ||
100 | } gen; | ||
96 | } u; | 101 | } u; |
97 | 102 | ||
98 | /* number of times this key has been used */ | 103 | /* number of times this key has been used */ |
@@ -113,9 +118,11 @@ struct ieee80211_key { | |||
113 | struct ieee80211_key_conf conf; | 118 | struct ieee80211_key_conf conf; |
114 | }; | 119 | }; |
115 | 120 | ||
116 | struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | 121 | struct ieee80211_key * |
117 | const u8 *key_data, | 122 | ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, |
118 | size_t seq_len, const u8 *seq); | 123 | const u8 *key_data, |
124 | size_t seq_len, const u8 *seq, | ||
125 | const struct ieee80211_cipher_scheme *cs); | ||
119 | /* | 126 | /* |
120 | * Insert a key into data structures (sdata, sta if necessary) | 127 | * Insert a key into data structures (sdata, sta if necessary) |
121 | * to make it used, free old key. On failure, also free the new key. | 128 | * to make it used, free old key. On failure, also free the new key. |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 21d5d44444d0..8af75f0eed6d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
651 | } | 651 | } |
652 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 652 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
653 | 653 | ||
654 | int ieee80211_register_hw(struct ieee80211_hw *hw) | 654 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) |
655 | { | 655 | { |
656 | struct ieee80211_local *local = hw_to_local(hw); | 656 | bool have_wep = !(IS_ERR(local->wep_tx_tfm) || |
657 | int result, i; | 657 | IS_ERR(local->wep_rx_tfm)); |
658 | enum ieee80211_band band; | 658 | bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE; |
659 | int channels, max_bitrates; | 659 | const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes; |
660 | bool supp_ht, supp_vht; | 660 | int n_suites = 0, r = 0, w = 0; |
661 | netdev_features_t feature_whitelist; | 661 | u32 *suites; |
662 | struct cfg80211_chan_def dflt_chandef = {}; | ||
663 | static const u32 cipher_suites[] = { | 662 | static const u32 cipher_suites[] = { |
664 | /* keep WEP first, it may be removed below */ | 663 | /* keep WEP first, it may be removed below */ |
665 | WLAN_CIPHER_SUITE_WEP40, | 664 | WLAN_CIPHER_SUITE_WEP40, |
@@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
671 | WLAN_CIPHER_SUITE_AES_CMAC | 670 | WLAN_CIPHER_SUITE_AES_CMAC |
672 | }; | 671 | }; |
673 | 672 | ||
673 | /* Driver specifies the ciphers, we have nothing to do... */ | ||
674 | if (local->hw.wiphy->cipher_suites && have_wep) | ||
675 | return 0; | ||
676 | |||
677 | /* Set up cipher suites if driver relies on mac80211 cipher defs */ | ||
678 | if (!local->hw.wiphy->cipher_suites && !cs) { | ||
679 | local->hw.wiphy->cipher_suites = cipher_suites; | ||
680 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
681 | |||
682 | if (!have_mfp) | ||
683 | local->hw.wiphy->n_cipher_suites--; | ||
684 | |||
685 | if (!have_wep) { | ||
686 | local->hw.wiphy->cipher_suites += 2; | ||
687 | local->hw.wiphy->n_cipher_suites -= 2; | ||
688 | } | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | if (!local->hw.wiphy->cipher_suites) { | ||
694 | /* | ||
695 | * Driver specifies cipher schemes only | ||
696 | * We start counting ciphers defined by schemes, TKIP and CCMP | ||
697 | */ | ||
698 | n_suites = local->hw.n_cipher_schemes + 2; | ||
699 | |||
700 | /* check if we have WEP40 and WEP104 */ | ||
701 | if (have_wep) | ||
702 | n_suites += 2; | ||
703 | |||
704 | /* check if we have AES_CMAC */ | ||
705 | if (have_mfp) | ||
706 | n_suites++; | ||
707 | |||
708 | suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL); | ||
709 | if (!suites) | ||
710 | return -ENOMEM; | ||
711 | |||
712 | suites[w++] = WLAN_CIPHER_SUITE_CCMP; | ||
713 | suites[w++] = WLAN_CIPHER_SUITE_TKIP; | ||
714 | |||
715 | if (have_wep) { | ||
716 | suites[w++] = WLAN_CIPHER_SUITE_WEP40; | ||
717 | suites[w++] = WLAN_CIPHER_SUITE_WEP104; | ||
718 | } | ||
719 | |||
720 | if (have_mfp) | ||
721 | suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC; | ||
722 | |||
723 | for (r = 0; r < local->hw.n_cipher_schemes; r++) | ||
724 | suites[w++] = cs[r].cipher; | ||
725 | } else { | ||
726 | /* Driver provides cipher suites, but we need to exclude WEP */ | ||
727 | suites = kmemdup(local->hw.wiphy->cipher_suites, | ||
728 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
729 | GFP_KERNEL); | ||
730 | if (!suites) | ||
731 | return -ENOMEM; | ||
732 | |||
733 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
734 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
735 | |||
736 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
737 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
738 | continue; | ||
739 | suites[w++] = suite; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | local->hw.wiphy->cipher_suites = suites; | ||
744 | local->hw.wiphy->n_cipher_suites = w; | ||
745 | local->wiphy_ciphers_allocated = true; | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | int ieee80211_register_hw(struct ieee80211_hw *hw) | ||
751 | { | ||
752 | struct ieee80211_local *local = hw_to_local(hw); | ||
753 | int result, i; | ||
754 | enum ieee80211_band band; | ||
755 | int channels, max_bitrates; | ||
756 | bool supp_ht, supp_vht; | ||
757 | netdev_features_t feature_whitelist; | ||
758 | struct cfg80211_chan_def dflt_chandef = {}; | ||
759 | |||
674 | if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && | 760 | if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && |
675 | (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || | 761 | (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || |
676 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 762 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
@@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
851 | if (local->hw.wiphy->max_scan_ie_len) | 937 | if (local->hw.wiphy->max_scan_ie_len) |
852 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; | 938 | local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; |
853 | 939 | ||
854 | /* Set up cipher suites unless driver already did */ | 940 | WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes, |
855 | if (!local->hw.wiphy->cipher_suites) { | 941 | local->hw.n_cipher_schemes)); |
856 | local->hw.wiphy->cipher_suites = cipher_suites; | 942 | |
857 | local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 943 | result = ieee80211_init_cipher_suites(local); |
858 | if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) | 944 | if (result < 0) |
859 | local->hw.wiphy->n_cipher_suites--; | 945 | goto fail_wiphy_register; |
860 | } | ||
861 | if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) { | ||
862 | if (local->hw.wiphy->cipher_suites == cipher_suites) { | ||
863 | local->hw.wiphy->cipher_suites += 2; | ||
864 | local->hw.wiphy->n_cipher_suites -= 2; | ||
865 | } else { | ||
866 | u32 *suites; | ||
867 | int r, w = 0; | ||
868 | |||
869 | /* Filter out WEP */ | ||
870 | |||
871 | suites = kmemdup( | ||
872 | local->hw.wiphy->cipher_suites, | ||
873 | sizeof(u32) * local->hw.wiphy->n_cipher_suites, | ||
874 | GFP_KERNEL); | ||
875 | if (!suites) { | ||
876 | result = -ENOMEM; | ||
877 | goto fail_wiphy_register; | ||
878 | } | ||
879 | for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) { | ||
880 | u32 suite = local->hw.wiphy->cipher_suites[r]; | ||
881 | if (suite == WLAN_CIPHER_SUITE_WEP40 || | ||
882 | suite == WLAN_CIPHER_SUITE_WEP104) | ||
883 | continue; | ||
884 | suites[w++] = suite; | ||
885 | } | ||
886 | local->hw.wiphy->cipher_suites = suites; | ||
887 | local->hw.wiphy->n_cipher_suites = w; | ||
888 | local->wiphy_ciphers_allocated = true; | ||
889 | } | ||
890 | } | ||
891 | 946 | ||
892 | if (!local->ops->remain_on_channel) | 947 | if (!local->ops->remain_on_channel) |
893 | local->hw.wiphy->max_remain_on_channel_duration = 5000; | 948 | local->hw.wiphy->max_remain_on_channel_duration = 5000; |
@@ -1087,6 +1142,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
1087 | ieee80211_free_ack_frame, NULL); | 1142 | ieee80211_free_ack_frame, NULL); |
1088 | idr_destroy(&local->ack_status_frames); | 1143 | idr_destroy(&local->ack_status_frames); |
1089 | 1144 | ||
1145 | kfree(rcu_access_pointer(local->tx_latency)); | ||
1146 | |||
1090 | wiphy_free(local->hw.wiphy); | 1147 | wiphy_free(local->hw.wiphy); |
1091 | } | 1148 | } |
1092 | EXPORT_SYMBOL(ieee80211_free_hw); | 1149 | EXPORT_SYMBOL(ieee80211_free_hw); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 896fe3bd599e..330d1f71c0c9 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -674,8 +674,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
674 | rcu_read_lock(); | 674 | rcu_read_lock(); |
675 | csa = rcu_dereference(ifmsh->csa); | 675 | csa = rcu_dereference(ifmsh->csa); |
676 | if (csa) { | 676 | if (csa) { |
677 | __le16 pre_value; | ||
678 | |||
679 | pos = skb_put(skb, 13); | 677 | pos = skb_put(skb, 13); |
680 | memset(pos, 0, 13); | 678 | memset(pos, 0, 13); |
681 | *pos++ = WLAN_EID_CHANNEL_SWITCH; | 679 | *pos++ = WLAN_EID_CHANNEL_SWITCH; |
@@ -697,8 +695,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
697 | WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; | 695 | WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; |
698 | put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); | 696 | put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); |
699 | pos += 2; | 697 | pos += 2; |
700 | pre_value = cpu_to_le16(ifmsh->pre_value); | 698 | put_unaligned_le16(ifmsh->pre_value, pos); |
701 | memcpy(pos, &pre_value, 2); | ||
702 | pos += 2; | 699 | pos += 2; |
703 | } | 700 | } |
704 | rcu_read_unlock(); | 701 | rcu_read_unlock(); |
@@ -959,7 +956,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, | |||
959 | IEEE80211_MAX_QUEUE_MAP, | 956 | IEEE80211_MAX_QUEUE_MAP, |
960 | IEEE80211_QUEUE_STOP_REASON_CSA); | 957 | IEEE80211_QUEUE_STOP_REASON_CSA); |
961 | 958 | ||
962 | sdata->local->csa_chandef = params.chandef; | 959 | sdata->csa_chandef = params.chandef; |
963 | sdata->vif.csa_active = true; | 960 | sdata->vif.csa_active = true; |
964 | 961 | ||
965 | ieee80211_bss_info_change_notify(sdata, err); | 962 | ieee80211_bss_info_change_notify(sdata, err); |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2bc7fd2f787d..f39a19f9090f 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -215,8 +215,6 @@ int mesh_rmc_check(struct ieee80211_sub_if_data *sdata, | |||
215 | bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | 215 | bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, |
216 | struct ieee802_11_elems *ie); | 216 | struct ieee802_11_elems *ie); |
217 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); | 217 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); |
218 | void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata, | ||
219 | struct sk_buff *skb); | ||
220 | int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, | 218 | int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, |
221 | struct sk_buff *skb); | 219 | struct sk_buff *skb); |
222 | int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, | 220 | int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, |
@@ -303,8 +301,8 @@ void mesh_mpath_table_grow(void); | |||
303 | void mesh_mpp_table_grow(void); | 301 | void mesh_mpp_table_grow(void); |
304 | /* Mesh paths */ | 302 | /* Mesh paths */ |
305 | int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | 303 | int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, |
306 | u8 ttl, const u8 *target, __le32 target_sn, | 304 | u8 ttl, const u8 *target, u32 target_sn, |
307 | __le16 target_rcode, const u8 *ra); | 305 | u16 target_rcode, const u8 *ra); |
308 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | 306 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); |
309 | void mesh_path_flush_pending(struct mesh_path *mpath); | 307 | void mesh_path_flush_pending(struct mesh_path *mpath); |
310 | void mesh_path_tx_pending(struct mesh_path *mpath); | 308 | void mesh_path_tx_pending(struct mesh_path *mpath); |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 486819cd02cd..f9514685d45a 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -102,12 +102,11 @@ enum mpath_frame_type { | |||
102 | static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 102 | static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
103 | 103 | ||
104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | 104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, |
105 | const u8 *orig_addr, __le32 orig_sn, | 105 | const u8 *orig_addr, u32 orig_sn, |
106 | u8 target_flags, const u8 *target, | 106 | u8 target_flags, const u8 *target, |
107 | __le32 target_sn, const u8 *da, | 107 | u32 target_sn, const u8 *da, |
108 | u8 hop_count, u8 ttl, | 108 | u8 hop_count, u8 ttl, |
109 | __le32 lifetime, __le32 metric, | 109 | u32 lifetime, u32 metric, u32 preq_id, |
110 | __le32 preq_id, | ||
111 | struct ieee80211_sub_if_data *sdata) | 110 | struct ieee80211_sub_if_data *sdata) |
112 | { | 111 | { |
113 | struct ieee80211_local *local = sdata->local; | 112 | struct ieee80211_local *local = sdata->local; |
@@ -167,33 +166,33 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
167 | if (action == MPATH_PREP) { | 166 | if (action == MPATH_PREP) { |
168 | memcpy(pos, target, ETH_ALEN); | 167 | memcpy(pos, target, ETH_ALEN); |
169 | pos += ETH_ALEN; | 168 | pos += ETH_ALEN; |
170 | memcpy(pos, &target_sn, 4); | 169 | put_unaligned_le32(target_sn, pos); |
171 | pos += 4; | 170 | pos += 4; |
172 | } else { | 171 | } else { |
173 | if (action == MPATH_PREQ) { | 172 | if (action == MPATH_PREQ) { |
174 | memcpy(pos, &preq_id, 4); | 173 | put_unaligned_le32(preq_id, pos); |
175 | pos += 4; | 174 | pos += 4; |
176 | } | 175 | } |
177 | memcpy(pos, orig_addr, ETH_ALEN); | 176 | memcpy(pos, orig_addr, ETH_ALEN); |
178 | pos += ETH_ALEN; | 177 | pos += ETH_ALEN; |
179 | memcpy(pos, &orig_sn, 4); | 178 | put_unaligned_le32(orig_sn, pos); |
180 | pos += 4; | 179 | pos += 4; |
181 | } | 180 | } |
182 | memcpy(pos, &lifetime, 4); /* interval for RANN */ | 181 | put_unaligned_le32(lifetime, pos); /* interval for RANN */ |
183 | pos += 4; | 182 | pos += 4; |
184 | memcpy(pos, &metric, 4); | 183 | put_unaligned_le32(metric, pos); |
185 | pos += 4; | 184 | pos += 4; |
186 | if (action == MPATH_PREQ) { | 185 | if (action == MPATH_PREQ) { |
187 | *pos++ = 1; /* destination count */ | 186 | *pos++ = 1; /* destination count */ |
188 | *pos++ = target_flags; | 187 | *pos++ = target_flags; |
189 | memcpy(pos, target, ETH_ALEN); | 188 | memcpy(pos, target, ETH_ALEN); |
190 | pos += ETH_ALEN; | 189 | pos += ETH_ALEN; |
191 | memcpy(pos, &target_sn, 4); | 190 | put_unaligned_le32(target_sn, pos); |
192 | pos += 4; | 191 | pos += 4; |
193 | } else if (action == MPATH_PREP) { | 192 | } else if (action == MPATH_PREP) { |
194 | memcpy(pos, orig_addr, ETH_ALEN); | 193 | memcpy(pos, orig_addr, ETH_ALEN); |
195 | pos += ETH_ALEN; | 194 | pos += ETH_ALEN; |
196 | memcpy(pos, &orig_sn, 4); | 195 | put_unaligned_le32(orig_sn, pos); |
197 | pos += 4; | 196 | pos += 4; |
198 | } | 197 | } |
199 | 198 | ||
@@ -239,8 +238,8 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata, | |||
239 | * frame directly but add it to the pending queue instead. | 238 | * frame directly but add it to the pending queue instead. |
240 | */ | 239 | */ |
241 | int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | 240 | int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, |
242 | u8 ttl, const u8 *target, __le32 target_sn, | 241 | u8 ttl, const u8 *target, u32 target_sn, |
243 | __le16 target_rcode, const u8 *ra) | 242 | u16 target_rcode, const u8 *ra) |
244 | { | 243 | { |
245 | struct ieee80211_local *local = sdata->local; | 244 | struct ieee80211_local *local = sdata->local; |
246 | struct sk_buff *skb; | 245 | struct sk_buff *skb; |
@@ -254,13 +253,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | |||
254 | return -EAGAIN; | 253 | return -EAGAIN; |
255 | 254 | ||
256 | skb = dev_alloc_skb(local->tx_headroom + | 255 | skb = dev_alloc_skb(local->tx_headroom + |
257 | IEEE80211_ENCRYPT_HEADROOM + | 256 | sdata->encrypt_headroom + |
258 | IEEE80211_ENCRYPT_TAILROOM + | 257 | IEEE80211_ENCRYPT_TAILROOM + |
259 | hdr_len + | 258 | hdr_len + |
260 | 2 + 15 /* PERR IE */); | 259 | 2 + 15 /* PERR IE */); |
261 | if (!skb) | 260 | if (!skb) |
262 | return -1; | 261 | return -1; |
263 | skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); | 262 | skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom); |
264 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 263 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); |
265 | memset(mgmt, 0, hdr_len); | 264 | memset(mgmt, 0, hdr_len); |
266 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 265 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
@@ -293,9 +292,9 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, | |||
293 | pos++; | 292 | pos++; |
294 | memcpy(pos, target, ETH_ALEN); | 293 | memcpy(pos, target, ETH_ALEN); |
295 | pos += ETH_ALEN; | 294 | pos += ETH_ALEN; |
296 | memcpy(pos, &target_sn, 4); | 295 | put_unaligned_le32(target_sn, pos); |
297 | pos += 4; | 296 | pos += 4; |
298 | memcpy(pos, &target_rcode, 2); | 297 | put_unaligned_le16(target_rcode, pos); |
299 | 298 | ||
300 | /* see note in function header */ | 299 | /* see note in function header */ |
301 | prepare_frame_for_deferred_tx(sdata, skb); | 300 | prepare_frame_for_deferred_tx(sdata, skb); |
@@ -592,10 +591,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
592 | if (ttl != 0) { | 591 | if (ttl != 0) { |
593 | mhwmp_dbg(sdata, "replying to the PREQ\n"); | 592 | mhwmp_dbg(sdata, "replying to the PREQ\n"); |
594 | mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr, | 593 | mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr, |
595 | cpu_to_le32(orig_sn), 0, target_addr, | 594 | orig_sn, 0, target_addr, |
596 | cpu_to_le32(target_sn), mgmt->sa, 0, ttl, | 595 | target_sn, mgmt->sa, 0, ttl, |
597 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 596 | lifetime, metric, 0, sdata); |
598 | 0, sdata); | ||
599 | } else { | 597 | } else { |
600 | ifmsh->mshstats.dropped_frames_ttl++; | 598 | ifmsh->mshstats.dropped_frames_ttl++; |
601 | } | 599 | } |
@@ -625,11 +623,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
625 | } | 623 | } |
626 | 624 | ||
627 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, | 625 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, |
628 | cpu_to_le32(orig_sn), target_flags, target_addr, | 626 | orig_sn, target_flags, target_addr, |
629 | cpu_to_le32(target_sn), da, | 627 | target_sn, da, hopcount, ttl, lifetime, |
630 | hopcount, ttl, cpu_to_le32(lifetime), | 628 | metric, preq_id, sdata); |
631 | cpu_to_le32(metric), cpu_to_le32(preq_id), | ||
632 | sdata); | ||
633 | if (!is_multicast_ether_addr(da)) | 629 | if (!is_multicast_ether_addr(da)) |
634 | ifmsh->mshstats.fwded_unicast++; | 630 | ifmsh->mshstats.fwded_unicast++; |
635 | else | 631 | else |
@@ -695,11 +691,9 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
695 | target_sn = PREP_IE_TARGET_SN(prep_elem); | 691 | target_sn = PREP_IE_TARGET_SN(prep_elem); |
696 | orig_sn = PREP_IE_ORIG_SN(prep_elem); | 692 | orig_sn = PREP_IE_ORIG_SN(prep_elem); |
697 | 693 | ||
698 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, | 694 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, orig_sn, 0, |
699 | cpu_to_le32(orig_sn), 0, target_addr, | 695 | target_addr, target_sn, next_hop, hopcount, |
700 | cpu_to_le32(target_sn), next_hop, hopcount, | 696 | ttl, lifetime, metric, 0, sdata); |
701 | ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), | ||
702 | 0, sdata); | ||
703 | rcu_read_unlock(); | 697 | rcu_read_unlock(); |
704 | 698 | ||
705 | sdata->u.mesh.mshstats.fwded_unicast++; | 699 | sdata->u.mesh.mshstats.fwded_unicast++; |
@@ -750,8 +744,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
750 | if (!ifmsh->mshcfg.dot11MeshForwarding) | 744 | if (!ifmsh->mshcfg.dot11MeshForwarding) |
751 | goto endperr; | 745 | goto endperr; |
752 | mesh_path_error_tx(sdata, ttl, target_addr, | 746 | mesh_path_error_tx(sdata, ttl, target_addr, |
753 | cpu_to_le32(target_sn), | 747 | target_sn, target_rcode, |
754 | cpu_to_le16(target_rcode), | ||
755 | broadcast_addr); | 748 | broadcast_addr); |
756 | } else | 749 | } else |
757 | spin_unlock_bh(&mpath->state_lock); | 750 | spin_unlock_bh(&mpath->state_lock); |
@@ -847,11 +840,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | |||
847 | 840 | ||
848 | if (ifmsh->mshcfg.dot11MeshForwarding) { | 841 | if (ifmsh->mshcfg.dot11MeshForwarding) { |
849 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, | 842 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, |
850 | cpu_to_le32(orig_sn), | 843 | orig_sn, 0, NULL, 0, broadcast_addr, |
851 | 0, NULL, 0, broadcast_addr, | 844 | hopcount, ttl, interval, |
852 | hopcount, ttl, cpu_to_le32(interval), | 845 | metric + metric_txsta, 0, sdata); |
853 | cpu_to_le32(metric + metric_txsta), | ||
854 | 0, sdata); | ||
855 | } | 846 | } |
856 | 847 | ||
857 | rcu_read_unlock(); | 848 | rcu_read_unlock(); |
@@ -1049,11 +1040,9 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
1049 | 1040 | ||
1050 | spin_unlock_bh(&mpath->state_lock); | 1041 | spin_unlock_bh(&mpath->state_lock); |
1051 | da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; | 1042 | da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; |
1052 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, | 1043 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, ifmsh->sn, |
1053 | cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, | 1044 | target_flags, mpath->dst, mpath->sn, da, 0, |
1054 | cpu_to_le32(mpath->sn), da, 0, | 1045 | ttl, lifetime, 0, ifmsh->preq_id++, sdata); |
1055 | ttl, cpu_to_le32(lifetime), 0, | ||
1056 | cpu_to_le32(ifmsh->preq_id++), sdata); | ||
1057 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); | 1046 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); |
1058 | 1047 | ||
1059 | enddiscovery: | 1048 | enddiscovery: |
@@ -1212,10 +1201,9 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | |||
1212 | switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) { | 1201 | switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) { |
1213 | case IEEE80211_PROACTIVE_RANN: | 1202 | case IEEE80211_PROACTIVE_RANN: |
1214 | mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, | 1203 | mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, |
1215 | cpu_to_le32(++ifmsh->sn), | 1204 | ++ifmsh->sn, 0, NULL, 0, broadcast_addr, |
1216 | 0, NULL, 0, broadcast_addr, | 1205 | 0, ifmsh->mshcfg.element_ttl, |
1217 | 0, ifmsh->mshcfg.element_ttl, | 1206 | interval, 0, 0, sdata); |
1218 | cpu_to_le32(interval), 0, 0, sdata); | ||
1219 | break; | 1207 | break; |
1220 | case IEEE80211_PROACTIVE_PREQ_WITH_PREP: | 1208 | case IEEE80211_PROACTIVE_PREQ_WITH_PREP: |
1221 | flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; | 1209 | flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; |
@@ -1224,11 +1212,10 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | |||
1224 | target_flags |= IEEE80211_PREQ_TO_FLAG | | 1212 | target_flags |= IEEE80211_PREQ_TO_FLAG | |
1225 | IEEE80211_PREQ_USN_FLAG; | 1213 | IEEE80211_PREQ_USN_FLAG; |
1226 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr, | 1214 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr, |
1227 | cpu_to_le32(++ifmsh->sn), target_flags, | 1215 | ++ifmsh->sn, target_flags, |
1228 | (u8 *) broadcast_addr, 0, broadcast_addr, | 1216 | (u8 *) broadcast_addr, 0, broadcast_addr, |
1229 | 0, ifmsh->mshcfg.element_ttl, | 1217 | 0, ifmsh->mshcfg.element_ttl, interval, |
1230 | cpu_to_le32(interval), | 1218 | 0, ifmsh->preq_id++, sdata); |
1231 | 0, cpu_to_le32(ifmsh->preq_id++), sdata); | ||
1232 | break; | 1219 | break; |
1233 | default: | 1220 | default: |
1234 | mhwmp_dbg(sdata, "Proactive mechanism not supported\n"); | 1221 | mhwmp_dbg(sdata, "Proactive mechanism not supported\n"); |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 89aacfd2756d..7d050ed6fe5a 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -722,7 +722,6 @@ void mesh_plink_broken(struct sta_info *sta) | |||
722 | struct mpath_node *node; | 722 | struct mpath_node *node; |
723 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 723 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
724 | int i; | 724 | int i; |
725 | __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE); | ||
726 | 725 | ||
727 | rcu_read_lock(); | 726 | rcu_read_lock(); |
728 | tbl = rcu_dereference(mesh_paths); | 727 | tbl = rcu_dereference(mesh_paths); |
@@ -736,9 +735,9 @@ void mesh_plink_broken(struct sta_info *sta) | |||
736 | ++mpath->sn; | 735 | ++mpath->sn; |
737 | spin_unlock_bh(&mpath->state_lock); | 736 | spin_unlock_bh(&mpath->state_lock); |
738 | mesh_path_error_tx(sdata, | 737 | mesh_path_error_tx(sdata, |
739 | sdata->u.mesh.mshcfg.element_ttl, | 738 | sdata->u.mesh.mshcfg.element_ttl, |
740 | mpath->dst, cpu_to_le32(mpath->sn), | 739 | mpath->dst, mpath->sn, |
741 | reason, bcast); | 740 | WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast); |
742 | } | 741 | } |
743 | } | 742 | } |
744 | rcu_read_unlock(); | 743 | rcu_read_unlock(); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 4301aa5aa227..cf83217103f9 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -19,12 +19,6 @@ | |||
19 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | 19 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ |
20 | jiffies + HZ * t / 1000)) | 20 | jiffies + HZ * t / 1000)) |
21 | 21 | ||
22 | /* We only need a valid sta if user configured a minimum rssi_threshold. */ | ||
23 | #define rssi_threshold_check(sta, sdata) \ | ||
24 | (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ | ||
25 | (sta && (s8) -ewma_read(&sta->avg_signal) > \ | ||
26 | sdata->u.mesh.mshcfg.rssi_threshold)) | ||
27 | |||
28 | enum plink_event { | 22 | enum plink_event { |
29 | PLINK_UNDEFINED, | 23 | PLINK_UNDEFINED, |
30 | OPN_ACPT, | 24 | OPN_ACPT, |
@@ -61,7 +55,17 @@ static const char * const mplevents[] = { | |||
61 | 55 | ||
62 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 56 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
63 | enum ieee80211_self_protected_actioncode action, | 57 | enum ieee80211_self_protected_actioncode action, |
64 | u8 *da, __le16 llid, __le16 plid, __le16 reason); | 58 | u8 *da, u16 llid, u16 plid, u16 reason); |
59 | |||
60 | |||
61 | /* We only need a valid sta if user configured a minimum rssi_threshold. */ | ||
62 | static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata, | ||
63 | struct sta_info *sta) | ||
64 | { | ||
65 | s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold; | ||
66 | return rssi_threshold == 0 || | ||
67 | (sta && (s8) -ewma_read(&sta->avg_signal) > rssi_threshold); | ||
68 | } | ||
65 | 69 | ||
66 | /** | 70 | /** |
67 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine | 71 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine |
@@ -242,7 +246,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta) | |||
242 | 246 | ||
243 | spin_lock_bh(&sta->lock); | 247 | spin_lock_bh(&sta->lock); |
244 | changed = __mesh_plink_deactivate(sta); | 248 | changed = __mesh_plink_deactivate(sta); |
245 | sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED); | 249 | sta->reason = WLAN_REASON_MESH_PEER_CANCELED; |
246 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 250 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, |
247 | sta->sta.addr, sta->llid, sta->plid, | 251 | sta->sta.addr, sta->llid, sta->plid, |
248 | sta->reason); | 252 | sta->reason); |
@@ -253,7 +257,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta) | |||
253 | 257 | ||
254 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 258 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
255 | enum ieee80211_self_protected_actioncode action, | 259 | enum ieee80211_self_protected_actioncode action, |
256 | u8 *da, __le16 llid, __le16 plid, __le16 reason) | 260 | u8 *da, u16 llid, u16 plid, u16 reason) |
257 | { | 261 | { |
258 | struct ieee80211_local *local = sdata->local; | 262 | struct ieee80211_local *local = sdata->local; |
259 | struct sk_buff *skb; | 263 | struct sk_buff *skb; |
@@ -279,7 +283,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
279 | 2 + 8 + /* peering IE */ | 283 | 2 + 8 + /* peering IE */ |
280 | sdata->u.mesh.ie_len); | 284 | sdata->u.mesh.ie_len); |
281 | if (!skb) | 285 | if (!skb) |
282 | return -1; | 286 | return err; |
283 | info = IEEE80211_SKB_CB(skb); | 287 | info = IEEE80211_SKB_CB(skb); |
284 | skb_reserve(skb, local->tx_headroom); | 288 | skb_reserve(skb, local->tx_headroom); |
285 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); | 289 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); |
@@ -301,7 +305,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
301 | if (action == WLAN_SP_MESH_PEERING_CONFIRM) { | 305 | if (action == WLAN_SP_MESH_PEERING_CONFIRM) { |
302 | /* AID */ | 306 | /* AID */ |
303 | pos = skb_put(skb, 2); | 307 | pos = skb_put(skb, 2); |
304 | memcpy(pos + 2, &plid, 2); | 308 | put_unaligned_le16(plid, pos + 2); |
305 | } | 309 | } |
306 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | 310 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || |
307 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | 311 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || |
@@ -343,14 +347,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
343 | *pos++ = ie_len; | 347 | *pos++ = ie_len; |
344 | memcpy(pos, &peering_proto, 2); | 348 | memcpy(pos, &peering_proto, 2); |
345 | pos += 2; | 349 | pos += 2; |
346 | memcpy(pos, &llid, 2); | 350 | put_unaligned_le16(llid, pos); |
347 | pos += 2; | 351 | pos += 2; |
348 | if (include_plid) { | 352 | if (include_plid) { |
349 | memcpy(pos, &plid, 2); | 353 | put_unaligned_le16(plid, pos); |
350 | pos += 2; | 354 | pos += 2; |
351 | } | 355 | } |
352 | if (action == WLAN_SP_MESH_PEERING_CLOSE) { | 356 | if (action == WLAN_SP_MESH_PEERING_CLOSE) { |
353 | memcpy(pos, &reason, 2); | 357 | put_unaligned_le16(reason, pos); |
354 | pos += 2; | 358 | pos += 2; |
355 | } | 359 | } |
356 | 360 | ||
@@ -518,7 +522,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
518 | sta->plink_state == NL80211_PLINK_LISTEN && | 522 | sta->plink_state == NL80211_PLINK_LISTEN && |
519 | sdata->u.mesh.accepting_plinks && | 523 | sdata->u.mesh.accepting_plinks && |
520 | sdata->u.mesh.mshcfg.auto_open_plinks && | 524 | sdata->u.mesh.mshcfg.auto_open_plinks && |
521 | rssi_threshold_check(sta, sdata)) | 525 | rssi_threshold_check(sdata, sta)) |
522 | changed = mesh_plink_open(sta); | 526 | changed = mesh_plink_open(sta); |
523 | 527 | ||
524 | ieee80211_mps_frame_release(sta, elems); | 528 | ieee80211_mps_frame_release(sta, elems); |
@@ -530,9 +534,10 @@ out: | |||
530 | static void mesh_plink_timer(unsigned long data) | 534 | static void mesh_plink_timer(unsigned long data) |
531 | { | 535 | { |
532 | struct sta_info *sta; | 536 | struct sta_info *sta; |
533 | __le16 llid, plid, reason; | 537 | u16 reason = 0; |
534 | struct ieee80211_sub_if_data *sdata; | 538 | struct ieee80211_sub_if_data *sdata; |
535 | struct mesh_config *mshcfg; | 539 | struct mesh_config *mshcfg; |
540 | enum ieee80211_self_protected_actioncode action = 0; | ||
536 | 541 | ||
537 | /* | 542 | /* |
538 | * This STA is valid because sta_info_destroy() will | 543 | * This STA is valid because sta_info_destroy() will |
@@ -553,9 +558,6 @@ static void mesh_plink_timer(unsigned long data) | |||
553 | mpl_dbg(sta->sdata, | 558 | mpl_dbg(sta->sdata, |
554 | "Mesh plink timer for %pM fired on state %s\n", | 559 | "Mesh plink timer for %pM fired on state %s\n", |
555 | sta->sta.addr, mplstates[sta->plink_state]); | 560 | sta->sta.addr, mplstates[sta->plink_state]); |
556 | reason = 0; | ||
557 | llid = sta->llid; | ||
558 | plid = sta->plid; | ||
559 | sdata = sta->sdata; | 561 | sdata = sta->sdata; |
560 | mshcfg = &sdata->u.mesh.mshcfg; | 562 | mshcfg = &sdata->u.mesh.mshcfg; |
561 | 563 | ||
@@ -574,33 +576,31 @@ static void mesh_plink_timer(unsigned long data) | |||
574 | rand % sta->plink_timeout; | 576 | rand % sta->plink_timeout; |
575 | ++sta->plink_retries; | 577 | ++sta->plink_retries; |
576 | mod_plink_timer(sta, sta->plink_timeout); | 578 | mod_plink_timer(sta, sta->plink_timeout); |
577 | spin_unlock_bh(&sta->lock); | 579 | action = WLAN_SP_MESH_PEERING_OPEN; |
578 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, | ||
579 | sta->sta.addr, llid, 0, 0); | ||
580 | break; | 580 | break; |
581 | } | 581 | } |
582 | reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES); | 582 | reason = WLAN_REASON_MESH_MAX_RETRIES; |
583 | /* fall through on else */ | 583 | /* fall through on else */ |
584 | case NL80211_PLINK_CNF_RCVD: | 584 | case NL80211_PLINK_CNF_RCVD: |
585 | /* confirm timer */ | 585 | /* confirm timer */ |
586 | if (!reason) | 586 | if (!reason) |
587 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); | 587 | reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT; |
588 | sta->plink_state = NL80211_PLINK_HOLDING; | 588 | sta->plink_state = NL80211_PLINK_HOLDING; |
589 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); | 589 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
590 | spin_unlock_bh(&sta->lock); | 590 | action = WLAN_SP_MESH_PEERING_CLOSE; |
591 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
592 | sta->sta.addr, llid, plid, reason); | ||
593 | break; | 591 | break; |
594 | case NL80211_PLINK_HOLDING: | 592 | case NL80211_PLINK_HOLDING: |
595 | /* holding timer */ | 593 | /* holding timer */ |
596 | del_timer(&sta->plink_timer); | 594 | del_timer(&sta->plink_timer); |
597 | mesh_plink_fsm_restart(sta); | 595 | mesh_plink_fsm_restart(sta); |
598 | spin_unlock_bh(&sta->lock); | ||
599 | break; | 596 | break; |
600 | default: | 597 | default: |
601 | spin_unlock_bh(&sta->lock); | ||
602 | break; | 598 | break; |
603 | } | 599 | } |
600 | spin_unlock_bh(&sta->lock); | ||
601 | if (action) | ||
602 | mesh_plink_frame_tx(sdata, action, sta->sta.addr, | ||
603 | sta->llid, sta->plid, reason); | ||
604 | } | 604 | } |
605 | 605 | ||
606 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | 606 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) |
@@ -612,9 +612,40 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | |||
612 | add_timer(&sta->plink_timer); | 612 | add_timer(&sta->plink_timer); |
613 | } | 613 | } |
614 | 614 | ||
615 | static bool llid_in_use(struct ieee80211_sub_if_data *sdata, | ||
616 | u16 llid) | ||
617 | { | ||
618 | struct ieee80211_local *local = sdata->local; | ||
619 | bool in_use = false; | ||
620 | struct sta_info *sta; | ||
621 | |||
622 | rcu_read_lock(); | ||
623 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
624 | if (!memcmp(&sta->llid, &llid, sizeof(llid))) { | ||
625 | in_use = true; | ||
626 | break; | ||
627 | } | ||
628 | } | ||
629 | rcu_read_unlock(); | ||
630 | |||
631 | return in_use; | ||
632 | } | ||
633 | |||
634 | static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) | ||
635 | { | ||
636 | u16 llid; | ||
637 | |||
638 | do { | ||
639 | get_random_bytes(&llid, sizeof(llid)); | ||
640 | /* for mesh PS we still only have the AID range for TIM bits */ | ||
641 | llid = (llid % IEEE80211_MAX_AID) + 1; | ||
642 | } while (llid_in_use(sdata, llid)); | ||
643 | |||
644 | return llid; | ||
645 | } | ||
646 | |||
615 | u32 mesh_plink_open(struct sta_info *sta) | 647 | u32 mesh_plink_open(struct sta_info *sta) |
616 | { | 648 | { |
617 | __le16 llid; | ||
618 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 649 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
619 | u32 changed; | 650 | u32 changed; |
620 | 651 | ||
@@ -622,8 +653,7 @@ u32 mesh_plink_open(struct sta_info *sta) | |||
622 | return 0; | 653 | return 0; |
623 | 654 | ||
624 | spin_lock_bh(&sta->lock); | 655 | spin_lock_bh(&sta->lock); |
625 | get_random_bytes(&llid, 2); | 656 | sta->llid = mesh_get_new_llid(sdata); |
626 | sta->llid = llid; | ||
627 | if (sta->plink_state != NL80211_PLINK_LISTEN && | 657 | if (sta->plink_state != NL80211_PLINK_LISTEN && |
628 | sta->plink_state != NL80211_PLINK_BLOCKED) { | 658 | sta->plink_state != NL80211_PLINK_BLOCKED) { |
629 | spin_unlock_bh(&sta->lock); | 659 | spin_unlock_bh(&sta->lock); |
@@ -640,7 +670,7 @@ u32 mesh_plink_open(struct sta_info *sta) | |||
640 | changed = ieee80211_mps_local_status_update(sdata); | 670 | changed = ieee80211_mps_local_status_update(sdata); |
641 | 671 | ||
642 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, | 672 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, |
643 | sta->sta.addr, llid, 0, 0); | 673 | sta->sta.addr, sta->llid, 0, 0); |
644 | return changed; | 674 | return changed; |
645 | } | 675 | } |
646 | 676 | ||
@@ -656,390 +686,147 @@ u32 mesh_plink_block(struct sta_info *sta) | |||
656 | return changed; | 686 | return changed; |
657 | } | 687 | } |
658 | 688 | ||
659 | 689 | static void mesh_plink_close(struct ieee80211_sub_if_data *sdata, | |
660 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | 690 | struct sta_info *sta, |
661 | struct ieee80211_mgmt *mgmt, size_t len, | 691 | enum plink_event event) |
662 | struct ieee80211_rx_status *rx_status) | ||
663 | { | 692 | { |
664 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; | 693 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; |
665 | struct ieee802_11_elems elems; | ||
666 | struct sta_info *sta; | ||
667 | enum plink_event event; | ||
668 | enum ieee80211_self_protected_actioncode ftype; | ||
669 | size_t baselen; | ||
670 | bool matches_local = true; | ||
671 | u8 ie_len; | ||
672 | u8 *baseaddr; | ||
673 | u32 changed = 0; | ||
674 | __le16 plid, llid, reason; | ||
675 | |||
676 | /* need action_code, aux */ | ||
677 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | ||
678 | return; | ||
679 | |||
680 | if (sdata->u.mesh.user_mpm) | ||
681 | /* userspace must register for these */ | ||
682 | return; | ||
683 | |||
684 | if (is_multicast_ether_addr(mgmt->da)) { | ||
685 | mpl_dbg(sdata, | ||
686 | "Mesh plink: ignore frame from multicast address\n"); | ||
687 | return; | ||
688 | } | ||
689 | |||
690 | baseaddr = mgmt->u.action.u.self_prot.variable; | ||
691 | baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; | ||
692 | if (mgmt->u.action.u.self_prot.action_code == | ||
693 | WLAN_SP_MESH_PEERING_CONFIRM) { | ||
694 | baseaddr += 4; | ||
695 | baselen += 4; | ||
696 | } | ||
697 | ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); | ||
698 | |||
699 | if (!elems.peering) { | ||
700 | mpl_dbg(sdata, | ||
701 | "Mesh plink: missing necessary peer link ie\n"); | ||
702 | return; | ||
703 | } | ||
704 | 694 | ||
705 | if (elems.rsn_len && | 695 | u16 reason = (event == CLS_ACPT) ? |
706 | sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | 696 | WLAN_REASON_MESH_CLOSE : WLAN_REASON_MESH_CONFIG; |
707 | mpl_dbg(sdata, | ||
708 | "Mesh plink: can't establish link with secure peer\n"); | ||
709 | return; | ||
710 | } | ||
711 | 697 | ||
712 | ftype = mgmt->u.action.u.self_prot.action_code; | 698 | sta->reason = reason; |
713 | ie_len = elems.peering_len; | 699 | sta->plink_state = NL80211_PLINK_HOLDING; |
714 | if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || | 700 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
715 | (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || | 701 | } |
716 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 | ||
717 | && ie_len != 8)) { | ||
718 | mpl_dbg(sdata, | ||
719 | "Mesh plink: incorrect plink ie length %d %d\n", | ||
720 | ftype, ie_len); | ||
721 | return; | ||
722 | } | ||
723 | |||
724 | if (ftype != WLAN_SP_MESH_PEERING_CLOSE && | ||
725 | (!elems.mesh_id || !elems.mesh_config)) { | ||
726 | mpl_dbg(sdata, "Mesh plink: missing necessary ie\n"); | ||
727 | return; | ||
728 | } | ||
729 | /* Note the lines below are correct, the llid in the frame is the plid | ||
730 | * from the point of view of this host. | ||
731 | */ | ||
732 | memcpy(&plid, PLINK_GET_LLID(elems.peering), 2); | ||
733 | if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || | ||
734 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) | ||
735 | memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); | ||
736 | |||
737 | /* WARNING: Only for sta pointer, is dropped & re-acquired */ | ||
738 | rcu_read_lock(); | ||
739 | |||
740 | sta = sta_info_get(sdata, mgmt->sa); | ||
741 | if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) { | ||
742 | mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); | ||
743 | rcu_read_unlock(); | ||
744 | return; | ||
745 | } | ||
746 | |||
747 | if (ftype == WLAN_SP_MESH_PEERING_OPEN && | ||
748 | !rssi_threshold_check(sta, sdata)) { | ||
749 | mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", | ||
750 | mgmt->sa); | ||
751 | rcu_read_unlock(); | ||
752 | return; | ||
753 | } | ||
754 | |||
755 | if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
756 | mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); | ||
757 | rcu_read_unlock(); | ||
758 | return; | ||
759 | } | ||
760 | 702 | ||
761 | if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) { | 703 | static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, |
762 | rcu_read_unlock(); | 704 | struct sta_info *sta) |
763 | return; | 705 | { |
764 | } | 706 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; |
707 | u32 changed = 0; | ||
765 | 708 | ||
766 | /* Now we will figure out the appropriate event... */ | 709 | del_timer(&sta->plink_timer); |
767 | event = PLINK_UNDEFINED; | 710 | sta->plink_state = NL80211_PLINK_ESTAB; |
768 | if (ftype != WLAN_SP_MESH_PEERING_CLOSE && | 711 | changed |= mesh_plink_inc_estab_count(sdata); |
769 | !mesh_matches_local(sdata, &elems)) { | 712 | changed |= mesh_set_ht_prot_mode(sdata); |
770 | matches_local = false; | 713 | changed |= mesh_set_short_slot_time(sdata); |
771 | switch (ftype) { | 714 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); |
772 | case WLAN_SP_MESH_PEERING_OPEN: | 715 | ieee80211_mps_sta_status_update(sta); |
773 | event = OPN_RJCT; | 716 | changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode); |
774 | break; | 717 | return changed; |
775 | case WLAN_SP_MESH_PEERING_CONFIRM: | 718 | } |
776 | event = CNF_RJCT; | ||
777 | break; | ||
778 | default: | ||
779 | break; | ||
780 | } | ||
781 | } | ||
782 | 719 | ||
783 | if (!sta && !matches_local) { | 720 | /** |
784 | rcu_read_unlock(); | 721 | * mesh_plink_fsm - step @sta MPM based on @event |
785 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); | 722 | * |
786 | llid = 0; | 723 | * @sdata: interface |
787 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 724 | * @sta: mesh neighbor |
788 | mgmt->sa, llid, plid, reason); | 725 | * @event: peering event |
789 | return; | 726 | * |
790 | } else if (!sta) { | 727 | * Return: changed MBSS flags |
791 | /* ftype == WLAN_SP_MESH_PEERING_OPEN */ | 728 | */ |
792 | if (!mesh_plink_free_count(sdata)) { | 729 | static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, |
793 | mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); | 730 | struct sta_info *sta, enum plink_event event) |
794 | rcu_read_unlock(); | 731 | { |
795 | return; | 732 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; |
796 | } | 733 | enum ieee80211_self_protected_actioncode action = 0; |
797 | event = OPN_ACPT; | 734 | u32 changed = 0; |
798 | } else if (matches_local) { | ||
799 | switch (ftype) { | ||
800 | case WLAN_SP_MESH_PEERING_OPEN: | ||
801 | if (!mesh_plink_free_count(sdata) || | ||
802 | (sta->plid && sta->plid != plid)) | ||
803 | event = OPN_IGNR; | ||
804 | else | ||
805 | event = OPN_ACPT; | ||
806 | break; | ||
807 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
808 | if (!mesh_plink_free_count(sdata) || | ||
809 | (sta->llid != llid || sta->plid != plid)) | ||
810 | event = CNF_IGNR; | ||
811 | else | ||
812 | event = CNF_ACPT; | ||
813 | break; | ||
814 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
815 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
816 | /* Do not check for llid or plid. This does not | ||
817 | * follow the standard but since multiple plinks | ||
818 | * per sta are not supported, it is necessary in | ||
819 | * order to avoid a livelock when MP A sees an | ||
820 | * establish peer link to MP B but MP B does not | ||
821 | * see it. This can be caused by a timeout in | ||
822 | * B's peer link establishment or B beign | ||
823 | * restarted. | ||
824 | */ | ||
825 | event = CLS_ACPT; | ||
826 | else if (sta->plid != plid) | ||
827 | event = CLS_IGNR; | ||
828 | else if (ie_len == 7 && sta->llid != llid) | ||
829 | event = CLS_IGNR; | ||
830 | else | ||
831 | event = CLS_ACPT; | ||
832 | break; | ||
833 | default: | ||
834 | mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); | ||
835 | rcu_read_unlock(); | ||
836 | return; | ||
837 | } | ||
838 | } | ||
839 | 735 | ||
840 | if (event == OPN_ACPT) { | 736 | mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr, |
841 | rcu_read_unlock(); | 737 | mplstates[sta->plink_state], mplevents[event]); |
842 | /* allocate sta entry if necessary and update info */ | ||
843 | sta = mesh_sta_info_get(sdata, mgmt->sa, &elems); | ||
844 | if (!sta) { | ||
845 | mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); | ||
846 | rcu_read_unlock(); | ||
847 | return; | ||
848 | } | ||
849 | } | ||
850 | 738 | ||
851 | mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa, | ||
852 | mplstates[sta->plink_state], mplevents[event]); | ||
853 | reason = 0; | ||
854 | spin_lock_bh(&sta->lock); | 739 | spin_lock_bh(&sta->lock); |
855 | switch (sta->plink_state) { | 740 | switch (sta->plink_state) { |
856 | /* spin_unlock as soon as state is updated at each case */ | ||
857 | case NL80211_PLINK_LISTEN: | 741 | case NL80211_PLINK_LISTEN: |
858 | switch (event) { | 742 | switch (event) { |
859 | case CLS_ACPT: | 743 | case CLS_ACPT: |
860 | mesh_plink_fsm_restart(sta); | 744 | mesh_plink_fsm_restart(sta); |
861 | spin_unlock_bh(&sta->lock); | ||
862 | break; | 745 | break; |
863 | case OPN_ACPT: | 746 | case OPN_ACPT: |
864 | sta->plink_state = NL80211_PLINK_OPN_RCVD; | 747 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
865 | sta->plid = plid; | 748 | sta->llid = mesh_get_new_llid(sdata); |
866 | get_random_bytes(&llid, 2); | ||
867 | sta->llid = llid; | ||
868 | mesh_plink_timer_set(sta, | 749 | mesh_plink_timer_set(sta, |
869 | mshcfg->dot11MeshRetryTimeout); | 750 | mshcfg->dot11MeshRetryTimeout); |
870 | 751 | ||
871 | /* set the non-peer mode to active during peering */ | 752 | /* set the non-peer mode to active during peering */ |
872 | changed |= ieee80211_mps_local_status_update(sdata); | 753 | changed |= ieee80211_mps_local_status_update(sdata); |
873 | 754 | action = WLAN_SP_MESH_PEERING_OPEN; | |
874 | spin_unlock_bh(&sta->lock); | ||
875 | mesh_plink_frame_tx(sdata, | ||
876 | WLAN_SP_MESH_PEERING_OPEN, | ||
877 | sta->sta.addr, llid, 0, 0); | ||
878 | mesh_plink_frame_tx(sdata, | ||
879 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
880 | sta->sta.addr, llid, plid, 0); | ||
881 | break; | 755 | break; |
882 | default: | 756 | default: |
883 | spin_unlock_bh(&sta->lock); | ||
884 | break; | 757 | break; |
885 | } | 758 | } |
886 | break; | 759 | break; |
887 | |||
888 | case NL80211_PLINK_OPN_SNT: | 760 | case NL80211_PLINK_OPN_SNT: |
889 | switch (event) { | 761 | switch (event) { |
890 | case OPN_RJCT: | 762 | case OPN_RJCT: |
891 | case CNF_RJCT: | 763 | case CNF_RJCT: |
892 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); | ||
893 | case CLS_ACPT: | 764 | case CLS_ACPT: |
894 | if (!reason) | 765 | mesh_plink_close(sdata, sta, event); |
895 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | 766 | action = WLAN_SP_MESH_PEERING_CLOSE; |
896 | sta->reason = reason; | ||
897 | sta->plink_state = NL80211_PLINK_HOLDING; | ||
898 | if (!mod_plink_timer(sta, | ||
899 | mshcfg->dot11MeshHoldingTimeout)) | ||
900 | sta->ignore_plink_timer = true; | ||
901 | |||
902 | llid = sta->llid; | ||
903 | spin_unlock_bh(&sta->lock); | ||
904 | mesh_plink_frame_tx(sdata, | ||
905 | WLAN_SP_MESH_PEERING_CLOSE, | ||
906 | sta->sta.addr, llid, plid, reason); | ||
907 | break; | 767 | break; |
908 | case OPN_ACPT: | 768 | case OPN_ACPT: |
909 | /* retry timer is left untouched */ | 769 | /* retry timer is left untouched */ |
910 | sta->plink_state = NL80211_PLINK_OPN_RCVD; | 770 | sta->plink_state = NL80211_PLINK_OPN_RCVD; |
911 | sta->plid = plid; | 771 | action = WLAN_SP_MESH_PEERING_CONFIRM; |
912 | llid = sta->llid; | ||
913 | spin_unlock_bh(&sta->lock); | ||
914 | mesh_plink_frame_tx(sdata, | ||
915 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
916 | sta->sta.addr, llid, plid, 0); | ||
917 | break; | 772 | break; |
918 | case CNF_ACPT: | 773 | case CNF_ACPT: |
919 | sta->plink_state = NL80211_PLINK_CNF_RCVD; | 774 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
920 | if (!mod_plink_timer(sta, | 775 | if (!mod_plink_timer(sta, |
921 | mshcfg->dot11MeshConfirmTimeout)) | 776 | mshcfg->dot11MeshConfirmTimeout)) |
922 | sta->ignore_plink_timer = true; | 777 | sta->ignore_plink_timer = true; |
923 | |||
924 | spin_unlock_bh(&sta->lock); | ||
925 | break; | 778 | break; |
926 | default: | 779 | default: |
927 | spin_unlock_bh(&sta->lock); | ||
928 | break; | 780 | break; |
929 | } | 781 | } |
930 | break; | 782 | break; |
931 | |||
932 | case NL80211_PLINK_OPN_RCVD: | 783 | case NL80211_PLINK_OPN_RCVD: |
933 | switch (event) { | 784 | switch (event) { |
934 | case OPN_RJCT: | 785 | case OPN_RJCT: |
935 | case CNF_RJCT: | 786 | case CNF_RJCT: |
936 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); | ||
937 | case CLS_ACPT: | 787 | case CLS_ACPT: |
938 | if (!reason) | 788 | mesh_plink_close(sdata, sta, event); |
939 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | 789 | action = WLAN_SP_MESH_PEERING_CLOSE; |
940 | sta->reason = reason; | ||
941 | sta->plink_state = NL80211_PLINK_HOLDING; | ||
942 | if (!mod_plink_timer(sta, | ||
943 | mshcfg->dot11MeshHoldingTimeout)) | ||
944 | sta->ignore_plink_timer = true; | ||
945 | |||
946 | llid = sta->llid; | ||
947 | spin_unlock_bh(&sta->lock); | ||
948 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
949 | sta->sta.addr, llid, plid, reason); | ||
950 | break; | 790 | break; |
951 | case OPN_ACPT: | 791 | case OPN_ACPT: |
952 | llid = sta->llid; | 792 | action = WLAN_SP_MESH_PEERING_CONFIRM; |
953 | spin_unlock_bh(&sta->lock); | ||
954 | mesh_plink_frame_tx(sdata, | ||
955 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
956 | sta->sta.addr, llid, plid, 0); | ||
957 | break; | 793 | break; |
958 | case CNF_ACPT: | 794 | case CNF_ACPT: |
959 | del_timer(&sta->plink_timer); | 795 | changed |= mesh_plink_establish(sdata, sta); |
960 | sta->plink_state = NL80211_PLINK_ESTAB; | ||
961 | spin_unlock_bh(&sta->lock); | ||
962 | changed |= mesh_plink_inc_estab_count(sdata); | ||
963 | changed |= mesh_set_ht_prot_mode(sdata); | ||
964 | changed |= mesh_set_short_slot_time(sdata); | ||
965 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", | ||
966 | sta->sta.addr); | ||
967 | ieee80211_mps_sta_status_update(sta); | ||
968 | changed |= ieee80211_mps_set_sta_local_pm(sta, | ||
969 | mshcfg->power_mode); | ||
970 | break; | 796 | break; |
971 | default: | 797 | default: |
972 | spin_unlock_bh(&sta->lock); | ||
973 | break; | 798 | break; |
974 | } | 799 | } |
975 | break; | 800 | break; |
976 | |||
977 | case NL80211_PLINK_CNF_RCVD: | 801 | case NL80211_PLINK_CNF_RCVD: |
978 | switch (event) { | 802 | switch (event) { |
979 | case OPN_RJCT: | 803 | case OPN_RJCT: |
980 | case CNF_RJCT: | 804 | case CNF_RJCT: |
981 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG); | ||
982 | case CLS_ACPT: | 805 | case CLS_ACPT: |
983 | if (!reason) | 806 | mesh_plink_close(sdata, sta, event); |
984 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | 807 | action = WLAN_SP_MESH_PEERING_CLOSE; |
985 | sta->reason = reason; | ||
986 | sta->plink_state = NL80211_PLINK_HOLDING; | ||
987 | if (!mod_plink_timer(sta, | ||
988 | mshcfg->dot11MeshHoldingTimeout)) | ||
989 | sta->ignore_plink_timer = true; | ||
990 | |||
991 | llid = sta->llid; | ||
992 | spin_unlock_bh(&sta->lock); | ||
993 | mesh_plink_frame_tx(sdata, | ||
994 | WLAN_SP_MESH_PEERING_CLOSE, | ||
995 | sta->sta.addr, llid, plid, reason); | ||
996 | break; | 808 | break; |
997 | case OPN_ACPT: | 809 | case OPN_ACPT: |
998 | del_timer(&sta->plink_timer); | 810 | changed |= mesh_plink_establish(sdata, sta); |
999 | sta->plink_state = NL80211_PLINK_ESTAB; | 811 | action = WLAN_SP_MESH_PEERING_CONFIRM; |
1000 | spin_unlock_bh(&sta->lock); | ||
1001 | changed |= mesh_plink_inc_estab_count(sdata); | ||
1002 | changed |= mesh_set_ht_prot_mode(sdata); | ||
1003 | changed |= mesh_set_short_slot_time(sdata); | ||
1004 | mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", | ||
1005 | sta->sta.addr); | ||
1006 | mesh_plink_frame_tx(sdata, | ||
1007 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
1008 | sta->sta.addr, llid, plid, 0); | ||
1009 | ieee80211_mps_sta_status_update(sta); | ||
1010 | changed |= ieee80211_mps_set_sta_local_pm(sta, | ||
1011 | mshcfg->power_mode); | ||
1012 | break; | 812 | break; |
1013 | default: | 813 | default: |
1014 | spin_unlock_bh(&sta->lock); | ||
1015 | break; | 814 | break; |
1016 | } | 815 | } |
1017 | break; | 816 | break; |
1018 | |||
1019 | case NL80211_PLINK_ESTAB: | 817 | case NL80211_PLINK_ESTAB: |
1020 | switch (event) { | 818 | switch (event) { |
1021 | case CLS_ACPT: | 819 | case CLS_ACPT: |
1022 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | ||
1023 | sta->reason = reason; | ||
1024 | changed |= __mesh_plink_deactivate(sta); | 820 | changed |= __mesh_plink_deactivate(sta); |
1025 | sta->plink_state = NL80211_PLINK_HOLDING; | ||
1026 | llid = sta->llid; | ||
1027 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); | ||
1028 | spin_unlock_bh(&sta->lock); | ||
1029 | changed |= mesh_set_ht_prot_mode(sdata); | 821 | changed |= mesh_set_ht_prot_mode(sdata); |
1030 | changed |= mesh_set_short_slot_time(sdata); | 822 | changed |= mesh_set_short_slot_time(sdata); |
1031 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 823 | mesh_plink_close(sdata, sta, event); |
1032 | sta->sta.addr, llid, plid, reason); | 824 | action = WLAN_SP_MESH_PEERING_CLOSE; |
1033 | break; | 825 | break; |
1034 | case OPN_ACPT: | 826 | case OPN_ACPT: |
1035 | llid = sta->llid; | 827 | action = WLAN_SP_MESH_PEERING_CONFIRM; |
1036 | spin_unlock_bh(&sta->lock); | ||
1037 | mesh_plink_frame_tx(sdata, | ||
1038 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
1039 | sta->sta.addr, llid, plid, 0); | ||
1040 | break; | 828 | break; |
1041 | default: | 829 | default: |
1042 | spin_unlock_bh(&sta->lock); | ||
1043 | break; | 830 | break; |
1044 | } | 831 | } |
1045 | break; | 832 | break; |
@@ -1049,32 +836,271 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
1049 | if (del_timer(&sta->plink_timer)) | 836 | if (del_timer(&sta->plink_timer)) |
1050 | sta->ignore_plink_timer = 1; | 837 | sta->ignore_plink_timer = 1; |
1051 | mesh_plink_fsm_restart(sta); | 838 | mesh_plink_fsm_restart(sta); |
1052 | spin_unlock_bh(&sta->lock); | ||
1053 | break; | 839 | break; |
1054 | case OPN_ACPT: | 840 | case OPN_ACPT: |
1055 | case CNF_ACPT: | 841 | case CNF_ACPT: |
1056 | case OPN_RJCT: | 842 | case OPN_RJCT: |
1057 | case CNF_RJCT: | 843 | case CNF_RJCT: |
1058 | llid = sta->llid; | 844 | action = WLAN_SP_MESH_PEERING_CLOSE; |
1059 | reason = sta->reason; | ||
1060 | spin_unlock_bh(&sta->lock); | ||
1061 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
1062 | sta->sta.addr, llid, plid, reason); | ||
1063 | break; | 845 | break; |
1064 | default: | 846 | default: |
1065 | spin_unlock_bh(&sta->lock); | 847 | break; |
1066 | } | 848 | } |
1067 | break; | 849 | break; |
1068 | default: | 850 | default: |
1069 | /* should not get here, PLINK_BLOCKED is dealt with at the | 851 | /* should not get here, PLINK_BLOCKED is dealt with at the |
1070 | * beginning of the function | 852 | * beginning of the function |
1071 | */ | 853 | */ |
1072 | spin_unlock_bh(&sta->lock); | ||
1073 | break; | 854 | break; |
1074 | } | 855 | } |
856 | spin_unlock_bh(&sta->lock); | ||
857 | if (action) { | ||
858 | mesh_plink_frame_tx(sdata, action, sta->sta.addr, | ||
859 | sta->llid, sta->plid, sta->reason); | ||
860 | |||
861 | /* also send confirm in open case */ | ||
862 | if (action == WLAN_SP_MESH_PEERING_OPEN) { | ||
863 | mesh_plink_frame_tx(sdata, | ||
864 | WLAN_SP_MESH_PEERING_CONFIRM, | ||
865 | sta->sta.addr, sta->llid, | ||
866 | sta->plid, 0); | ||
867 | } | ||
868 | } | ||
869 | |||
870 | return changed; | ||
871 | } | ||
872 | |||
873 | /* | ||
874 | * mesh_plink_get_event - get correct MPM event | ||
875 | * | ||
876 | * @sdata: interface | ||
877 | * @sta: peer, leave NULL if processing a frame from a new suitable peer | ||
878 | * @elems: peering management IEs | ||
879 | * @ftype: frame type | ||
880 | * @llid: peer's peer link ID | ||
881 | * @plid: peer's local link ID | ||
882 | * | ||
883 | * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as | ||
884 | * an error. | ||
885 | */ | ||
886 | static enum plink_event | ||
887 | mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, | ||
888 | struct sta_info *sta, | ||
889 | struct ieee802_11_elems *elems, | ||
890 | enum ieee80211_self_protected_actioncode ftype, | ||
891 | u16 llid, u16 plid) | ||
892 | { | ||
893 | enum plink_event event = PLINK_UNDEFINED; | ||
894 | u8 ie_len = elems->peering_len; | ||
895 | bool matches_local; | ||
896 | |||
897 | matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || | ||
898 | mesh_matches_local(sdata, elems)); | ||
899 | |||
900 | /* deny open request from non-matching peer */ | ||
901 | if (!matches_local && !sta) { | ||
902 | event = OPN_RJCT; | ||
903 | goto out; | ||
904 | } | ||
905 | |||
906 | if (!sta) { | ||
907 | if (ftype != WLAN_SP_MESH_PEERING_OPEN) { | ||
908 | mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); | ||
909 | goto out; | ||
910 | } | ||
911 | /* ftype == WLAN_SP_MESH_PEERING_OPEN */ | ||
912 | if (!mesh_plink_free_count(sdata)) { | ||
913 | mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); | ||
914 | goto out; | ||
915 | } | ||
916 | } else { | ||
917 | if (!test_sta_flag(sta, WLAN_STA_AUTH)) { | ||
918 | mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); | ||
919 | goto out; | ||
920 | } | ||
921 | if (sta->plink_state == NL80211_PLINK_BLOCKED) | ||
922 | goto out; | ||
923 | } | ||
924 | |||
925 | /* new matching peer */ | ||
926 | if (!sta) { | ||
927 | event = OPN_ACPT; | ||
928 | goto out; | ||
929 | } | ||
930 | |||
931 | switch (ftype) { | ||
932 | case WLAN_SP_MESH_PEERING_OPEN: | ||
933 | if (!matches_local) | ||
934 | event = OPN_RJCT; | ||
935 | if (!mesh_plink_free_count(sdata) || | ||
936 | (sta->plid && sta->plid != plid)) | ||
937 | event = OPN_IGNR; | ||
938 | else | ||
939 | event = OPN_ACPT; | ||
940 | break; | ||
941 | case WLAN_SP_MESH_PEERING_CONFIRM: | ||
942 | if (!matches_local) | ||
943 | event = CNF_RJCT; | ||
944 | if (!mesh_plink_free_count(sdata) || | ||
945 | (sta->llid != llid || sta->plid != plid)) | ||
946 | event = CNF_IGNR; | ||
947 | else | ||
948 | event = CNF_ACPT; | ||
949 | break; | ||
950 | case WLAN_SP_MESH_PEERING_CLOSE: | ||
951 | if (sta->plink_state == NL80211_PLINK_ESTAB) | ||
952 | /* Do not check for llid or plid. This does not | ||
953 | * follow the standard but since multiple plinks | ||
954 | * per sta are not supported, it is necessary in | ||
955 | * order to avoid a livelock when MP A sees an | ||
956 | * establish peer link to MP B but MP B does not | ||
957 | * see it. This can be caused by a timeout in | ||
958 | * B's peer link establishment or B beign | ||
959 | * restarted. | ||
960 | */ | ||
961 | event = CLS_ACPT; | ||
962 | else if (sta->plid != plid) | ||
963 | event = CLS_IGNR; | ||
964 | else if (ie_len == 8 && sta->llid != llid) | ||
965 | event = CLS_IGNR; | ||
966 | else | ||
967 | event = CLS_ACPT; | ||
968 | break; | ||
969 | default: | ||
970 | mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); | ||
971 | break; | ||
972 | } | ||
973 | |||
974 | out: | ||
975 | return event; | ||
976 | } | ||
1075 | 977 | ||
978 | static void | ||
979 | mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | ||
980 | struct ieee80211_mgmt *mgmt, | ||
981 | struct ieee802_11_elems *elems) | ||
982 | { | ||
983 | |||
984 | struct sta_info *sta; | ||
985 | enum plink_event event; | ||
986 | enum ieee80211_self_protected_actioncode ftype; | ||
987 | u32 changed = 0; | ||
988 | u8 ie_len = elems->peering_len; | ||
989 | __le16 _plid, _llid; | ||
990 | u16 plid, llid = 0; | ||
991 | |||
992 | if (!elems->peering) { | ||
993 | mpl_dbg(sdata, | ||
994 | "Mesh plink: missing necessary peer link ie\n"); | ||
995 | return; | ||
996 | } | ||
997 | |||
998 | if (elems->rsn_len && | ||
999 | sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | ||
1000 | mpl_dbg(sdata, | ||
1001 | "Mesh plink: can't establish link with secure peer\n"); | ||
1002 | return; | ||
1003 | } | ||
1004 | |||
1005 | ftype = mgmt->u.action.u.self_prot.action_code; | ||
1006 | if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || | ||
1007 | (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || | ||
1008 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 | ||
1009 | && ie_len != 8)) { | ||
1010 | mpl_dbg(sdata, | ||
1011 | "Mesh plink: incorrect plink ie length %d %d\n", | ||
1012 | ftype, ie_len); | ||
1013 | return; | ||
1014 | } | ||
1015 | |||
1016 | if (ftype != WLAN_SP_MESH_PEERING_CLOSE && | ||
1017 | (!elems->mesh_id || !elems->mesh_config)) { | ||
1018 | mpl_dbg(sdata, "Mesh plink: missing necessary ie\n"); | ||
1019 | return; | ||
1020 | } | ||
1021 | /* Note the lines below are correct, the llid in the frame is the plid | ||
1022 | * from the point of view of this host. | ||
1023 | */ | ||
1024 | memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16)); | ||
1025 | plid = le16_to_cpu(_plid); | ||
1026 | if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || | ||
1027 | (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) { | ||
1028 | memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16)); | ||
1029 | llid = le16_to_cpu(_llid); | ||
1030 | } | ||
1031 | |||
1032 | /* WARNING: Only for sta pointer, is dropped & re-acquired */ | ||
1033 | rcu_read_lock(); | ||
1034 | |||
1035 | sta = sta_info_get(sdata, mgmt->sa); | ||
1036 | |||
1037 | if (ftype == WLAN_SP_MESH_PEERING_OPEN && | ||
1038 | !rssi_threshold_check(sdata, sta)) { | ||
1039 | mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", | ||
1040 | mgmt->sa); | ||
1041 | goto unlock_rcu; | ||
1042 | } | ||
1043 | |||
1044 | /* Now we will figure out the appropriate event... */ | ||
1045 | event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid); | ||
1046 | |||
1047 | if (event == OPN_ACPT) { | ||
1048 | rcu_read_unlock(); | ||
1049 | /* allocate sta entry if necessary and update info */ | ||
1050 | sta = mesh_sta_info_get(sdata, mgmt->sa, elems); | ||
1051 | if (!sta) { | ||
1052 | mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); | ||
1053 | goto unlock_rcu; | ||
1054 | } | ||
1055 | sta->plid = plid; | ||
1056 | } else if (!sta && event == OPN_RJCT) { | ||
1057 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | ||
1058 | mgmt->sa, 0, plid, | ||
1059 | WLAN_REASON_MESH_CONFIG); | ||
1060 | goto unlock_rcu; | ||
1061 | } else if (!sta || event == PLINK_UNDEFINED) { | ||
1062 | /* something went wrong */ | ||
1063 | goto unlock_rcu; | ||
1064 | } | ||
1065 | |||
1066 | changed |= mesh_plink_fsm(sdata, sta, event); | ||
1067 | |||
1068 | unlock_rcu: | ||
1076 | rcu_read_unlock(); | 1069 | rcu_read_unlock(); |
1077 | 1070 | ||
1078 | if (changed) | 1071 | if (changed) |
1079 | ieee80211_mbss_info_change_notify(sdata, changed); | 1072 | ieee80211_mbss_info_change_notify(sdata, changed); |
1080 | } | 1073 | } |
1074 | |||
1075 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | ||
1076 | struct ieee80211_mgmt *mgmt, size_t len, | ||
1077 | struct ieee80211_rx_status *rx_status) | ||
1078 | { | ||
1079 | struct ieee802_11_elems elems; | ||
1080 | size_t baselen; | ||
1081 | u8 *baseaddr; | ||
1082 | |||
1083 | /* need action_code, aux */ | ||
1084 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | ||
1085 | return; | ||
1086 | |||
1087 | if (sdata->u.mesh.user_mpm) | ||
1088 | /* userspace must register for these */ | ||
1089 | return; | ||
1090 | |||
1091 | if (is_multicast_ether_addr(mgmt->da)) { | ||
1092 | mpl_dbg(sdata, | ||
1093 | "Mesh plink: ignore frame from multicast address\n"); | ||
1094 | return; | ||
1095 | } | ||
1096 | |||
1097 | baseaddr = mgmt->u.action.u.self_prot.variable; | ||
1098 | baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; | ||
1099 | if (mgmt->u.action.u.self_prot.action_code == | ||
1100 | WLAN_SP_MESH_PEERING_CONFIRM) { | ||
1101 | baseaddr += 4; | ||
1102 | baselen += 4; | ||
1103 | } | ||
1104 | ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems); | ||
1105 | mesh_process_plink_frame(sdata, mgmt, &elems); | ||
1106 | } | ||
diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index 0f79b78b5e86..2802f9d9279d 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c | |||
@@ -576,10 +576,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta, | |||
576 | int ac, buffer_local = 0; | 576 | int ac, buffer_local = 0; |
577 | bool has_buffered = false; | 577 | bool has_buffered = false; |
578 | 578 | ||
579 | /* TIM map only for LLID <= IEEE80211_MAX_AID */ | ||
580 | if (sta->plink_state == NL80211_PLINK_ESTAB) | 579 | if (sta->plink_state == NL80211_PLINK_ESTAB) |
581 | has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, | 580 | has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, |
582 | le16_to_cpu(sta->llid) % IEEE80211_MAX_AID); | 581 | sta->llid); |
583 | 582 | ||
584 | if (has_buffered) | 583 | if (has_buffered) |
585 | mps_dbg(sta->sdata, "%pM indicates buffered frames\n", | 584 | mps_dbg(sta->sdata, "%pM indicates buffered frames\n", |
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 05a256b38e24..d1cf2d553499 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c | |||
@@ -92,12 +92,20 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
92 | if (stype != IEEE80211_STYPE_BEACON) | 92 | if (stype != IEEE80211_STYPE_BEACON) |
93 | return; | 93 | return; |
94 | 94 | ||
95 | /* The current tsf is a first approximation for the timestamp | 95 | /* |
96 | * for the received beacon. Further down we try to get a | 96 | * Get time when timestamp field was received. If we don't |
97 | * better value from the rx_status->mactime field if | 97 | * have rx timestamps, then use current tsf as an approximation. |
98 | * available. Also we have to call drv_get_tsf() before | 98 | * drv_get_tsf() must be called before entering the rcu-read |
99 | * entering the rcu-read section.*/ | 99 | * section. |
100 | t_r = drv_get_tsf(local, sdata); | 100 | */ |
101 | if (ieee80211_have_rx_timestamp(rx_status)) | ||
102 | t_r = ieee80211_calculate_rx_timestamp(local, rx_status, | ||
103 | 24 + 12 + | ||
104 | elems->total_len + | ||
105 | FCS_LEN, | ||
106 | 24); | ||
107 | else | ||
108 | t_r = drv_get_tsf(local, sdata); | ||
101 | 109 | ||
102 | rcu_read_lock(); | 110 | rcu_read_lock(); |
103 | sta = sta_info_get(sdata, mgmt->sa); | 111 | sta = sta_info_get(sdata, mgmt->sa); |
@@ -117,14 +125,6 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
117 | goto no_sync; | 125 | goto no_sync; |
118 | } | 126 | } |
119 | 127 | ||
120 | if (ieee80211_have_rx_timestamp(rx_status)) | ||
121 | /* time when timestamp field was received */ | ||
122 | t_r = ieee80211_calculate_rx_timestamp(local, rx_status, | ||
123 | 24 + 12 + | ||
124 | elems->total_len + | ||
125 | FCS_LEN, | ||
126 | 24); | ||
127 | |||
128 | /* Timing offset calculation (see 13.13.2.2.2) */ | 128 | /* Timing offset calculation (see 13.13.2.2.2) */ |
129 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); | 129 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); |
130 | sta->t_offset = t_t - t_r; | 130 | sta->t_offset = t_t - t_r; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d7504ab61a34..33bcf8018d8e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -330,6 +330,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
330 | if (WARN_ON_ONCE(!sta)) | 330 | if (WARN_ON_ONCE(!sta)) |
331 | return -EINVAL; | 331 | return -EINVAL; |
332 | 332 | ||
333 | /* | ||
334 | * if bss configuration changed store the new one - | ||
335 | * this may be applicable even if channel is identical | ||
336 | */ | ||
337 | ht_opmode = le16_to_cpu(ht_oper->operation_mode); | ||
338 | if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { | ||
339 | *changed |= BSS_CHANGED_HT; | ||
340 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | ||
341 | } | ||
342 | |||
333 | chan = sdata->vif.bss_conf.chandef.chan; | 343 | chan = sdata->vif.bss_conf.chandef.chan; |
334 | sband = local->hw.wiphy->bands[chan->band]; | 344 | sband = local->hw.wiphy->bands[chan->band]; |
335 | 345 | ||
@@ -416,14 +426,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
416 | IEEE80211_RC_BW_CHANGED); | 426 | IEEE80211_RC_BW_CHANGED); |
417 | } | 427 | } |
418 | 428 | ||
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; | 429 | return 0; |
428 | } | 430 | } |
429 | 431 | ||
@@ -714,7 +716,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
714 | } | 716 | } |
715 | 717 | ||
716 | /* if present, add any custom IEs that go before HT */ | 718 | /* if present, add any custom IEs that go before HT */ |
717 | if (assoc_data->ie_len && assoc_data->ie) { | 719 | if (assoc_data->ie_len) { |
718 | static const u8 before_ht[] = { | 720 | static const u8 before_ht[] = { |
719 | WLAN_EID_SSID, | 721 | WLAN_EID_SSID, |
720 | WLAN_EID_SUPP_RATES, | 722 | WLAN_EID_SUPP_RATES, |
@@ -748,7 +750,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
748 | &assoc_data->ap_vht_cap); | 750 | &assoc_data->ap_vht_cap); |
749 | 751 | ||
750 | /* if present, add any custom non-vendor IEs that go after HT */ | 752 | /* if present, add any custom non-vendor IEs that go after HT */ |
751 | if (assoc_data->ie_len && assoc_data->ie) { | 753 | if (assoc_data->ie_len) { |
752 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, | 754 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, |
753 | assoc_data->ie_len, | 755 | assoc_data->ie_len, |
754 | offset); | 756 | offset); |
@@ -779,7 +781,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
779 | } | 781 | } |
780 | 782 | ||
781 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 783 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
782 | if (assoc_data->ie_len && assoc_data->ie) { | 784 | if (assoc_data->ie_len) { |
783 | noffset = assoc_data->ie_len; | 785 | noffset = assoc_data->ie_len; |
784 | pos = skb_put(skb, noffset - offset); | 786 | pos = skb_put(skb, noffset - offset); |
785 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 787 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
@@ -886,8 +888,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
886 | if (!ifmgd->associated) | 888 | if (!ifmgd->associated) |
887 | goto out; | 889 | goto out; |
888 | 890 | ||
889 | ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef, | 891 | ret = ieee80211_vif_change_channel(sdata, &changed); |
890 | &changed); | ||
891 | if (ret) { | 892 | if (ret) { |
892 | sdata_info(sdata, | 893 | sdata_info(sdata, |
893 | "vif channel switch failed, disconnecting\n"); | 894 | "vif channel switch failed, disconnecting\n"); |
@@ -897,7 +898,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
897 | } | 898 | } |
898 | 899 | ||
899 | if (!local->use_chanctx) { | 900 | if (!local->use_chanctx) { |
900 | local->_oper_chandef = local->csa_chandef; | 901 | local->_oper_chandef = sdata->csa_chandef; |
901 | /* Call "hw_config" only if doing sw channel switch. | 902 | /* Call "hw_config" only if doing sw channel switch. |
902 | * Otherwise update the channel directly | 903 | * Otherwise update the channel directly |
903 | */ | 904 | */ |
@@ -908,7 +909,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
908 | } | 909 | } |
909 | 910 | ||
910 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 911 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
911 | ifmgd->associated->channel = local->csa_chandef.chan; | 912 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
912 | 913 | ||
913 | /* XXX: wait for a beacon first? */ | 914 | /* XXX: wait for a beacon first? */ |
914 | ieee80211_wake_queues_by_reason(&local->hw, | 915 | ieee80211_wake_queues_by_reason(&local->hw, |
@@ -1035,7 +1036,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1035 | } | 1036 | } |
1036 | mutex_unlock(&local->chanctx_mtx); | 1037 | mutex_unlock(&local->chanctx_mtx); |
1037 | 1038 | ||
1038 | local->csa_chandef = csa_ie.chandef; | 1039 | sdata->csa_chandef = csa_ie.chandef; |
1039 | 1040 | ||
1040 | if (csa_ie.mode) | 1041 | if (csa_ie.mode) |
1041 | ieee80211_stop_queues_by_reason(&local->hw, | 1042 | ieee80211_stop_queues_by_reason(&local->hw, |
@@ -1398,10 +1399,12 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) | |||
1398 | struct ieee80211_sub_if_data *sdata = | 1399 | struct ieee80211_sub_if_data *sdata = |
1399 | container_of(delayed_work, struct ieee80211_sub_if_data, | 1400 | container_of(delayed_work, struct ieee80211_sub_if_data, |
1400 | dfs_cac_timer_work); | 1401 | dfs_cac_timer_work); |
1402 | struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef; | ||
1401 | 1403 | ||
1402 | ieee80211_vif_release_channel(sdata); | 1404 | ieee80211_vif_release_channel(sdata); |
1403 | 1405 | cfg80211_cac_event(sdata->dev, &chandef, | |
1404 | cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); | 1406 | NL80211_RADAR_CAC_FINISHED, |
1407 | GFP_KERNEL); | ||
1405 | } | 1408 | } |
1406 | 1409 | ||
1407 | /* MLME */ | 1410 | /* MLME */ |
@@ -1745,6 +1748,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1745 | 1748 | ||
1746 | ifmgd->flags = 0; | 1749 | ifmgd->flags = 0; |
1747 | ieee80211_vif_release_channel(sdata); | 1750 | ieee80211_vif_release_channel(sdata); |
1751 | |||
1752 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
1748 | } | 1753 | } |
1749 | 1754 | ||
1750 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1755 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -4189,6 +4194,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4189 | 4194 | ||
4190 | sdata->control_port_protocol = req->crypto.control_port_ethertype; | 4195 | sdata->control_port_protocol = req->crypto.control_port_ethertype; |
4191 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; | 4196 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; |
4197 | sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto, | ||
4198 | sdata->vif.type); | ||
4192 | 4199 | ||
4193 | /* kick off associate process */ | 4200 | /* kick off associate process */ |
4194 | 4201 | ||
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 505bc0dea074..b95e16c07081 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -54,6 +54,8 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
54 | struct ieee80211_supported_band *sband; | 54 | struct ieee80211_supported_band *sband; |
55 | struct ieee80211_chanctx_conf *chanctx_conf; | 55 | struct ieee80211_chanctx_conf *chanctx_conf; |
56 | 56 | ||
57 | ieee80211_sta_set_rx_nss(sta); | ||
58 | |||
57 | if (!ref) | 59 | if (!ref) |
58 | return; | 60 | return; |
59 | 61 | ||
@@ -67,8 +69,6 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
67 | 69 | ||
68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; | 70 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; |
69 | 71 | ||
70 | ieee80211_sta_set_rx_nss(sta); | ||
71 | |||
72 | ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, | 72 | ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, |
73 | priv_sta); | 73 | priv_sta); |
74 | rcu_read_unlock(); | 74 | rcu_read_unlock(); |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 7fa1b36e6202..d2f19f7e7091 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -422,10 +422,9 @@ init_sample_table(struct minstrel_sta_info *mi) | |||
422 | memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); | 422 | memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); |
423 | 423 | ||
424 | for (col = 0; col < SAMPLE_COLUMNS; col++) { | 424 | for (col = 0; col < SAMPLE_COLUMNS; col++) { |
425 | prandom_bytes(rnd, sizeof(rnd)); | ||
425 | for (i = 0; i < mi->n_rates; i++) { | 426 | for (i = 0; i < mi->n_rates; i++) { |
426 | get_random_bytes(rnd, sizeof(rnd)); | ||
427 | new_idx = (i + rnd[i & 7]) % mi->n_rates; | 427 | new_idx = (i + rnd[i & 7]) % mi->n_rates; |
428 | |||
429 | while (SAMPLE_TBL(mi, new_idx, col) != 0xff) | 428 | while (SAMPLE_TBL(mi, new_idx, col) != 0xff) |
430 | new_idx = (new_idx + 1) % mi->n_rates; | 429 | new_idx = (new_idx + 1) % mi->n_rates; |
431 | 430 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 5d60779a0c1b..b91655a0d8f0 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -135,7 +135,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); | |||
135 | static int | 135 | static int |
136 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | 136 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) |
137 | { | 137 | { |
138 | return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1, | 138 | return GROUP_IDX((rate->idx / 8) + 1, |
139 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | 139 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), |
140 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); | 140 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); |
141 | } | 141 | } |
@@ -148,7 +148,7 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
148 | 148 | ||
149 | if (rate->flags & IEEE80211_TX_RC_MCS) { | 149 | if (rate->flags & IEEE80211_TX_RC_MCS) { |
150 | group = minstrel_ht_get_group_idx(rate); | 150 | group = minstrel_ht_get_group_idx(rate); |
151 | idx = rate->idx % MCS_GROUP_RATES; | 151 | idx = rate->idx % 8; |
152 | } else { | 152 | } else { |
153 | group = MINSTREL_CCK_GROUP; | 153 | group = MINSTREL_CCK_GROUP; |
154 | 154 | ||
@@ -636,8 +636,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
636 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | 636 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; |
637 | flags = 0; | 637 | flags = 0; |
638 | } else { | 638 | } else { |
639 | idx = index % MCS_GROUP_RATES + | 639 | idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; |
640 | (group->streams - 1) * MCS_GROUP_RATES; | ||
641 | flags = IEEE80211_TX_RC_MCS | group->flags; | 640 | flags = IEEE80211_TX_RC_MCS | group->flags; |
642 | } | 641 | } |
643 | 642 | ||
@@ -701,12 +700,16 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
701 | if (!mi->sample_tries) | 700 | if (!mi->sample_tries) |
702 | return -1; | 701 | return -1; |
703 | 702 | ||
704 | mg = &mi->groups[mi->sample_group]; | 703 | sample_group = mi->sample_group; |
704 | mg = &mi->groups[sample_group]; | ||
705 | sample_idx = sample_table[mg->column][mg->index]; | 705 | sample_idx = sample_table[mg->column][mg->index]; |
706 | minstrel_next_sample_idx(mi); | ||
707 | |||
708 | if (!(mg->supported & BIT(sample_idx))) | ||
709 | return -1; | ||
710 | |||
706 | mr = &mg->rates[sample_idx]; | 711 | mr = &mg->rates[sample_idx]; |
707 | sample_group = mi->sample_group; | ||
708 | sample_idx += sample_group * MCS_GROUP_RATES; | 712 | sample_idx += sample_group * MCS_GROUP_RATES; |
709 | minstrel_next_sample_idx(mi); | ||
710 | 713 | ||
711 | /* | 714 | /* |
712 | * Sampling might add some overhead (RTS, no aggregation) | 715 | * Sampling might add some overhead (RTS, no aggregation) |
@@ -817,7 +820,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
817 | } | 820 | } |
818 | 821 | ||
819 | rate->idx = sample_idx % MCS_GROUP_RATES + | 822 | rate->idx = sample_idx % MCS_GROUP_RATES + |
820 | (sample_group->streams - 1) * MCS_GROUP_RATES; | 823 | (sample_group->streams - 1) * 8; |
821 | rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; | 824 | rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; |
822 | } | 825 | } |
823 | 826 | ||
@@ -1052,10 +1055,9 @@ init_sample_table(void) | |||
1052 | 1055 | ||
1053 | memset(sample_table, 0xff, sizeof(sample_table)); | 1056 | memset(sample_table, 0xff, sizeof(sample_table)); |
1054 | for (col = 0; col < SAMPLE_COLUMNS; col++) { | 1057 | for (col = 0; col < SAMPLE_COLUMNS; col++) { |
1058 | prandom_bytes(rnd, sizeof(rnd)); | ||
1055 | for (i = 0; i < MCS_GROUP_RATES; i++) { | 1059 | for (i = 0; i < MCS_GROUP_RATES; i++) { |
1056 | get_random_bytes(rnd, sizeof(rnd)); | ||
1057 | new_idx = (i + rnd[i]) % MCS_GROUP_RATES; | 1060 | new_idx = (i + rnd[i]) % MCS_GROUP_RATES; |
1058 | |||
1059 | while (sample_table[col][new_idx] != 0xff) | 1061 | while (sample_table[col][new_idx] != 0xff) |
1060 | new_idx = (new_idx + 1) % MCS_GROUP_RATES; | 1062 | new_idx = (new_idx + 1) % MCS_GROUP_RATES; |
1061 | 1063 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index df44a5ad8270..3e7d793de0c3 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
@@ -54,8 +54,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
54 | int r = bitrates[j % 4]; | 54 | int r = bitrates[j % 4]; |
55 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); | 55 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); |
56 | } else { | 56 | } else { |
57 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * | 57 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); |
58 | MCS_GROUP_RATES + j); | ||
59 | } | 58 | } |
60 | 59 | ||
61 | tp = mr->cur_tp / 10; | 60 | tp = mr->cur_tp / 10; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index caecef870c0e..30ac6099da06 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -638,6 +638,27 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
638 | return le16_to_cpu(mmie->key_id); | 638 | return le16_to_cpu(mmie->key_id); |
639 | } | 639 | } |
640 | 640 | ||
641 | static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, | ||
642 | struct sk_buff *skb) | ||
643 | { | ||
644 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
645 | __le16 fc; | ||
646 | int hdrlen; | ||
647 | u8 keyid; | ||
648 | |||
649 | fc = hdr->frame_control; | ||
650 | hdrlen = ieee80211_hdrlen(fc); | ||
651 | |||
652 | if (skb->len < hdrlen + cs->hdr_len) | ||
653 | return -EINVAL; | ||
654 | |||
655 | skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1); | ||
656 | keyid &= cs->key_idx_mask; | ||
657 | keyid >>= cs->key_idx_shift; | ||
658 | |||
659 | return keyid; | ||
660 | } | ||
661 | |||
641 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | 662 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) |
642 | { | 663 | { |
643 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 664 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
@@ -729,9 +750,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata | |||
729 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 750 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
730 | 751 | ||
731 | while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 752 | while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
732 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, | 753 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
733 | tid_agg_rx->ssn) % | ||
734 | tid_agg_rx->buf_size; | ||
735 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 754 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
736 | frames); | 755 | frames); |
737 | } | 756 | } |
@@ -757,8 +776,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
757 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 776 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
758 | 777 | ||
759 | /* release the buffer until next missing frame */ | 778 | /* release the buffer until next missing frame */ |
760 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, | 779 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
761 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | ||
762 | if (!tid_agg_rx->reorder_buf[index] && | 780 | if (!tid_agg_rx->reorder_buf[index] && |
763 | tid_agg_rx->stored_mpdu_num) { | 781 | tid_agg_rx->stored_mpdu_num) { |
764 | /* | 782 | /* |
@@ -793,15 +811,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
793 | } else while (tid_agg_rx->reorder_buf[index]) { | 811 | } else while (tid_agg_rx->reorder_buf[index]) { |
794 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 812 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
795 | frames); | 813 | frames); |
796 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, | 814 | index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
797 | tid_agg_rx->ssn) % | ||
798 | tid_agg_rx->buf_size; | ||
799 | } | 815 | } |
800 | 816 | ||
801 | if (tid_agg_rx->stored_mpdu_num) { | 817 | if (tid_agg_rx->stored_mpdu_num) { |
802 | j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, | 818 | j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size; |
803 | tid_agg_rx->ssn) % | ||
804 | tid_agg_rx->buf_size; | ||
805 | 819 | ||
806 | for (; j != (index - 1) % tid_agg_rx->buf_size; | 820 | for (; j != (index - 1) % tid_agg_rx->buf_size; |
807 | j = (j + 1) % tid_agg_rx->buf_size) { | 821 | j = (j + 1) % tid_agg_rx->buf_size) { |
@@ -861,8 +875,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
861 | 875 | ||
862 | /* Now the new frame is always in the range of the reordering buffer */ | 876 | /* Now the new frame is always in the range of the reordering buffer */ |
863 | 877 | ||
864 | index = ieee80211_sn_sub(mpdu_seq_num, | 878 | index = mpdu_seq_num % tid_agg_rx->buf_size; |
865 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | ||
866 | 879 | ||
867 | /* check if we already stored this frame */ | 880 | /* check if we already stored this frame */ |
868 | if (tid_agg_rx->reorder_buf[index]) { | 881 | if (tid_agg_rx->reorder_buf[index]) { |
@@ -1368,6 +1381,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1368 | struct ieee80211_key *sta_ptk = NULL; | 1381 | struct ieee80211_key *sta_ptk = NULL; |
1369 | int mmie_keyidx = -1; | 1382 | int mmie_keyidx = -1; |
1370 | __le16 fc; | 1383 | __le16 fc; |
1384 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
1371 | 1385 | ||
1372 | /* | 1386 | /* |
1373 | * Key selection 101 | 1387 | * Key selection 101 |
@@ -1405,11 +1419,19 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1405 | 1419 | ||
1406 | /* start without a key */ | 1420 | /* start without a key */ |
1407 | rx->key = NULL; | 1421 | rx->key = NULL; |
1422 | fc = hdr->frame_control; | ||
1408 | 1423 | ||
1409 | if (rx->sta) | 1424 | if (rx->sta) { |
1410 | sta_ptk = rcu_dereference(rx->sta->ptk); | 1425 | int keyid = rx->sta->ptk_idx; |
1411 | 1426 | ||
1412 | fc = hdr->frame_control; | 1427 | if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) { |
1428 | cs = rx->sta->cipher_scheme; | ||
1429 | keyid = iwl80211_get_cs_keyid(cs, rx->skb); | ||
1430 | if (unlikely(keyid < 0)) | ||
1431 | return RX_DROP_UNUSABLE; | ||
1432 | } | ||
1433 | sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); | ||
1434 | } | ||
1413 | 1435 | ||
1414 | if (!ieee80211_has_protected(fc)) | 1436 | if (!ieee80211_has_protected(fc)) |
1415 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | 1437 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); |
@@ -1471,6 +1493,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1471 | return RX_CONTINUE; | 1493 | return RX_CONTINUE; |
1472 | } else { | 1494 | } else { |
1473 | u8 keyid; | 1495 | u8 keyid; |
1496 | |||
1474 | /* | 1497 | /* |
1475 | * The device doesn't give us the IV so we won't be | 1498 | * The device doesn't give us the IV so we won't be |
1476 | * able to look up the key. That's ok though, we | 1499 | * able to look up the key. That's ok though, we |
@@ -1486,15 +1509,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1486 | 1509 | ||
1487 | hdrlen = ieee80211_hdrlen(fc); | 1510 | hdrlen = ieee80211_hdrlen(fc); |
1488 | 1511 | ||
1489 | if (rx->skb->len < 8 + hdrlen) | 1512 | if (cs) { |
1490 | return RX_DROP_UNUSABLE; /* TODO: count this? */ | 1513 | keyidx = iwl80211_get_cs_keyid(cs, rx->skb); |
1491 | 1514 | ||
1492 | /* | 1515 | if (unlikely(keyidx < 0)) |
1493 | * no need to call ieee80211_wep_get_keyidx, | 1516 | return RX_DROP_UNUSABLE; |
1494 | * it verifies a bunch of things we've done already | 1517 | } else { |
1495 | */ | 1518 | if (rx->skb->len < 8 + hdrlen) |
1496 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | 1519 | return RX_DROP_UNUSABLE; /* TODO: count this? */ |
1497 | keyidx = keyid >> 6; | 1520 | /* |
1521 | * no need to call ieee80211_wep_get_keyidx, | ||
1522 | * it verifies a bunch of things we've done already | ||
1523 | */ | ||
1524 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | ||
1525 | keyidx = keyid >> 6; | ||
1526 | } | ||
1498 | 1527 | ||
1499 | /* check per-station GTK first, if multicast packet */ | 1528 | /* check per-station GTK first, if multicast packet */ |
1500 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) | 1529 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) |
@@ -1542,11 +1571,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1542 | result = ieee80211_crypto_aes_cmac_decrypt(rx); | 1571 | result = ieee80211_crypto_aes_cmac_decrypt(rx); |
1543 | break; | 1572 | break; |
1544 | default: | 1573 | default: |
1545 | /* | 1574 | result = ieee80211_crypto_hw_decrypt(rx); |
1546 | * We can reach here only with HW-only algorithms | ||
1547 | * but why didn't it decrypt the frame?! | ||
1548 | */ | ||
1549 | return RX_DROP_UNUSABLE; | ||
1550 | } | 1575 | } |
1551 | 1576 | ||
1552 | /* the hdr variable is invalid after the decrypt handlers */ | 1577 | /* the hdr variable is invalid after the decrypt handlers */ |
@@ -2056,7 +2081,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
2056 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 2081 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
2057 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 2082 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
2058 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2083 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2059 | __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD); | ||
2060 | u16 q, hdrlen; | 2084 | u16 q, hdrlen; |
2061 | 2085 | ||
2062 | hdr = (struct ieee80211_hdr *) skb->data; | 2086 | hdr = (struct ieee80211_hdr *) skb->data; |
@@ -2164,7 +2188,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
2164 | } else { | 2188 | } else { |
2165 | /* unable to resolve next hop */ | 2189 | /* unable to resolve next hop */ |
2166 | mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl, | 2190 | mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl, |
2167 | fwd_hdr->addr3, 0, reason, fwd_hdr->addr2); | 2191 | fwd_hdr->addr3, 0, |
2192 | WLAN_REASON_MESH_PATH_NOFORWARD, | ||
2193 | fwd_hdr->addr2); | ||
2168 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); | 2194 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); |
2169 | kfree_skb(fwd_skb); | 2195 | kfree_skb(fwd_skb); |
2170 | return RX_DROP_MONITOR; | 2196 | return RX_DROP_MONITOR; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5ad66a83ef7f..c22cbb57b49d 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -526,7 +526,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
526 | ieee80211_hw_config(local, 0); | 526 | ieee80211_hw_config(local, 0); |
527 | 527 | ||
528 | if ((req->channels[0]->flags & | 528 | if ((req->channels[0]->flags & |
529 | IEEE80211_CHAN_PASSIVE_SCAN) || | 529 | IEEE80211_CHAN_NO_IR) || |
530 | !local->scan_req->n_ssids) { | 530 | !local->scan_req->n_ssids) { |
531 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 531 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
532 | } else { | 532 | } else { |
@@ -572,7 +572,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) | |||
572 | * TODO: channel switching also consumes quite some time, | 572 | * TODO: channel switching also consumes quite some time, |
573 | * add that delay as well to get a better estimation | 573 | * add that delay as well to get a better estimation |
574 | */ | 574 | */ |
575 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 575 | if (chan->flags & IEEE80211_CHAN_NO_IR) |
576 | return IEEE80211_PASSIVE_CHANNEL_TIME; | 576 | return IEEE80211_PASSIVE_CHANNEL_TIME; |
577 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; | 577 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; |
578 | } | 578 | } |
@@ -696,7 +696,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
696 | * | 696 | * |
697 | * In any case, it is not necessary for a passive scan. | 697 | * In any case, it is not necessary for a passive scan. |
698 | */ | 698 | */ |
699 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || | 699 | if (chan->flags & IEEE80211_CHAN_NO_IR || |
700 | !local->scan_req->n_ssids) { | 700 | !local->scan_req->n_ssids) { |
701 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 701 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
702 | local->next_scan_state = SCAN_DECISION; | 702 | local->next_scan_state = SCAN_DECISION; |
@@ -881,7 +881,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | |||
881 | struct ieee80211_channel *tmp_ch = | 881 | struct ieee80211_channel *tmp_ch = |
882 | &local->hw.wiphy->bands[band]->channels[i]; | 882 | &local->hw.wiphy->bands[band]->channels[i]; |
883 | 883 | ||
884 | if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | | 884 | if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR | |
885 | IEEE80211_CHAN_DISABLED)) | 885 | IEEE80211_CHAN_DISABLED)) |
886 | continue; | 886 | continue; |
887 | 887 | ||
@@ -895,7 +895,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | |||
895 | 895 | ||
896 | local->int_scan_req->n_channels = n_ch; | 896 | local->int_scan_req->n_channels = n_ch; |
897 | } else { | 897 | } else { |
898 | if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | | 898 | if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR | |
899 | IEEE80211_CHAN_DISABLED))) | 899 | IEEE80211_CHAN_DISABLED))) |
900 | goto unlock; | 900 | goto unlock; |
901 | 901 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1eb66e26e49d..8ed97f76c3cf 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -266,9 +266,17 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, | |||
266 | */ | 266 | */ |
267 | void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) | 267 | void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) |
268 | { | 268 | { |
269 | int i; | ||
270 | |||
269 | if (sta->rate_ctrl) | 271 | if (sta->rate_ctrl) |
270 | rate_control_free_sta(sta); | 272 | rate_control_free_sta(sta); |
271 | 273 | ||
274 | if (sta->tx_lat) { | ||
275 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) | ||
276 | kfree(sta->tx_lat[i].bins); | ||
277 | kfree(sta->tx_lat); | ||
278 | } | ||
279 | |||
272 | sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); | 280 | sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); |
273 | 281 | ||
274 | kfree(sta); | 282 | kfree(sta); |
@@ -333,6 +341,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
333 | struct ieee80211_local *local = sdata->local; | 341 | struct ieee80211_local *local = sdata->local; |
334 | struct sta_info *sta; | 342 | struct sta_info *sta; |
335 | struct timespec uptime; | 343 | struct timespec uptime; |
344 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
336 | int i; | 345 | int i; |
337 | 346 | ||
338 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); | 347 | sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); |
@@ -410,6 +419,31 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
410 | } | 419 | } |
411 | } | 420 | } |
412 | 421 | ||
422 | rcu_read_lock(); | ||
423 | |||
424 | tx_latency = rcu_dereference(local->tx_latency); | ||
425 | /* init stations Tx latency statistics && TID bins */ | ||
426 | if (tx_latency) | ||
427 | sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS * | ||
428 | sizeof(struct ieee80211_tx_latency_stat), | ||
429 | GFP_ATOMIC); | ||
430 | |||
431 | /* | ||
432 | * if Tx latency and bins are enabled and the previous allocation | ||
433 | * succeeded | ||
434 | */ | ||
435 | if (tx_latency && tx_latency->n_ranges && sta->tx_lat) | ||
436 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | ||
437 | /* size of bins is size of the ranges +1 */ | ||
438 | sta->tx_lat[i].bin_count = | ||
439 | tx_latency->n_ranges + 1; | ||
440 | sta->tx_lat[i].bins = kcalloc(sta->tx_lat[i].bin_count, | ||
441 | sizeof(u32), | ||
442 | GFP_ATOMIC); | ||
443 | } | ||
444 | |||
445 | rcu_read_unlock(); | ||
446 | |||
413 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); | 447 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); |
414 | 448 | ||
415 | return sta; | 449 | return sta; |
@@ -507,6 +541,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
507 | 541 | ||
508 | set_sta_flag(sta, WLAN_STA_INSERTED); | 542 | set_sta_flag(sta, WLAN_STA_INSERTED); |
509 | 543 | ||
544 | ieee80211_recalc_min_chandef(sdata); | ||
510 | ieee80211_sta_debugfs_add(sta); | 545 | ieee80211_sta_debugfs_add(sta); |
511 | rate_control_add_sta_debugfs(sta); | 546 | rate_control_add_sta_debugfs(sta); |
512 | 547 | ||
@@ -630,8 +665,8 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
630 | #ifdef CONFIG_MAC80211_MESH | 665 | #ifdef CONFIG_MAC80211_MESH |
631 | } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | 666 | } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { |
632 | ps = &sta->sdata->u.mesh.ps; | 667 | ps = &sta->sdata->u.mesh.ps; |
633 | /* TIM map only for PLID <= IEEE80211_MAX_AID */ | 668 | /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */ |
634 | id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID; | 669 | id = sta->plid % (IEEE80211_MAX_AID + 1); |
635 | #endif | 670 | #endif |
636 | } else { | 671 | } else { |
637 | return; | 672 | return; |
@@ -869,6 +904,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
869 | 904 | ||
870 | rate_control_remove_sta_debugfs(sta); | 905 | rate_control_remove_sta_debugfs(sta); |
871 | ieee80211_sta_debugfs_remove(sta); | 906 | ieee80211_sta_debugfs_remove(sta); |
907 | ieee80211_recalc_min_chandef(sdata); | ||
872 | 908 | ||
873 | call_rcu(&sta->rcu_head, free_sta_rcu); | 909 | call_rcu(&sta->rcu_head, free_sta_rcu); |
874 | 910 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3ef06a26b9cb..0218caf5c14a 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -220,6 +220,25 @@ struct sta_ampdu_mlme { | |||
220 | u8 dialog_token_allocator; | 220 | u8 dialog_token_allocator; |
221 | }; | 221 | }; |
222 | 222 | ||
223 | /* | ||
224 | * struct ieee80211_tx_latency_stat - Tx latency statistics | ||
225 | * | ||
226 | * Measures TX latency and jitter for a station per TID. | ||
227 | * | ||
228 | * @max: worst case latency | ||
229 | * @sum: sum of all latencies | ||
230 | * @counter: amount of Tx frames sent from interface | ||
231 | * @bins: each bin counts how many frames transmitted within a certain | ||
232 | * latency range. when disabled it is NULL. | ||
233 | * @bin_count: amount of bins. | ||
234 | */ | ||
235 | struct ieee80211_tx_latency_stat { | ||
236 | u32 max; | ||
237 | u32 sum; | ||
238 | u32 counter; | ||
239 | u32 *bins; | ||
240 | u32 bin_count; | ||
241 | }; | ||
223 | 242 | ||
224 | /** | 243 | /** |
225 | * struct sta_info - STA information | 244 | * struct sta_info - STA information |
@@ -231,8 +250,10 @@ struct sta_ampdu_mlme { | |||
231 | * @hnext: hash table linked list pointer | 250 | * @hnext: hash table linked list pointer |
232 | * @local: pointer to the global information | 251 | * @local: pointer to the global information |
233 | * @sdata: virtual interface this station belongs to | 252 | * @sdata: virtual interface this station belongs to |
234 | * @ptk: peer key negotiated with this station, if any | 253 | * @ptk: peer keys negotiated with this station, if any |
254 | * @ptk_idx: last installed peer key index | ||
235 | * @gtk: group keys negotiated with this station, if any | 255 | * @gtk: group keys negotiated with this station, if any |
256 | * @gtk_idx: last installed group key index | ||
236 | * @rate_ctrl: rate control algorithm reference | 257 | * @rate_ctrl: rate control algorithm reference |
237 | * @rate_ctrl_priv: rate control private per-STA pointer | 258 | * @rate_ctrl_priv: rate control private per-STA pointer |
238 | * @last_tx_rate: rate used for last transmit, to report to userspace as | 259 | * @last_tx_rate: rate used for last transmit, to report to userspace as |
@@ -274,6 +295,7 @@ struct sta_ampdu_mlme { | |||
274 | * @tid_seq: per-TID sequence numbers for sending to this STA | 295 | * @tid_seq: per-TID sequence numbers for sending to this STA |
275 | * @ampdu_mlme: A-MPDU state machine state | 296 | * @ampdu_mlme: A-MPDU state machine state |
276 | * @timer_to_tid: identity mapping to ID timers | 297 | * @timer_to_tid: identity mapping to ID timers |
298 | * @tx_lat: Tx latency statistics | ||
277 | * @llid: Local link ID | 299 | * @llid: Local link ID |
278 | * @plid: Peer link ID | 300 | * @plid: Peer link ID |
279 | * @reason: Cancel reason on PLINK_HOLDING state | 301 | * @reason: Cancel reason on PLINK_HOLDING state |
@@ -303,6 +325,7 @@ struct sta_ampdu_mlme { | |||
303 | * @chain_signal_avg: signal average (per chain) | 325 | * @chain_signal_avg: signal average (per chain) |
304 | * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for | 326 | * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for |
305 | * AP only. | 327 | * AP only. |
328 | * @cipher_scheme: optional cipher scheme for this station | ||
306 | */ | 329 | */ |
307 | struct sta_info { | 330 | struct sta_info { |
308 | /* General information, mostly static */ | 331 | /* General information, mostly static */ |
@@ -312,7 +335,9 @@ struct sta_info { | |||
312 | struct ieee80211_local *local; | 335 | struct ieee80211_local *local; |
313 | struct ieee80211_sub_if_data *sdata; | 336 | struct ieee80211_sub_if_data *sdata; |
314 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; | 337 | struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; |
315 | struct ieee80211_key __rcu *ptk; | 338 | struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS]; |
339 | u8 gtk_idx; | ||
340 | u8 ptk_idx; | ||
316 | struct rate_control_ref *rate_ctrl; | 341 | struct rate_control_ref *rate_ctrl; |
317 | void *rate_ctrl_priv; | 342 | void *rate_ctrl_priv; |
318 | spinlock_t lock; | 343 | spinlock_t lock; |
@@ -380,14 +405,16 @@ struct sta_info { | |||
380 | struct sta_ampdu_mlme ampdu_mlme; | 405 | struct sta_ampdu_mlme ampdu_mlme; |
381 | u8 timer_to_tid[IEEE80211_NUM_TIDS]; | 406 | u8 timer_to_tid[IEEE80211_NUM_TIDS]; |
382 | 407 | ||
408 | struct ieee80211_tx_latency_stat *tx_lat; | ||
409 | |||
383 | #ifdef CONFIG_MAC80211_MESH | 410 | #ifdef CONFIG_MAC80211_MESH |
384 | /* | 411 | /* |
385 | * Mesh peer link attributes | 412 | * Mesh peer link attributes |
386 | * TODO: move to a sub-structure that is referenced with pointer? | 413 | * TODO: move to a sub-structure that is referenced with pointer? |
387 | */ | 414 | */ |
388 | __le16 llid; | 415 | u16 llid; |
389 | __le16 plid; | 416 | u16 plid; |
390 | __le16 reason; | 417 | u16 reason; |
391 | u8 plink_retries; | 418 | u8 plink_retries; |
392 | bool ignore_plink_timer; | 419 | bool ignore_plink_timer; |
393 | enum nl80211_plink_state plink_state; | 420 | enum nl80211_plink_state plink_state; |
@@ -414,6 +441,7 @@ struct sta_info { | |||
414 | unsigned int beacon_loss_count; | 441 | unsigned int beacon_loss_count; |
415 | 442 | ||
416 | enum ieee80211_smps_mode known_smps_mode; | 443 | enum ieee80211_smps_mode known_smps_mode; |
444 | const struct ieee80211_cipher_scheme *cipher_scheme; | ||
417 | 445 | ||
418 | /* keep last! */ | 446 | /* keep last! */ |
419 | struct ieee80211_sta sta; | 447 | struct ieee80211_sta sta; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 52a152b01b06..1ee85c402439 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/export.h> | 12 | #include <linux/export.h> |
13 | #include <linux/etherdevice.h> | 13 | #include <linux/etherdevice.h> |
14 | #include <linux/time.h> | ||
14 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
15 | #include <asm/unaligned.h> | 16 | #include <asm/unaligned.h> |
16 | #include "ieee80211_i.h" | 17 | #include "ieee80211_i.h" |
@@ -463,6 +464,77 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
463 | } | 464 | } |
464 | 465 | ||
465 | /* | 466 | /* |
467 | * Measure Tx frame completion and removal time for Tx latency statistics | ||
468 | * calculation. A single Tx frame latency should be measured from when it | ||
469 | * is entering the Kernel until we receive Tx complete confirmation indication | ||
470 | * and remove the skb. | ||
471 | */ | ||
472 | static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | ||
473 | struct sk_buff *skb, | ||
474 | struct sta_info *sta, | ||
475 | struct ieee80211_hdr *hdr) | ||
476 | { | ||
477 | ktime_t skb_dprt; | ||
478 | struct timespec dprt_time; | ||
479 | u32 msrmnt; | ||
480 | u16 tid; | ||
481 | u8 *qc; | ||
482 | int i, bin_range_count, bin_count; | ||
483 | u32 *bin_ranges; | ||
484 | __le16 fc; | ||
485 | struct ieee80211_tx_latency_stat *tx_lat; | ||
486 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
487 | ktime_t skb_arv = skb->tstamp; | ||
488 | |||
489 | tx_latency = rcu_dereference(local->tx_latency); | ||
490 | |||
491 | /* assert Tx latency stats are enabled & frame arrived when enabled */ | ||
492 | if (!tx_latency || !ktime_to_ns(skb_arv)) | ||
493 | return; | ||
494 | |||
495 | fc = hdr->frame_control; | ||
496 | |||
497 | if (!ieee80211_is_data(fc)) /* make sure it is a data frame */ | ||
498 | return; | ||
499 | |||
500 | /* get frame tid */ | ||
501 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
502 | qc = ieee80211_get_qos_ctl(hdr); | ||
503 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||
504 | } else { | ||
505 | tid = 0; | ||
506 | } | ||
507 | |||
508 | tx_lat = &sta->tx_lat[tid]; | ||
509 | |||
510 | ktime_get_ts(&dprt_time); /* time stamp completion time */ | ||
511 | skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec); | ||
512 | msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv)); | ||
513 | |||
514 | if (tx_lat->max < msrmnt) /* update stats */ | ||
515 | tx_lat->max = msrmnt; | ||
516 | tx_lat->counter++; | ||
517 | tx_lat->sum += msrmnt; | ||
518 | |||
519 | if (!tx_lat->bins) /* bins not activated */ | ||
520 | return; | ||
521 | |||
522 | /* count how many Tx frames transmitted with the appropriate latency */ | ||
523 | bin_range_count = tx_latency->n_ranges; | ||
524 | bin_ranges = tx_latency->ranges; | ||
525 | bin_count = tx_lat->bin_count; | ||
526 | |||
527 | for (i = 0; i < bin_range_count; i++) { | ||
528 | if (msrmnt <= bin_ranges[i]) { | ||
529 | tx_lat->bins[i]++; | ||
530 | break; | ||
531 | } | ||
532 | } | ||
533 | if (i == bin_range_count) /* msrmnt is bigger than the biggest range */ | ||
534 | tx_lat->bins[i]++; | ||
535 | } | ||
536 | |||
537 | /* | ||
466 | * Use a static threshold for now, best value to be determined | 538 | * Use a static threshold for now, best value to be determined |
467 | * by testing ... | 539 | * by testing ... |
468 | * Should it depend on: | 540 | * Should it depend on: |
@@ -620,6 +692,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
620 | 692 | ||
621 | if (acked) | 693 | if (acked) |
622 | sta->last_ack_signal = info->status.ack_signal; | 694 | sta->last_ack_signal = info->status.ack_signal; |
695 | |||
696 | /* | ||
697 | * Measure frame removal for tx latency | ||
698 | * statistics calculation | ||
699 | */ | ||
700 | ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr); | ||
623 | } | 701 | } |
624 | 702 | ||
625 | rcu_read_unlock(); | 703 | rcu_read_unlock(); |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index d4cee98533fd..e9ccf22f6dd9 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -41,14 +41,31 @@ | |||
41 | #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ | 41 | #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ |
42 | __entry->center_freq1, __entry->center_freq2 | 42 | __entry->center_freq1, __entry->center_freq2 |
43 | 43 | ||
44 | #define MIN_CHANDEF_ENTRY \ | ||
45 | __field(u32, min_control_freq) \ | ||
46 | __field(u32, min_chan_width) \ | ||
47 | __field(u32, min_center_freq1) \ | ||
48 | __field(u32, min_center_freq2) | ||
49 | |||
50 | #define MIN_CHANDEF_ASSIGN(c) \ | ||
51 | __entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \ | ||
52 | __entry->min_chan_width = (c)->width; \ | ||
53 | __entry->min_center_freq1 = (c)->center_freq1; \ | ||
54 | __entry->min_center_freq2 = (c)->center_freq2; | ||
55 | #define MIN_CHANDEF_PR_FMT " min_control:%d MHz min_width:%d min_center: %d/%d MHz" | ||
56 | #define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_chan_width, \ | ||
57 | __entry->min_center_freq1, __entry->min_center_freq2 | ||
58 | |||
44 | #define CHANCTX_ENTRY CHANDEF_ENTRY \ | 59 | #define CHANCTX_ENTRY CHANDEF_ENTRY \ |
60 | MIN_CHANDEF_ENTRY \ | ||
45 | __field(u8, rx_chains_static) \ | 61 | __field(u8, rx_chains_static) \ |
46 | __field(u8, rx_chains_dynamic) | 62 | __field(u8, rx_chains_dynamic) |
47 | #define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \ | 63 | #define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \ |
64 | MIN_CHANDEF_ASSIGN(&ctx->conf.min_def) \ | ||
48 | __entry->rx_chains_static = ctx->conf.rx_chains_static; \ | 65 | __entry->rx_chains_static = ctx->conf.rx_chains_static; \ |
49 | __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic | 66 | __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic |
50 | #define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d" | 67 | #define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT " chains:%d/%d" |
51 | #define CHANCTX_PR_ARG CHANDEF_PR_ARG, \ | 68 | #define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG, \ |
52 | __entry->rx_chains_static, __entry->rx_chains_dynamic | 69 | __entry->rx_chains_static, __entry->rx_chains_dynamic |
53 | 70 | ||
54 | 71 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c558b246ef00..6d59e21cdb9f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/bitmap.h> | 19 | #include <linux/bitmap.h> |
20 | #include <linux/rcupdate.h> | 20 | #include <linux/rcupdate.h> |
21 | #include <linux/export.h> | 21 | #include <linux/export.h> |
22 | #include <linux/time.h> | ||
22 | #include <net/net_namespace.h> | 23 | #include <net/net_namespace.h> |
23 | #include <net/ieee80211_radiotap.h> | 24 | #include <net/ieee80211_radiotap.h> |
24 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
@@ -557,7 +558,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
557 | 558 | ||
558 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) | 559 | if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) |
559 | tx->key = NULL; | 560 | tx->key = NULL; |
560 | else if (tx->sta && (key = rcu_dereference(tx->sta->ptk))) | 561 | else if (tx->sta && |
562 | (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]))) | ||
561 | tx->key = key; | 563 | tx->key = key; |
562 | else if (ieee80211_is_mgmt(hdr->frame_control) && | 564 | else if (ieee80211_is_mgmt(hdr->frame_control) && |
563 | is_multicast_ether_addr(hdr->addr1) && | 565 | is_multicast_ether_addr(hdr->addr1) && |
@@ -840,15 +842,16 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx, | |||
840 | rem -= fraglen; | 842 | rem -= fraglen; |
841 | tmp = dev_alloc_skb(local->tx_headroom + | 843 | tmp = dev_alloc_skb(local->tx_headroom + |
842 | frag_threshold + | 844 | frag_threshold + |
843 | IEEE80211_ENCRYPT_HEADROOM + | 845 | tx->sdata->encrypt_headroom + |
844 | IEEE80211_ENCRYPT_TAILROOM); | 846 | IEEE80211_ENCRYPT_TAILROOM); |
845 | if (!tmp) | 847 | if (!tmp) |
846 | return -ENOMEM; | 848 | return -ENOMEM; |
847 | 849 | ||
848 | __skb_queue_tail(&tx->skbs, tmp); | 850 | __skb_queue_tail(&tx->skbs, tmp); |
849 | 851 | ||
850 | skb_reserve(tmp, local->tx_headroom + | 852 | skb_reserve(tmp, |
851 | IEEE80211_ENCRYPT_HEADROOM); | 853 | local->tx_headroom + tx->sdata->encrypt_headroom); |
854 | |||
852 | /* copy control information */ | 855 | /* copy control information */ |
853 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); | 856 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); |
854 | 857 | ||
@@ -1485,7 +1488,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
1485 | 1488 | ||
1486 | headroom = local->tx_headroom; | 1489 | headroom = local->tx_headroom; |
1487 | if (may_encrypt) | 1490 | if (may_encrypt) |
1488 | headroom += IEEE80211_ENCRYPT_HEADROOM; | 1491 | headroom += sdata->encrypt_headroom; |
1489 | headroom -= skb_headroom(skb); | 1492 | headroom -= skb_headroom(skb); |
1490 | headroom = max_t(int, 0, headroom); | 1493 | headroom = max_t(int, 0, headroom); |
1491 | 1494 | ||
@@ -1724,8 +1727,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1724 | * radar detection by itself. We can do that later by adding a | 1727 | * radar detection by itself. We can do that later by adding a |
1725 | * monitor flag interfaces used for AP support. | 1728 | * monitor flag interfaces used for AP support. |
1726 | */ | 1729 | */ |
1727 | if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR | | 1730 | if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))) |
1728 | IEEE80211_CHAN_PASSIVE_SCAN))) | ||
1729 | goto fail_rcu; | 1731 | goto fail_rcu; |
1730 | 1732 | ||
1731 | ieee80211_xmit(sdata, skb, chan->band); | 1733 | ieee80211_xmit(sdata, skb, chan->band); |
@@ -1740,6 +1742,26 @@ fail: | |||
1740 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ | 1742 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ |
1741 | } | 1743 | } |
1742 | 1744 | ||
1745 | /* | ||
1746 | * Measure Tx frame arrival time for Tx latency statistics calculation | ||
1747 | * A single Tx frame latency should be measured from when it is entering the | ||
1748 | * Kernel until we receive Tx complete confirmation indication and the skb is | ||
1749 | * freed. | ||
1750 | */ | ||
1751 | static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | ||
1752 | struct sk_buff *skb) | ||
1753 | { | ||
1754 | struct timespec skb_arv; | ||
1755 | struct ieee80211_tx_latency_bin_ranges *tx_latency; | ||
1756 | |||
1757 | tx_latency = rcu_dereference(local->tx_latency); | ||
1758 | if (!tx_latency) | ||
1759 | return; | ||
1760 | |||
1761 | ktime_get_ts(&skb_arv); | ||
1762 | skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec); | ||
1763 | } | ||
1764 | |||
1743 | /** | 1765 | /** |
1744 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type | 1766 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type |
1745 | * subinterfaces (wlan#, WDS, and VLAN interfaces) | 1767 | * subinterfaces (wlan#, WDS, and VLAN interfaces) |
@@ -1790,6 +1812,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1790 | 1812 | ||
1791 | rcu_read_lock(); | 1813 | rcu_read_lock(); |
1792 | 1814 | ||
1815 | /* Measure frame arrival for Tx latency statistics calculation */ | ||
1816 | ieee80211_tx_latency_start_msrmnt(local, skb); | ||
1817 | |||
1793 | switch (sdata->vif.type) { | 1818 | switch (sdata->vif.type) { |
1794 | case NL80211_IFTYPE_AP_VLAN: | 1819 | case NL80211_IFTYPE_AP_VLAN: |
1795 | sta = rcu_dereference(sdata->u.vlan.sta); | 1820 | sta = rcu_dereference(sdata->u.vlan.sta); |
@@ -2109,7 +2134,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2109 | */ | 2134 | */ |
2110 | 2135 | ||
2111 | if (head_need > 0 || skb_cloned(skb)) { | 2136 | if (head_need > 0 || skb_cloned(skb)) { |
2112 | head_need += IEEE80211_ENCRYPT_HEADROOM; | 2137 | head_need += sdata->encrypt_headroom; |
2113 | head_need += local->tx_headroom; | 2138 | head_need += local->tx_headroom; |
2114 | head_need = max_t(int, 0, head_need); | 2139 | head_need = max_t(int, 0, head_need); |
2115 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2140 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 592a18171f95..06265d7f8cc3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1804,6 +1804,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) | |||
1804 | mutex_unlock(&local->chanctx_mtx); | 1804 | mutex_unlock(&local->chanctx_mtx); |
1805 | } | 1805 | } |
1806 | 1806 | ||
1807 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata) | ||
1808 | { | ||
1809 | struct ieee80211_local *local = sdata->local; | ||
1810 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
1811 | struct ieee80211_chanctx *chanctx; | ||
1812 | |||
1813 | mutex_lock(&local->chanctx_mtx); | ||
1814 | |||
1815 | chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1816 | lockdep_is_held(&local->chanctx_mtx)); | ||
1817 | |||
1818 | if (WARN_ON_ONCE(!chanctx_conf)) | ||
1819 | goto unlock; | ||
1820 | |||
1821 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | ||
1822 | ieee80211_recalc_chanctx_min_def(local, chanctx); | ||
1823 | unlock: | ||
1824 | mutex_unlock(&local->chanctx_mtx); | ||
1825 | } | ||
1826 | |||
1807 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | 1827 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) |
1808 | { | 1828 | { |
1809 | int i; | 1829 | int i; |
@@ -2259,14 +2279,17 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
2259 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) | 2279 | void ieee80211_dfs_cac_cancel(struct ieee80211_local *local) |
2260 | { | 2280 | { |
2261 | struct ieee80211_sub_if_data *sdata; | 2281 | struct ieee80211_sub_if_data *sdata; |
2282 | struct cfg80211_chan_def chandef; | ||
2262 | 2283 | ||
2263 | mutex_lock(&local->iflist_mtx); | 2284 | mutex_lock(&local->iflist_mtx); |
2264 | list_for_each_entry(sdata, &local->interfaces, list) { | 2285 | list_for_each_entry(sdata, &local->interfaces, list) { |
2265 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 2286 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); |
2266 | 2287 | ||
2267 | if (sdata->wdev.cac_started) { | 2288 | if (sdata->wdev.cac_started) { |
2289 | chandef = sdata->vif.bss_conf.chandef; | ||
2268 | ieee80211_vif_release_channel(sdata); | 2290 | ieee80211_vif_release_channel(sdata); |
2269 | cfg80211_cac_event(sdata->dev, | 2291 | cfg80211_cac_event(sdata->dev, |
2292 | &chandef, | ||
2270 | NL80211_RADAR_CAC_ABORTED, | 2293 | NL80211_RADAR_CAC_ABORTED, |
2271 | GFP_KERNEL); | 2294 | GFP_KERNEL); |
2272 | } | 2295 | } |
@@ -2447,7 +2470,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | |||
2447 | 2470 | ||
2448 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2471 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
2449 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 2472 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2450 | __le16 pre_value; | ||
2451 | 2473 | ||
2452 | skb_put(skb, 8); | 2474 | skb_put(skb, 8); |
2453 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */ | 2475 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; /* EID */ |
@@ -2463,8 +2485,7 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | |||
2463 | ifmsh->pre_value = 1; | 2485 | ifmsh->pre_value = 1; |
2464 | else | 2486 | else |
2465 | ifmsh->pre_value++; | 2487 | ifmsh->pre_value++; |
2466 | pre_value = cpu_to_le16(ifmsh->pre_value); | 2488 | put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */ |
2467 | memcpy(pos, &pre_value, 2); /* Precedence Value */ | ||
2468 | pos += 2; | 2489 | pos += 2; |
2469 | ifmsh->chsw_init = true; | 2490 | ifmsh->chsw_init = true; |
2470 | } | 2491 | } |
@@ -2472,3 +2493,71 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, | |||
2472 | ieee80211_tx_skb(sdata, skb); | 2493 | ieee80211_tx_skb(sdata, skb); |
2473 | return 0; | 2494 | return 0; |
2474 | } | 2495 | } |
2496 | |||
2497 | bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs) | ||
2498 | { | ||
2499 | return !(cs == NULL || cs->cipher == 0 || | ||
2500 | cs->hdr_len < cs->pn_len + cs->pn_off || | ||
2501 | cs->hdr_len <= cs->key_idx_off || | ||
2502 | cs->key_idx_shift > 7 || | ||
2503 | cs->key_idx_mask == 0); | ||
2504 | } | ||
2505 | |||
2506 | bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n) | ||
2507 | { | ||
2508 | int i; | ||
2509 | |||
2510 | /* Ensure we have enough iftype bitmap space for all iftype values */ | ||
2511 | WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype)); | ||
2512 | |||
2513 | for (i = 0; i < n; i++) | ||
2514 | if (!ieee80211_cs_valid(&cs[i])) | ||
2515 | return false; | ||
2516 | |||
2517 | return true; | ||
2518 | } | ||
2519 | |||
2520 | const struct ieee80211_cipher_scheme * | ||
2521 | ieee80211_cs_get(struct ieee80211_local *local, u32 cipher, | ||
2522 | enum nl80211_iftype iftype) | ||
2523 | { | ||
2524 | const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes; | ||
2525 | int n = local->hw.n_cipher_schemes; | ||
2526 | int i; | ||
2527 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
2528 | |||
2529 | for (i = 0; i < n; i++) { | ||
2530 | if (l[i].cipher == cipher) { | ||
2531 | cs = &l[i]; | ||
2532 | break; | ||
2533 | } | ||
2534 | } | ||
2535 | |||
2536 | if (!cs || !(cs->iftype & BIT(iftype))) | ||
2537 | return NULL; | ||
2538 | |||
2539 | return cs; | ||
2540 | } | ||
2541 | |||
2542 | int ieee80211_cs_headroom(struct ieee80211_local *local, | ||
2543 | struct cfg80211_crypto_settings *crypto, | ||
2544 | enum nl80211_iftype iftype) | ||
2545 | { | ||
2546 | const struct ieee80211_cipher_scheme *cs; | ||
2547 | int headroom = IEEE80211_ENCRYPT_HEADROOM; | ||
2548 | int i; | ||
2549 | |||
2550 | for (i = 0; i < crypto->n_ciphers_pairwise; i++) { | ||
2551 | cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i], | ||
2552 | iftype); | ||
2553 | |||
2554 | if (cs && headroom < cs->hdr_len) | ||
2555 | headroom = cs->hdr_len; | ||
2556 | } | ||
2557 | |||
2558 | cs = ieee80211_cs_get(local, crypto->cipher_group, iftype); | ||
2559 | if (cs && headroom < cs->hdr_len) | ||
2560 | headroom = cs->hdr_len; | ||
2561 | |||
2562 | return headroom; | ||
2563 | } | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index de0112785aae..d75f35c6e1a0 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -182,16 +182,15 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
182 | IEEE80211_VHT_CAP_SHORT_GI_160); | 182 | IEEE80211_VHT_CAP_SHORT_GI_160); |
183 | 183 | ||
184 | /* remaining ones */ | 184 | /* remaining ones */ |
185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { | 185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) |
186 | vht_cap->cap |= cap_info & | 186 | vht_cap->cap |= cap_info & |
187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | 187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | |
188 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); | 188 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); |
189 | } | ||
190 | 189 | ||
191 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) | 190 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) |
192 | vht_cap->cap |= cap_info & | 191 | vht_cap->cap |= cap_info & |
193 | (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | 192 | (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | |
194 | IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX); | 193 | IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK); |
195 | 194 | ||
196 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) | 195 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) |
197 | vht_cap->cap |= cap_info & | 196 | vht_cap->cap |= cap_info & |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index d65728220763..7313d379c0d3 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -545,6 +545,106 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
545 | return RX_CONTINUE; | 545 | return RX_CONTINUE; |
546 | } | 546 | } |
547 | 547 | ||
548 | static ieee80211_tx_result | ||
549 | ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | ||
550 | struct sk_buff *skb) | ||
551 | { | ||
552 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
553 | struct ieee80211_key *key = tx->key; | ||
554 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
555 | const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme; | ||
556 | int hdrlen; | ||
557 | u8 *pos; | ||
558 | |||
559 | if (info->control.hw_key && | ||
560 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { | ||
561 | /* hwaccel has no need for preallocated head room */ | ||
562 | return TX_CONTINUE; | ||
563 | } | ||
564 | |||
565 | if (unlikely(skb_headroom(skb) < cs->hdr_len && | ||
566 | pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC))) | ||
567 | return TX_DROP; | ||
568 | |||
569 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
570 | |||
571 | pos = skb_push(skb, cs->hdr_len); | ||
572 | memmove(pos, pos + cs->hdr_len, hdrlen); | ||
573 | skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); | ||
574 | |||
575 | return TX_CONTINUE; | ||
576 | } | ||
577 | |||
578 | static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len) | ||
579 | { | ||
580 | int i; | ||
581 | |||
582 | /* pn is little endian */ | ||
583 | for (i = len - 1; i >= 0; i--) { | ||
584 | if (pn1[i] < pn2[i]) | ||
585 | return -1; | ||
586 | else if (pn1[i] > pn2[i]) | ||
587 | return 1; | ||
588 | } | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static ieee80211_rx_result | ||
594 | ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx) | ||
595 | { | ||
596 | struct ieee80211_key *key = rx->key; | ||
597 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
598 | const struct ieee80211_cipher_scheme *cs = NULL; | ||
599 | int hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
600 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | ||
601 | int data_len; | ||
602 | u8 *rx_pn; | ||
603 | u8 *skb_pn; | ||
604 | u8 qos_tid; | ||
605 | |||
606 | if (!rx->sta || !rx->sta->cipher_scheme || | ||
607 | !(status->flag & RX_FLAG_DECRYPTED)) | ||
608 | return RX_DROP_UNUSABLE; | ||
609 | |||
610 | if (!ieee80211_is_data(hdr->frame_control)) | ||
611 | return RX_CONTINUE; | ||
612 | |||
613 | cs = rx->sta->cipher_scheme; | ||
614 | |||
615 | data_len = rx->skb->len - hdrlen - cs->hdr_len; | ||
616 | |||
617 | if (data_len < 0) | ||
618 | return RX_DROP_UNUSABLE; | ||
619 | |||
620 | if (ieee80211_is_data_qos(hdr->frame_control)) | ||
621 | qos_tid = *ieee80211_get_qos_ctl(hdr) & | ||
622 | IEEE80211_QOS_CTL_TID_MASK; | ||
623 | else | ||
624 | qos_tid = 0; | ||
625 | |||
626 | if (skb_linearize(rx->skb)) | ||
627 | return RX_DROP_UNUSABLE; | ||
628 | |||
629 | hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
630 | |||
631 | rx_pn = key->u.gen.rx_pn[qos_tid]; | ||
632 | skb_pn = rx->skb->data + hdrlen + cs->pn_off; | ||
633 | |||
634 | if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0) | ||
635 | return RX_DROP_UNUSABLE; | ||
636 | |||
637 | memcpy(rx_pn, skb_pn, cs->pn_len); | ||
638 | |||
639 | /* remove security header and MIC */ | ||
640 | if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len)) | ||
641 | return RX_DROP_UNUSABLE; | ||
642 | |||
643 | memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen); | ||
644 | skb_pull(rx->skb, cs->hdr_len); | ||
645 | |||
646 | return RX_CONTINUE; | ||
647 | } | ||
548 | 648 | ||
549 | static void bip_aad(struct sk_buff *skb, u8 *aad) | 649 | static void bip_aad(struct sk_buff *skb, u8 *aad) |
550 | { | 650 | { |
@@ -685,6 +785,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
685 | { | 785 | { |
686 | struct sk_buff *skb; | 786 | struct sk_buff *skb; |
687 | struct ieee80211_tx_info *info = NULL; | 787 | struct ieee80211_tx_info *info = NULL; |
788 | ieee80211_tx_result res; | ||
688 | 789 | ||
689 | skb_queue_walk(&tx->skbs, skb) { | 790 | skb_queue_walk(&tx->skbs, skb) { |
690 | info = IEEE80211_SKB_CB(skb); | 791 | info = IEEE80211_SKB_CB(skb); |
@@ -692,9 +793,24 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx) | |||
692 | /* handle hw-only algorithm */ | 793 | /* handle hw-only algorithm */ |
693 | if (!info->control.hw_key) | 794 | if (!info->control.hw_key) |
694 | return TX_DROP; | 795 | return TX_DROP; |
796 | |||
797 | if (tx->key->sta->cipher_scheme) { | ||
798 | res = ieee80211_crypto_cs_encrypt(tx, skb); | ||
799 | if (res != TX_CONTINUE) | ||
800 | return res; | ||
801 | } | ||
695 | } | 802 | } |
696 | 803 | ||
697 | ieee80211_tx_set_protected(tx); | 804 | ieee80211_tx_set_protected(tx); |
698 | 805 | ||
699 | return TX_CONTINUE; | 806 | return TX_CONTINUE; |
700 | } | 807 | } |
808 | |||
809 | ieee80211_rx_result | ||
810 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx) | ||
811 | { | ||
812 | if (rx->sta->cipher_scheme) | ||
813 | return ieee80211_crypto_cs_decrypt(rx); | ||
814 | |||
815 | return RX_DROP_UNUSABLE; | ||
816 | } | ||
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 07e33f899c71..62e5a12dfe0a 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h | |||
@@ -34,5 +34,7 @@ ieee80211_rx_result | |||
34 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); | 34 | ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx); |
35 | ieee80211_tx_result | 35 | ieee80211_tx_result |
36 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); | 36 | ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx); |
37 | ieee80211_rx_result | ||
38 | ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx); | ||
37 | 39 | ||
38 | #endif /* WPA_H */ | 40 | #endif /* WPA_H */ |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 9b8cc877eb19..78559b5bbd1f 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -277,6 +277,32 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy, | |||
277 | width, dfs_state); | 277 | width, dfs_state); |
278 | } | 278 | } |
279 | 279 | ||
280 | static u32 cfg80211_get_start_freq(u32 center_freq, | ||
281 | u32 bandwidth) | ||
282 | { | ||
283 | u32 start_freq; | ||
284 | |||
285 | if (bandwidth <= 20) | ||
286 | start_freq = center_freq; | ||
287 | else | ||
288 | start_freq = center_freq - bandwidth/2 + 10; | ||
289 | |||
290 | return start_freq; | ||
291 | } | ||
292 | |||
293 | static u32 cfg80211_get_end_freq(u32 center_freq, | ||
294 | u32 bandwidth) | ||
295 | { | ||
296 | u32 end_freq; | ||
297 | |||
298 | if (bandwidth <= 20) | ||
299 | end_freq = center_freq; | ||
300 | else | ||
301 | end_freq = center_freq + bandwidth/2 - 10; | ||
302 | |||
303 | return end_freq; | ||
304 | } | ||
305 | |||
280 | static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, | 306 | static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, |
281 | u32 center_freq, | 307 | u32 center_freq, |
282 | u32 bandwidth) | 308 | u32 bandwidth) |
@@ -284,13 +310,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, | |||
284 | struct ieee80211_channel *c; | 310 | struct ieee80211_channel *c; |
285 | u32 freq, start_freq, end_freq; | 311 | u32 freq, start_freq, end_freq; |
286 | 312 | ||
287 | if (bandwidth <= 20) { | 313 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); |
288 | start_freq = center_freq; | 314 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); |
289 | end_freq = center_freq; | ||
290 | } else { | ||
291 | start_freq = center_freq - bandwidth/2 + 10; | ||
292 | end_freq = center_freq + bandwidth/2 - 10; | ||
293 | } | ||
294 | 315 | ||
295 | for (freq = start_freq; freq <= end_freq; freq += 20) { | 316 | for (freq = start_freq; freq <= end_freq; freq += 20) { |
296 | c = ieee80211_get_channel(wiphy, freq); | 317 | c = ieee80211_get_channel(wiphy, freq); |
@@ -330,33 +351,159 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | |||
330 | } | 351 | } |
331 | EXPORT_SYMBOL(cfg80211_chandef_dfs_required); | 352 | EXPORT_SYMBOL(cfg80211_chandef_dfs_required); |
332 | 353 | ||
333 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | 354 | static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy, |
334 | u32 center_freq, u32 bandwidth, | 355 | u32 center_freq, |
335 | u32 prohibited_flags) | 356 | u32 bandwidth) |
336 | { | 357 | { |
337 | struct ieee80211_channel *c; | 358 | struct ieee80211_channel *c; |
338 | u32 freq, start_freq, end_freq; | 359 | u32 freq, start_freq, end_freq; |
360 | int count = 0; | ||
339 | 361 | ||
340 | if (bandwidth <= 20) { | 362 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); |
341 | start_freq = center_freq; | 363 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); |
342 | end_freq = center_freq; | 364 | |
343 | } else { | 365 | /* |
344 | start_freq = center_freq - bandwidth/2 + 10; | 366 | * Check entire range of channels for the bandwidth. |
345 | end_freq = center_freq + bandwidth/2 - 10; | 367 | * Check all channels are DFS channels (DFS_USABLE or |
368 | * DFS_AVAILABLE). Return number of usable channels | ||
369 | * (require CAC). Allow DFS and non-DFS channel mix. | ||
370 | */ | ||
371 | for (freq = start_freq; freq <= end_freq; freq += 20) { | ||
372 | c = ieee80211_get_channel(wiphy, freq); | ||
373 | if (!c) | ||
374 | return -EINVAL; | ||
375 | |||
376 | if (c->flags & IEEE80211_CHAN_DISABLED) | ||
377 | return -EINVAL; | ||
378 | |||
379 | if (c->flags & IEEE80211_CHAN_RADAR) { | ||
380 | if (c->dfs_state == NL80211_DFS_UNAVAILABLE) | ||
381 | return -EINVAL; | ||
382 | |||
383 | if (c->dfs_state == NL80211_DFS_USABLE) | ||
384 | count++; | ||
385 | } | ||
346 | } | 386 | } |
347 | 387 | ||
388 | return count; | ||
389 | } | ||
390 | |||
391 | bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, | ||
392 | const struct cfg80211_chan_def *chandef) | ||
393 | { | ||
394 | int width; | ||
395 | int r1, r2 = 0; | ||
396 | |||
397 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
398 | return false; | ||
399 | |||
400 | width = cfg80211_chandef_get_width(chandef); | ||
401 | if (width < 0) | ||
402 | return false; | ||
403 | |||
404 | r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1, | ||
405 | width); | ||
406 | |||
407 | if (r1 < 0) | ||
408 | return false; | ||
409 | |||
410 | switch (chandef->width) { | ||
411 | case NL80211_CHAN_WIDTH_80P80: | ||
412 | WARN_ON(!chandef->center_freq2); | ||
413 | r2 = cfg80211_get_chans_dfs_usable(wiphy, | ||
414 | chandef->center_freq2, | ||
415 | width); | ||
416 | if (r2 < 0) | ||
417 | return false; | ||
418 | break; | ||
419 | default: | ||
420 | WARN_ON(chandef->center_freq2); | ||
421 | break; | ||
422 | } | ||
423 | |||
424 | return (r1 + r2 > 0); | ||
425 | } | ||
426 | |||
427 | |||
428 | static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy, | ||
429 | u32 center_freq, | ||
430 | u32 bandwidth) | ||
431 | { | ||
432 | struct ieee80211_channel *c; | ||
433 | u32 freq, start_freq, end_freq; | ||
434 | |||
435 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); | ||
436 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); | ||
437 | |||
438 | /* | ||
439 | * Check entire range of channels for the bandwidth. | ||
440 | * If any channel in between is disabled or has not | ||
441 | * had gone through CAC return false | ||
442 | */ | ||
348 | for (freq = start_freq; freq <= end_freq; freq += 20) { | 443 | for (freq = start_freq; freq <= end_freq; freq += 20) { |
349 | c = ieee80211_get_channel(wiphy, freq); | 444 | c = ieee80211_get_channel(wiphy, freq); |
350 | if (!c) | 445 | if (!c) |
351 | return false; | 446 | return false; |
352 | 447 | ||
353 | /* check for radar flags */ | 448 | if (c->flags & IEEE80211_CHAN_DISABLED) |
354 | if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) && | 449 | return false; |
450 | |||
451 | if ((c->flags & IEEE80211_CHAN_RADAR) && | ||
355 | (c->dfs_state != NL80211_DFS_AVAILABLE)) | 452 | (c->dfs_state != NL80211_DFS_AVAILABLE)) |
356 | return false; | 453 | return false; |
454 | } | ||
455 | |||
456 | return true; | ||
457 | } | ||
458 | |||
459 | static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy, | ||
460 | const struct cfg80211_chan_def *chandef) | ||
461 | { | ||
462 | int width; | ||
463 | int r; | ||
464 | |||
465 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
466 | return false; | ||
467 | |||
468 | width = cfg80211_chandef_get_width(chandef); | ||
469 | if (width < 0) | ||
470 | return false; | ||
471 | |||
472 | r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1, | ||
473 | width); | ||
474 | |||
475 | /* If any of channels unavailable for cf1 just return */ | ||
476 | if (!r) | ||
477 | return r; | ||
478 | |||
479 | switch (chandef->width) { | ||
480 | case NL80211_CHAN_WIDTH_80P80: | ||
481 | WARN_ON(!chandef->center_freq2); | ||
482 | r = cfg80211_get_chans_dfs_available(wiphy, | ||
483 | chandef->center_freq2, | ||
484 | width); | ||
485 | default: | ||
486 | WARN_ON(chandef->center_freq2); | ||
487 | break; | ||
488 | } | ||
489 | |||
490 | return r; | ||
491 | } | ||
357 | 492 | ||
358 | /* check for the other flags */ | 493 | |
359 | if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR) | 494 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, |
495 | u32 center_freq, u32 bandwidth, | ||
496 | u32 prohibited_flags) | ||
497 | { | ||
498 | struct ieee80211_channel *c; | ||
499 | u32 freq, start_freq, end_freq; | ||
500 | |||
501 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); | ||
502 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); | ||
503 | |||
504 | for (freq = start_freq; freq <= end_freq; freq += 20) { | ||
505 | c = ieee80211_get_channel(wiphy, freq); | ||
506 | if (!c || c->flags & prohibited_flags) | ||
360 | return false; | 507 | return false; |
361 | } | 508 | } |
362 | 509 | ||
@@ -462,14 +609,19 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | |||
462 | struct cfg80211_chan_def *chandef) | 609 | struct cfg80211_chan_def *chandef) |
463 | { | 610 | { |
464 | bool res; | 611 | bool res; |
612 | u32 prohibited_flags = IEEE80211_CHAN_DISABLED | | ||
613 | IEEE80211_CHAN_NO_IR | | ||
614 | IEEE80211_CHAN_RADAR; | ||
465 | 615 | ||
466 | trace_cfg80211_reg_can_beacon(wiphy, chandef); | 616 | trace_cfg80211_reg_can_beacon(wiphy, chandef); |
467 | 617 | ||
468 | res = cfg80211_chandef_usable(wiphy, chandef, | 618 | if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 && |
469 | IEEE80211_CHAN_DISABLED | | 619 | cfg80211_chandef_dfs_available(wiphy, chandef)) { |
470 | IEEE80211_CHAN_PASSIVE_SCAN | | 620 | /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */ |
471 | IEEE80211_CHAN_NO_IBSS | | 621 | prohibited_flags = IEEE80211_CHAN_DISABLED; |
472 | IEEE80211_CHAN_RADAR); | 622 | } |
623 | |||
624 | res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags); | ||
473 | 625 | ||
474 | trace_cfg80211_return_bool(res); | 626 | trace_cfg80211_return_bool(res); |
475 | return res; | 627 | return res; |
@@ -510,6 +662,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
510 | : CHAN_MODE_EXCLUSIVE; | 662 | : CHAN_MODE_EXCLUSIVE; |
511 | return; | 663 | return; |
512 | } | 664 | } |
665 | break; | ||
513 | case NL80211_IFTYPE_STATION: | 666 | case NL80211_IFTYPE_STATION: |
514 | case NL80211_IFTYPE_P2P_CLIENT: | 667 | case NL80211_IFTYPE_P2P_CLIENT: |
515 | if (wdev->current_bss) { | 668 | if (wdev->current_bss) { |
diff --git a/net/wireless/core.c b/net/wireless/core.c index aff959e5a1b3..fc968c861ee4 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -357,8 +357,6 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
357 | rdev->wiphy.rts_threshold = (u32) -1; | 357 | rdev->wiphy.rts_threshold = (u32) -1; |
358 | rdev->wiphy.coverage_class = 0; | 358 | rdev->wiphy.coverage_class = 0; |
359 | 359 | ||
360 | rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH; | ||
361 | |||
362 | return &rdev->wiphy; | 360 | return &rdev->wiphy; |
363 | } | 361 | } |
364 | EXPORT_SYMBOL(wiphy_new); | 362 | EXPORT_SYMBOL(wiphy_new); |
@@ -566,6 +564,8 @@ int wiphy_register(struct wiphy *wiphy) | |||
566 | /* check and set up bitrates */ | 564 | /* check and set up bitrates */ |
567 | ieee80211_set_bitrate_flags(wiphy); | 565 | ieee80211_set_bitrate_flags(wiphy); |
568 | 566 | ||
567 | rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH; | ||
568 | |||
569 | rtnl_lock(); | 569 | rtnl_lock(); |
570 | res = device_add(&rdev->wiphy.dev); | 570 | res = device_add(&rdev->wiphy.dev); |
571 | if (res) { | 571 | if (res) { |
@@ -586,7 +586,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
586 | if (IS_ERR(rdev->wiphy.debugfsdir)) | 586 | if (IS_ERR(rdev->wiphy.debugfsdir)) |
587 | rdev->wiphy.debugfsdir = NULL; | 587 | rdev->wiphy.debugfsdir = NULL; |
588 | 588 | ||
589 | if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { | 589 | if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { |
590 | struct regulatory_request request; | 590 | struct regulatory_request request; |
591 | 591 | ||
592 | request.wiphy_idx = get_wiphy_idx(wiphy); | 592 | request.wiphy_idx = get_wiphy_idx(wiphy); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index af10e59af2d8..0a277c33bb02 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -317,9 +317,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); | |||
317 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); | 317 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
318 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 318 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
319 | struct wireless_dev *wdev, | 319 | struct wireless_dev *wdev, |
320 | struct ieee80211_channel *chan, bool offchan, | 320 | struct cfg80211_mgmt_tx_params *params, |
321 | unsigned int wait, const u8 *buf, size_t len, | 321 | u64 *cookie); |
322 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); | ||
323 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | 322 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, |
324 | const struct ieee80211_ht_cap *ht_capa_mask); | 323 | const struct ieee80211_ht_cap *ht_capa_mask); |
325 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | 324 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, |
@@ -382,6 +381,19 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
382 | enum cfg80211_chan_mode chanmode, | 381 | enum cfg80211_chan_mode chanmode, |
383 | u8 radar_detect); | 382 | u8 radar_detect); |
384 | 383 | ||
384 | /** | ||
385 | * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable | ||
386 | * @wiphy: the wiphy to validate against | ||
387 | * @chandef: the channel definition to check | ||
388 | * | ||
389 | * Checks if chandef is usable and we can/need start CAC on such channel. | ||
390 | * | ||
391 | * Return: Return true if all channels available and at least | ||
392 | * one channel require CAC (NL80211_DFS_USABLE) | ||
393 | */ | ||
394 | bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, | ||
395 | const struct cfg80211_chan_def *chandef); | ||
396 | |||
385 | void cfg80211_set_dfs_state(struct wiphy *wiphy, | 397 | void cfg80211_set_dfs_state(struct wiphy *wiphy, |
386 | const struct cfg80211_chan_def *chandef, | 398 | const struct cfg80211_chan_def *chandef, |
387 | enum nl80211_dfs_state dfs_state); | 399 | enum nl80211_dfs_state dfs_state); |
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 42ed274e81f4..9a8217d2a908 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk | |||
@@ -33,15 +33,7 @@ BEGIN { | |||
33 | regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" | 33 | regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" |
34 | } | 34 | } |
35 | 35 | ||
36 | /^[ \t]*#/ { | 36 | function parse_country_head() { |
37 | # Ignore | ||
38 | } | ||
39 | |||
40 | !active && /^[ \t]*$/ { | ||
41 | # Ignore | ||
42 | } | ||
43 | |||
44 | !active && /country/ { | ||
45 | country=$2 | 37 | country=$2 |
46 | sub(/:/, "", country) | 38 | sub(/:/, "", country) |
47 | printf "static const struct ieee80211_regdomain regdom_%s = {\n", country | 39 | printf "static const struct ieee80211_regdomain regdom_%s = {\n", country |
@@ -57,7 +49,8 @@ BEGIN { | |||
57 | regdb = regdb "\t®dom_" country ",\n" | 49 | regdb = regdb "\t®dom_" country ",\n" |
58 | } | 50 | } |
59 | 51 | ||
60 | active && /^[ \t]*\(/ { | 52 | function parse_reg_rule() |
53 | { | ||
61 | start = $1 | 54 | start = $1 |
62 | sub(/\(/, "", start) | 55 | sub(/\(/, "", start) |
63 | end = $3 | 56 | end = $3 |
@@ -107,17 +100,21 @@ active && /^[ \t]*\(/ { | |||
107 | } else if (flagarray[arg] == "PTMP-ONLY") { | 100 | } else if (flagarray[arg] == "PTMP-ONLY") { |
108 | flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " | 101 | flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " |
109 | } else if (flagarray[arg] == "PASSIVE-SCAN") { | 102 | } else if (flagarray[arg] == "PASSIVE-SCAN") { |
110 | flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | " | 103 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " |
111 | } else if (flagarray[arg] == "NO-IBSS") { | 104 | } else if (flagarray[arg] == "NO-IBSS") { |
112 | flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | " | 105 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " |
106 | } else if (flagarray[arg] == "NO-IR") { | ||
107 | flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " | ||
113 | } | 108 | } |
109 | |||
114 | } | 110 | } |
115 | flags = flags "0" | 111 | flags = flags "0" |
116 | printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags | 112 | printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags |
117 | rules++ | 113 | rules++ |
118 | } | 114 | } |
119 | 115 | ||
120 | active && /^[ \t]*$/ { | 116 | function print_tail_country() |
117 | { | ||
121 | active = 0 | 118 | active = 0 |
122 | printf "\t},\n" | 119 | printf "\t},\n" |
123 | printf "\t.n_reg_rules = %d\n", rules | 120 | printf "\t.n_reg_rules = %d\n", rules |
@@ -125,7 +122,29 @@ active && /^[ \t]*$/ { | |||
125 | rules = 0; | 122 | rules = 0; |
126 | } | 123 | } |
127 | 124 | ||
125 | /^[ \t]*#/ { | ||
126 | # Ignore | ||
127 | } | ||
128 | |||
129 | !active && /^[ \t]*$/ { | ||
130 | # Ignore | ||
131 | } | ||
132 | |||
133 | !active && /country/ { | ||
134 | parse_country_head() | ||
135 | } | ||
136 | |||
137 | active && /^[ \t]*\(/ { | ||
138 | parse_reg_rule() | ||
139 | } | ||
140 | |||
141 | active && /^[ \t]*$/ { | ||
142 | print_tail_country() | ||
143 | } | ||
144 | |||
128 | END { | 145 | END { |
146 | if (active) | ||
147 | print_tail_country() | ||
129 | print regdb "};" | 148 | print regdb "};" |
130 | print "" | 149 | print "" |
131 | print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" | 150 | print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);" |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 9d797df56649..f79105712949 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -274,7 +274,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
274 | 274 | ||
275 | for (i = 0; i < sband->n_channels; i++) { | 275 | for (i = 0; i < sband->n_channels; i++) { |
276 | chan = &sband->channels[i]; | 276 | chan = &sband->channels[i]; |
277 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) | 277 | if (chan->flags & IEEE80211_CHAN_NO_IR) |
278 | continue; | 278 | continue; |
279 | if (chan->flags & IEEE80211_CHAN_DISABLED) | 279 | if (chan->flags & IEEE80211_CHAN_DISABLED) |
280 | continue; | 280 | continue; |
@@ -345,7 +345,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
345 | chan = ieee80211_get_channel(wdev->wiphy, freq); | 345 | chan = ieee80211_get_channel(wdev->wiphy, freq); |
346 | if (!chan) | 346 | if (!chan) |
347 | return -EINVAL; | 347 | return -EINVAL; |
348 | if (chan->flags & IEEE80211_CHAN_NO_IBSS || | 348 | if (chan->flags & IEEE80211_CHAN_NO_IR || |
349 | chan->flags & IEEE80211_CHAN_DISABLED) | 349 | chan->flags & IEEE80211_CHAN_DISABLED) |
350 | return -EINVAL; | 350 | return -EINVAL; |
351 | } | 351 | } |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 0553fd4d85ae..b0e1869de7de 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -141,8 +141,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
141 | 141 | ||
142 | for (i = 0; i < sband->n_channels; i++) { | 142 | for (i = 0; i < sband->n_channels; i++) { |
143 | chan = &sband->channels[i]; | 143 | chan = &sband->channels[i]; |
144 | if (chan->flags & (IEEE80211_CHAN_NO_IBSS | | 144 | if (chan->flags & (IEEE80211_CHAN_NO_IR | |
145 | IEEE80211_CHAN_PASSIVE_SCAN | | ||
146 | IEEE80211_CHAN_DISABLED | | 145 | IEEE80211_CHAN_DISABLED | |
147 | IEEE80211_CHAN_RADAR)) | 146 | IEEE80211_CHAN_RADAR)) |
148 | continue; | 147 | continue; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 6a6b1c8e907d..52cca05044a8 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -520,9 +520,7 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) | |||
520 | 520 | ||
521 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | 521 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
522 | struct wireless_dev *wdev, | 522 | struct wireless_dev *wdev, |
523 | struct ieee80211_channel *chan, bool offchan, | 523 | struct cfg80211_mgmt_tx_params *params, u64 *cookie) |
524 | unsigned int wait, const u8 *buf, size_t len, | ||
525 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
526 | { | 524 | { |
527 | const struct ieee80211_mgmt *mgmt; | 525 | const struct ieee80211_mgmt *mgmt; |
528 | u16 stype; | 526 | u16 stype; |
@@ -533,10 +531,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
533 | if (!rdev->ops->mgmt_tx) | 531 | if (!rdev->ops->mgmt_tx) |
534 | return -EOPNOTSUPP; | 532 | return -EOPNOTSUPP; |
535 | 533 | ||
536 | if (len < 24 + 1) | 534 | if (params->len < 24 + 1) |
537 | return -EINVAL; | 535 | return -EINVAL; |
538 | 536 | ||
539 | mgmt = (const struct ieee80211_mgmt *) buf; | 537 | mgmt = (const struct ieee80211_mgmt *)params->buf; |
540 | 538 | ||
541 | if (!ieee80211_is_mgmt(mgmt->frame_control)) | 539 | if (!ieee80211_is_mgmt(mgmt->frame_control)) |
542 | return -EINVAL; | 540 | return -EINVAL; |
@@ -615,9 +613,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
615 | return -EINVAL; | 613 | return -EINVAL; |
616 | 614 | ||
617 | /* Transmit the Action frame as requested by user space */ | 615 | /* Transmit the Action frame as requested by user space */ |
618 | return rdev_mgmt_tx(rdev, wdev, chan, offchan, | 616 | return rdev_mgmt_tx(rdev, wdev, params, cookie); |
619 | wait, buf, len, no_cck, dont_wait_for_ack, | ||
620 | cookie); | ||
621 | } | 617 | } |
622 | 618 | ||
623 | bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, | 619 | bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, |
@@ -763,12 +759,12 @@ void cfg80211_radar_event(struct wiphy *wiphy, | |||
763 | EXPORT_SYMBOL(cfg80211_radar_event); | 759 | EXPORT_SYMBOL(cfg80211_radar_event); |
764 | 760 | ||
765 | void cfg80211_cac_event(struct net_device *netdev, | 761 | void cfg80211_cac_event(struct net_device *netdev, |
762 | const struct cfg80211_chan_def *chandef, | ||
766 | enum nl80211_radar_event event, gfp_t gfp) | 763 | enum nl80211_radar_event event, gfp_t gfp) |
767 | { | 764 | { |
768 | struct wireless_dev *wdev = netdev->ieee80211_ptr; | 765 | struct wireless_dev *wdev = netdev->ieee80211_ptr; |
769 | struct wiphy *wiphy = wdev->wiphy; | 766 | struct wiphy *wiphy = wdev->wiphy; |
770 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 767 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
771 | struct cfg80211_chan_def chandef; | ||
772 | unsigned long timeout; | 768 | unsigned long timeout; |
773 | 769 | ||
774 | trace_cfg80211_cac_event(netdev, event); | 770 | trace_cfg80211_cac_event(netdev, event); |
@@ -779,14 +775,12 @@ void cfg80211_cac_event(struct net_device *netdev, | |||
779 | if (WARN_ON(!wdev->channel)) | 775 | if (WARN_ON(!wdev->channel)) |
780 | return; | 776 | return; |
781 | 777 | ||
782 | cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT); | ||
783 | |||
784 | switch (event) { | 778 | switch (event) { |
785 | case NL80211_RADAR_CAC_FINISHED: | 779 | case NL80211_RADAR_CAC_FINISHED: |
786 | timeout = wdev->cac_start_time + | 780 | timeout = wdev->cac_start_time + |
787 | msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | 781 | msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); |
788 | WARN_ON(!time_after_eq(jiffies, timeout)); | 782 | WARN_ON(!time_after_eq(jiffies, timeout)); |
789 | cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE); | 783 | cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); |
790 | break; | 784 | break; |
791 | case NL80211_RADAR_CAC_ABORTED: | 785 | case NL80211_RADAR_CAC_ABORTED: |
792 | break; | 786 | break; |
@@ -796,6 +790,6 @@ void cfg80211_cac_event(struct net_device *netdev, | |||
796 | } | 790 | } |
797 | wdev->cac_started = false; | 791 | wdev->cac_started = false; |
798 | 792 | ||
799 | nl80211_radar_notify(rdev, &chandef, event, netdev, gfp); | 793 | nl80211_radar_notify(rdev, chandef, event, netdev, gfp); |
800 | } | 794 | } |
801 | EXPORT_SYMBOL(cfg80211_cac_event); | 795 | EXPORT_SYMBOL(cfg80211_cac_event); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a1eb21073176..efaa23e562b4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -564,12 +564,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
564 | if ((chan->flags & IEEE80211_CHAN_DISABLED) && | 564 | if ((chan->flags & IEEE80211_CHAN_DISABLED) && |
565 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED)) | 565 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED)) |
566 | goto nla_put_failure; | 566 | goto nla_put_failure; |
567 | if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) && | 567 | if (chan->flags & IEEE80211_CHAN_NO_IR) { |
568 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN)) | 568 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR)) |
569 | goto nla_put_failure; | 569 | goto nla_put_failure; |
570 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && | 570 | if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS)) |
571 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) | 571 | goto nla_put_failure; |
572 | goto nla_put_failure; | 572 | } |
573 | if (chan->flags & IEEE80211_CHAN_RADAR) { | 573 | if (chan->flags & IEEE80211_CHAN_RADAR) { |
574 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | 574 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) |
575 | goto nla_put_failure; | 575 | goto nla_put_failure; |
@@ -1247,10 +1247,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1247 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && | 1247 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && |
1248 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) | 1248 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) |
1249 | goto nla_put_failure; | 1249 | goto nla_put_failure; |
1250 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && | ||
1251 | nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ)) | ||
1252 | goto nla_put_failure; | ||
1253 | |||
1254 | state->split_start++; | 1250 | state->split_start++; |
1255 | if (state->split) | 1251 | if (state->split) |
1256 | break; | 1252 | break; |
@@ -1579,6 +1575,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1579 | if (nl80211_send_coalesce(msg, dev)) | 1575 | if (nl80211_send_coalesce(msg, dev)) |
1580 | goto nla_put_failure; | 1576 | goto nla_put_failure; |
1581 | 1577 | ||
1578 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) && | ||
1579 | (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || | ||
1580 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) | ||
1581 | goto nla_put_failure; | ||
1582 | |||
1582 | /* done */ | 1583 | /* done */ |
1583 | state->split_start = 0; | 1584 | state->split_start = 0; |
1584 | break; | 1585 | break; |
@@ -2187,7 +2188,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev) | |||
2187 | } | 2188 | } |
2188 | 2189 | ||
2189 | static int nl80211_send_chandef(struct sk_buff *msg, | 2190 | static int nl80211_send_chandef(struct sk_buff *msg, |
2190 | struct cfg80211_chan_def *chandef) | 2191 | const struct cfg80211_chan_def *chandef) |
2191 | { | 2192 | { |
2192 | WARN_ON(!cfg80211_chandef_valid(chandef)); | 2193 | WARN_ON(!cfg80211_chandef_valid(chandef)); |
2193 | 2194 | ||
@@ -3236,6 +3237,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3236 | return PTR_ERR(params.acl); | 3237 | return PTR_ERR(params.acl); |
3237 | } | 3238 | } |
3238 | 3239 | ||
3240 | wdev_lock(wdev); | ||
3239 | err = rdev_start_ap(rdev, dev, ¶ms); | 3241 | err = rdev_start_ap(rdev, dev, ¶ms); |
3240 | if (!err) { | 3242 | if (!err) { |
3241 | wdev->preset_chandef = params.chandef; | 3243 | wdev->preset_chandef = params.chandef; |
@@ -3244,6 +3246,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3244 | wdev->ssid_len = params.ssid_len; | 3246 | wdev->ssid_len = params.ssid_len; |
3245 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); | 3247 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); |
3246 | } | 3248 | } |
3249 | wdev_unlock(wdev); | ||
3247 | 3250 | ||
3248 | kfree(params.acl); | 3251 | kfree(params.acl); |
3249 | 3252 | ||
@@ -3272,7 +3275,11 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info) | |||
3272 | if (err) | 3275 | if (err) |
3273 | return err; | 3276 | return err; |
3274 | 3277 | ||
3275 | return rdev_change_beacon(rdev, dev, ¶ms); | 3278 | wdev_lock(wdev); |
3279 | err = rdev_change_beacon(rdev, dev, ¶ms); | ||
3280 | wdev_unlock(wdev); | ||
3281 | |||
3282 | return err; | ||
3276 | } | 3283 | } |
3277 | 3284 | ||
3278 | static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | 3285 | static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) |
@@ -4478,7 +4485,9 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
4478 | { | 4485 | { |
4479 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4486 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4480 | struct net_device *dev = info->user_ptr[1]; | 4487 | struct net_device *dev = info->user_ptr[1]; |
4488 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
4481 | struct bss_parameters params; | 4489 | struct bss_parameters params; |
4490 | int err; | ||
4482 | 4491 | ||
4483 | memset(¶ms, 0, sizeof(params)); | 4492 | memset(¶ms, 0, sizeof(params)); |
4484 | /* default to not changing parameters */ | 4493 | /* default to not changing parameters */ |
@@ -4544,7 +4553,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
4544 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 4553 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
4545 | return -EOPNOTSUPP; | 4554 | return -EOPNOTSUPP; |
4546 | 4555 | ||
4547 | return rdev_change_bss(rdev, dev, ¶ms); | 4556 | wdev_lock(wdev); |
4557 | err = rdev_change_bss(rdev, dev, ¶ms); | ||
4558 | wdev_unlock(wdev); | ||
4559 | |||
4560 | return err; | ||
4548 | } | 4561 | } |
4549 | 4562 | ||
4550 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | 4563 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { |
@@ -5098,7 +5111,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
5098 | char *alpha2 = NULL; | 5111 | char *alpha2 = NULL; |
5099 | int rem_reg_rules = 0, r = 0; | 5112 | int rem_reg_rules = 0, r = 0; |
5100 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 5113 | u32 num_rules = 0, rule_idx = 0, size_of_regd; |
5101 | u8 dfs_region = 0; | 5114 | enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET; |
5102 | struct ieee80211_regdomain *rd = NULL; | 5115 | struct ieee80211_regdomain *rd = NULL; |
5103 | 5116 | ||
5104 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 5117 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
@@ -5119,6 +5132,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
5119 | return -EINVAL; | 5132 | return -EINVAL; |
5120 | } | 5133 | } |
5121 | 5134 | ||
5135 | if (!reg_is_valid_request(alpha2)) | ||
5136 | return -EINVAL; | ||
5137 | |||
5122 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 5138 | size_of_regd = sizeof(struct ieee80211_regdomain) + |
5123 | num_rules * sizeof(struct ieee80211_reg_rule); | 5139 | num_rules * sizeof(struct ieee80211_reg_rule); |
5124 | 5140 | ||
@@ -5361,10 +5377,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5361 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { | 5377 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { |
5362 | request->flags = nla_get_u32( | 5378 | request->flags = nla_get_u32( |
5363 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); | 5379 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); |
5364 | if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && | 5380 | if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && |
5365 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) || | 5381 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { |
5366 | ((request->flags & NL80211_SCAN_FLAG_FLUSH) && | ||
5367 | !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) { | ||
5368 | err = -EOPNOTSUPP; | 5382 | err = -EOPNOTSUPP; |
5369 | goto out_free; | 5383 | goto out_free; |
5370 | } | 5384 | } |
@@ -5604,10 +5618,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5604 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { | 5618 | if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { |
5605 | request->flags = nla_get_u32( | 5619 | request->flags = nla_get_u32( |
5606 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); | 5620 | info->attrs[NL80211_ATTR_SCAN_FLAGS]); |
5607 | if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && | 5621 | if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && |
5608 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) || | 5622 | !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { |
5609 | ((request->flags & NL80211_SCAN_FLAG_FLUSH) && | ||
5610 | !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) { | ||
5611 | err = -EOPNOTSUPP; | 5623 | err = -EOPNOTSUPP; |
5612 | goto out_free; | 5624 | goto out_free; |
5613 | } | 5625 | } |
@@ -5670,7 +5682,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5670 | if (err == 0) | 5682 | if (err == 0) |
5671 | return -EINVAL; | 5683 | return -EINVAL; |
5672 | 5684 | ||
5673 | if (chandef.chan->dfs_state != NL80211_DFS_USABLE) | 5685 | if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef)) |
5674 | return -EINVAL; | 5686 | return -EINVAL; |
5675 | 5687 | ||
5676 | if (!rdev->ops->start_radar_detection) | 5688 | if (!rdev->ops->start_radar_detection) |
@@ -5810,7 +5822,11 @@ skip_beacons: | |||
5810 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) | 5822 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) |
5811 | params.block_tx = true; | 5823 | params.block_tx = true; |
5812 | 5824 | ||
5813 | return rdev_channel_switch(rdev, dev, ¶ms); | 5825 | wdev_lock(wdev); |
5826 | err = rdev_channel_switch(rdev, dev, ¶ms); | ||
5827 | wdev_unlock(wdev); | ||
5828 | |||
5829 | return err; | ||
5814 | } | 5830 | } |
5815 | 5831 | ||
5816 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | 5832 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, |
@@ -7443,10 +7459,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7443 | void *hdr = NULL; | 7459 | void *hdr = NULL; |
7444 | u64 cookie; | 7460 | u64 cookie; |
7445 | struct sk_buff *msg = NULL; | 7461 | struct sk_buff *msg = NULL; |
7446 | unsigned int wait = 0; | 7462 | struct cfg80211_mgmt_tx_params params = { |
7447 | bool offchan, no_cck, dont_wait_for_ack; | 7463 | .dont_wait_for_ack = |
7448 | 7464 | info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK], | |
7449 | dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; | 7465 | }; |
7450 | 7466 | ||
7451 | if (!info->attrs[NL80211_ATTR_FRAME]) | 7467 | if (!info->attrs[NL80211_ATTR_FRAME]) |
7452 | return -EINVAL; | 7468 | return -EINVAL; |
@@ -7473,24 +7489,24 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7473 | if (info->attrs[NL80211_ATTR_DURATION]) { | 7489 | if (info->attrs[NL80211_ATTR_DURATION]) { |
7474 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 7490 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
7475 | return -EINVAL; | 7491 | return -EINVAL; |
7476 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 7492 | params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
7477 | 7493 | ||
7478 | /* | 7494 | /* |
7479 | * We should wait on the channel for at least a minimum amount | 7495 | * We should wait on the channel for at least a minimum amount |
7480 | * of time (10ms) but no longer than the driver supports. | 7496 | * of time (10ms) but no longer than the driver supports. |
7481 | */ | 7497 | */ |
7482 | if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || | 7498 | if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || |
7483 | wait > rdev->wiphy.max_remain_on_channel_duration) | 7499 | params.wait > rdev->wiphy.max_remain_on_channel_duration) |
7484 | return -EINVAL; | 7500 | return -EINVAL; |
7485 | 7501 | ||
7486 | } | 7502 | } |
7487 | 7503 | ||
7488 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; | 7504 | params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; |
7489 | 7505 | ||
7490 | if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 7506 | if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
7491 | return -EINVAL; | 7507 | return -EINVAL; |
7492 | 7508 | ||
7493 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 7509 | params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
7494 | 7510 | ||
7495 | /* get the channel if any has been specified, otherwise pass NULL to | 7511 | /* get the channel if any has been specified, otherwise pass NULL to |
7496 | * the driver. The latter will use the current one | 7512 | * the driver. The latter will use the current one |
@@ -7502,10 +7518,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7502 | return err; | 7518 | return err; |
7503 | } | 7519 | } |
7504 | 7520 | ||
7505 | if (!chandef.chan && offchan) | 7521 | if (!chandef.chan && params.offchan) |
7506 | return -EINVAL; | 7522 | return -EINVAL; |
7507 | 7523 | ||
7508 | if (!dont_wait_for_ack) { | 7524 | if (!params.dont_wait_for_ack) { |
7509 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 7525 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7510 | if (!msg) | 7526 | if (!msg) |
7511 | return -ENOMEM; | 7527 | return -ENOMEM; |
@@ -7518,10 +7534,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7518 | } | 7534 | } |
7519 | } | 7535 | } |
7520 | 7536 | ||
7521 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait, | 7537 | params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); |
7522 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 7538 | params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]); |
7523 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 7539 | params.chan = chandef.chan; |
7524 | no_cck, dont_wait_for_ack, &cookie); | 7540 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, ¶ms, &cookie); |
7525 | if (err) | 7541 | if (err) |
7526 | goto free_msg; | 7542 | goto free_msg; |
7527 | 7543 | ||
@@ -10805,21 +10821,18 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
10805 | struct wiphy *wiphy = wdev->wiphy; | 10821 | struct wiphy *wiphy = wdev->wiphy; |
10806 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 10822 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
10807 | 10823 | ||
10808 | trace_cfg80211_ch_switch_notify(dev, chandef); | 10824 | ASSERT_WDEV_LOCK(wdev); |
10809 | 10825 | ||
10810 | wdev_lock(wdev); | 10826 | trace_cfg80211_ch_switch_notify(dev, chandef); |
10811 | 10827 | ||
10812 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | 10828 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && |
10813 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | 10829 | wdev->iftype != NL80211_IFTYPE_P2P_GO && |
10814 | wdev->iftype != NL80211_IFTYPE_ADHOC && | 10830 | wdev->iftype != NL80211_IFTYPE_ADHOC && |
10815 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | 10831 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) |
10816 | goto out; | 10832 | return; |
10817 | 10833 | ||
10818 | wdev->channel = chandef->chan; | 10834 | wdev->channel = chandef->chan; |
10819 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | 10835 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); |
10820 | out: | ||
10821 | wdev_unlock(wdev); | ||
10822 | return; | ||
10823 | } | 10836 | } |
10824 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | 10837 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); |
10825 | 10838 | ||
@@ -10878,7 +10891,7 @@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | |||
10878 | 10891 | ||
10879 | void | 10892 | void |
10880 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 10893 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
10881 | struct cfg80211_chan_def *chandef, | 10894 | const struct cfg80211_chan_def *chandef, |
10882 | enum nl80211_radar_event event, | 10895 | enum nl80211_radar_event event, |
10883 | struct net_device *netdev, gfp_t gfp) | 10896 | struct net_device *netdev, gfp_t gfp) |
10884 | { | 10897 | { |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2c0f2b3c07cb..b1b231324e10 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -70,7 +70,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
70 | 70 | ||
71 | void | 71 | void |
72 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 72 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
73 | struct cfg80211_chan_def *chandef, | 73 | const struct cfg80211_chan_def *chandef, |
74 | enum nl80211_radar_event event, | 74 | enum nl80211_radar_event event, |
75 | struct net_device *netdev, gfp_t gfp); | 75 | struct net_device *netdev, gfp_t gfp); |
76 | 76 | ||
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 37ce9fdfe934..a6c03ab14a0d 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -624,16 +624,12 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev, | |||
624 | 624 | ||
625 | static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, | 625 | static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev, |
626 | struct wireless_dev *wdev, | 626 | struct wireless_dev *wdev, |
627 | struct ieee80211_channel *chan, bool offchan, | 627 | struct cfg80211_mgmt_tx_params *params, |
628 | unsigned int wait, const u8 *buf, size_t len, | 628 | u64 *cookie) |
629 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
630 | { | 629 | { |
631 | int ret; | 630 | int ret; |
632 | trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, | 631 | trace_rdev_mgmt_tx(&rdev->wiphy, wdev, params); |
633 | wait, no_cck, dont_wait_for_ack); | 632 | ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, params, cookie); |
634 | ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, | ||
635 | wait, buf, len, no_cck, | ||
636 | dont_wait_for_ack, cookie); | ||
637 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); | 633 | trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie); |
638 | return ret; | 634 | return ret; |
639 | } | 635 | } |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7da67fd0b418..ec54e1aac8e2 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -120,6 +120,21 @@ static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) | |||
120 | return rtnl_dereference(wiphy->regd); | 120 | return rtnl_dereference(wiphy->regd); |
121 | } | 121 | } |
122 | 122 | ||
123 | static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region) | ||
124 | { | ||
125 | switch (dfs_region) { | ||
126 | case NL80211_DFS_UNSET: | ||
127 | return "unset"; | ||
128 | case NL80211_DFS_FCC: | ||
129 | return "FCC"; | ||
130 | case NL80211_DFS_ETSI: | ||
131 | return "ETSI"; | ||
132 | case NL80211_DFS_JP: | ||
133 | return "JP"; | ||
134 | } | ||
135 | return "Unknown"; | ||
136 | } | ||
137 | |||
123 | static void rcu_free_regdom(const struct ieee80211_regdomain *r) | 138 | static void rcu_free_regdom(const struct ieee80211_regdomain *r) |
124 | { | 139 | { |
125 | if (!r) | 140 | if (!r) |
@@ -163,35 +178,29 @@ static const struct ieee80211_regdomain world_regdom = { | |||
163 | REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), | 178 | REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), |
164 | /* IEEE 802.11b/g, channels 12..13. */ | 179 | /* IEEE 802.11b/g, channels 12..13. */ |
165 | REG_RULE(2467-10, 2472+10, 40, 6, 20, | 180 | REG_RULE(2467-10, 2472+10, 40, 6, 20, |
166 | NL80211_RRF_PASSIVE_SCAN | | 181 | NL80211_RRF_NO_IR), |
167 | NL80211_RRF_NO_IBSS), | ||
168 | /* IEEE 802.11 channel 14 - Only JP enables | 182 | /* IEEE 802.11 channel 14 - Only JP enables |
169 | * this and for 802.11b only */ | 183 | * this and for 802.11b only */ |
170 | REG_RULE(2484-10, 2484+10, 20, 6, 20, | 184 | REG_RULE(2484-10, 2484+10, 20, 6, 20, |
171 | NL80211_RRF_PASSIVE_SCAN | | 185 | NL80211_RRF_NO_IR | |
172 | NL80211_RRF_NO_IBSS | | ||
173 | NL80211_RRF_NO_OFDM), | 186 | NL80211_RRF_NO_OFDM), |
174 | /* IEEE 802.11a, channel 36..48 */ | 187 | /* IEEE 802.11a, channel 36..48 */ |
175 | REG_RULE(5180-10, 5240+10, 160, 6, 20, | 188 | REG_RULE(5180-10, 5240+10, 160, 6, 20, |
176 | NL80211_RRF_PASSIVE_SCAN | | 189 | NL80211_RRF_NO_IR), |
177 | NL80211_RRF_NO_IBSS), | ||
178 | 190 | ||
179 | /* IEEE 802.11a, channel 52..64 - DFS required */ | 191 | /* IEEE 802.11a, channel 52..64 - DFS required */ |
180 | REG_RULE(5260-10, 5320+10, 160, 6, 20, | 192 | REG_RULE(5260-10, 5320+10, 160, 6, 20, |
181 | NL80211_RRF_PASSIVE_SCAN | | 193 | NL80211_RRF_NO_IR | |
182 | NL80211_RRF_NO_IBSS | | ||
183 | NL80211_RRF_DFS), | 194 | NL80211_RRF_DFS), |
184 | 195 | ||
185 | /* IEEE 802.11a, channel 100..144 - DFS required */ | 196 | /* IEEE 802.11a, channel 100..144 - DFS required */ |
186 | REG_RULE(5500-10, 5720+10, 160, 6, 20, | 197 | REG_RULE(5500-10, 5720+10, 160, 6, 20, |
187 | NL80211_RRF_PASSIVE_SCAN | | 198 | NL80211_RRF_NO_IR | |
188 | NL80211_RRF_NO_IBSS | | ||
189 | NL80211_RRF_DFS), | 199 | NL80211_RRF_DFS), |
190 | 200 | ||
191 | /* IEEE 802.11a, channel 149..165 */ | 201 | /* IEEE 802.11a, channel 149..165 */ |
192 | REG_RULE(5745-10, 5825+10, 80, 6, 20, | 202 | REG_RULE(5745-10, 5825+10, 80, 6, 20, |
193 | NL80211_RRF_PASSIVE_SCAN | | 203 | NL80211_RRF_NO_IR), |
194 | NL80211_RRF_NO_IBSS), | ||
195 | 204 | ||
196 | /* IEEE 802.11ad (60gHz), channels 1..3 */ | 205 | /* IEEE 802.11ad (60gHz), channels 1..3 */ |
197 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), | 206 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), |
@@ -208,11 +217,26 @@ static char user_alpha2[2]; | |||
208 | module_param(ieee80211_regdom, charp, 0444); | 217 | module_param(ieee80211_regdom, charp, 0444); |
209 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 218 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
210 | 219 | ||
220 | static void reg_kfree_last_request(void) | ||
221 | { | ||
222 | struct regulatory_request *lr; | ||
223 | |||
224 | lr = get_last_request(); | ||
225 | |||
226 | if (lr != &core_request_world && lr) | ||
227 | kfree_rcu(lr, rcu_head); | ||
228 | } | ||
229 | |||
230 | static void reg_update_last_request(struct regulatory_request *request) | ||
231 | { | ||
232 | reg_kfree_last_request(); | ||
233 | rcu_assign_pointer(last_request, request); | ||
234 | } | ||
235 | |||
211 | static void reset_regdomains(bool full_reset, | 236 | static void reset_regdomains(bool full_reset, |
212 | const struct ieee80211_regdomain *new_regdom) | 237 | const struct ieee80211_regdomain *new_regdom) |
213 | { | 238 | { |
214 | const struct ieee80211_regdomain *r; | 239 | const struct ieee80211_regdomain *r; |
215 | struct regulatory_request *lr; | ||
216 | 240 | ||
217 | ASSERT_RTNL(); | 241 | ASSERT_RTNL(); |
218 | 242 | ||
@@ -235,10 +259,7 @@ static void reset_regdomains(bool full_reset, | |||
235 | if (!full_reset) | 259 | if (!full_reset) |
236 | return; | 260 | return; |
237 | 261 | ||
238 | lr = get_last_request(); | 262 | reg_update_last_request(&core_request_world); |
239 | if (lr != &core_request_world && lr) | ||
240 | kfree_rcu(lr, rcu_head); | ||
241 | rcu_assign_pointer(last_request, &core_request_world); | ||
242 | } | 263 | } |
243 | 264 | ||
244 | /* | 265 | /* |
@@ -456,7 +477,15 @@ static int call_crda(const char *alpha2) | |||
456 | return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE); | 477 | return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE); |
457 | } | 478 | } |
458 | 479 | ||
459 | static bool reg_is_valid_request(const char *alpha2) | 480 | static enum reg_request_treatment |
481 | reg_call_crda(struct regulatory_request *request) | ||
482 | { | ||
483 | if (call_crda(request->alpha2)) | ||
484 | return REG_REQ_IGNORE; | ||
485 | return REG_REQ_OK; | ||
486 | } | ||
487 | |||
488 | bool reg_is_valid_request(const char *alpha2) | ||
460 | { | 489 | { |
461 | struct regulatory_request *lr = get_last_request(); | 490 | struct regulatory_request *lr = get_last_request(); |
462 | 491 | ||
@@ -557,6 +586,20 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
557 | } | 586 | } |
558 | 587 | ||
559 | /* | 588 | /* |
589 | * Later on we can perhaps use the more restrictive DFS | ||
590 | * region but we don't have information for that yet so | ||
591 | * for now simply disallow conflicts. | ||
592 | */ | ||
593 | static enum nl80211_dfs_regions | ||
594 | reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1, | ||
595 | const enum nl80211_dfs_regions dfs_region2) | ||
596 | { | ||
597 | if (dfs_region1 != dfs_region2) | ||
598 | return NL80211_DFS_UNSET; | ||
599 | return dfs_region1; | ||
600 | } | ||
601 | |||
602 | /* | ||
560 | * Helper for regdom_intersect(), this does the real | 603 | * Helper for regdom_intersect(), this does the real |
561 | * mathematical intersection fun | 604 | * mathematical intersection fun |
562 | */ | 605 | */ |
@@ -687,6 +730,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
687 | rd->n_reg_rules = num_rules; | 730 | rd->n_reg_rules = num_rules; |
688 | rd->alpha2[0] = '9'; | 731 | rd->alpha2[0] = '9'; |
689 | rd->alpha2[1] = '8'; | 732 | rd->alpha2[1] = '8'; |
733 | rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region, | ||
734 | rd2->dfs_region); | ||
690 | 735 | ||
691 | return rd; | 736 | return rd; |
692 | } | 737 | } |
@@ -698,10 +743,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
698 | static u32 map_regdom_flags(u32 rd_flags) | 743 | static u32 map_regdom_flags(u32 rd_flags) |
699 | { | 744 | { |
700 | u32 channel_flags = 0; | 745 | u32 channel_flags = 0; |
701 | if (rd_flags & NL80211_RRF_PASSIVE_SCAN) | 746 | if (rd_flags & NL80211_RRF_NO_IR_ALL) |
702 | channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN; | 747 | channel_flags |= IEEE80211_CHAN_NO_IR; |
703 | if (rd_flags & NL80211_RRF_NO_IBSS) | ||
704 | channel_flags |= IEEE80211_CHAN_NO_IBSS; | ||
705 | if (rd_flags & NL80211_RRF_DFS) | 748 | if (rd_flags & NL80211_RRF_DFS) |
706 | channel_flags |= IEEE80211_CHAN_RADAR; | 749 | channel_flags |= IEEE80211_CHAN_RADAR; |
707 | if (rd_flags & NL80211_RRF_NO_OFDM) | 750 | if (rd_flags & NL80211_RRF_NO_OFDM) |
@@ -854,8 +897,18 @@ static void handle_channel(struct wiphy *wiphy, | |||
854 | PTR_ERR(reg_rule) == -ERANGE) | 897 | PTR_ERR(reg_rule) == -ERANGE) |
855 | return; | 898 | return; |
856 | 899 | ||
857 | REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq); | 900 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
858 | chan->flags |= IEEE80211_CHAN_DISABLED; | 901 | request_wiphy && request_wiphy == wiphy && |
902 | request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { | ||
903 | REG_DBG_PRINT("Disabling freq %d MHz for good\n", | ||
904 | chan->center_freq); | ||
905 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; | ||
906 | chan->flags = chan->orig_flags; | ||
907 | } else { | ||
908 | REG_DBG_PRINT("Disabling freq %d MHz\n", | ||
909 | chan->center_freq); | ||
910 | chan->flags |= IEEE80211_CHAN_DISABLED; | ||
911 | } | ||
859 | return; | 912 | return; |
860 | } | 913 | } |
861 | 914 | ||
@@ -873,7 +926,7 @@ static void handle_channel(struct wiphy *wiphy, | |||
873 | 926 | ||
874 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 927 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
875 | request_wiphy && request_wiphy == wiphy && | 928 | request_wiphy && request_wiphy == wiphy && |
876 | request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { | 929 | request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
877 | /* | 930 | /* |
878 | * This guarantees the driver's requested regulatory domain | 931 | * This guarantees the driver's requested regulatory domain |
879 | * will always be used as a base for further regulatory | 932 | * will always be used as a base for further regulatory |
@@ -899,13 +952,11 @@ static void handle_channel(struct wiphy *wiphy, | |||
899 | chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 952 | chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
900 | if (chan->orig_mpwr) { | 953 | if (chan->orig_mpwr) { |
901 | /* | 954 | /* |
902 | * Devices that have their own custom regulatory domain | 955 | * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER |
903 | * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the | 956 | * will always follow the passed country IE power settings. |
904 | * passed country IE power settings. | ||
905 | */ | 957 | */ |
906 | if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && | 958 | if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && |
907 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && | 959 | wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER) |
908 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) | ||
909 | chan->max_power = chan->max_reg_power; | 960 | chan->max_power = chan->max_reg_power; |
910 | else | 961 | else |
911 | chan->max_power = min(chan->orig_mpwr, | 962 | chan->max_power = min(chan->orig_mpwr, |
@@ -975,8 +1026,8 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) | |||
975 | 1026 | ||
976 | static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) | 1027 | static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) |
977 | { | 1028 | { |
978 | if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && | 1029 | if (wiphy->regulatory_flags & REGULATORY_STRICT_REG && |
979 | !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) | 1030 | !(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)) |
980 | return true; | 1031 | return true; |
981 | return false; | 1032 | return false; |
982 | } | 1033 | } |
@@ -994,7 +1045,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
994 | } | 1045 | } |
995 | 1046 | ||
996 | if (initiator == NL80211_REGDOM_SET_BY_CORE && | 1047 | if (initiator == NL80211_REGDOM_SET_BY_CORE && |
997 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { | 1048 | wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { |
998 | REG_DBG_PRINT("Ignoring regulatory request set by %s " | 1049 | REG_DBG_PRINT("Ignoring regulatory request set by %s " |
999 | "since the driver uses its own custom " | 1050 | "since the driver uses its own custom " |
1000 | "regulatory domain\n", | 1051 | "regulatory domain\n", |
@@ -1032,7 +1083,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) | |||
1032 | return true; | 1083 | return true; |
1033 | 1084 | ||
1034 | if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | 1085 | if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && |
1035 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) | 1086 | wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) |
1036 | return true; | 1087 | return true; |
1037 | 1088 | ||
1038 | return false; | 1089 | return false; |
@@ -1060,19 +1111,14 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx, | |||
1060 | if (!reg_is_world_roaming(wiphy)) | 1111 | if (!reg_is_world_roaming(wiphy)) |
1061 | return; | 1112 | return; |
1062 | 1113 | ||
1063 | if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS) | 1114 | if (wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS) |
1064 | return; | 1115 | return; |
1065 | 1116 | ||
1066 | chan_before.center_freq = chan->center_freq; | 1117 | chan_before.center_freq = chan->center_freq; |
1067 | chan_before.flags = chan->flags; | 1118 | chan_before.flags = chan->flags; |
1068 | 1119 | ||
1069 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { | 1120 | if (chan->flags & IEEE80211_CHAN_NO_IR) { |
1070 | chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; | 1121 | chan->flags &= ~IEEE80211_CHAN_NO_IR; |
1071 | channel_changed = true; | ||
1072 | } | ||
1073 | |||
1074 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) { | ||
1075 | chan->flags &= ~IEEE80211_CHAN_NO_IBSS; | ||
1076 | channel_changed = true; | 1122 | channel_changed = true; |
1077 | } | 1123 | } |
1078 | 1124 | ||
@@ -1205,14 +1251,30 @@ static void reg_process_ht_flags(struct wiphy *wiphy) | |||
1205 | reg_process_ht_flags_band(wiphy, wiphy->bands[band]); | 1251 | reg_process_ht_flags_band(wiphy, wiphy->bands[band]); |
1206 | } | 1252 | } |
1207 | 1253 | ||
1254 | static void reg_call_notifier(struct wiphy *wiphy, | ||
1255 | struct regulatory_request *request) | ||
1256 | { | ||
1257 | if (wiphy->reg_notifier) | ||
1258 | wiphy->reg_notifier(wiphy, request); | ||
1259 | } | ||
1260 | |||
1208 | static void wiphy_update_regulatory(struct wiphy *wiphy, | 1261 | static void wiphy_update_regulatory(struct wiphy *wiphy, |
1209 | enum nl80211_reg_initiator initiator) | 1262 | enum nl80211_reg_initiator initiator) |
1210 | { | 1263 | { |
1211 | enum ieee80211_band band; | 1264 | enum ieee80211_band band; |
1212 | struct regulatory_request *lr = get_last_request(); | 1265 | struct regulatory_request *lr = get_last_request(); |
1213 | 1266 | ||
1214 | if (ignore_reg_update(wiphy, initiator)) | 1267 | if (ignore_reg_update(wiphy, initiator)) { |
1268 | /* | ||
1269 | * Regulatory updates set by CORE are ignored for custom | ||
1270 | * regulatory cards. Let us notify the changes to the driver, | ||
1271 | * as some drivers used this to restore its orig_* reg domain. | ||
1272 | */ | ||
1273 | if (initiator == NL80211_REGDOM_SET_BY_CORE && | ||
1274 | wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) | ||
1275 | reg_call_notifier(wiphy, lr); | ||
1215 | return; | 1276 | return; |
1277 | } | ||
1216 | 1278 | ||
1217 | lr->dfs_region = get_cfg80211_regdom()->dfs_region; | 1279 | lr->dfs_region = get_cfg80211_regdom()->dfs_region; |
1218 | 1280 | ||
@@ -1221,9 +1283,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, | |||
1221 | 1283 | ||
1222 | reg_process_beacons(wiphy); | 1284 | reg_process_beacons(wiphy); |
1223 | reg_process_ht_flags(wiphy); | 1285 | reg_process_ht_flags(wiphy); |
1224 | 1286 | reg_call_notifier(wiphy, lr); | |
1225 | if (wiphy->reg_notifier) | ||
1226 | wiphy->reg_notifier(wiphy, lr); | ||
1227 | } | 1287 | } |
1228 | 1288 | ||
1229 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | 1289 | static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) |
@@ -1236,15 +1296,6 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | |||
1236 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 1296 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
1237 | wiphy = &rdev->wiphy; | 1297 | wiphy = &rdev->wiphy; |
1238 | wiphy_update_regulatory(wiphy, initiator); | 1298 | wiphy_update_regulatory(wiphy, initiator); |
1239 | /* | ||
1240 | * Regulatory updates set by CORE are ignored for custom | ||
1241 | * regulatory cards. Let us notify the changes to the driver, | ||
1242 | * as some drivers used this to restore its orig_* reg domain. | ||
1243 | */ | ||
1244 | if (initiator == NL80211_REGDOM_SET_BY_CORE && | ||
1245 | wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && | ||
1246 | wiphy->reg_notifier) | ||
1247 | wiphy->reg_notifier(wiphy, get_last_request()); | ||
1248 | } | 1299 | } |
1249 | } | 1300 | } |
1250 | 1301 | ||
@@ -1263,7 +1314,8 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1263 | if (IS_ERR(reg_rule)) { | 1314 | if (IS_ERR(reg_rule)) { |
1264 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", | 1315 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", |
1265 | chan->center_freq); | 1316 | chan->center_freq); |
1266 | chan->flags = IEEE80211_CHAN_DISABLED; | 1317 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; |
1318 | chan->flags = chan->orig_flags; | ||
1267 | return; | 1319 | return; |
1268 | } | 1320 | } |
1269 | 1321 | ||
@@ -1305,6 +1357,10 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
1305 | enum ieee80211_band band; | 1357 | enum ieee80211_band band; |
1306 | unsigned int bands_set = 0; | 1358 | unsigned int bands_set = 0; |
1307 | 1359 | ||
1360 | WARN(!(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG), | ||
1361 | "wiphy should have REGULATORY_CUSTOM_REG\n"); | ||
1362 | wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; | ||
1363 | |||
1308 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1364 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1309 | if (!wiphy->bands[band]) | 1365 | if (!wiphy->bands[band]) |
1310 | continue; | 1366 | continue; |
@@ -1320,225 +1376,285 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
1320 | } | 1376 | } |
1321 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); | 1377 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); |
1322 | 1378 | ||
1323 | /* This has the logic which determines when a new request | 1379 | static void reg_set_request_processed(void) |
1324 | * should be ignored. */ | ||
1325 | static enum reg_request_treatment | ||
1326 | get_reg_request_treatment(struct wiphy *wiphy, | ||
1327 | struct regulatory_request *pending_request) | ||
1328 | { | 1380 | { |
1329 | struct wiphy *last_wiphy = NULL; | 1381 | bool need_more_processing = false; |
1330 | struct regulatory_request *lr = get_last_request(); | 1382 | struct regulatory_request *lr = get_last_request(); |
1331 | 1383 | ||
1332 | /* All initial requests are respected */ | 1384 | lr->processed = true; |
1333 | if (!lr) | ||
1334 | return REG_REQ_OK; | ||
1335 | 1385 | ||
1336 | switch (pending_request->initiator) { | 1386 | spin_lock(®_requests_lock); |
1337 | case NL80211_REGDOM_SET_BY_CORE: | 1387 | if (!list_empty(®_requests_list)) |
1338 | return REG_REQ_OK; | 1388 | need_more_processing = true; |
1339 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | 1389 | spin_unlock(®_requests_lock); |
1340 | if (reg_request_cell_base(lr)) { | ||
1341 | /* Trust a Cell base station over the AP's country IE */ | ||
1342 | if (regdom_changes(pending_request->alpha2)) | ||
1343 | return REG_REQ_IGNORE; | ||
1344 | return REG_REQ_ALREADY_SET; | ||
1345 | } | ||
1346 | 1390 | ||
1347 | last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | 1391 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER) |
1392 | cancel_delayed_work(®_timeout); | ||
1348 | 1393 | ||
1349 | if (unlikely(!is_an_alpha2(pending_request->alpha2))) | 1394 | if (need_more_processing) |
1350 | return -EINVAL; | 1395 | schedule_work(®_work); |
1351 | if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 1396 | } |
1352 | if (last_wiphy != wiphy) { | ||
1353 | /* | ||
1354 | * Two cards with two APs claiming different | ||
1355 | * Country IE alpha2s. We could | ||
1356 | * intersect them, but that seems unlikely | ||
1357 | * to be correct. Reject second one for now. | ||
1358 | */ | ||
1359 | if (regdom_changes(pending_request->alpha2)) | ||
1360 | return REG_REQ_IGNORE; | ||
1361 | return REG_REQ_ALREADY_SET; | ||
1362 | } | ||
1363 | /* | ||
1364 | * Two consecutive Country IE hints on the same wiphy. | ||
1365 | * This should be picked up early by the driver/stack | ||
1366 | */ | ||
1367 | if (WARN_ON(regdom_changes(pending_request->alpha2))) | ||
1368 | return REG_REQ_OK; | ||
1369 | return REG_REQ_ALREADY_SET; | ||
1370 | } | ||
1371 | return REG_REQ_OK; | ||
1372 | case NL80211_REGDOM_SET_BY_DRIVER: | ||
1373 | if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { | ||
1374 | if (regdom_changes(pending_request->alpha2)) | ||
1375 | return REG_REQ_OK; | ||
1376 | return REG_REQ_ALREADY_SET; | ||
1377 | } | ||
1378 | 1397 | ||
1379 | /* | 1398 | /** |
1380 | * This would happen if you unplug and plug your card | 1399 | * reg_process_hint_core - process core regulatory requests |
1381 | * back in or if you add a new device for which the previously | 1400 | * @pending_request: a pending core regulatory request |
1382 | * loaded card also agrees on the regulatory domain. | 1401 | * |
1383 | */ | 1402 | * The wireless subsystem can use this function to process |
1384 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 1403 | * a regulatory request issued by the regulatory core. |
1385 | !regdom_changes(pending_request->alpha2)) | 1404 | * |
1386 | return REG_REQ_ALREADY_SET; | 1405 | * Returns one of the different reg request treatment values. |
1406 | */ | ||
1407 | static enum reg_request_treatment | ||
1408 | reg_process_hint_core(struct regulatory_request *core_request) | ||
1409 | { | ||
1410 | |||
1411 | core_request->intersect = false; | ||
1412 | core_request->processed = false; | ||
1413 | |||
1414 | reg_update_last_request(core_request); | ||
1387 | 1415 | ||
1416 | return reg_call_crda(core_request); | ||
1417 | } | ||
1418 | |||
1419 | static enum reg_request_treatment | ||
1420 | __reg_process_hint_user(struct regulatory_request *user_request) | ||
1421 | { | ||
1422 | struct regulatory_request *lr = get_last_request(); | ||
1423 | |||
1424 | if (reg_request_cell_base(user_request)) | ||
1425 | return reg_ignore_cell_hint(user_request); | ||
1426 | |||
1427 | if (reg_request_cell_base(lr)) | ||
1428 | return REG_REQ_IGNORE; | ||
1429 | |||
1430 | if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) | ||
1388 | return REG_REQ_INTERSECT; | 1431 | return REG_REQ_INTERSECT; |
1389 | case NL80211_REGDOM_SET_BY_USER: | 1432 | /* |
1390 | if (reg_request_cell_base(pending_request)) | 1433 | * If the user knows better the user should set the regdom |
1391 | return reg_ignore_cell_hint(pending_request); | 1434 | * to their country before the IE is picked up |
1435 | */ | ||
1436 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER && | ||
1437 | lr->intersect) | ||
1438 | return REG_REQ_IGNORE; | ||
1439 | /* | ||
1440 | * Process user requests only after previous user/driver/core | ||
1441 | * requests have been processed | ||
1442 | */ | ||
1443 | if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE || | ||
1444 | lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || | ||
1445 | lr->initiator == NL80211_REGDOM_SET_BY_USER) && | ||
1446 | regdom_changes(lr->alpha2)) | ||
1447 | return REG_REQ_IGNORE; | ||
1392 | 1448 | ||
1393 | if (reg_request_cell_base(lr)) | 1449 | if (!regdom_changes(user_request->alpha2)) |
1394 | return REG_REQ_IGNORE; | 1450 | return REG_REQ_ALREADY_SET; |
1395 | 1451 | ||
1396 | if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) | 1452 | return REG_REQ_OK; |
1397 | return REG_REQ_INTERSECT; | 1453 | } |
1398 | /* | ||
1399 | * If the user knows better the user should set the regdom | ||
1400 | * to their country before the IE is picked up | ||
1401 | */ | ||
1402 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER && | ||
1403 | lr->intersect) | ||
1404 | return REG_REQ_IGNORE; | ||
1405 | /* | ||
1406 | * Process user requests only after previous user/driver/core | ||
1407 | * requests have been processed | ||
1408 | */ | ||
1409 | if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE || | ||
1410 | lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || | ||
1411 | lr->initiator == NL80211_REGDOM_SET_BY_USER) && | ||
1412 | regdom_changes(lr->alpha2)) | ||
1413 | return REG_REQ_IGNORE; | ||
1414 | 1454 | ||
1415 | if (!regdom_changes(pending_request->alpha2)) | 1455 | /** |
1416 | return REG_REQ_ALREADY_SET; | 1456 | * reg_process_hint_user - process user regulatory requests |
1457 | * @user_request: a pending user regulatory request | ||
1458 | * | ||
1459 | * The wireless subsystem can use this function to process | ||
1460 | * a regulatory request initiated by userspace. | ||
1461 | * | ||
1462 | * Returns one of the different reg request treatment values. | ||
1463 | */ | ||
1464 | static enum reg_request_treatment | ||
1465 | reg_process_hint_user(struct regulatory_request *user_request) | ||
1466 | { | ||
1467 | enum reg_request_treatment treatment; | ||
1417 | 1468 | ||
1418 | return REG_REQ_OK; | 1469 | treatment = __reg_process_hint_user(user_request); |
1470 | if (treatment == REG_REQ_IGNORE || | ||
1471 | treatment == REG_REQ_ALREADY_SET) { | ||
1472 | kfree(user_request); | ||
1473 | return treatment; | ||
1419 | } | 1474 | } |
1420 | 1475 | ||
1421 | return REG_REQ_IGNORE; | 1476 | user_request->intersect = treatment == REG_REQ_INTERSECT; |
1477 | user_request->processed = false; | ||
1478 | |||
1479 | reg_update_last_request(user_request); | ||
1480 | |||
1481 | user_alpha2[0] = user_request->alpha2[0]; | ||
1482 | user_alpha2[1] = user_request->alpha2[1]; | ||
1483 | |||
1484 | return reg_call_crda(user_request); | ||
1422 | } | 1485 | } |
1423 | 1486 | ||
1424 | static void reg_set_request_processed(void) | 1487 | static enum reg_request_treatment |
1488 | __reg_process_hint_driver(struct regulatory_request *driver_request) | ||
1425 | { | 1489 | { |
1426 | bool need_more_processing = false; | ||
1427 | struct regulatory_request *lr = get_last_request(); | 1490 | struct regulatory_request *lr = get_last_request(); |
1428 | 1491 | ||
1429 | lr->processed = true; | 1492 | if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { |
1430 | 1493 | if (regdom_changes(driver_request->alpha2)) | |
1431 | spin_lock(®_requests_lock); | 1494 | return REG_REQ_OK; |
1432 | if (!list_empty(®_requests_list)) | 1495 | return REG_REQ_ALREADY_SET; |
1433 | need_more_processing = true; | 1496 | } |
1434 | spin_unlock(®_requests_lock); | ||
1435 | 1497 | ||
1436 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER) | 1498 | /* |
1437 | cancel_delayed_work(®_timeout); | 1499 | * This would happen if you unplug and plug your card |
1500 | * back in or if you add a new device for which the previously | ||
1501 | * loaded card also agrees on the regulatory domain. | ||
1502 | */ | ||
1503 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | ||
1504 | !regdom_changes(driver_request->alpha2)) | ||
1505 | return REG_REQ_ALREADY_SET; | ||
1438 | 1506 | ||
1439 | if (need_more_processing) | 1507 | return REG_REQ_INTERSECT; |
1440 | schedule_work(®_work); | ||
1441 | } | 1508 | } |
1442 | 1509 | ||
1443 | /** | 1510 | /** |
1444 | * __regulatory_hint - hint to the wireless core a regulatory domain | 1511 | * reg_process_hint_driver - process driver regulatory requests |
1445 | * @wiphy: if the hint comes from country information from an AP, this | 1512 | * @driver_request: a pending driver regulatory request |
1446 | * is required to be set to the wiphy that received the information | ||
1447 | * @pending_request: the regulatory request currently being processed | ||
1448 | * | 1513 | * |
1449 | * The Wireless subsystem can use this function to hint to the wireless core | 1514 | * The wireless subsystem can use this function to process |
1450 | * what it believes should be the current regulatory domain. | 1515 | * a regulatory request issued by an 802.11 driver. |
1451 | * | 1516 | * |
1452 | * Returns one of the different reg request treatment values. | 1517 | * Returns one of the different reg request treatment values. |
1453 | */ | 1518 | */ |
1454 | static enum reg_request_treatment | 1519 | static enum reg_request_treatment |
1455 | __regulatory_hint(struct wiphy *wiphy, | 1520 | reg_process_hint_driver(struct wiphy *wiphy, |
1456 | struct regulatory_request *pending_request) | 1521 | struct regulatory_request *driver_request) |
1457 | { | 1522 | { |
1458 | const struct ieee80211_regdomain *regd; | 1523 | const struct ieee80211_regdomain *regd; |
1459 | bool intersect = false; | ||
1460 | enum reg_request_treatment treatment; | 1524 | enum reg_request_treatment treatment; |
1461 | struct regulatory_request *lr; | ||
1462 | 1525 | ||
1463 | treatment = get_reg_request_treatment(wiphy, pending_request); | 1526 | treatment = __reg_process_hint_driver(driver_request); |
1464 | 1527 | ||
1465 | switch (treatment) { | 1528 | switch (treatment) { |
1466 | case REG_REQ_INTERSECT: | ||
1467 | if (pending_request->initiator == | ||
1468 | NL80211_REGDOM_SET_BY_DRIVER) { | ||
1469 | regd = reg_copy_regd(get_cfg80211_regdom()); | ||
1470 | if (IS_ERR(regd)) { | ||
1471 | kfree(pending_request); | ||
1472 | return PTR_ERR(regd); | ||
1473 | } | ||
1474 | rcu_assign_pointer(wiphy->regd, regd); | ||
1475 | } | ||
1476 | intersect = true; | ||
1477 | break; | ||
1478 | case REG_REQ_OK: | 1529 | case REG_REQ_OK: |
1479 | break; | 1530 | break; |
1480 | default: | 1531 | case REG_REQ_IGNORE: |
1481 | /* | 1532 | kfree(driver_request); |
1482 | * If the regulatory domain being requested by the | ||
1483 | * driver has already been set just copy it to the | ||
1484 | * wiphy | ||
1485 | */ | ||
1486 | if (treatment == REG_REQ_ALREADY_SET && | ||
1487 | pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) { | ||
1488 | regd = reg_copy_regd(get_cfg80211_regdom()); | ||
1489 | if (IS_ERR(regd)) { | ||
1490 | kfree(pending_request); | ||
1491 | return REG_REQ_IGNORE; | ||
1492 | } | ||
1493 | treatment = REG_REQ_ALREADY_SET; | ||
1494 | rcu_assign_pointer(wiphy->regd, regd); | ||
1495 | goto new_request; | ||
1496 | } | ||
1497 | kfree(pending_request); | ||
1498 | return treatment; | 1533 | return treatment; |
1534 | case REG_REQ_INTERSECT: | ||
1535 | /* fall through */ | ||
1536 | case REG_REQ_ALREADY_SET: | ||
1537 | regd = reg_copy_regd(get_cfg80211_regdom()); | ||
1538 | if (IS_ERR(regd)) { | ||
1539 | kfree(driver_request); | ||
1540 | return REG_REQ_IGNORE; | ||
1541 | } | ||
1542 | rcu_assign_pointer(wiphy->regd, regd); | ||
1499 | } | 1543 | } |
1500 | 1544 | ||
1501 | new_request: | ||
1502 | lr = get_last_request(); | ||
1503 | if (lr != &core_request_world && lr) | ||
1504 | kfree_rcu(lr, rcu_head); | ||
1505 | 1545 | ||
1506 | pending_request->intersect = intersect; | 1546 | driver_request->intersect = treatment == REG_REQ_INTERSECT; |
1507 | pending_request->processed = false; | 1547 | driver_request->processed = false; |
1508 | rcu_assign_pointer(last_request, pending_request); | ||
1509 | lr = pending_request; | ||
1510 | 1548 | ||
1511 | pending_request = NULL; | 1549 | reg_update_last_request(driver_request); |
1512 | 1550 | ||
1513 | if (lr->initiator == NL80211_REGDOM_SET_BY_USER) { | 1551 | /* |
1514 | user_alpha2[0] = lr->alpha2[0]; | 1552 | * Since CRDA will not be called in this case as we already |
1515 | user_alpha2[1] = lr->alpha2[1]; | 1553 | * have applied the requested regulatory domain before we just |
1554 | * inform userspace we have processed the request | ||
1555 | */ | ||
1556 | if (treatment == REG_REQ_ALREADY_SET) { | ||
1557 | nl80211_send_reg_change_event(driver_request); | ||
1558 | reg_set_request_processed(); | ||
1559 | return treatment; | ||
1516 | } | 1560 | } |
1517 | 1561 | ||
1518 | /* When r == REG_REQ_INTERSECT we do need to call CRDA */ | 1562 | return reg_call_crda(driver_request); |
1519 | if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) { | 1563 | } |
1564 | |||
1565 | static enum reg_request_treatment | ||
1566 | __reg_process_hint_country_ie(struct wiphy *wiphy, | ||
1567 | struct regulatory_request *country_ie_request) | ||
1568 | { | ||
1569 | struct wiphy *last_wiphy = NULL; | ||
1570 | struct regulatory_request *lr = get_last_request(); | ||
1571 | |||
1572 | if (reg_request_cell_base(lr)) { | ||
1573 | /* Trust a Cell base station over the AP's country IE */ | ||
1574 | if (regdom_changes(country_ie_request->alpha2)) | ||
1575 | return REG_REQ_IGNORE; | ||
1576 | return REG_REQ_ALREADY_SET; | ||
1577 | } else { | ||
1578 | if (wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_IGNORE) | ||
1579 | return REG_REQ_IGNORE; | ||
1580 | } | ||
1581 | |||
1582 | if (unlikely(!is_an_alpha2(country_ie_request->alpha2))) | ||
1583 | return -EINVAL; | ||
1584 | |||
1585 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) | ||
1586 | return REG_REQ_OK; | ||
1587 | |||
1588 | last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | ||
1589 | |||
1590 | if (last_wiphy != wiphy) { | ||
1520 | /* | 1591 | /* |
1521 | * Since CRDA will not be called in this case as we already | 1592 | * Two cards with two APs claiming different |
1522 | * have applied the requested regulatory domain before we just | 1593 | * Country IE alpha2s. We could |
1523 | * inform userspace we have processed the request | 1594 | * intersect them, but that seems unlikely |
1595 | * to be correct. Reject second one for now. | ||
1524 | */ | 1596 | */ |
1525 | if (treatment == REG_REQ_ALREADY_SET) { | 1597 | if (regdom_changes(country_ie_request->alpha2)) |
1526 | nl80211_send_reg_change_event(lr); | 1598 | return REG_REQ_IGNORE; |
1527 | reg_set_request_processed(); | 1599 | return REG_REQ_ALREADY_SET; |
1528 | } | ||
1529 | return treatment; | ||
1530 | } | 1600 | } |
1601 | /* | ||
1602 | * Two consecutive Country IE hints on the same wiphy. | ||
1603 | * This should be picked up early by the driver/stack | ||
1604 | */ | ||
1605 | if (WARN_ON(regdom_changes(country_ie_request->alpha2))) | ||
1606 | return REG_REQ_OK; | ||
1607 | return REG_REQ_ALREADY_SET; | ||
1608 | } | ||
1609 | |||
1610 | /** | ||
1611 | * reg_process_hint_country_ie - process regulatory requests from country IEs | ||
1612 | * @country_ie_request: a regulatory request from a country IE | ||
1613 | * | ||
1614 | * The wireless subsystem can use this function to process | ||
1615 | * a regulatory request issued by a country Information Element. | ||
1616 | * | ||
1617 | * Returns one of the different reg request treatment values. | ||
1618 | */ | ||
1619 | static enum reg_request_treatment | ||
1620 | reg_process_hint_country_ie(struct wiphy *wiphy, | ||
1621 | struct regulatory_request *country_ie_request) | ||
1622 | { | ||
1623 | enum reg_request_treatment treatment; | ||
1624 | |||
1625 | treatment = __reg_process_hint_country_ie(wiphy, country_ie_request); | ||
1531 | 1626 | ||
1532 | if (call_crda(lr->alpha2)) | 1627 | switch (treatment) { |
1628 | case REG_REQ_OK: | ||
1629 | break; | ||
1630 | case REG_REQ_IGNORE: | ||
1631 | /* fall through */ | ||
1632 | case REG_REQ_ALREADY_SET: | ||
1633 | kfree(country_ie_request); | ||
1634 | return treatment; | ||
1635 | case REG_REQ_INTERSECT: | ||
1636 | kfree(country_ie_request); | ||
1637 | /* | ||
1638 | * This doesn't happen yet, not sure we | ||
1639 | * ever want to support it for this case. | ||
1640 | */ | ||
1641 | WARN_ONCE(1, "Unexpected intersection for country IEs"); | ||
1533 | return REG_REQ_IGNORE; | 1642 | return REG_REQ_IGNORE; |
1534 | return REG_REQ_OK; | 1643 | } |
1644 | |||
1645 | country_ie_request->intersect = false; | ||
1646 | country_ie_request->processed = false; | ||
1647 | |||
1648 | reg_update_last_request(country_ie_request); | ||
1649 | |||
1650 | return reg_call_crda(country_ie_request); | ||
1535 | } | 1651 | } |
1536 | 1652 | ||
1537 | /* This processes *all* regulatory hints */ | 1653 | /* This processes *all* regulatory hints */ |
1538 | static void reg_process_hint(struct regulatory_request *reg_request, | 1654 | static void reg_process_hint(struct regulatory_request *reg_request) |
1539 | enum nl80211_reg_initiator reg_initiator) | ||
1540 | { | 1655 | { |
1541 | struct wiphy *wiphy = NULL; | 1656 | struct wiphy *wiphy = NULL; |
1657 | enum reg_request_treatment treatment; | ||
1542 | 1658 | ||
1543 | if (WARN_ON(!reg_request->alpha2)) | 1659 | if (WARN_ON(!reg_request->alpha2)) |
1544 | return; | 1660 | return; |
@@ -1546,23 +1662,37 @@ static void reg_process_hint(struct regulatory_request *reg_request, | |||
1546 | if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) | 1662 | if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) |
1547 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | 1663 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); |
1548 | 1664 | ||
1549 | if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { | 1665 | if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { |
1550 | kfree(reg_request); | 1666 | kfree(reg_request); |
1551 | return; | 1667 | return; |
1552 | } | 1668 | } |
1553 | 1669 | ||
1554 | switch (__regulatory_hint(wiphy, reg_request)) { | 1670 | switch (reg_request->initiator) { |
1555 | case REG_REQ_ALREADY_SET: | 1671 | case NL80211_REGDOM_SET_BY_CORE: |
1556 | /* This is required so that the orig_* parameters are saved */ | 1672 | reg_process_hint_core(reg_request); |
1557 | if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) | 1673 | return; |
1558 | wiphy_update_regulatory(wiphy, reg_initiator); | 1674 | case NL80211_REGDOM_SET_BY_USER: |
1675 | treatment = reg_process_hint_user(reg_request); | ||
1676 | if (treatment == REG_REQ_OK || | ||
1677 | treatment == REG_REQ_ALREADY_SET) | ||
1678 | return; | ||
1679 | schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); | ||
1680 | return; | ||
1681 | case NL80211_REGDOM_SET_BY_DRIVER: | ||
1682 | treatment = reg_process_hint_driver(wiphy, reg_request); | ||
1559 | break; | 1683 | break; |
1560 | default: | 1684 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: |
1561 | if (reg_initiator == NL80211_REGDOM_SET_BY_USER) | 1685 | treatment = reg_process_hint_country_ie(wiphy, reg_request); |
1562 | schedule_delayed_work(®_timeout, | ||
1563 | msecs_to_jiffies(3142)); | ||
1564 | break; | 1686 | break; |
1687 | default: | ||
1688 | WARN(1, "invalid initiator %d\n", reg_request->initiator); | ||
1689 | return; | ||
1565 | } | 1690 | } |
1691 | |||
1692 | /* This is required so that the orig_* parameters are saved */ | ||
1693 | if (treatment == REG_REQ_ALREADY_SET && wiphy && | ||
1694 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) | ||
1695 | wiphy_update_regulatory(wiphy, reg_request->initiator); | ||
1566 | } | 1696 | } |
1567 | 1697 | ||
1568 | /* | 1698 | /* |
@@ -1596,7 +1726,7 @@ static void reg_process_pending_hints(void) | |||
1596 | 1726 | ||
1597 | spin_unlock(®_requests_lock); | 1727 | spin_unlock(®_requests_lock); |
1598 | 1728 | ||
1599 | reg_process_hint(reg_request, reg_request->initiator); | 1729 | reg_process_hint(reg_request); |
1600 | } | 1730 | } |
1601 | 1731 | ||
1602 | /* Processes beacon hints -- this has nothing to do with country IEs */ | 1732 | /* Processes beacon hints -- this has nothing to do with country IEs */ |
@@ -1888,7 +2018,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
1888 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; | 2018 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; |
1889 | 2019 | ||
1890 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 2020 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
1891 | if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY) | 2021 | if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) |
1892 | restore_custom_reg_settings(&rdev->wiphy); | 2022 | restore_custom_reg_settings(&rdev->wiphy); |
1893 | } | 2023 | } |
1894 | 2024 | ||
@@ -2016,7 +2146,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
2016 | } | 2146 | } |
2017 | } | 2147 | } |
2018 | 2148 | ||
2019 | bool reg_supported_dfs_region(u8 dfs_region) | 2149 | bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region) |
2020 | { | 2150 | { |
2021 | switch (dfs_region) { | 2151 | switch (dfs_region) { |
2022 | case NL80211_DFS_UNSET: | 2152 | case NL80211_DFS_UNSET: |
@@ -2031,27 +2161,6 @@ bool reg_supported_dfs_region(u8 dfs_region) | |||
2031 | } | 2161 | } |
2032 | } | 2162 | } |
2033 | 2163 | ||
2034 | static void print_dfs_region(u8 dfs_region) | ||
2035 | { | ||
2036 | if (!dfs_region) | ||
2037 | return; | ||
2038 | |||
2039 | switch (dfs_region) { | ||
2040 | case NL80211_DFS_FCC: | ||
2041 | pr_info(" DFS Master region FCC"); | ||
2042 | break; | ||
2043 | case NL80211_DFS_ETSI: | ||
2044 | pr_info(" DFS Master region ETSI"); | ||
2045 | break; | ||
2046 | case NL80211_DFS_JP: | ||
2047 | pr_info(" DFS Master region JP"); | ||
2048 | break; | ||
2049 | default: | ||
2050 | pr_info(" DFS Master region Unknown"); | ||
2051 | break; | ||
2052 | } | ||
2053 | } | ||
2054 | |||
2055 | static void print_regdomain(const struct ieee80211_regdomain *rd) | 2164 | static void print_regdomain(const struct ieee80211_regdomain *rd) |
2056 | { | 2165 | { |
2057 | struct regulatory_request *lr = get_last_request(); | 2166 | struct regulatory_request *lr = get_last_request(); |
@@ -2083,7 +2192,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
2083 | } | 2192 | } |
2084 | } | 2193 | } |
2085 | 2194 | ||
2086 | print_dfs_region(rd->dfs_region); | 2195 | pr_info(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region)); |
2087 | print_rd_rules(rd); | 2196 | print_rd_rules(rd); |
2088 | } | 2197 | } |
2089 | 2198 | ||
@@ -2093,48 +2202,60 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
2093 | print_rd_rules(rd); | 2202 | print_rd_rules(rd); |
2094 | } | 2203 | } |
2095 | 2204 | ||
2096 | /* Takes ownership of rd only if it doesn't fail */ | 2205 | static int reg_set_rd_core(const struct ieee80211_regdomain *rd) |
2097 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 2206 | { |
2207 | if (!is_world_regdom(rd->alpha2)) | ||
2208 | return -EINVAL; | ||
2209 | update_world_regdomain(rd); | ||
2210 | return 0; | ||
2211 | } | ||
2212 | |||
2213 | static int reg_set_rd_user(const struct ieee80211_regdomain *rd, | ||
2214 | struct regulatory_request *user_request) | ||
2098 | { | 2215 | { |
2099 | const struct ieee80211_regdomain *regd; | ||
2100 | const struct ieee80211_regdomain *intersected_rd = NULL; | 2216 | const struct ieee80211_regdomain *intersected_rd = NULL; |
2101 | struct wiphy *request_wiphy; | ||
2102 | struct regulatory_request *lr = get_last_request(); | ||
2103 | 2217 | ||
2104 | /* Some basic sanity checks first */ | 2218 | if (is_world_regdom(rd->alpha2)) |
2219 | return -EINVAL; | ||
2220 | |||
2221 | if (!regdom_changes(rd->alpha2)) | ||
2222 | return -EALREADY; | ||
2105 | 2223 | ||
2106 | if (!reg_is_valid_request(rd->alpha2)) | 2224 | if (!is_valid_rd(rd)) { |
2225 | pr_err("Invalid regulatory domain detected:\n"); | ||
2226 | print_regdomain_info(rd); | ||
2107 | return -EINVAL; | 2227 | return -EINVAL; |
2228 | } | ||
2108 | 2229 | ||
2109 | if (is_world_regdom(rd->alpha2)) { | 2230 | if (!user_request->intersect) { |
2110 | update_world_regdomain(rd); | 2231 | reset_regdomains(false, rd); |
2111 | return 0; | 2232 | return 0; |
2112 | } | 2233 | } |
2113 | 2234 | ||
2114 | if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && | 2235 | intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); |
2115 | !is_unknown_alpha2(rd->alpha2)) | 2236 | if (!intersected_rd) |
2116 | return -EINVAL; | 2237 | return -EINVAL; |
2117 | 2238 | ||
2118 | /* | 2239 | kfree(rd); |
2119 | * Lets only bother proceeding on the same alpha2 if the current | 2240 | rd = NULL; |
2120 | * rd is non static (it means CRDA was present and was used last) | 2241 | reset_regdomains(false, intersected_rd); |
2121 | * and the pending request came in from a country IE | ||
2122 | */ | ||
2123 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { | ||
2124 | /* | ||
2125 | * If someone else asked us to change the rd lets only bother | ||
2126 | * checking if the alpha2 changes if CRDA was already called | ||
2127 | */ | ||
2128 | if (!regdom_changes(rd->alpha2)) | ||
2129 | return -EALREADY; | ||
2130 | } | ||
2131 | 2242 | ||
2132 | /* | 2243 | return 0; |
2133 | * Now lets set the regulatory domain, update all driver channels | 2244 | } |
2134 | * and finally inform them of what we have done, in case they want | 2245 | |
2135 | * to review or adjust their own settings based on their own | 2246 | static int reg_set_rd_driver(const struct ieee80211_regdomain *rd, |
2136 | * internal EEPROM data | 2247 | struct regulatory_request *driver_request) |
2137 | */ | 2248 | { |
2249 | const struct ieee80211_regdomain *regd; | ||
2250 | const struct ieee80211_regdomain *intersected_rd = NULL; | ||
2251 | const struct ieee80211_regdomain *tmp; | ||
2252 | struct wiphy *request_wiphy; | ||
2253 | |||
2254 | if (is_world_regdom(rd->alpha2)) | ||
2255 | return -EINVAL; | ||
2256 | |||
2257 | if (!regdom_changes(rd->alpha2)) | ||
2258 | return -EALREADY; | ||
2138 | 2259 | ||
2139 | if (!is_valid_rd(rd)) { | 2260 | if (!is_valid_rd(rd)) { |
2140 | pr_err("Invalid regulatory domain detected:\n"); | 2261 | pr_err("Invalid regulatory domain detected:\n"); |
@@ -2142,29 +2263,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2142 | return -EINVAL; | 2263 | return -EINVAL; |
2143 | } | 2264 | } |
2144 | 2265 | ||
2145 | request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | 2266 | request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); |
2146 | if (!request_wiphy && | 2267 | if (!request_wiphy) { |
2147 | (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER || | ||
2148 | lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { | ||
2149 | schedule_delayed_work(®_timeout, 0); | 2268 | schedule_delayed_work(®_timeout, 0); |
2150 | return -ENODEV; | 2269 | return -ENODEV; |
2151 | } | 2270 | } |
2152 | 2271 | ||
2153 | if (!lr->intersect) { | 2272 | if (!driver_request->intersect) { |
2154 | if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) { | ||
2155 | reset_regdomains(false, rd); | ||
2156 | return 0; | ||
2157 | } | ||
2158 | |||
2159 | /* | ||
2160 | * For a driver hint, lets copy the regulatory domain the | ||
2161 | * driver wanted to the wiphy to deal with conflicts | ||
2162 | */ | ||
2163 | |||
2164 | /* | ||
2165 | * Userspace could have sent two replies with only | ||
2166 | * one kernel request. | ||
2167 | */ | ||
2168 | if (request_wiphy->regd) | 2273 | if (request_wiphy->regd) |
2169 | return -EALREADY; | 2274 | return -EALREADY; |
2170 | 2275 | ||
@@ -2177,38 +2282,59 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2177 | return 0; | 2282 | return 0; |
2178 | } | 2283 | } |
2179 | 2284 | ||
2180 | /* Intersection requires a bit more work */ | 2285 | intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); |
2286 | if (!intersected_rd) | ||
2287 | return -EINVAL; | ||
2181 | 2288 | ||
2182 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 2289 | /* |
2183 | intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); | 2290 | * We can trash what CRDA provided now. |
2184 | if (!intersected_rd) | 2291 | * However if a driver requested this specific regulatory |
2185 | return -EINVAL; | 2292 | * domain we keep it for its private use |
2293 | */ | ||
2294 | tmp = get_wiphy_regdom(request_wiphy); | ||
2295 | rcu_assign_pointer(request_wiphy->regd, rd); | ||
2296 | rcu_free_regdom(tmp); | ||
2186 | 2297 | ||
2187 | /* | 2298 | rd = NULL; |
2188 | * We can trash what CRDA provided now. | ||
2189 | * However if a driver requested this specific regulatory | ||
2190 | * domain we keep it for its private use | ||
2191 | */ | ||
2192 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) { | ||
2193 | const struct ieee80211_regdomain *tmp; | ||
2194 | 2299 | ||
2195 | tmp = get_wiphy_regdom(request_wiphy); | 2300 | reset_regdomains(false, intersected_rd); |
2196 | rcu_assign_pointer(request_wiphy->regd, rd); | ||
2197 | rcu_free_regdom(tmp); | ||
2198 | } else { | ||
2199 | kfree(rd); | ||
2200 | } | ||
2201 | 2301 | ||
2202 | rd = NULL; | 2302 | return 0; |
2303 | } | ||
2203 | 2304 | ||
2204 | reset_regdomains(false, intersected_rd); | 2305 | static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd, |
2306 | struct regulatory_request *country_ie_request) | ||
2307 | { | ||
2308 | struct wiphy *request_wiphy; | ||
2205 | 2309 | ||
2206 | return 0; | 2310 | if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && |
2311 | !is_unknown_alpha2(rd->alpha2)) | ||
2312 | return -EINVAL; | ||
2313 | |||
2314 | /* | ||
2315 | * Lets only bother proceeding on the same alpha2 if the current | ||
2316 | * rd is non static (it means CRDA was present and was used last) | ||
2317 | * and the pending request came in from a country IE | ||
2318 | */ | ||
2319 | |||
2320 | if (!is_valid_rd(rd)) { | ||
2321 | pr_err("Invalid regulatory domain detected:\n"); | ||
2322 | print_regdomain_info(rd); | ||
2323 | return -EINVAL; | ||
2207 | } | 2324 | } |
2208 | 2325 | ||
2209 | return -EINVAL; | 2326 | request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); |
2210 | } | 2327 | if (!request_wiphy) { |
2328 | schedule_delayed_work(®_timeout, 0); | ||
2329 | return -ENODEV; | ||
2330 | } | ||
2331 | |||
2332 | if (country_ie_request->intersect) | ||
2333 | return -EINVAL; | ||
2211 | 2334 | ||
2335 | reset_regdomains(false, rd); | ||
2336 | return 0; | ||
2337 | } | ||
2212 | 2338 | ||
2213 | /* | 2339 | /* |
2214 | * Use this call to set the current regulatory domain. Conflicts with | 2340 | * Use this call to set the current regulatory domain. Conflicts with |
@@ -2220,10 +2346,32 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2220 | struct regulatory_request *lr; | 2346 | struct regulatory_request *lr; |
2221 | int r; | 2347 | int r; |
2222 | 2348 | ||
2349 | if (!reg_is_valid_request(rd->alpha2)) { | ||
2350 | kfree(rd); | ||
2351 | return -EINVAL; | ||
2352 | } | ||
2353 | |||
2223 | lr = get_last_request(); | 2354 | lr = get_last_request(); |
2224 | 2355 | ||
2225 | /* Note that this doesn't update the wiphys, this is done below */ | 2356 | /* Note that this doesn't update the wiphys, this is done below */ |
2226 | r = __set_regdom(rd); | 2357 | switch (lr->initiator) { |
2358 | case NL80211_REGDOM_SET_BY_CORE: | ||
2359 | r = reg_set_rd_core(rd); | ||
2360 | break; | ||
2361 | case NL80211_REGDOM_SET_BY_USER: | ||
2362 | r = reg_set_rd_user(rd, lr); | ||
2363 | break; | ||
2364 | case NL80211_REGDOM_SET_BY_DRIVER: | ||
2365 | r = reg_set_rd_driver(rd, lr); | ||
2366 | break; | ||
2367 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | ||
2368 | r = reg_set_rd_country_ie(rd, lr); | ||
2369 | break; | ||
2370 | default: | ||
2371 | WARN(1, "invalid initiator %d\n", lr->initiator); | ||
2372 | return -EINVAL; | ||
2373 | } | ||
2374 | |||
2227 | if (r) { | 2375 | if (r) { |
2228 | if (r == -EALREADY) | 2376 | if (r == -EALREADY) |
2229 | reg_set_request_processed(); | 2377 | reg_set_request_processed(); |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 9677e3c13da9..cc4c2c0a6723 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -18,8 +18,9 @@ | |||
18 | 18 | ||
19 | extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; | 19 | extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; |
20 | 20 | ||
21 | bool reg_is_valid_request(const char *alpha2); | ||
21 | bool is_world_regdom(const char *alpha2); | 22 | bool is_world_regdom(const char *alpha2); |
22 | bool reg_supported_dfs_region(u8 dfs_region); | 23 | bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region); |
23 | 24 | ||
24 | int regulatory_hint_user(const char *alpha2, | 25 | int regulatory_hint_user(const char *alpha2, |
25 | enum nl80211_user_reg_hint_type user_reg_hint_type); | 26 | enum nl80211_user_reg_hint_type user_reg_hint_type); |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ba5f0d6614d5..f7aa7a72d9bc 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1653,9 +1653,8 @@ TRACE_EVENT(rdev_cancel_remain_on_channel, | |||
1653 | 1653 | ||
1654 | TRACE_EVENT(rdev_mgmt_tx, | 1654 | TRACE_EVENT(rdev_mgmt_tx, |
1655 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | 1655 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, |
1656 | struct ieee80211_channel *chan, bool offchan, | 1656 | struct cfg80211_mgmt_tx_params *params), |
1657 | unsigned int wait, bool no_cck, bool dont_wait_for_ack), | 1657 | TP_ARGS(wiphy, wdev, params), |
1658 | TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack), | ||
1659 | TP_STRUCT__entry( | 1658 | TP_STRUCT__entry( |
1660 | WIPHY_ENTRY | 1659 | WIPHY_ENTRY |
1661 | WDEV_ENTRY | 1660 | WDEV_ENTRY |
@@ -1668,11 +1667,11 @@ TRACE_EVENT(rdev_mgmt_tx, | |||
1668 | TP_fast_assign( | 1667 | TP_fast_assign( |
1669 | WIPHY_ASSIGN; | 1668 | WIPHY_ASSIGN; |
1670 | WDEV_ASSIGN; | 1669 | WDEV_ASSIGN; |
1671 | CHAN_ASSIGN(chan); | 1670 | CHAN_ASSIGN(params->chan); |
1672 | __entry->offchan = offchan; | 1671 | __entry->offchan = params->offchan; |
1673 | __entry->wait = wait; | 1672 | __entry->wait = params->wait; |
1674 | __entry->no_cck = no_cck; | 1673 | __entry->no_cck = params->no_cck; |
1675 | __entry->dont_wait_for_ack = dont_wait_for_ack; | 1674 | __entry->dont_wait_for_ack = params->dont_wait_for_ack; |
1676 | ), | 1675 | ), |
1677 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s," | 1676 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s," |
1678 | " wait: %u, no cck: %s, dont wait for ack: %s", | 1677 | " wait: %u, no cck: %s, dont wait for ack: %s", |