diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-12-02 14:25:38 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-12-02 14:25:38 -0500 |
commit | 4b074b07625f603d40d4d04937f8874a00415dc4 (patch) | |
tree | 2dffdc46e3fea0320524f483cf5ac2c058ab59f2 /net/mac80211 | |
parent | 7d68849f40cd9169088249cc889d95c8998c3fb8 (diff) | |
parent | ddcc347b70f298f9d624cd0e250581d831d915fb (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Diffstat (limited to 'net/mac80211')
33 files changed, 1673 insertions, 639 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 */ |