diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-02-20 15:02:02 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-02-20 15:02:02 -0500 |
commit | 88daf80dcca19ff995cc263592426f734a9702f3 (patch) | |
tree | 7a52e25df74e52d00c3821032e719244e8a5526f /net | |
parent | 010d3c3989706d800ae72253773fa6537cc9f74c (diff) | |
parent | 35582ad9d342025653aaf28ed321bf5352488d7f (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net')
39 files changed, 773 insertions, 422 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 13b7683de5a4..ce9633a3cfb0 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -107,7 +107,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | |||
107 | mgmt->u.action.u.addba_req.start_seq_num = | 107 | mgmt->u.action.u.addba_req.start_seq_num = |
108 | cpu_to_le16(start_seq_num << 4); | 108 | cpu_to_le16(start_seq_num << 4); |
109 | 109 | ||
110 | ieee80211_tx_skb_tid(sdata, skb, tid); | 110 | ieee80211_tx_skb(sdata, skb); |
111 | } | 111 | } |
112 | 112 | ||
113 | void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) | 113 | void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 453e974287d1..363d19b5d5c8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -451,11 +451,11 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) | |||
451 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 451 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
452 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) | 452 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) |
453 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; | 453 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; |
454 | if (sta->last_rx_rate_flag & RX_FLAG_80MHZ) | 454 | if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80MHZ) |
455 | rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | 455 | rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; |
456 | if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ) | 456 | if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80P80MHZ) |
457 | rinfo->flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | 457 | rinfo->flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; |
458 | if (sta->last_rx_rate_flag & RX_FLAG_160MHZ) | 458 | if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_160MHZ) |
459 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 459 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; |
460 | } | 460 | } |
461 | 461 | ||
@@ -970,9 +970,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
970 | /* TODO: make hostapd tell us what it wants */ | 970 | /* TODO: make hostapd tell us what it wants */ |
971 | sdata->smps_mode = IEEE80211_SMPS_OFF; | 971 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
972 | sdata->needed_rx_chains = sdata->local->rx_chains; | 972 | sdata->needed_rx_chains = sdata->local->rx_chains; |
973 | sdata->radar_required = params->radar_required; | ||
974 | 973 | ||
975 | mutex_lock(&local->mtx); | 974 | mutex_lock(&local->mtx); |
975 | sdata->radar_required = params->radar_required; | ||
976 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, | 976 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, |
977 | IEEE80211_CHANCTX_SHARED); | 977 | IEEE80211_CHANCTX_SHARED); |
978 | mutex_unlock(&local->mtx); | 978 | mutex_unlock(&local->mtx); |
@@ -1056,6 +1056,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
1056 | int err; | 1056 | int err; |
1057 | 1057 | ||
1058 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1058 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1059 | sdata_assert_lock(sdata); | ||
1059 | 1060 | ||
1060 | /* don't allow changing the beacon while CSA is in place - offset | 1061 | /* don't allow changing the beacon while CSA is in place - offset |
1061 | * of channel switch counter may change | 1062 | * of channel switch counter may change |
@@ -1083,6 +1084,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1083 | struct probe_resp *old_probe_resp; | 1084 | struct probe_resp *old_probe_resp; |
1084 | struct cfg80211_chan_def chandef; | 1085 | struct cfg80211_chan_def chandef; |
1085 | 1086 | ||
1087 | sdata_assert_lock(sdata); | ||
1088 | |||
1086 | old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata); | 1089 | old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata); |
1087 | if (!old_beacon) | 1090 | if (!old_beacon) |
1088 | return -ENOENT; | 1091 | return -ENOENT; |
@@ -1343,6 +1346,18 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1343 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 1346 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
1344 | params->vht_capa, sta); | 1347 | params->vht_capa, sta); |
1345 | 1348 | ||
1349 | if (params->opmode_notif_used) { | ||
1350 | enum ieee80211_band band = | ||
1351 | ieee80211_get_sdata_band(sdata); | ||
1352 | |||
1353 | /* returned value is only needed for rc update, but the | ||
1354 | * rc isn't initialized here yet, so ignore it | ||
1355 | */ | ||
1356 | __ieee80211_vht_handle_opmode(sdata, sta, | ||
1357 | params->opmode_notif, | ||
1358 | band, false); | ||
1359 | } | ||
1360 | |||
1346 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 1361 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
1347 | #ifdef CONFIG_MAC80211_MESH | 1362 | #ifdef CONFIG_MAC80211_MESH |
1348 | u32 changed = 0; | 1363 | u32 changed = 0; |
@@ -2630,6 +2645,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2630 | if (!roc) | 2645 | if (!roc) |
2631 | return -ENOMEM; | 2646 | return -ENOMEM; |
2632 | 2647 | ||
2648 | /* | ||
2649 | * If the duration is zero, then the driver | ||
2650 | * wouldn't actually do anything. Set it to | ||
2651 | * 10 for now. | ||
2652 | * | ||
2653 | * TODO: cancel the off-channel operation | ||
2654 | * when we get the SKB's TX status and | ||
2655 | * the wait time was zero before. | ||
2656 | */ | ||
2657 | if (!duration) | ||
2658 | duration = 10; | ||
2659 | |||
2633 | roc->chan = channel; | 2660 | roc->chan = channel; |
2634 | roc->duration = duration; | 2661 | roc->duration = duration; |
2635 | roc->req_duration = duration; | 2662 | roc->req_duration = duration; |
@@ -2671,18 +2698,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2671 | 2698 | ||
2672 | /* otherwise actually kick it off here (for error handling) */ | 2699 | /* otherwise actually kick it off here (for error handling) */ |
2673 | 2700 | ||
2674 | /* | ||
2675 | * If the duration is zero, then the driver | ||
2676 | * wouldn't actually do anything. Set it to | ||
2677 | * 10 for now. | ||
2678 | * | ||
2679 | * TODO: cancel the off-channel operation | ||
2680 | * when we get the SKB's TX status and | ||
2681 | * the wait time was zero before. | ||
2682 | */ | ||
2683 | if (!duration) | ||
2684 | duration = 10; | ||
2685 | |||
2686 | ret = drv_remain_on_channel(local, sdata, channel, duration, type); | 2701 | ret = drv_remain_on_channel(local, sdata, channel, duration, type); |
2687 | if (ret) { | 2702 | if (ret) { |
2688 | kfree(roc); | 2703 | kfree(roc); |
@@ -2990,69 +3005,88 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) | |||
2990 | return new_beacon; | 3005 | return new_beacon; |
2991 | } | 3006 | } |
2992 | 3007 | ||
2993 | void ieee80211_csa_finalize_work(struct work_struct *work) | 3008 | void ieee80211_csa_finish(struct ieee80211_vif *vif) |
3009 | { | ||
3010 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
3011 | |||
3012 | ieee80211_queue_work(&sdata->local->hw, | ||
3013 | &sdata->csa_finalize_work); | ||
3014 | } | ||
3015 | EXPORT_SYMBOL(ieee80211_csa_finish); | ||
3016 | |||
3017 | static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | ||
2994 | { | 3018 | { |
2995 | struct ieee80211_sub_if_data *sdata = | ||
2996 | container_of(work, struct ieee80211_sub_if_data, | ||
2997 | csa_finalize_work); | ||
2998 | struct ieee80211_local *local = sdata->local; | 3019 | struct ieee80211_local *local = sdata->local; |
2999 | int err, changed = 0; | 3020 | int err, changed = 0; |
3000 | 3021 | ||
3001 | sdata_lock(sdata); | 3022 | sdata_assert_lock(sdata); |
3002 | /* AP might have been stopped while waiting for the lock. */ | ||
3003 | if (!sdata->vif.csa_active) | ||
3004 | goto unlock; | ||
3005 | |||
3006 | if (!ieee80211_sdata_running(sdata)) | ||
3007 | goto unlock; | ||
3008 | 3023 | ||
3009 | sdata->radar_required = sdata->csa_radar_required; | ||
3010 | mutex_lock(&local->mtx); | 3024 | mutex_lock(&local->mtx); |
3025 | sdata->radar_required = sdata->csa_radar_required; | ||
3011 | err = ieee80211_vif_change_channel(sdata, &changed); | 3026 | err = ieee80211_vif_change_channel(sdata, &changed); |
3012 | mutex_unlock(&local->mtx); | 3027 | mutex_unlock(&local->mtx); |
3013 | if (WARN_ON(err < 0)) | 3028 | if (WARN_ON(err < 0)) |
3014 | goto unlock; | 3029 | return; |
3015 | 3030 | ||
3016 | if (!local->use_chanctx) { | 3031 | if (!local->use_chanctx) { |
3017 | local->_oper_chandef = sdata->csa_chandef; | 3032 | local->_oper_chandef = sdata->csa_chandef; |
3018 | ieee80211_hw_config(local, 0); | 3033 | ieee80211_hw_config(local, 0); |
3019 | } | 3034 | } |
3020 | 3035 | ||
3021 | ieee80211_bss_info_change_notify(sdata, changed); | ||
3022 | |||
3023 | sdata->vif.csa_active = false; | 3036 | sdata->vif.csa_active = false; |
3024 | switch (sdata->vif.type) { | 3037 | switch (sdata->vif.type) { |
3025 | case NL80211_IFTYPE_AP: | 3038 | case NL80211_IFTYPE_AP: |
3026 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | 3039 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); |
3027 | if (err < 0) | ||
3028 | goto unlock; | ||
3029 | |||
3030 | changed |= err; | ||
3031 | kfree(sdata->u.ap.next_beacon); | 3040 | kfree(sdata->u.ap.next_beacon); |
3032 | sdata->u.ap.next_beacon = NULL; | 3041 | sdata->u.ap.next_beacon = NULL; |
3033 | 3042 | ||
3034 | ieee80211_bss_info_change_notify(sdata, err); | 3043 | if (err < 0) |
3044 | return; | ||
3045 | changed |= err; | ||
3035 | break; | 3046 | break; |
3036 | case NL80211_IFTYPE_ADHOC: | 3047 | case NL80211_IFTYPE_ADHOC: |
3037 | ieee80211_ibss_finish_csa(sdata); | 3048 | err = ieee80211_ibss_finish_csa(sdata); |
3049 | if (err < 0) | ||
3050 | return; | ||
3051 | changed |= err; | ||
3038 | break; | 3052 | break; |
3039 | #ifdef CONFIG_MAC80211_MESH | 3053 | #ifdef CONFIG_MAC80211_MESH |
3040 | case NL80211_IFTYPE_MESH_POINT: | 3054 | case NL80211_IFTYPE_MESH_POINT: |
3041 | err = ieee80211_mesh_finish_csa(sdata); | 3055 | err = ieee80211_mesh_finish_csa(sdata); |
3042 | if (err < 0) | 3056 | if (err < 0) |
3043 | goto unlock; | 3057 | return; |
3058 | changed |= err; | ||
3044 | break; | 3059 | break; |
3045 | #endif | 3060 | #endif |
3046 | default: | 3061 | default: |
3047 | WARN_ON(1); | 3062 | WARN_ON(1); |
3048 | goto unlock; | 3063 | return; |
3049 | } | 3064 | } |
3050 | 3065 | ||
3066 | ieee80211_bss_info_change_notify(sdata, changed); | ||
3067 | |||
3051 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 3068 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
3052 | IEEE80211_MAX_QUEUE_MAP, | 3069 | IEEE80211_MAX_QUEUE_MAP, |
3053 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3070 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3054 | 3071 | ||
3055 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | 3072 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); |
3073 | } | ||
3074 | |||
3075 | void ieee80211_csa_finalize_work(struct work_struct *work) | ||
3076 | { | ||
3077 | struct ieee80211_sub_if_data *sdata = | ||
3078 | container_of(work, struct ieee80211_sub_if_data, | ||
3079 | csa_finalize_work); | ||
3080 | |||
3081 | sdata_lock(sdata); | ||
3082 | /* AP might have been stopped while waiting for the lock. */ | ||
3083 | if (!sdata->vif.csa_active) | ||
3084 | goto unlock; | ||
3085 | |||
3086 | if (!ieee80211_sdata_running(sdata)) | ||
3087 | goto unlock; | ||
3088 | |||
3089 | ieee80211_csa_finalize(sdata); | ||
3056 | 3090 | ||
3057 | unlock: | 3091 | unlock: |
3058 | sdata_unlock(sdata); | 3092 | sdata_unlock(sdata); |
@@ -3066,9 +3100,9 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3066 | struct ieee80211_chanctx_conf *chanctx_conf; | 3100 | struct ieee80211_chanctx_conf *chanctx_conf; |
3067 | struct ieee80211_chanctx *chanctx; | 3101 | struct ieee80211_chanctx *chanctx; |
3068 | struct ieee80211_if_mesh __maybe_unused *ifmsh; | 3102 | struct ieee80211_if_mesh __maybe_unused *ifmsh; |
3069 | int err, num_chanctx; | 3103 | int err, num_chanctx, changed = 0; |
3070 | 3104 | ||
3071 | lockdep_assert_held(&sdata->wdev.mtx); | 3105 | sdata_assert_lock(sdata); |
3072 | 3106 | ||
3073 | if (!list_empty(&local->roc_list) || local->scanning) | 3107 | if (!list_empty(&local->roc_list) || local->scanning) |
3074 | return -EBUSY; | 3108 | return -EBUSY; |
@@ -3107,19 +3141,40 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3107 | 3141 | ||
3108 | switch (sdata->vif.type) { | 3142 | switch (sdata->vif.type) { |
3109 | case NL80211_IFTYPE_AP: | 3143 | case NL80211_IFTYPE_AP: |
3110 | sdata->csa_counter_offset_beacon = | ||
3111 | params->counter_offset_beacon; | ||
3112 | sdata->csa_counter_offset_presp = params->counter_offset_presp; | ||
3113 | sdata->u.ap.next_beacon = | 3144 | sdata->u.ap.next_beacon = |
3114 | cfg80211_beacon_dup(¶ms->beacon_after); | 3145 | cfg80211_beacon_dup(¶ms->beacon_after); |
3115 | if (!sdata->u.ap.next_beacon) | 3146 | if (!sdata->u.ap.next_beacon) |
3116 | return -ENOMEM; | 3147 | return -ENOMEM; |
3117 | 3148 | ||
3149 | /* | ||
3150 | * With a count of 0, we don't have to wait for any | ||
3151 | * TBTT before switching, so complete the CSA | ||
3152 | * immediately. In theory, with a count == 1 we | ||
3153 | * should delay the switch until just before the next | ||
3154 | * TBTT, but that would complicate things so we switch | ||
3155 | * immediately too. If we would delay the switch | ||
3156 | * until the next TBTT, we would have to set the probe | ||
3157 | * response here. | ||
3158 | * | ||
3159 | * TODO: A channel switch with count <= 1 without | ||
3160 | * sending a CSA action frame is kind of useless, | ||
3161 | * because the clients won't know we're changing | ||
3162 | * channels. The action frame must be implemented | ||
3163 | * either here or in the userspace. | ||
3164 | */ | ||
3165 | if (params->count <= 1) | ||
3166 | break; | ||
3167 | |||
3168 | sdata->csa_counter_offset_beacon = | ||
3169 | params->counter_offset_beacon; | ||
3170 | sdata->csa_counter_offset_presp = params->counter_offset_presp; | ||
3118 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | 3171 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); |
3119 | if (err < 0) { | 3172 | if (err < 0) { |
3120 | kfree(sdata->u.ap.next_beacon); | 3173 | kfree(sdata->u.ap.next_beacon); |
3121 | return err; | 3174 | return err; |
3122 | } | 3175 | } |
3176 | changed |= err; | ||
3177 | |||
3123 | break; | 3178 | break; |
3124 | case NL80211_IFTYPE_ADHOC: | 3179 | case NL80211_IFTYPE_ADHOC: |
3125 | if (!sdata->vif.bss_conf.ibss_joined) | 3180 | if (!sdata->vif.bss_conf.ibss_joined) |
@@ -3147,17 +3202,21 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3147 | params->chandef.chan->band) | 3202 | params->chandef.chan->band) |
3148 | return -EINVAL; | 3203 | return -EINVAL; |
3149 | 3204 | ||
3150 | err = ieee80211_ibss_csa_beacon(sdata, params); | 3205 | /* see comments in the NL80211_IFTYPE_AP block */ |
3151 | if (err < 0) | 3206 | if (params->count > 1) { |
3152 | return err; | 3207 | err = ieee80211_ibss_csa_beacon(sdata, params); |
3208 | if (err < 0) | ||
3209 | return err; | ||
3210 | changed |= err; | ||
3211 | } | ||
3212 | |||
3213 | ieee80211_send_action_csa(sdata, params); | ||
3214 | |||
3153 | break; | 3215 | break; |
3154 | #ifdef CONFIG_MAC80211_MESH | 3216 | #ifdef CONFIG_MAC80211_MESH |
3155 | case NL80211_IFTYPE_MESH_POINT: | 3217 | case NL80211_IFTYPE_MESH_POINT: |
3156 | ifmsh = &sdata->u.mesh; | 3218 | ifmsh = &sdata->u.mesh; |
3157 | 3219 | ||
3158 | if (!ifmsh->mesh_id) | ||
3159 | return -EINVAL; | ||
3160 | |||
3161 | if (params->chandef.width != sdata->vif.bss_conf.chandef.width) | 3220 | if (params->chandef.width != sdata->vif.bss_conf.chandef.width) |
3162 | return -EINVAL; | 3221 | return -EINVAL; |
3163 | 3222 | ||
@@ -3166,17 +3225,27 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3166 | params->chandef.chan->band) | 3225 | params->chandef.chan->band) |
3167 | return -EINVAL; | 3226 | return -EINVAL; |
3168 | 3227 | ||
3169 | ifmsh->chsw_init = true; | 3228 | if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) { |
3170 | if (!ifmsh->pre_value) | 3229 | ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT; |
3171 | ifmsh->pre_value = 1; | 3230 | if (!ifmsh->pre_value) |
3172 | else | 3231 | ifmsh->pre_value = 1; |
3173 | ifmsh->pre_value++; | 3232 | else |
3233 | ifmsh->pre_value++; | ||
3234 | } | ||
3174 | 3235 | ||
3175 | err = ieee80211_mesh_csa_beacon(sdata, params, true); | 3236 | /* see comments in the NL80211_IFTYPE_AP block */ |
3176 | if (err < 0) { | 3237 | if (params->count > 1) { |
3177 | ifmsh->chsw_init = false; | 3238 | err = ieee80211_mesh_csa_beacon(sdata, params); |
3178 | return err; | 3239 | if (err < 0) { |
3240 | ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; | ||
3241 | return err; | ||
3242 | } | ||
3243 | changed |= err; | ||
3179 | } | 3244 | } |
3245 | |||
3246 | if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) | ||
3247 | ieee80211_send_action_csa(sdata, params); | ||
3248 | |||
3180 | break; | 3249 | break; |
3181 | #endif | 3250 | #endif |
3182 | default: | 3251 | default: |
@@ -3193,8 +3262,13 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3193 | sdata->csa_chandef = params->chandef; | 3262 | sdata->csa_chandef = params->chandef; |
3194 | sdata->vif.csa_active = true; | 3263 | sdata->vif.csa_active = true; |
3195 | 3264 | ||
3196 | ieee80211_bss_info_change_notify(sdata, err); | 3265 | if (changed) { |
3197 | drv_channel_switch_beacon(sdata, ¶ms->chandef); | 3266 | ieee80211_bss_info_change_notify(sdata, changed); |
3267 | drv_channel_switch_beacon(sdata, ¶ms->chandef); | ||
3268 | } else { | ||
3269 | /* if the beacon didn't change, we can finalize immediately */ | ||
3270 | ieee80211_csa_finalize(sdata); | ||
3271 | } | ||
3198 | 3272 | ||
3199 | return 0; | 3273 | return 0; |
3200 | } | 3274 | } |
@@ -3865,7 +3939,7 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy, | |||
3865 | return 0; | 3939 | return 0; |
3866 | } | 3940 | } |
3867 | 3941 | ||
3868 | struct cfg80211_ops mac80211_config_ops = { | 3942 | const struct cfg80211_ops mac80211_config_ops = { |
3869 | .add_virtual_intf = ieee80211_add_iface, | 3943 | .add_virtual_intf = ieee80211_add_iface, |
3870 | .del_virtual_intf = ieee80211_del_iface, | 3944 | .del_virtual_intf = ieee80211_del_iface, |
3871 | .change_virtual_intf = ieee80211_change_iface, | 3945 | .change_virtual_intf = ieee80211_change_iface, |
diff --git a/net/mac80211/cfg.h b/net/mac80211/cfg.h index 7d7879f5b00b..2d51f62dc76c 100644 --- a/net/mac80211/cfg.h +++ b/net/mac80211/cfg.h | |||
@@ -4,6 +4,6 @@ | |||
4 | #ifndef __CFG_H | 4 | #ifndef __CFG_H |
5 | #define __CFG_H | 5 | #define __CFG_H |
6 | 6 | ||
7 | extern struct cfg80211_ops mac80211_config_ops; | 7 | extern const struct cfg80211_ops mac80211_config_ops; |
8 | 8 | ||
9 | #endif /* __CFG_H */ | 9 | #endif /* __CFG_H */ |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f43613a97dd6..42c659229a09 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -196,6 +196,8 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local) | |||
196 | { | 196 | { |
197 | struct ieee80211_sub_if_data *sdata; | 197 | struct ieee80211_sub_if_data *sdata; |
198 | 198 | ||
199 | lockdep_assert_held(&local->mtx); | ||
200 | |||
199 | rcu_read_lock(); | 201 | rcu_read_lock(); |
200 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 202 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
201 | if (sdata->radar_required) { | 203 | if (sdata->radar_required) { |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 80194b557a0c..2ecb4deddb5d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -195,7 +195,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | |||
195 | static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf, | 195 | static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf, |
196 | size_t count, loff_t *ppos) | 196 | size_t count, loff_t *ppos) |
197 | { | 197 | { |
198 | char _buf[12], *buf = _buf; | 198 | char _buf[12] = {}, *buf = _buf; |
199 | struct sta_info *sta = file->private_data; | 199 | struct sta_info *sta = file->private_data; |
200 | bool start, tx; | 200 | bool start, tx; |
201 | unsigned long tid; | 201 | unsigned long tid; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 70dd013de836..afbe2b203c3e 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -375,7 +375,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
375 | mgmt->u.action.u.delba.params = cpu_to_le16(params); | 375 | mgmt->u.action.u.delba.params = cpu_to_le16(params); |
376 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); | 376 | mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); |
377 | 377 | ||
378 | ieee80211_tx_skb_tid(sdata, skb, tid); | 378 | ieee80211_tx_skb(sdata, skb); |
379 | } | 379 | } |
380 | 380 | ||
381 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, | 381 | void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 2796a198728f..4453e2725e40 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -220,7 +220,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
220 | { | 220 | { |
221 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 221 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
222 | struct ieee80211_local *local = sdata->local; | 222 | struct ieee80211_local *local = sdata->local; |
223 | struct ieee80211_supported_band *sband; | ||
224 | struct ieee80211_mgmt *mgmt; | 223 | struct ieee80211_mgmt *mgmt; |
225 | struct cfg80211_bss *bss; | 224 | struct cfg80211_bss *bss; |
226 | u32 bss_change; | 225 | u32 bss_change; |
@@ -294,7 +293,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
294 | } | 293 | } |
295 | 294 | ||
296 | mutex_lock(&local->mtx); | 295 | mutex_lock(&local->mtx); |
297 | ieee80211_vif_release_channel(sdata); | ||
298 | if (ieee80211_vif_use_channel(sdata, &chandef, | 296 | if (ieee80211_vif_use_channel(sdata, &chandef, |
299 | ifibss->fixed_channel ? | 297 | ifibss->fixed_channel ? |
300 | IEEE80211_CHANCTX_SHARED : | 298 | IEEE80211_CHANCTX_SHARED : |
@@ -303,12 +301,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
303 | mutex_unlock(&local->mtx); | 301 | mutex_unlock(&local->mtx); |
304 | return; | 302 | return; |
305 | } | 303 | } |
304 | sdata->radar_required = radar_required; | ||
306 | mutex_unlock(&local->mtx); | 305 | mutex_unlock(&local->mtx); |
307 | 306 | ||
308 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | 307 | memcpy(ifibss->bssid, bssid, ETH_ALEN); |
309 | 308 | ||
310 | sband = local->hw.wiphy->bands[chan->band]; | ||
311 | |||
312 | presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, | 309 | presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, |
313 | capability, tsf, &chandef, | 310 | capability, tsf, &chandef, |
314 | &have_higher_than_11mbit, NULL); | 311 | &have_higher_than_11mbit, NULL); |
@@ -318,7 +315,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
318 | rcu_assign_pointer(ifibss->presp, presp); | 315 | rcu_assign_pointer(ifibss->presp, presp); |
319 | mgmt = (void *)presp->head; | 316 | mgmt = (void *)presp->head; |
320 | 317 | ||
321 | sdata->radar_required = radar_required; | ||
322 | sdata->vif.bss_conf.enable_beacon = true; | 318 | sdata->vif.bss_conf.enable_beacon = true; |
323 | sdata->vif.bss_conf.beacon_int = beacon_int; | 319 | sdata->vif.bss_conf.beacon_int = beacon_int; |
324 | sdata->vif.bss_conf.basic_rates = basic_rates; | 320 | sdata->vif.bss_conf.basic_rates = basic_rates; |
@@ -386,7 +382,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
386 | presp->head_len, 0, GFP_KERNEL); | 382 | presp->head_len, 0, GFP_KERNEL); |
387 | cfg80211_put_bss(local->hw.wiphy, bss); | 383 | cfg80211_put_bss(local->hw.wiphy, bss); |
388 | netif_carrier_on(sdata->dev); | 384 | netif_carrier_on(sdata->dev); |
389 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); | 385 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL); |
390 | } | 386 | } |
391 | 387 | ||
392 | static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 388 | static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, |
@@ -521,12 +517,6 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
521 | if (old_presp) | 517 | if (old_presp) |
522 | kfree_rcu(old_presp, rcu_head); | 518 | kfree_rcu(old_presp, rcu_head); |
523 | 519 | ||
524 | /* it might not send the beacon for a while. send an action frame | ||
525 | * immediately to announce the channel switch. | ||
526 | */ | ||
527 | if (csa_settings) | ||
528 | ieee80211_send_action_csa(sdata, csa_settings); | ||
529 | |||
530 | return BSS_CHANGED_BEACON; | 520 | return BSS_CHANGED_BEACON; |
531 | out: | 521 | out: |
532 | return ret; | 522 | return ret; |
@@ -536,7 +526,7 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
536 | { | 526 | { |
537 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 527 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
538 | struct cfg80211_bss *cbss; | 528 | struct cfg80211_bss *cbss; |
539 | int err; | 529 | int err, changed = 0; |
540 | u16 capability; | 530 | u16 capability; |
541 | 531 | ||
542 | sdata_assert_lock(sdata); | 532 | sdata_assert_lock(sdata); |
@@ -568,10 +558,9 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
568 | if (err < 0) | 558 | if (err < 0) |
569 | return err; | 559 | return err; |
570 | 560 | ||
571 | if (err) | 561 | changed |= err; |
572 | ieee80211_bss_info_change_notify(sdata, err); | ||
573 | 562 | ||
574 | return 0; | 563 | return changed; |
575 | } | 564 | } |
576 | 565 | ||
577 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata) | 566 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata) |
@@ -799,6 +788,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
799 | int err; | 788 | int err; |
800 | u32 sta_flags; | 789 | u32 sta_flags; |
801 | 790 | ||
791 | sdata_assert_lock(sdata); | ||
792 | |||
802 | sta_flags = IEEE80211_STA_DISABLE_VHT; | 793 | sta_flags = IEEE80211_STA_DISABLE_VHT; |
803 | switch (ifibss->chandef.width) { | 794 | switch (ifibss->chandef.width) { |
804 | case NL80211_CHAN_WIDTH_5: | 795 | case NL80211_CHAN_WIDTH_5: |
@@ -1468,6 +1459,11 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1468 | memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN); | 1459 | memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN); |
1469 | ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa); | 1460 | ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa); |
1470 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1461 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1462 | |||
1463 | /* avoid excessive retries for probe request to wildcard SSIDs */ | ||
1464 | if (pos[1] == 0) | ||
1465 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
1466 | |||
1471 | ieee80211_tx_skb(sdata, skb); | 1467 | ieee80211_tx_skb(sdata, skb); |
1472 | } | 1468 | } |
1473 | 1469 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3701930c6649..0014b5396ce5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -616,7 +616,11 @@ struct ieee80211_if_mesh { | |||
616 | struct ps_data ps; | 616 | struct ps_data ps; |
617 | /* Channel Switching Support */ | 617 | /* Channel Switching Support */ |
618 | struct mesh_csa_settings __rcu *csa; | 618 | struct mesh_csa_settings __rcu *csa; |
619 | bool chsw_init; | 619 | enum { |
620 | IEEE80211_MESH_CSA_ROLE_NONE, | ||
621 | IEEE80211_MESH_CSA_ROLE_INIT, | ||
622 | IEEE80211_MESH_CSA_ROLE_REPEATER, | ||
623 | } csa_role; | ||
620 | u8 chsw_ttl; | 624 | u8 chsw_ttl; |
621 | u16 pre_value; | 625 | u16 pre_value; |
622 | 626 | ||
@@ -1408,8 +1412,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); | |||
1408 | void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1412 | void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1409 | struct sk_buff *skb); | 1413 | struct sk_buff *skb); |
1410 | int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, | 1414 | int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, |
1411 | struct cfg80211_csa_settings *csa_settings, | 1415 | struct cfg80211_csa_settings *csa_settings); |
1412 | bool csa_action); | ||
1413 | int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata); | 1416 | int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata); |
1414 | 1417 | ||
1415 | /* scan/BSS handling */ | 1418 | /* scan/BSS handling */ |
@@ -1553,6 +1556,9 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
1553 | struct sta_info *sta); | 1556 | struct sta_info *sta); |
1554 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); | 1557 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); |
1555 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); | 1558 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); |
1559 | u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | ||
1560 | struct sta_info *sta, u8 opmode, | ||
1561 | enum ieee80211_band band, bool nss_only); | ||
1556 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 1562 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
1557 | struct sta_info *sta, u8 opmode, | 1563 | struct sta_info *sta, u8 opmode, |
1558 | enum ieee80211_band band, bool nss_only); | 1564 | enum ieee80211_band band, bool nss_only); |
@@ -1605,7 +1611,7 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) | |||
1605 | } | 1611 | } |
1606 | 1612 | ||
1607 | /* utility functions/constants */ | 1613 | /* utility functions/constants */ |
1608 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ | 1614 | extern const void *const mac80211_wiphy_privid; /* for wiphy privid */ |
1609 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | 1615 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, |
1610 | enum nl80211_iftype type); | 1616 | enum nl80211_iftype type); |
1611 | int ieee80211_frame_duration(enum ieee80211_band band, size_t len, | 1617 | int ieee80211_frame_duration(enum ieee80211_band band, size_t len, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ce1c44370610..088111af6c7c 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -833,7 +833,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
833 | cancel_work_sync(&local->dynamic_ps_enable_work); | 833 | cancel_work_sync(&local->dynamic_ps_enable_work); |
834 | 834 | ||
835 | cancel_work_sync(&sdata->recalc_smps); | 835 | cancel_work_sync(&sdata->recalc_smps); |
836 | sdata_lock(sdata); | ||
836 | sdata->vif.csa_active = false; | 837 | sdata->vif.csa_active = false; |
838 | sdata_unlock(sdata); | ||
837 | cancel_work_sync(&sdata->csa_finalize_work); | 839 | cancel_work_sync(&sdata->csa_finalize_work); |
838 | 840 | ||
839 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 841 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d767cfb9b45f..1f7d8422d62d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -893,10 +893,15 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
893 | /* mac80211 supports control port protocol changing */ | 893 | /* mac80211 supports control port protocol changing */ |
894 | local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; | 894 | local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; |
895 | 895 | ||
896 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 896 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { |
897 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 897 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
898 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 898 | } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) { |
899 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | 899 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; |
900 | if (hw->max_signal <= 0) { | ||
901 | result = -EINVAL; | ||
902 | goto fail_wiphy_register; | ||
903 | } | ||
904 | } | ||
900 | 905 | ||
901 | WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | 906 | WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) |
902 | && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), | 907 | && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 5b919cab1de0..f70e9cd10552 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -688,7 +688,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | |||
688 | *pos++ = csa->settings.count; | 688 | *pos++ = csa->settings.count; |
689 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; | 689 | *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; |
690 | *pos++ = 6; | 690 | *pos++ = 6; |
691 | if (ifmsh->chsw_init) { | 691 | if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) { |
692 | *pos++ = ifmsh->mshcfg.dot11MeshTTL; | 692 | *pos++ = ifmsh->mshcfg.dot11MeshTTL; |
693 | *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; | 693 | *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; |
694 | } else { | 694 | } else { |
@@ -859,18 +859,12 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, | |||
859 | { | 859 | { |
860 | struct cfg80211_csa_settings params; | 860 | struct cfg80211_csa_settings params; |
861 | struct ieee80211_csa_ie csa_ie; | 861 | struct ieee80211_csa_ie csa_ie; |
862 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
863 | struct ieee80211_chanctx *chanctx; | ||
864 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 862 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
865 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | 863 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
866 | int err, num_chanctx; | 864 | int err; |
867 | u32 sta_flags; | 865 | u32 sta_flags; |
868 | 866 | ||
869 | if (sdata->vif.csa_active) | 867 | sdata_assert_lock(sdata); |
870 | return true; | ||
871 | |||
872 | if (!ifmsh->mesh_id) | ||
873 | return false; | ||
874 | 868 | ||
875 | sta_flags = IEEE80211_STA_DISABLE_VHT; | 869 | sta_flags = IEEE80211_STA_DISABLE_VHT; |
876 | switch (sdata->vif.bss_conf.chandef.width) { | 870 | switch (sdata->vif.bss_conf.chandef.width) { |
@@ -896,10 +890,6 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, | |||
896 | params.chandef = csa_ie.chandef; | 890 | params.chandef = csa_ie.chandef; |
897 | params.count = csa_ie.count; | 891 | params.count = csa_ie.count; |
898 | 892 | ||
899 | if (sdata->vif.bss_conf.chandef.chan->band != | ||
900 | params.chandef.chan->band) | ||
901 | return false; | ||
902 | |||
903 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, | 893 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, |
904 | IEEE80211_CHAN_DISABLED)) { | 894 | IEEE80211_CHAN_DISABLED)) { |
905 | sdata_info(sdata, | 895 | sdata_info(sdata, |
@@ -922,24 +912,12 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, | |||
922 | return false; | 912 | return false; |
923 | } | 913 | } |
924 | 914 | ||
925 | rcu_read_lock(); | 915 | if (cfg80211_chandef_identical(¶ms.chandef, |
926 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 916 | &sdata->vif.bss_conf.chandef)) { |
927 | if (!chanctx_conf) | 917 | mcsa_dbg(sdata, |
928 | goto failed_chswitch; | 918 | "received csa with an identical chandef, ignoring\n"); |
929 | 919 | return true; | |
930 | /* don't handle for multi-VIF cases */ | 920 | } |
931 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | ||
932 | if (chanctx->refcount > 1) | ||
933 | goto failed_chswitch; | ||
934 | |||
935 | num_chanctx = 0; | ||
936 | list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list) | ||
937 | num_chanctx++; | ||
938 | |||
939 | if (num_chanctx > 1) | ||
940 | goto failed_chswitch; | ||
941 | |||
942 | rcu_read_unlock(); | ||
943 | 921 | ||
944 | mcsa_dbg(sdata, | 922 | mcsa_dbg(sdata, |
945 | "received channel switch announcement to go to channel %d MHz\n", | 923 | "received channel switch announcement to go to channel %d MHz\n", |
@@ -953,30 +931,16 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, | |||
953 | ifmsh->pre_value = csa_ie.pre_value; | 931 | ifmsh->pre_value = csa_ie.pre_value; |
954 | } | 932 | } |
955 | 933 | ||
956 | if (ifmsh->chsw_ttl < ifmsh->mshcfg.dot11MeshTTL) { | 934 | if (ifmsh->chsw_ttl >= ifmsh->mshcfg.dot11MeshTTL) |
957 | if (ieee80211_mesh_csa_beacon(sdata, ¶ms, false) < 0) | ||
958 | return false; | ||
959 | } else { | ||
960 | return false; | 935 | return false; |
961 | } | ||
962 | 936 | ||
963 | sdata->csa_radar_required = params.radar_required; | 937 | ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_REPEATER; |
964 | 938 | ||
965 | if (params.block_tx) | 939 | if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev, |
966 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | 940 | ¶ms) < 0) |
967 | IEEE80211_MAX_QUEUE_MAP, | 941 | return false; |
968 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
969 | |||
970 | sdata->csa_chandef = params.chandef; | ||
971 | sdata->vif.csa_active = true; | ||
972 | |||
973 | ieee80211_bss_info_change_notify(sdata, err); | ||
974 | drv_channel_switch_beacon(sdata, ¶ms.chandef); | ||
975 | 942 | ||
976 | return true; | 943 | return true; |
977 | failed_chswitch: | ||
978 | rcu_read_unlock(); | ||
979 | return false; | ||
980 | } | 944 | } |
981 | 945 | ||
982 | static void | 946 | static void |
@@ -1086,7 +1050,8 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
1086 | ifmsh->sync_ops->rx_bcn_presp(sdata, | 1050 | ifmsh->sync_ops->rx_bcn_presp(sdata, |
1087 | stype, mgmt, &elems, rx_status); | 1051 | stype, mgmt, &elems, rx_status); |
1088 | 1052 | ||
1089 | if (!ifmsh->chsw_init) | 1053 | if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && |
1054 | !sdata->vif.csa_active) | ||
1090 | ieee80211_mesh_process_chnswitch(sdata, &elems, true); | 1055 | ieee80211_mesh_process_chnswitch(sdata, &elems, true); |
1091 | } | 1056 | } |
1092 | 1057 | ||
@@ -1095,29 +1060,30 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) | |||
1095 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 1060 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
1096 | struct mesh_csa_settings *tmp_csa_settings; | 1061 | struct mesh_csa_settings *tmp_csa_settings; |
1097 | int ret = 0; | 1062 | int ret = 0; |
1063 | int changed = 0; | ||
1098 | 1064 | ||
1099 | /* Reset the TTL value and Initiator flag */ | 1065 | /* Reset the TTL value and Initiator flag */ |
1100 | ifmsh->chsw_init = false; | 1066 | ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; |
1101 | ifmsh->chsw_ttl = 0; | 1067 | ifmsh->chsw_ttl = 0; |
1102 | 1068 | ||
1103 | /* Remove the CSA and MCSP elements from the beacon */ | 1069 | /* Remove the CSA and MCSP elements from the beacon */ |
1104 | tmp_csa_settings = rcu_dereference(ifmsh->csa); | 1070 | tmp_csa_settings = rcu_dereference(ifmsh->csa); |
1105 | rcu_assign_pointer(ifmsh->csa, NULL); | 1071 | rcu_assign_pointer(ifmsh->csa, NULL); |
1106 | kfree_rcu(tmp_csa_settings, rcu_head); | 1072 | if (tmp_csa_settings) |
1073 | kfree_rcu(tmp_csa_settings, rcu_head); | ||
1107 | ret = ieee80211_mesh_rebuild_beacon(sdata); | 1074 | ret = ieee80211_mesh_rebuild_beacon(sdata); |
1108 | if (ret) | 1075 | if (ret) |
1109 | return -EINVAL; | 1076 | return -EINVAL; |
1110 | 1077 | ||
1111 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 1078 | changed |= BSS_CHANGED_BEACON; |
1112 | 1079 | ||
1113 | mcsa_dbg(sdata, "complete switching to center freq %d MHz", | 1080 | mcsa_dbg(sdata, "complete switching to center freq %d MHz", |
1114 | sdata->vif.bss_conf.chandef.chan->center_freq); | 1081 | sdata->vif.bss_conf.chandef.chan->center_freq); |
1115 | return 0; | 1082 | return changed; |
1116 | } | 1083 | } |
1117 | 1084 | ||
1118 | int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, | 1085 | int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, |
1119 | struct cfg80211_csa_settings *csa_settings, | 1086 | struct cfg80211_csa_settings *csa_settings) |
1120 | bool csa_action) | ||
1121 | { | 1087 | { |
1122 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 1088 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
1123 | struct mesh_csa_settings *tmp_csa_settings; | 1089 | struct mesh_csa_settings *tmp_csa_settings; |
@@ -1141,12 +1107,7 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
1141 | return ret; | 1107 | return ret; |
1142 | } | 1108 | } |
1143 | 1109 | ||
1144 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 1110 | return BSS_CHANGED_BEACON; |
1145 | |||
1146 | if (csa_action) | ||
1147 | ieee80211_send_action_csa(sdata, csa_settings); | ||
1148 | |||
1149 | return 0; | ||
1150 | } | 1111 | } |
1151 | 1112 | ||
1152 | static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, | 1113 | static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, |
@@ -1210,7 +1171,8 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, | |||
1210 | 1171 | ||
1211 | ifmsh->pre_value = pre_value; | 1172 | ifmsh->pre_value = pre_value; |
1212 | 1173 | ||
1213 | if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { | 1174 | if (!sdata->vif.csa_active && |
1175 | !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { | ||
1214 | mcsa_dbg(sdata, "Failed to process CSA action frame"); | 1176 | mcsa_dbg(sdata, "Failed to process CSA action frame"); |
1215 | return; | 1177 | return; |
1216 | } | 1178 | } |
@@ -1257,7 +1219,7 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1257 | sdata_lock(sdata); | 1219 | sdata_lock(sdata); |
1258 | 1220 | ||
1259 | /* mesh already went down */ | 1221 | /* mesh already went down */ |
1260 | if (!sdata->wdev.mesh_id_len) | 1222 | if (!sdata->u.mesh.mesh_id_len) |
1261 | goto out; | 1223 | goto out; |
1262 | 1224 | ||
1263 | rx_status = IEEE80211_SKB_RXCB(skb); | 1225 | rx_status = IEEE80211_SKB_RXCB(skb); |
@@ -1310,7 +1272,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) | |||
1310 | sdata_lock(sdata); | 1272 | sdata_lock(sdata); |
1311 | 1273 | ||
1312 | /* mesh already went down */ | 1274 | /* mesh already went down */ |
1313 | if (!sdata->wdev.mesh_id_len) | 1275 | if (!sdata->u.mesh.mesh_id_len) |
1314 | goto out; | 1276 | goto out; |
1315 | 1277 | ||
1316 | if (ifmsh->preq_queue_len && | 1278 | if (ifmsh->preq_queue_len && |
@@ -1365,7 +1327,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
1365 | mesh_rmc_init(sdata); | 1327 | mesh_rmc_init(sdata); |
1366 | ifmsh->last_preq = jiffies; | 1328 | ifmsh->last_preq = jiffies; |
1367 | ifmsh->next_perr = jiffies; | 1329 | ifmsh->next_perr = jiffies; |
1368 | ifmsh->chsw_init = false; | 1330 | ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; |
1369 | /* Allocate all mesh structures when creating the first mesh interface. */ | 1331 | /* Allocate all mesh structures when creating the first mesh interface. */ |
1370 | if (!mesh_allocated) | 1332 | if (!mesh_allocated) |
1371 | ieee80211s_init(); | 1333 | ieee80211s_init(); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fc1d82465b3c..61604834b914 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -508,6 +508,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
508 | u8 *pos; | 508 | u8 *pos; |
509 | u32 cap; | 509 | u32 cap; |
510 | struct ieee80211_sta_vht_cap vht_cap; | 510 | struct ieee80211_sta_vht_cap vht_cap; |
511 | u32 mask, ap_bf_sts, our_bf_sts; | ||
511 | 512 | ||
512 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); | 513 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); |
513 | 514 | ||
@@ -535,6 +536,16 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
535 | cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) | 536 | cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) |
536 | cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; | 537 | cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; |
537 | 538 | ||
539 | mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; | ||
540 | |||
541 | ap_bf_sts = le32_to_cpu(ap_vht_cap->vht_cap_info) & mask; | ||
542 | our_bf_sts = cap & mask; | ||
543 | |||
544 | if (ap_bf_sts < our_bf_sts) { | ||
545 | cap &= ~mask; | ||
546 | cap |= ap_bf_sts; | ||
547 | } | ||
548 | |||
538 | /* reserve and fill IE */ | 549 | /* reserve and fill IE */ |
539 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); | 550 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); |
540 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); | 551 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); |
@@ -745,6 +756,34 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
745 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, | 756 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, |
746 | sband, chan, sdata->smps_mode); | 757 | sband, chan, sdata->smps_mode); |
747 | 758 | ||
759 | /* if present, add any custom IEs that go before VHT */ | ||
760 | if (assoc_data->ie_len) { | ||
761 | static const u8 before_vht[] = { | ||
762 | WLAN_EID_SSID, | ||
763 | WLAN_EID_SUPP_RATES, | ||
764 | WLAN_EID_EXT_SUPP_RATES, | ||
765 | WLAN_EID_PWR_CAPABILITY, | ||
766 | WLAN_EID_SUPPORTED_CHANNELS, | ||
767 | WLAN_EID_RSN, | ||
768 | WLAN_EID_QOS_CAPA, | ||
769 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | ||
770 | WLAN_EID_MOBILITY_DOMAIN, | ||
771 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
772 | WLAN_EID_HT_CAPABILITY, | ||
773 | WLAN_EID_BSS_COEX_2040, | ||
774 | WLAN_EID_EXT_CAPABILITY, | ||
775 | WLAN_EID_QOS_TRAFFIC_CAPA, | ||
776 | WLAN_EID_TIM_BCAST_REQ, | ||
777 | WLAN_EID_INTERWORKING, | ||
778 | }; | ||
779 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | ||
780 | before_vht, ARRAY_SIZE(before_vht), | ||
781 | offset); | ||
782 | pos = skb_put(skb, noffset - offset); | ||
783 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | ||
784 | offset = noffset; | ||
785 | } | ||
786 | |||
748 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | 787 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
749 | ieee80211_add_vht_ie(sdata, skb, sband, | 788 | ieee80211_add_vht_ie(sdata, skb, sband, |
750 | &assoc_data->ap_vht_cap); | 789 | &assoc_data->ap_vht_cap); |
@@ -1001,7 +1040,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1001 | } | 1040 | } |
1002 | 1041 | ||
1003 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 1042 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
1004 | sdata->vif.csa_active = true; | ||
1005 | 1043 | ||
1006 | mutex_lock(&local->chanctx_mtx); | 1044 | mutex_lock(&local->chanctx_mtx); |
1007 | if (local->use_chanctx) { | 1045 | if (local->use_chanctx) { |
@@ -1039,6 +1077,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1039 | mutex_unlock(&local->chanctx_mtx); | 1077 | mutex_unlock(&local->chanctx_mtx); |
1040 | 1078 | ||
1041 | sdata->csa_chandef = csa_ie.chandef; | 1079 | sdata->csa_chandef = csa_ie.chandef; |
1080 | sdata->vif.csa_active = true; | ||
1042 | 1081 | ||
1043 | if (csa_ie.mode) | 1082 | if (csa_ie.mode) |
1044 | ieee80211_stop_queues_by_reason(&local->hw, | 1083 | ieee80211_stop_queues_by_reason(&local->hw, |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 22b223f13c9f..8fdadfd94ba8 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -10,15 +10,15 @@ | |||
10 | 10 | ||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/rtnetlink.h> | 12 | #include <linux/rtnetlink.h> |
13 | #include <linux/slab.h> | ||
14 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/slab.h> | ||
15 | #include "rate.h" | 15 | #include "rate.h" |
16 | #include "ieee80211_i.h" | 16 | #include "ieee80211_i.h" |
17 | #include "debugfs.h" | 17 | #include "debugfs.h" |
18 | 18 | ||
19 | struct rate_control_alg { | 19 | struct rate_control_alg { |
20 | struct list_head list; | 20 | struct list_head list; |
21 | struct rate_control_ops *ops; | 21 | const struct rate_control_ops *ops; |
22 | }; | 22 | }; |
23 | 23 | ||
24 | static LIST_HEAD(rate_ctrl_algs); | 24 | static LIST_HEAD(rate_ctrl_algs); |
@@ -29,7 +29,7 @@ module_param(ieee80211_default_rc_algo, charp, 0644); | |||
29 | MODULE_PARM_DESC(ieee80211_default_rc_algo, | 29 | MODULE_PARM_DESC(ieee80211_default_rc_algo, |
30 | "Default rate control algorithm for mac80211 to use"); | 30 | "Default rate control algorithm for mac80211 to use"); |
31 | 31 | ||
32 | int ieee80211_rate_control_register(struct rate_control_ops *ops) | 32 | int ieee80211_rate_control_register(const struct rate_control_ops *ops) |
33 | { | 33 | { |
34 | struct rate_control_alg *alg; | 34 | struct rate_control_alg *alg; |
35 | 35 | ||
@@ -60,7 +60,7 @@ int ieee80211_rate_control_register(struct rate_control_ops *ops) | |||
60 | } | 60 | } |
61 | EXPORT_SYMBOL(ieee80211_rate_control_register); | 61 | EXPORT_SYMBOL(ieee80211_rate_control_register); |
62 | 62 | ||
63 | void ieee80211_rate_control_unregister(struct rate_control_ops *ops) | 63 | void ieee80211_rate_control_unregister(const struct rate_control_ops *ops) |
64 | { | 64 | { |
65 | struct rate_control_alg *alg; | 65 | struct rate_control_alg *alg; |
66 | 66 | ||
@@ -76,32 +76,31 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops) | |||
76 | } | 76 | } |
77 | EXPORT_SYMBOL(ieee80211_rate_control_unregister); | 77 | EXPORT_SYMBOL(ieee80211_rate_control_unregister); |
78 | 78 | ||
79 | static struct rate_control_ops * | 79 | static const struct rate_control_ops * |
80 | ieee80211_try_rate_control_ops_get(const char *name) | 80 | ieee80211_try_rate_control_ops_get(const char *name) |
81 | { | 81 | { |
82 | struct rate_control_alg *alg; | 82 | struct rate_control_alg *alg; |
83 | struct rate_control_ops *ops = NULL; | 83 | const struct rate_control_ops *ops = NULL; |
84 | 84 | ||
85 | if (!name) | 85 | if (!name) |
86 | return NULL; | 86 | return NULL; |
87 | 87 | ||
88 | mutex_lock(&rate_ctrl_mutex); | 88 | mutex_lock(&rate_ctrl_mutex); |
89 | list_for_each_entry(alg, &rate_ctrl_algs, list) { | 89 | list_for_each_entry(alg, &rate_ctrl_algs, list) { |
90 | if (!strcmp(alg->ops->name, name)) | 90 | if (!strcmp(alg->ops->name, name)) { |
91 | if (try_module_get(alg->ops->module)) { | 91 | ops = alg->ops; |
92 | ops = alg->ops; | 92 | break; |
93 | break; | 93 | } |
94 | } | ||
95 | } | 94 | } |
96 | mutex_unlock(&rate_ctrl_mutex); | 95 | mutex_unlock(&rate_ctrl_mutex); |
97 | return ops; | 96 | return ops; |
98 | } | 97 | } |
99 | 98 | ||
100 | /* Get the rate control algorithm. */ | 99 | /* Get the rate control algorithm. */ |
101 | static struct rate_control_ops * | 100 | static const struct rate_control_ops * |
102 | ieee80211_rate_control_ops_get(const char *name) | 101 | ieee80211_rate_control_ops_get(const char *name) |
103 | { | 102 | { |
104 | struct rate_control_ops *ops; | 103 | const struct rate_control_ops *ops; |
105 | const char *alg_name; | 104 | const char *alg_name; |
106 | 105 | ||
107 | kparam_block_sysfs_write(ieee80211_default_rc_algo); | 106 | kparam_block_sysfs_write(ieee80211_default_rc_algo); |
@@ -111,10 +110,6 @@ ieee80211_rate_control_ops_get(const char *name) | |||
111 | alg_name = name; | 110 | alg_name = name; |
112 | 111 | ||
113 | ops = ieee80211_try_rate_control_ops_get(alg_name); | 112 | ops = ieee80211_try_rate_control_ops_get(alg_name); |
114 | if (!ops) { | ||
115 | request_module("rc80211_%s", alg_name); | ||
116 | ops = ieee80211_try_rate_control_ops_get(alg_name); | ||
117 | } | ||
118 | if (!ops && name) | 113 | if (!ops && name) |
119 | /* try default if specific alg requested but not found */ | 114 | /* try default if specific alg requested but not found */ |
120 | ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); | 115 | ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); |
@@ -127,11 +122,6 @@ ieee80211_rate_control_ops_get(const char *name) | |||
127 | return ops; | 122 | return ops; |
128 | } | 123 | } |
129 | 124 | ||
130 | static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops) | ||
131 | { | ||
132 | module_put(ops->module); | ||
133 | } | ||
134 | |||
135 | #ifdef CONFIG_MAC80211_DEBUGFS | 125 | #ifdef CONFIG_MAC80211_DEBUGFS |
136 | static ssize_t rcname_read(struct file *file, char __user *userbuf, | 126 | static ssize_t rcname_read(struct file *file, char __user *userbuf, |
137 | size_t count, loff_t *ppos) | 127 | size_t count, loff_t *ppos) |
@@ -158,11 +148,11 @@ static struct rate_control_ref *rate_control_alloc(const char *name, | |||
158 | 148 | ||
159 | ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); | 149 | ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); |
160 | if (!ref) | 150 | if (!ref) |
161 | goto fail_ref; | 151 | return NULL; |
162 | ref->local = local; | 152 | ref->local = local; |
163 | ref->ops = ieee80211_rate_control_ops_get(name); | 153 | ref->ops = ieee80211_rate_control_ops_get(name); |
164 | if (!ref->ops) | 154 | if (!ref->ops) |
165 | goto fail_ops; | 155 | goto free; |
166 | 156 | ||
167 | #ifdef CONFIG_MAC80211_DEBUGFS | 157 | #ifdef CONFIG_MAC80211_DEBUGFS |
168 | debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir); | 158 | debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir); |
@@ -172,14 +162,11 @@ static struct rate_control_ref *rate_control_alloc(const char *name, | |||
172 | 162 | ||
173 | ref->priv = ref->ops->alloc(&local->hw, debugfsdir); | 163 | ref->priv = ref->ops->alloc(&local->hw, debugfsdir); |
174 | if (!ref->priv) | 164 | if (!ref->priv) |
175 | goto fail_priv; | 165 | goto free; |
176 | return ref; | 166 | return ref; |
177 | 167 | ||
178 | fail_priv: | 168 | free: |
179 | ieee80211_rate_control_ops_put(ref->ops); | ||
180 | fail_ops: | ||
181 | kfree(ref); | 169 | kfree(ref); |
182 | fail_ref: | ||
183 | return NULL; | 170 | return NULL; |
184 | } | 171 | } |
185 | 172 | ||
@@ -192,7 +179,6 @@ static void rate_control_free(struct rate_control_ref *ctrl_ref) | |||
192 | ctrl_ref->local->debugfs.rcdir = NULL; | 179 | ctrl_ref->local->debugfs.rcdir = NULL; |
193 | #endif | 180 | #endif |
194 | 181 | ||
195 | ieee80211_rate_control_ops_put(ctrl_ref->ops); | ||
196 | kfree(ctrl_ref); | 182 | kfree(ctrl_ref); |
197 | } | 183 | } |
198 | 184 | ||
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index b95e16c07081..9aa2a1190a86 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -21,7 +21,7 @@ | |||
21 | 21 | ||
22 | struct rate_control_ref { | 22 | struct rate_control_ref { |
23 | struct ieee80211_local *local; | 23 | struct ieee80211_local *local; |
24 | struct rate_control_ops *ops; | 24 | const struct rate_control_ops *ops; |
25 | void *priv; | 25 | void *priv; |
26 | }; | 26 | }; |
27 | 27 | ||
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index f3d88b0c054c..26fd94fa0aed 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -657,7 +657,7 @@ minstrel_free(void *priv) | |||
657 | kfree(priv); | 657 | kfree(priv); |
658 | } | 658 | } |
659 | 659 | ||
660 | struct rate_control_ops mac80211_minstrel = { | 660 | const struct rate_control_ops mac80211_minstrel = { |
661 | .name = "minstrel", | 661 | .name = "minstrel", |
662 | .tx_status = minstrel_tx_status, | 662 | .tx_status = minstrel_tx_status, |
663 | .get_rate = minstrel_get_rate, | 663 | .get_rate = minstrel_get_rate, |
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index f4301f4b2e41..046d1bd598a8 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
@@ -123,7 +123,7 @@ struct minstrel_debugfs_info { | |||
123 | char buf[]; | 123 | char buf[]; |
124 | }; | 124 | }; |
125 | 125 | ||
126 | extern struct rate_control_ops mac80211_minstrel; | 126 | extern const struct rate_control_ops mac80211_minstrel; |
127 | void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); | 127 | void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); |
128 | void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); | 128 | void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); |
129 | 129 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index c1b5b73c5b91..bccaf854a309 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -124,7 +124,7 @@ const struct mcs_group minstrel_mcs_groups[] = { | |||
124 | 124 | ||
125 | #define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1) | 125 | #define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1) |
126 | 126 | ||
127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; | 127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; |
128 | 128 | ||
129 | static void | 129 | static void |
130 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); | 130 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); |
@@ -1031,7 +1031,7 @@ minstrel_ht_free(void *priv) | |||
1031 | mac80211_minstrel.free(priv); | 1031 | mac80211_minstrel.free(priv); |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | static struct rate_control_ops mac80211_minstrel_ht = { | 1034 | static const struct rate_control_ops mac80211_minstrel_ht = { |
1035 | .name = "minstrel_ht", | 1035 | .name = "minstrel_ht", |
1036 | .tx_status = minstrel_ht_tx_status, | 1036 | .tx_status = minstrel_ht_tx_status, |
1037 | .get_rate = minstrel_ht_get_rate, | 1037 | .get_rate = minstrel_ht_get_rate, |
@@ -1048,8 +1048,7 @@ static struct rate_control_ops mac80211_minstrel_ht = { | |||
1048 | }; | 1048 | }; |
1049 | 1049 | ||
1050 | 1050 | ||
1051 | static void | 1051 | static void __init init_sample_table(void) |
1052 | init_sample_table(void) | ||
1053 | { | 1052 | { |
1054 | int col, i, new_idx; | 1053 | int col, i, new_idx; |
1055 | u8 rnd[MCS_GROUP_RATES]; | 1054 | u8 rnd[MCS_GROUP_RATES]; |
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 958fad07b54c..d0da2a70fe68 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c | |||
@@ -452,7 +452,7 @@ static void rate_control_pid_free_sta(void *priv, struct ieee80211_sta *sta, | |||
452 | kfree(priv_sta); | 452 | kfree(priv_sta); |
453 | } | 453 | } |
454 | 454 | ||
455 | static struct rate_control_ops mac80211_rcpid = { | 455 | static const struct rate_control_ops mac80211_rcpid = { |
456 | .name = "pid", | 456 | .name = "pid", |
457 | .tx_status = rate_control_pid_tx_status, | 457 | .tx_status = rate_control_pid_tx_status, |
458 | .get_rate = rate_control_pid_get_rate, | 458 | .get_rate = rate_control_pid_get_rate, |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c24ca0d0f469..593062109c50 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -40,8 +40,6 @@ | |||
40 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | 40 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, |
41 | struct sk_buff *skb) | 41 | struct sk_buff *skb) |
42 | { | 42 | { |
43 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
44 | |||
45 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 43 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
46 | if (likely(skb->len > FCS_LEN)) | 44 | if (likely(skb->len > FCS_LEN)) |
47 | __pskb_trim(skb, skb->len - FCS_LEN); | 45 | __pskb_trim(skb, skb->len - FCS_LEN); |
@@ -53,9 +51,6 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
53 | } | 51 | } |
54 | } | 52 | } |
55 | 53 | ||
56 | if (status->vendor_radiotap_len) | ||
57 | __pskb_pull(skb, status->vendor_radiotap_len); | ||
58 | |||
59 | return skb; | 54 | return skb; |
60 | } | 55 | } |
61 | 56 | ||
@@ -64,14 +59,13 @@ static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) | |||
64 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 59 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
65 | struct ieee80211_hdr *hdr; | 60 | struct ieee80211_hdr *hdr; |
66 | 61 | ||
67 | hdr = (void *)(skb->data + status->vendor_radiotap_len); | 62 | hdr = (void *)(skb->data); |
68 | 63 | ||
69 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | 64 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
70 | RX_FLAG_FAILED_PLCP_CRC | | 65 | RX_FLAG_FAILED_PLCP_CRC | |
71 | RX_FLAG_AMPDU_IS_ZEROLEN)) | 66 | RX_FLAG_AMPDU_IS_ZEROLEN)) |
72 | return 1; | 67 | return 1; |
73 | if (unlikely(skb->len < 16 + present_fcs_len + | 68 | if (unlikely(skb->len < 16 + present_fcs_len)) |
74 | status->vendor_radiotap_len)) | ||
75 | return 1; | 69 | return 1; |
76 | if (ieee80211_is_ctl(hdr->frame_control) && | 70 | if (ieee80211_is_ctl(hdr->frame_control) && |
77 | !ieee80211_is_pspoll(hdr->frame_control) && | 71 | !ieee80211_is_pspoll(hdr->frame_control) && |
@@ -90,8 +84,6 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, | |||
90 | len = sizeof(struct ieee80211_radiotap_header) + 8; | 84 | len = sizeof(struct ieee80211_radiotap_header) + 8; |
91 | 85 | ||
92 | /* allocate extra bitmaps */ | 86 | /* allocate extra bitmaps */ |
93 | if (status->vendor_radiotap_len) | ||
94 | len += 4; | ||
95 | if (status->chains) | 87 | if (status->chains) |
96 | len += 4 * hweight8(status->chains); | 88 | len += 4 * hweight8(status->chains); |
97 | 89 | ||
@@ -127,18 +119,6 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, | |||
127 | len += 2 * hweight8(status->chains); | 119 | len += 2 * hweight8(status->chains); |
128 | } | 120 | } |
129 | 121 | ||
130 | if (status->vendor_radiotap_len) { | ||
131 | if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) | ||
132 | status->vendor_radiotap_align = 1; | ||
133 | /* align standard part of vendor namespace */ | ||
134 | len = ALIGN(len, 2); | ||
135 | /* allocate standard part of vendor namespace */ | ||
136 | len += 6; | ||
137 | /* align vendor-defined part */ | ||
138 | len = ALIGN(len, status->vendor_radiotap_align); | ||
139 | /* vendor-defined part is already in skb */ | ||
140 | } | ||
141 | |||
142 | return len; | 122 | return len; |
143 | } | 123 | } |
144 | 124 | ||
@@ -172,7 +152,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
172 | it_present = &rthdr->it_present; | 152 | it_present = &rthdr->it_present; |
173 | 153 | ||
174 | /* radiotap header, set always present flags */ | 154 | /* radiotap header, set always present flags */ |
175 | rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); | 155 | rthdr->it_len = cpu_to_le16(rtap_len); |
176 | it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) | | 156 | it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) | |
177 | BIT(IEEE80211_RADIOTAP_CHANNEL) | | 157 | BIT(IEEE80211_RADIOTAP_CHANNEL) | |
178 | BIT(IEEE80211_RADIOTAP_RX_FLAGS); | 158 | BIT(IEEE80211_RADIOTAP_RX_FLAGS); |
@@ -190,14 +170,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
190 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); | 170 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); |
191 | } | 171 | } |
192 | 172 | ||
193 | if (status->vendor_radiotap_len) { | ||
194 | it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | | ||
195 | BIT(IEEE80211_RADIOTAP_EXT); | ||
196 | put_unaligned_le32(it_present_val, it_present); | ||
197 | it_present++; | ||
198 | it_present_val = status->vendor_radiotap_bitmap; | ||
199 | } | ||
200 | |||
201 | put_unaligned_le32(it_present_val, it_present); | 173 | put_unaligned_le32(it_present_val, it_present); |
202 | 174 | ||
203 | pos = (void *)(it_present + 1); | 175 | pos = (void *)(it_present + 1); |
@@ -307,6 +279,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
307 | *pos |= IEEE80211_RADIOTAP_MCS_BW_40; | 279 | *pos |= IEEE80211_RADIOTAP_MCS_BW_40; |
308 | if (status->flag & RX_FLAG_HT_GF) | 280 | if (status->flag & RX_FLAG_HT_GF) |
309 | *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; | 281 | *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; |
282 | if (status->flag & RX_FLAG_LDPC) | ||
283 | *pos |= IEEE80211_RADIOTAP_MCS_FEC_LDPC; | ||
310 | stbc = (status->flag & RX_FLAG_STBC_MASK) >> RX_FLAG_STBC_SHIFT; | 284 | stbc = (status->flag & RX_FLAG_STBC_MASK) >> RX_FLAG_STBC_SHIFT; |
311 | *pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT; | 285 | *pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT; |
312 | pos++; | 286 | pos++; |
@@ -349,20 +323,23 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
349 | 323 | ||
350 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); | 324 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); |
351 | /* known field - how to handle 80+80? */ | 325 | /* known field - how to handle 80+80? */ |
352 | if (status->flag & RX_FLAG_80P80MHZ) | 326 | if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) |
353 | known &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; | 327 | known &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; |
354 | put_unaligned_le16(known, pos); | 328 | put_unaligned_le16(known, pos); |
355 | pos += 2; | 329 | pos += 2; |
356 | /* flags */ | 330 | /* flags */ |
357 | if (status->flag & RX_FLAG_SHORT_GI) | 331 | if (status->flag & RX_FLAG_SHORT_GI) |
358 | *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; | 332 | *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; |
333 | /* in VHT, STBC is binary */ | ||
334 | if (status->flag & RX_FLAG_STBC_MASK) | ||
335 | *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; | ||
359 | pos++; | 336 | pos++; |
360 | /* bandwidth */ | 337 | /* bandwidth */ |
361 | if (status->flag & RX_FLAG_80MHZ) | 338 | if (status->vht_flag & RX_VHT_FLAG_80MHZ) |
362 | *pos++ = 4; | 339 | *pos++ = 4; |
363 | else if (status->flag & RX_FLAG_80P80MHZ) | 340 | else if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) |
364 | *pos++ = 0; /* marked not known above */ | 341 | *pos++ = 0; /* marked not known above */ |
365 | else if (status->flag & RX_FLAG_160MHZ) | 342 | else if (status->vht_flag & RX_VHT_FLAG_160MHZ) |
366 | *pos++ = 11; | 343 | *pos++ = 11; |
367 | else if (status->flag & RX_FLAG_40MHZ) | 344 | else if (status->flag & RX_FLAG_40MHZ) |
368 | *pos++ = 1; | 345 | *pos++ = 1; |
@@ -372,6 +349,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
372 | *pos = (status->rate_idx << 4) | status->vht_nss; | 349 | *pos = (status->rate_idx << 4) | status->vht_nss; |
373 | pos += 4; | 350 | pos += 4; |
374 | /* coding field */ | 351 | /* coding field */ |
352 | if (status->flag & RX_FLAG_LDPC) | ||
353 | *pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0; | ||
375 | pos++; | 354 | pos++; |
376 | /* group ID */ | 355 | /* group ID */ |
377 | pos++; | 356 | pos++; |
@@ -383,21 +362,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
383 | *pos++ = status->chain_signal[chain]; | 362 | *pos++ = status->chain_signal[chain]; |
384 | *pos++ = chain; | 363 | *pos++ = chain; |
385 | } | 364 | } |
386 | |||
387 | if (status->vendor_radiotap_len) { | ||
388 | /* ensure 2 byte alignment for the vendor field as required */ | ||
389 | if ((pos - (u8 *)rthdr) & 1) | ||
390 | *pos++ = 0; | ||
391 | *pos++ = status->vendor_radiotap_oui[0]; | ||
392 | *pos++ = status->vendor_radiotap_oui[1]; | ||
393 | *pos++ = status->vendor_radiotap_oui[2]; | ||
394 | *pos++ = status->vendor_radiotap_subns; | ||
395 | put_unaligned_le16(status->vendor_radiotap_len, pos); | ||
396 | pos += 2; | ||
397 | /* align the actual payload as requested */ | ||
398 | while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1)) | ||
399 | *pos++ = 0; | ||
400 | } | ||
401 | } | 365 | } |
402 | 366 | ||
403 | /* | 367 | /* |
@@ -428,8 +392,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
428 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 392 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
429 | present_fcs_len = FCS_LEN; | 393 | present_fcs_len = FCS_LEN; |
430 | 394 | ||
431 | /* ensure hdr->frame_control and vendor radiotap data are in skb head */ | 395 | /* ensure hdr->frame_control is in skb head */ |
432 | if (!pskb_may_pull(origskb, 2 + status->vendor_radiotap_len)) { | 396 | if (!pskb_may_pull(origskb, 2)) { |
433 | dev_kfree_skb(origskb); | 397 | dev_kfree_skb(origskb); |
434 | return NULL; | 398 | return NULL; |
435 | } | 399 | } |
@@ -599,10 +563,10 @@ static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) | |||
599 | { | 563 | { |
600 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 564 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
601 | 565 | ||
602 | if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1)) | 566 | if (is_multicast_ether_addr(hdr->addr1)) |
603 | return 0; | 567 | return 0; |
604 | 568 | ||
605 | return ieee80211_is_robust_mgmt_frame(hdr); | 569 | return ieee80211_is_robust_mgmt_frame(skb); |
606 | } | 570 | } |
607 | 571 | ||
608 | 572 | ||
@@ -610,10 +574,10 @@ static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb) | |||
610 | { | 574 | { |
611 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 575 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
612 | 576 | ||
613 | if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1)) | 577 | if (!is_multicast_ether_addr(hdr->addr1)) |
614 | return 0; | 578 | return 0; |
615 | 579 | ||
616 | return ieee80211_is_robust_mgmt_frame(hdr); | 580 | return ieee80211_is_robust_mgmt_frame(skb); |
617 | } | 581 | } |
618 | 582 | ||
619 | 583 | ||
@@ -626,7 +590,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
626 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) | 590 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) |
627 | return -1; | 591 | return -1; |
628 | 592 | ||
629 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) | 593 | if (!ieee80211_is_robust_mgmt_frame(skb)) |
630 | return -1; /* not a robust management frame */ | 594 | return -1; /* not a robust management frame */ |
631 | 595 | ||
632 | mmie = (struct ieee80211_mmie *) | 596 | mmie = (struct ieee80211_mmie *) |
@@ -1261,6 +1225,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1261 | if (ieee80211_is_data(hdr->frame_control)) { | 1225 | if (ieee80211_is_data(hdr->frame_control)) { |
1262 | sta->last_rx_rate_idx = status->rate_idx; | 1226 | sta->last_rx_rate_idx = status->rate_idx; |
1263 | sta->last_rx_rate_flag = status->flag; | 1227 | sta->last_rx_rate_flag = status->flag; |
1228 | sta->last_rx_rate_vht_flag = status->vht_flag; | ||
1264 | sta->last_rx_rate_vht_nss = status->vht_nss; | 1229 | sta->last_rx_rate_vht_nss = status->vht_nss; |
1265 | } | 1230 | } |
1266 | } | 1231 | } |
@@ -1311,18 +1276,15 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1311 | !ieee80211_has_morefrags(hdr->frame_control) && | 1276 | !ieee80211_has_morefrags(hdr->frame_control) && |
1312 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && | 1277 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && |
1313 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | 1278 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || |
1314 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { | 1279 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && |
1280 | /* PM bit is only checked in frames where it isn't reserved, | ||
1281 | * in AP mode it's reserved in non-bufferable management frames | ||
1282 | * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field) | ||
1283 | */ | ||
1284 | (!ieee80211_is_mgmt(hdr->frame_control) || | ||
1285 | ieee80211_is_bufferable_mmpdu(hdr->frame_control))) { | ||
1315 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | 1286 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { |
1316 | /* | 1287 | if (!ieee80211_has_pm(hdr->frame_control)) |
1317 | * Ignore doze->wake transitions that are | ||
1318 | * indicated by non-data frames, the standard | ||
1319 | * is unclear here, but for example going to | ||
1320 | * PS mode and then scanning would cause a | ||
1321 | * doze->wake transition for the probe request, | ||
1322 | * and that is clearly undesirable. | ||
1323 | */ | ||
1324 | if (ieee80211_is_data(hdr->frame_control) && | ||
1325 | !ieee80211_has_pm(hdr->frame_control)) | ||
1326 | sta_ps_end(sta); | 1288 | sta_ps_end(sta); |
1327 | } else { | 1289 | } else { |
1328 | if (ieee80211_has_pm(hdr->frame_control)) | 1290 | if (ieee80211_has_pm(hdr->frame_control)) |
@@ -1845,8 +1807,7 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | |||
1845 | * having configured keys. | 1807 | * having configured keys. |
1846 | */ | 1808 | */ |
1847 | if (unlikely(ieee80211_is_action(fc) && !rx->key && | 1809 | if (unlikely(ieee80211_is_action(fc) && !rx->key && |
1848 | ieee80211_is_robust_mgmt_frame( | 1810 | ieee80211_is_robust_mgmt_frame(rx->skb))) |
1849 | (struct ieee80211_hdr *) rx->skb->data))) | ||
1850 | return -EACCES; | 1811 | return -EACCES; |
1851 | } | 1812 | } |
1852 | 1813 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d77ff7090630..d4d85de0d75d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -261,6 +261,7 @@ struct ieee80211_tx_latency_stat { | |||
261 | * "the" transmit rate | 261 | * "the" transmit rate |
262 | * @last_rx_rate_idx: rx status rate index of the last data packet | 262 | * @last_rx_rate_idx: rx status rate index of the last data packet |
263 | * @last_rx_rate_flag: rx status flag of the last data packet | 263 | * @last_rx_rate_flag: rx status flag of the last data packet |
264 | * @last_rx_rate_vht_flag: rx status vht flag of the last data packet | ||
264 | * @last_rx_rate_vht_nss: rx status nss of last data packet | 265 | * @last_rx_rate_vht_nss: rx status nss of last data packet |
265 | * @lock: used for locking all fields that require locking, see comments | 266 | * @lock: used for locking all fields that require locking, see comments |
266 | * in the header file. | 267 | * in the header file. |
@@ -397,6 +398,7 @@ struct sta_info { | |||
397 | struct ieee80211_tx_rate last_tx_rate; | 398 | struct ieee80211_tx_rate last_tx_rate; |
398 | int last_rx_rate_idx; | 399 | int last_rx_rate_idx; |
399 | u32 last_rx_rate_flag; | 400 | u32 last_rx_rate_flag; |
401 | u32 last_rx_rate_vht_flag; | ||
400 | u8 last_rx_rate_vht_nss; | 402 | u8 last_rx_rate_vht_nss; |
401 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; | 403 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; |
402 | 404 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 1ee85c402439..e6e574a307c8 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -479,7 +479,7 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | |||
479 | u32 msrmnt; | 479 | u32 msrmnt; |
480 | u16 tid; | 480 | u16 tid; |
481 | u8 *qc; | 481 | u8 *qc; |
482 | int i, bin_range_count, bin_count; | 482 | int i, bin_range_count; |
483 | u32 *bin_ranges; | 483 | u32 *bin_ranges; |
484 | __le16 fc; | 484 | __le16 fc; |
485 | struct ieee80211_tx_latency_stat *tx_lat; | 485 | struct ieee80211_tx_latency_stat *tx_lat; |
@@ -522,7 +522,6 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local, | |||
522 | /* count how many Tx frames transmitted with the appropriate latency */ | 522 | /* count how many Tx frames transmitted with the appropriate latency */ |
523 | bin_range_count = tx_latency->n_ranges; | 523 | bin_range_count = tx_latency->n_ranges; |
524 | bin_ranges = tx_latency->ranges; | 524 | bin_ranges = tx_latency->ranges; |
525 | bin_count = tx_lat->bin_count; | ||
526 | 525 | ||
527 | for (i = 0; i < bin_range_count; i++) { | 526 | for (i = 0; i < bin_range_count; i++) { |
528 | if (msrmnt <= bin_ranges[i]) { | 527 | if (msrmnt <= bin_ranges[i]) { |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 97a02d3f7d87..722151fa5dce 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -452,8 +452,7 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, | |||
452 | if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP)) | 452 | if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP)) |
453 | return 0; | 453 | return 0; |
454 | 454 | ||
455 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) | 455 | if (!ieee80211_is_robust_mgmt_frame(skb)) |
456 | skb->data)) | ||
457 | return 0; | 456 | return 0; |
458 | 457 | ||
459 | return 1; | 458 | return 1; |
@@ -523,11 +522,8 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) | |||
523 | if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED)) | 522 | if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED)) |
524 | return TX_CONTINUE; | 523 | return TX_CONTINUE; |
525 | 524 | ||
526 | /* only deauth, disassoc and action are bufferable MMPDUs */ | ||
527 | if (ieee80211_is_mgmt(hdr->frame_control) && | 525 | if (ieee80211_is_mgmt(hdr->frame_control) && |
528 | !ieee80211_is_deauth(hdr->frame_control) && | 526 | !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { |
529 | !ieee80211_is_disassoc(hdr->frame_control) && | ||
530 | !ieee80211_is_action(hdr->frame_control)) { | ||
531 | if (tx->flags & IEEE80211_TX_UNICAST) | 527 | if (tx->flags & IEEE80211_TX_UNICAST) |
532 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; | 528 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; |
533 | return TX_CONTINUE; | 529 | return TX_CONTINUE; |
@@ -567,7 +563,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
567 | tx->key = key; | 563 | tx->key = key; |
568 | else if (ieee80211_is_mgmt(hdr->frame_control) && | 564 | else if (ieee80211_is_mgmt(hdr->frame_control) && |
569 | is_multicast_ether_addr(hdr->addr1) && | 565 | is_multicast_ether_addr(hdr->addr1) && |
570 | ieee80211_is_robust_mgmt_frame(hdr) && | 566 | ieee80211_is_robust_mgmt_frame(tx->skb) && |
571 | (key = rcu_dereference(tx->sdata->default_mgmt_key))) | 567 | (key = rcu_dereference(tx->sdata->default_mgmt_key))) |
572 | tx->key = key; | 568 | tx->key = key; |
573 | else if (is_multicast_ether_addr(hdr->addr1) && | 569 | else if (is_multicast_ether_addr(hdr->addr1) && |
@@ -582,12 +578,12 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
582 | tx->key = NULL; | 578 | tx->key = NULL; |
583 | else if (tx->skb->protocol == tx->sdata->control_port_protocol) | 579 | else if (tx->skb->protocol == tx->sdata->control_port_protocol) |
584 | tx->key = NULL; | 580 | tx->key = NULL; |
585 | else if (ieee80211_is_robust_mgmt_frame(hdr) && | 581 | else if (ieee80211_is_robust_mgmt_frame(tx->skb) && |
586 | !(ieee80211_is_action(hdr->frame_control) && | 582 | !(ieee80211_is_action(hdr->frame_control) && |
587 | tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) | 583 | tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) |
588 | tx->key = NULL; | 584 | tx->key = NULL; |
589 | else if (ieee80211_is_mgmt(hdr->frame_control) && | 585 | else if (ieee80211_is_mgmt(hdr->frame_control) && |
590 | !ieee80211_is_robust_mgmt_frame(hdr)) | 586 | !ieee80211_is_robust_mgmt_frame(tx->skb)) |
591 | tx->key = NULL; | 587 | tx->key = NULL; |
592 | else { | 588 | else { |
593 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); | 589 | I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); |
@@ -2402,15 +2398,6 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
2402 | return 0; | 2398 | return 0; |
2403 | } | 2399 | } |
2404 | 2400 | ||
2405 | void ieee80211_csa_finish(struct ieee80211_vif *vif) | ||
2406 | { | ||
2407 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
2408 | |||
2409 | ieee80211_queue_work(&sdata->local->hw, | ||
2410 | &sdata->csa_finalize_work); | ||
2411 | } | ||
2412 | EXPORT_SYMBOL(ieee80211_csa_finish); | ||
2413 | |||
2414 | static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, | 2401 | static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, |
2415 | struct beacon_data *beacon) | 2402 | struct beacon_data *beacon) |
2416 | { | 2403 | { |
@@ -2439,8 +2426,12 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, | |||
2439 | if (WARN_ON(counter_offset_beacon >= beacon_data_len)) | 2426 | if (WARN_ON(counter_offset_beacon >= beacon_data_len)) |
2440 | return; | 2427 | return; |
2441 | 2428 | ||
2442 | /* warn if the driver did not check for/react to csa completeness */ | 2429 | /* Warn if the driver did not check for/react to csa |
2443 | if (WARN_ON(beacon_data[counter_offset_beacon] == 0)) | 2430 | * completeness. A beacon with CSA counter set to 0 should |
2431 | * never occur, because a counter of 1 means switch just | ||
2432 | * before the next beacon. | ||
2433 | */ | ||
2434 | if (WARN_ON(beacon_data[counter_offset_beacon] == 1)) | ||
2444 | return; | 2435 | return; |
2445 | 2436 | ||
2446 | beacon_data[counter_offset_beacon]--; | 2437 | beacon_data[counter_offset_beacon]--; |
@@ -2506,7 +2497,7 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | |||
2506 | if (WARN_ON(counter_beacon > beacon_data_len)) | 2497 | if (WARN_ON(counter_beacon > beacon_data_len)) |
2507 | goto out; | 2498 | goto out; |
2508 | 2499 | ||
2509 | if (beacon_data[counter_beacon] == 0) | 2500 | if (beacon_data[counter_beacon] == 1) |
2510 | ret = true; | 2501 | ret = true; |
2511 | out: | 2502 | out: |
2512 | rcu_read_unlock(); | 2503 | rcu_read_unlock(); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 676dc0967f37..d842af5c8a95 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include "wep.h" | 34 | #include "wep.h" |
35 | 35 | ||
36 | /* privid for wiphys to determine whether they belong to us or not */ | 36 | /* privid for wiphys to determine whether they belong to us or not */ |
37 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; | 37 | const void *const mac80211_wiphy_privid = &mac80211_wiphy_privid; |
38 | 38 | ||
39 | struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) | 39 | struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) |
40 | { | 40 | { |
@@ -1281,13 +1281,32 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1281 | * that calculates local->scan_ies_len. | 1281 | * that calculates local->scan_ies_len. |
1282 | */ | 1282 | */ |
1283 | 1283 | ||
1284 | /* add any remaining custom IEs */ | 1284 | /* insert custom IEs that go before VHT */ |
1285 | if (ie && ie_len) { | 1285 | if (ie && ie_len) { |
1286 | noffset = ie_len; | 1286 | static const u8 before_vht[] = { |
1287 | WLAN_EID_SSID, | ||
1288 | WLAN_EID_SUPP_RATES, | ||
1289 | WLAN_EID_REQUEST, | ||
1290 | WLAN_EID_EXT_SUPP_RATES, | ||
1291 | WLAN_EID_DS_PARAMS, | ||
1292 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
1293 | WLAN_EID_HT_CAPABILITY, | ||
1294 | WLAN_EID_BSS_COEX_2040, | ||
1295 | WLAN_EID_EXT_CAPABILITY, | ||
1296 | WLAN_EID_SSID_LIST, | ||
1297 | WLAN_EID_CHANNEL_USAGE, | ||
1298 | WLAN_EID_INTERWORKING, | ||
1299 | /* mesh ID can't happen here */ | ||
1300 | /* 60 GHz can't happen here right now */ | ||
1301 | }; | ||
1302 | noffset = ieee80211_ie_split(ie, ie_len, | ||
1303 | before_vht, ARRAY_SIZE(before_vht), | ||
1304 | offset); | ||
1287 | if (end - pos < noffset - offset) | 1305 | if (end - pos < noffset - offset) |
1288 | goto out_err; | 1306 | goto out_err; |
1289 | memcpy(pos, ie + offset, noffset - offset); | 1307 | memcpy(pos, ie + offset, noffset - offset); |
1290 | pos += noffset - offset; | 1308 | pos += noffset - offset; |
1309 | offset = noffset; | ||
1291 | } | 1310 | } |
1292 | 1311 | ||
1293 | if (sband->vht_cap.vht_supported) { | 1312 | if (sband->vht_cap.vht_supported) { |
@@ -1297,6 +1316,15 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1297 | sband->vht_cap.cap); | 1316 | sband->vht_cap.cap); |
1298 | } | 1317 | } |
1299 | 1318 | ||
1319 | /* add any remaining custom IEs */ | ||
1320 | if (ie && ie_len) { | ||
1321 | noffset = ie_len; | ||
1322 | if (end - pos < noffset - offset) | ||
1323 | goto out_err; | ||
1324 | memcpy(pos, ie + offset, noffset - offset); | ||
1325 | pos += noffset - offset; | ||
1326 | } | ||
1327 | |||
1300 | return pos - buffer; | 1328 | return pos - buffer; |
1301 | out_err: | 1329 | out_err: |
1302 | WARN_ONCE(1, "not enough space for preq IEs\n"); | 1330 | WARN_ONCE(1, "not enough space for preq IEs\n"); |
@@ -1374,7 +1402,6 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, | |||
1374 | enum ieee80211_band band, u32 *basic_rates) | 1402 | enum ieee80211_band band, u32 *basic_rates) |
1375 | { | 1403 | { |
1376 | struct ieee80211_supported_band *sband; | 1404 | struct ieee80211_supported_band *sband; |
1377 | struct ieee80211_rate *bitrates; | ||
1378 | size_t num_rates; | 1405 | size_t num_rates; |
1379 | u32 supp_rates, rate_flags; | 1406 | u32 supp_rates, rate_flags; |
1380 | int i, j, shift; | 1407 | int i, j, shift; |
@@ -1386,7 +1413,6 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, | |||
1386 | if (WARN_ON(!sband)) | 1413 | if (WARN_ON(!sband)) |
1387 | return 1; | 1414 | return 1; |
1388 | 1415 | ||
1389 | bitrates = sband->bitrates; | ||
1390 | num_rates = sband->n_bitrates; | 1416 | num_rates = sband->n_bitrates; |
1391 | supp_rates = 0; | 1417 | supp_rates = 0; |
1392 | for (i = 0; i < elems->supp_rates_len + | 1418 | for (i = 0; i < elems->supp_rates_len + |
@@ -2272,11 +2298,11 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
2272 | ri.nss = status->vht_nss; | 2298 | ri.nss = status->vht_nss; |
2273 | if (status->flag & RX_FLAG_40MHZ) | 2299 | if (status->flag & RX_FLAG_40MHZ) |
2274 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 2300 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
2275 | if (status->flag & RX_FLAG_80MHZ) | 2301 | if (status->vht_flag & RX_VHT_FLAG_80MHZ) |
2276 | ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | 2302 | ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; |
2277 | if (status->flag & RX_FLAG_80P80MHZ) | 2303 | if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) |
2278 | ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | 2304 | ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; |
2279 | if (status->flag & RX_FLAG_160MHZ) | 2305 | if (status->vht_flag & RX_VHT_FLAG_160MHZ) |
2280 | ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 2306 | ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; |
2281 | if (status->flag & RX_FLAG_SHORT_GI) | 2307 | if (status->flag & RX_FLAG_SHORT_GI) |
2282 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | 2308 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index d75f35c6e1a0..e9e36a256165 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -349,9 +349,9 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta) | |||
349 | sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss); | 349 | sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss); |
350 | } | 350 | } |
351 | 351 | ||
352 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 352 | u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
353 | struct sta_info *sta, u8 opmode, | 353 | struct sta_info *sta, u8 opmode, |
354 | enum ieee80211_band band, bool nss_only) | 354 | enum ieee80211_band band, bool nss_only) |
355 | { | 355 | { |
356 | struct ieee80211_local *local = sdata->local; | 356 | struct ieee80211_local *local = sdata->local; |
357 | struct ieee80211_supported_band *sband; | 357 | struct ieee80211_supported_band *sband; |
@@ -363,7 +363,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | |||
363 | 363 | ||
364 | /* ignore - no support for BF yet */ | 364 | /* ignore - no support for BF yet */ |
365 | if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF) | 365 | if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF) |
366 | return; | 366 | return 0; |
367 | 367 | ||
368 | nss = opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; | 368 | nss = opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK; |
369 | nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; | 369 | nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; |
@@ -375,7 +375,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | |||
375 | } | 375 | } |
376 | 376 | ||
377 | if (nss_only) | 377 | if (nss_only) |
378 | goto change; | 378 | return changed; |
379 | 379 | ||
380 | switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { | 380 | switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { |
381 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: | 381 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: |
@@ -398,7 +398,19 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | |||
398 | changed |= IEEE80211_RC_BW_CHANGED; | 398 | changed |= IEEE80211_RC_BW_CHANGED; |
399 | } | 399 | } |
400 | 400 | ||
401 | change: | 401 | return changed; |
402 | if (changed) | 402 | } |
403 | |||
404 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | ||
405 | struct sta_info *sta, u8 opmode, | ||
406 | enum ieee80211_band band, bool nss_only) | ||
407 | { | ||
408 | struct ieee80211_local *local = sdata->local; | ||
409 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; | ||
410 | |||
411 | u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, | ||
412 | band, nss_only); | ||
413 | |||
414 | if (changed > 0) | ||
403 | rate_control_rate_update(local, sband, sta, changed); | 415 | rate_control_rate_update(local, sband, sta, changed); |
404 | } | 416 | } |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 21448d629b15..b8600e3c29c8 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -301,8 +301,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) | |||
301 | } | 301 | } |
302 | 302 | ||
303 | 303 | ||
304 | static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad, | 304 | static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad) |
305 | int encrypted) | ||
306 | { | 305 | { |
307 | __le16 mask_fc; | 306 | __le16 mask_fc; |
308 | int a4_included, mgmt; | 307 | int a4_included, mgmt; |
@@ -456,7 +455,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
456 | return 0; | 455 | return 0; |
457 | 456 | ||
458 | pos += IEEE80211_CCMP_HDR_LEN; | 457 | pos += IEEE80211_CCMP_HDR_LEN; |
459 | ccmp_special_blocks(skb, pn, b_0, aad, 0); | 458 | ccmp_special_blocks(skb, pn, b_0, aad); |
460 | ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, | 459 | ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, |
461 | skb_put(skb, IEEE80211_CCMP_MIC_LEN)); | 460 | skb_put(skb, IEEE80211_CCMP_MIC_LEN)); |
462 | 461 | ||
@@ -495,7 +494,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
495 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 494 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
496 | 495 | ||
497 | if (!ieee80211_is_data(hdr->frame_control) && | 496 | if (!ieee80211_is_data(hdr->frame_control) && |
498 | !ieee80211_is_robust_mgmt_frame(hdr)) | 497 | !ieee80211_is_robust_mgmt_frame(skb)) |
499 | return RX_CONTINUE; | 498 | return RX_CONTINUE; |
500 | 499 | ||
501 | data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - | 500 | data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - |
@@ -524,7 +523,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
524 | u8 aad[2 * AES_BLOCK_SIZE]; | 523 | u8 aad[2 * AES_BLOCK_SIZE]; |
525 | u8 b_0[AES_BLOCK_SIZE]; | 524 | u8 b_0[AES_BLOCK_SIZE]; |
526 | /* hardware didn't decrypt/verify MIC */ | 525 | /* hardware didn't decrypt/verify MIC */ |
527 | ccmp_special_blocks(skb, pn, b_0, aad, 1); | 526 | ccmp_special_blocks(skb, pn, b_0, aad); |
528 | 527 | ||
529 | if (ieee80211_aes_ccm_decrypt( | 528 | if (ieee80211_aes_ccm_decrypt( |
530 | key->u.ccmp.tfm, b_0, aad, | 529 | key->u.ccmp.tfm, b_0, aad, |
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index ed7e0b4e7f90..b3b16c070a7f 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
@@ -789,7 +789,8 @@ void rfkill_resume_polling(struct rfkill *rfkill) | |||
789 | if (!rfkill->ops->poll) | 789 | if (!rfkill->ops->poll) |
790 | return; | 790 | return; |
791 | 791 | ||
792 | schedule_work(&rfkill->poll_work.work); | 792 | queue_delayed_work(system_power_efficient_wq, |
793 | &rfkill->poll_work, 0); | ||
793 | } | 794 | } |
794 | EXPORT_SYMBOL(rfkill_resume_polling); | 795 | EXPORT_SYMBOL(rfkill_resume_polling); |
795 | 796 | ||
@@ -894,7 +895,8 @@ static void rfkill_poll(struct work_struct *work) | |||
894 | */ | 895 | */ |
895 | rfkill->ops->poll(rfkill, rfkill->data); | 896 | rfkill->ops->poll(rfkill, rfkill->data); |
896 | 897 | ||
897 | schedule_delayed_work(&rfkill->poll_work, | 898 | queue_delayed_work(system_power_efficient_wq, |
899 | &rfkill->poll_work, | ||
898 | round_jiffies_relative(POLL_INTERVAL)); | 900 | round_jiffies_relative(POLL_INTERVAL)); |
899 | } | 901 | } |
900 | 902 | ||
@@ -958,7 +960,8 @@ int __must_check rfkill_register(struct rfkill *rfkill) | |||
958 | INIT_WORK(&rfkill->sync_work, rfkill_sync_work); | 960 | INIT_WORK(&rfkill->sync_work, rfkill_sync_work); |
959 | 961 | ||
960 | if (rfkill->ops->poll) | 962 | if (rfkill->ops->poll) |
961 | schedule_delayed_work(&rfkill->poll_work, | 963 | queue_delayed_work(system_power_efficient_wq, |
964 | &rfkill->poll_work, | ||
962 | round_jiffies_relative(POLL_INTERVAL)); | 965 | round_jiffies_relative(POLL_INTERVAL)); |
963 | 966 | ||
964 | if (!rfkill->persistent || rfkill_epo_lock_active) { | 967 | if (!rfkill->persistent || rfkill_epo_lock_active) { |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 11ee4ed04f73..68602be07cc1 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
@@ -27,9 +27,10 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
27 | err = rdev_stop_ap(rdev, dev); | 27 | err = rdev_stop_ap(rdev, dev); |
28 | if (!err) { | 28 | if (!err) { |
29 | wdev->beacon_interval = 0; | 29 | wdev->beacon_interval = 0; |
30 | wdev->channel = NULL; | 30 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); |
31 | wdev->ssid_len = 0; | 31 | wdev->ssid_len = 0; |
32 | rdev_set_qos_map(rdev, dev, NULL); | 32 | rdev_set_qos_map(rdev, dev, NULL); |
33 | nl80211_send_ap_stopped(wdev); | ||
33 | } | 34 | } |
34 | 35 | ||
35 | return err; | 36 | return err; |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index a04b884f5d04..2d4268c5529d 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | |||
642 | void | 642 | void |
643 | cfg80211_get_chan_state(struct wireless_dev *wdev, | 643 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
644 | struct ieee80211_channel **chan, | 644 | struct ieee80211_channel **chan, |
645 | enum cfg80211_chan_mode *chanmode) | 645 | enum cfg80211_chan_mode *chanmode, |
646 | u8 *radar_detect) | ||
646 | { | 647 | { |
647 | *chan = NULL; | 648 | *chan = NULL; |
648 | *chanmode = CHAN_MODE_UNDEFINED; | 649 | *chanmode = CHAN_MODE_UNDEFINED; |
@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
660 | !wdev->ibss_dfs_possible) | 661 | !wdev->ibss_dfs_possible) |
661 | ? CHAN_MODE_SHARED | 662 | ? CHAN_MODE_SHARED |
662 | : CHAN_MODE_EXCLUSIVE; | 663 | : CHAN_MODE_EXCLUSIVE; |
664 | |||
665 | /* consider worst-case - IBSS can try to return to the | ||
666 | * original user-specified channel as creator */ | ||
667 | if (wdev->ibss_dfs_possible) | ||
668 | *radar_detect |= BIT(wdev->chandef.width); | ||
663 | return; | 669 | return; |
664 | } | 670 | } |
665 | break; | 671 | break; |
@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
674 | case NL80211_IFTYPE_AP: | 680 | case NL80211_IFTYPE_AP: |
675 | case NL80211_IFTYPE_P2P_GO: | 681 | case NL80211_IFTYPE_P2P_GO: |
676 | if (wdev->cac_started) { | 682 | if (wdev->cac_started) { |
677 | *chan = wdev->channel; | 683 | *chan = wdev->chandef.chan; |
678 | *chanmode = CHAN_MODE_SHARED; | 684 | *chanmode = CHAN_MODE_SHARED; |
685 | *radar_detect |= BIT(wdev->chandef.width); | ||
679 | } else if (wdev->beacon_interval) { | 686 | } else if (wdev->beacon_interval) { |
680 | *chan = wdev->channel; | 687 | *chan = wdev->chandef.chan; |
681 | *chanmode = CHAN_MODE_SHARED; | 688 | *chanmode = CHAN_MODE_SHARED; |
689 | |||
690 | if (cfg80211_chandef_dfs_required(wdev->wiphy, | ||
691 | &wdev->chandef)) | ||
692 | *radar_detect |= BIT(wdev->chandef.width); | ||
682 | } | 693 | } |
683 | return; | 694 | return; |
684 | case NL80211_IFTYPE_MESH_POINT: | 695 | case NL80211_IFTYPE_MESH_POINT: |
685 | if (wdev->mesh_id_len) { | 696 | if (wdev->mesh_id_len) { |
686 | *chan = wdev->channel; | 697 | *chan = wdev->chandef.chan; |
687 | *chanmode = CHAN_MODE_SHARED; | 698 | *chanmode = CHAN_MODE_SHARED; |
699 | |||
700 | if (cfg80211_chandef_dfs_required(wdev->wiphy, | ||
701 | &wdev->chandef)) | ||
702 | *radar_detect |= BIT(wdev->chandef.width); | ||
688 | } | 703 | } |
689 | return; | 704 | return; |
690 | case NL80211_IFTYPE_MONITOR: | 705 | case NL80211_IFTYPE_MONITOR: |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 010892b81a06..76ae6a605abb 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -737,7 +737,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
737 | } | 737 | } |
738 | EXPORT_SYMBOL(cfg80211_unregister_wdev); | 738 | EXPORT_SYMBOL(cfg80211_unregister_wdev); |
739 | 739 | ||
740 | static struct device_type wiphy_type = { | 740 | static const struct device_type wiphy_type = { |
741 | .name = "wlan", | 741 | .name = "wlan", |
742 | }; | 742 | }; |
743 | 743 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index f1d193b557b6..40683004d523 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -211,6 +211,7 @@ struct cfg80211_event { | |||
211 | } dc; | 211 | } dc; |
212 | struct { | 212 | struct { |
213 | u8 bssid[ETH_ALEN]; | 213 | u8 bssid[ETH_ALEN]; |
214 | struct ieee80211_channel *channel; | ||
214 | } ij; | 215 | } ij; |
215 | }; | 216 | }; |
216 | }; | 217 | }; |
@@ -258,7 +259,8 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | |||
258 | struct net_device *dev, bool nowext); | 259 | struct net_device *dev, bool nowext); |
259 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 260 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
260 | struct net_device *dev, bool nowext); | 261 | struct net_device *dev, bool nowext); |
261 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); | 262 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, |
263 | struct ieee80211_channel *channel); | ||
262 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 264 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, |
263 | struct wireless_dev *wdev); | 265 | struct wireless_dev *wdev); |
264 | 266 | ||
@@ -443,7 +445,8 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | |||
443 | void | 445 | void |
444 | cfg80211_get_chan_state(struct wireless_dev *wdev, | 446 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
445 | struct ieee80211_channel **chan, | 447 | struct ieee80211_channel **chan, |
446 | enum cfg80211_chan_mode *chanmode); | 448 | enum cfg80211_chan_mode *chanmode, |
449 | u8 *radar_detect); | ||
447 | 450 | ||
448 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | 451 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, |
449 | struct cfg80211_chan_def *chandef); | 452 | struct cfg80211_chan_def *chandef); |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index f911c5f9f903..1470b90e438f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -14,7 +14,8 @@ | |||
14 | #include "rdev-ops.h" | 14 | #include "rdev-ops.h" |
15 | 15 | ||
16 | 16 | ||
17 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | 17 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, |
18 | struct ieee80211_channel *channel) | ||
18 | { | 19 | { |
19 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 20 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
20 | struct cfg80211_bss *bss; | 21 | struct cfg80211_bss *bss; |
@@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | |||
28 | if (!wdev->ssid_len) | 29 | if (!wdev->ssid_len) |
29 | return; | 30 | return; |
30 | 31 | ||
31 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 32 | bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, |
32 | wdev->ssid, wdev->ssid_len, | ||
33 | WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); | 33 | WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS); |
34 | 34 | ||
35 | if (WARN_ON(!bss)) | 35 | if (WARN_ON(!bss)) |
@@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid) | |||
54 | #endif | 54 | #endif |
55 | } | 55 | } |
56 | 56 | ||
57 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | 57 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, |
58 | struct ieee80211_channel *channel, gfp_t gfp) | ||
58 | { | 59 | { |
59 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 60 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
60 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 61 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
61 | struct cfg80211_event *ev; | 62 | struct cfg80211_event *ev; |
62 | unsigned long flags; | 63 | unsigned long flags; |
63 | 64 | ||
64 | trace_cfg80211_ibss_joined(dev, bssid); | 65 | trace_cfg80211_ibss_joined(dev, bssid, channel); |
66 | |||
67 | if (WARN_ON(!channel)) | ||
68 | return; | ||
65 | 69 | ||
66 | ev = kzalloc(sizeof(*ev), gfp); | 70 | ev = kzalloc(sizeof(*ev), gfp); |
67 | if (!ev) | 71 | if (!ev) |
68 | return; | 72 | return; |
69 | 73 | ||
70 | ev->type = EVENT_IBSS_JOINED; | 74 | ev->type = EVENT_IBSS_JOINED; |
71 | memcpy(ev->cr.bssid, bssid, ETH_ALEN); | 75 | memcpy(ev->ij.bssid, bssid, ETH_ALEN); |
76 | ev->ij.channel = channel; | ||
72 | 77 | ||
73 | spin_lock_irqsave(&wdev->event_lock, flags); | 78 | spin_lock_irqsave(&wdev->event_lock, flags); |
74 | list_add_tail(&ev->list, &wdev->event_list); | 79 | list_add_tail(&ev->list, &wdev->event_list); |
@@ -117,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
117 | 122 | ||
118 | wdev->ibss_fixed = params->channel_fixed; | 123 | wdev->ibss_fixed = params->channel_fixed; |
119 | wdev->ibss_dfs_possible = params->userspace_handles_dfs; | 124 | wdev->ibss_dfs_possible = params->userspace_handles_dfs; |
125 | wdev->chandef = params->chandef; | ||
120 | #ifdef CONFIG_CFG80211_WEXT | 126 | #ifdef CONFIG_CFG80211_WEXT |
121 | wdev->wext.ibss.chandef = params->chandef; | 127 | wdev->wext.ibss.chandef = params->chandef; |
122 | #endif | 128 | #endif |
@@ -200,6 +206,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
200 | 206 | ||
201 | wdev->current_bss = NULL; | 207 | wdev->current_bss = NULL; |
202 | wdev->ssid_len = 0; | 208 | wdev->ssid_len = 0; |
209 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); | ||
203 | #ifdef CONFIG_CFG80211_WEXT | 210 | #ifdef CONFIG_CFG80211_WEXT |
204 | if (!nowext) | 211 | if (!nowext) |
205 | wdev->wext.ibss.ssid_len = 0; | 212 | wdev->wext.ibss.ssid_len = 0; |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 885862447b63..d42a3fcb2f67 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
195 | if (!err) { | 195 | if (!err) { |
196 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 196 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
197 | wdev->mesh_id_len = setup->mesh_id_len; | 197 | wdev->mesh_id_len = setup->mesh_id_len; |
198 | wdev->channel = setup->chandef.chan; | 198 | wdev->chandef = setup->chandef; |
199 | } | 199 | } |
200 | 200 | ||
201 | return err; | 201 | return err; |
@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
244 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, | 244 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, |
245 | chandef->chan); | 245 | chandef->chan); |
246 | if (!err) | 246 | if (!err) |
247 | wdev->channel = chandef->chan; | 247 | wdev->chandef = *chandef; |
248 | 248 | ||
249 | return err; | 249 | return err; |
250 | } | 250 | } |
@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
276 | err = rdev_leave_mesh(rdev, dev); | 276 | err = rdev_leave_mesh(rdev, dev); |
277 | if (!err) { | 277 | if (!err) { |
278 | wdev->mesh_id_len = 0; | 278 | wdev->mesh_id_len = 0; |
279 | wdev->channel = NULL; | 279 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); |
280 | rdev_set_qos_map(rdev, dev, NULL); | 280 | rdev_set_qos_map(rdev, dev, NULL); |
281 | } | 281 | } |
282 | 282 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 52cca05044a8..d47c9d127b1e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_device *netdev, | |||
772 | if (WARN_ON(!wdev->cac_started)) | 772 | if (WARN_ON(!wdev->cac_started)) |
773 | return; | 773 | return; |
774 | 774 | ||
775 | if (WARN_ON(!wdev->channel)) | 775 | if (WARN_ON(!wdev->chandef.chan)) |
776 | return; | 776 | return; |
777 | 777 | ||
778 | switch (event) { | 778 | switch (event) { |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4fe2e6e2bc76..8e6b6a2d35cb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -382,6 +382,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
382 | [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, | 382 | [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, |
383 | [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY, | 383 | [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY, |
384 | .len = IEEE80211_QOS_MAP_LEN_MAX }, | 384 | .len = IEEE80211_QOS_MAP_LEN_MAX }, |
385 | [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, | ||
386 | [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, | ||
385 | }; | 387 | }; |
386 | 388 | ||
387 | /* policy for the key attributes */ | 389 | /* policy for the key attributes */ |
@@ -855,6 +857,19 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
855 | return 0; | 857 | return 0; |
856 | } | 858 | } |
857 | 859 | ||
860 | static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy, | ||
861 | struct nlattr *tb) | ||
862 | { | ||
863 | struct ieee80211_channel *chan; | ||
864 | |||
865 | if (tb == NULL) | ||
866 | return NULL; | ||
867 | chan = ieee80211_get_channel(wiphy, nla_get_u32(tb)); | ||
868 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||
869 | return NULL; | ||
870 | return chan; | ||
871 | } | ||
872 | |||
858 | static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) | 873 | static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) |
859 | { | 874 | { |
860 | struct nlattr *nl_modes = nla_nest_start(msg, attr); | 875 | struct nlattr *nl_modes = nla_nest_start(msg, attr); |
@@ -1586,6 +1601,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1586 | (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || | 1601 | (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) || |
1587 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) | 1602 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ))) |
1588 | goto nla_put_failure; | 1603 | goto nla_put_failure; |
1604 | |||
1605 | if (dev->wiphy.max_ap_assoc_sta && | ||
1606 | nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA, | ||
1607 | dev->wiphy.max_ap_assoc_sta)) | ||
1608 | goto nla_put_failure; | ||
1609 | |||
1589 | state->split_start++; | 1610 | state->split_start++; |
1590 | break; | 1611 | break; |
1591 | case 11: | 1612 | case 11: |
@@ -2035,10 +2056,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2035 | nla_for_each_nested(nl_txq_params, | 2056 | nla_for_each_nested(nl_txq_params, |
2036 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], | 2057 | info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], |
2037 | rem_txq_params) { | 2058 | rem_txq_params) { |
2038 | nla_parse(tb, NL80211_TXQ_ATTR_MAX, | 2059 | result = nla_parse(tb, NL80211_TXQ_ATTR_MAX, |
2039 | nla_data(nl_txq_params), | 2060 | nla_data(nl_txq_params), |
2040 | nla_len(nl_txq_params), | 2061 | nla_len(nl_txq_params), |
2041 | txq_params_policy); | 2062 | txq_params_policy); |
2063 | if (result) | ||
2064 | return result; | ||
2042 | result = parse_txq_params(tb, &txq_params); | 2065 | result = parse_txq_params(tb, &txq_params); |
2043 | if (result) | 2066 | if (result) |
2044 | return result; | 2067 | return result; |
@@ -3259,7 +3282,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3259 | if (!err) { | 3282 | if (!err) { |
3260 | wdev->preset_chandef = params.chandef; | 3283 | wdev->preset_chandef = params.chandef; |
3261 | wdev->beacon_interval = params.beacon_interval; | 3284 | wdev->beacon_interval = params.beacon_interval; |
3262 | wdev->channel = params.chandef.chan; | 3285 | wdev->chandef = params.chandef; |
3263 | wdev->ssid_len = params.ssid_len; | 3286 | wdev->ssid_len = params.ssid_len; |
3264 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); | 3287 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); |
3265 | } | 3288 | } |
@@ -3902,8 +3925,8 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
3902 | return ERR_PTR(ret); | 3925 | return ERR_PTR(ret); |
3903 | } | 3926 | } |
3904 | 3927 | ||
3905 | static struct nla_policy | 3928 | static const struct nla_policy |
3906 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | 3929 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = { |
3907 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | 3930 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, |
3908 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | 3931 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, |
3909 | }; | 3932 | }; |
@@ -4604,8 +4627,6 @@ static int parse_reg_rule(struct nlattr *tb[], | |||
4604 | return -EINVAL; | 4627 | return -EINVAL; |
4605 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) | 4628 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) |
4606 | return -EINVAL; | 4629 | return -EINVAL; |
4607 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) | ||
4608 | return -EINVAL; | ||
4609 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) | 4630 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) |
4610 | return -EINVAL; | 4631 | return -EINVAL; |
4611 | 4632 | ||
@@ -4615,8 +4636,9 @@ static int parse_reg_rule(struct nlattr *tb[], | |||
4615 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); | 4636 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); |
4616 | freq_range->end_freq_khz = | 4637 | freq_range->end_freq_khz = |
4617 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); | 4638 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); |
4618 | freq_range->max_bandwidth_khz = | 4639 | if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) |
4619 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | 4640 | freq_range->max_bandwidth_khz = |
4641 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | ||
4620 | 4642 | ||
4621 | power_rule->max_eirp = | 4643 | power_rule->max_eirp = |
4622 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); | 4644 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); |
@@ -5086,6 +5108,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5086 | const struct ieee80211_reg_rule *reg_rule; | 5108 | const struct ieee80211_reg_rule *reg_rule; |
5087 | const struct ieee80211_freq_range *freq_range; | 5109 | const struct ieee80211_freq_range *freq_range; |
5088 | const struct ieee80211_power_rule *power_rule; | 5110 | const struct ieee80211_power_rule *power_rule; |
5111 | unsigned int max_bandwidth_khz; | ||
5089 | 5112 | ||
5090 | reg_rule = ®dom->reg_rules[i]; | 5113 | reg_rule = ®dom->reg_rules[i]; |
5091 | freq_range = ®_rule->freq_range; | 5114 | freq_range = ®_rule->freq_range; |
@@ -5095,6 +5118,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5095 | if (!nl_reg_rule) | 5118 | if (!nl_reg_rule) |
5096 | goto nla_put_failure_rcu; | 5119 | goto nla_put_failure_rcu; |
5097 | 5120 | ||
5121 | max_bandwidth_khz = freq_range->max_bandwidth_khz; | ||
5122 | if (!max_bandwidth_khz) | ||
5123 | max_bandwidth_khz = reg_get_max_bandwidth(regdom, | ||
5124 | reg_rule); | ||
5125 | |||
5098 | if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS, | 5126 | if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS, |
5099 | reg_rule->flags) || | 5127 | reg_rule->flags) || |
5100 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START, | 5128 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START, |
@@ -5102,7 +5130,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
5102 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END, | 5130 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END, |
5103 | freq_range->end_freq_khz) || | 5131 | freq_range->end_freq_khz) || |
5104 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, | 5132 | nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW, |
5105 | freq_range->max_bandwidth_khz) || | 5133 | max_bandwidth_khz) || |
5106 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, | 5134 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, |
5107 | power_rule->max_antenna_gain) || | 5135 | power_rule->max_antenna_gain) || |
5108 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, | 5136 | nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, |
@@ -5178,9 +5206,11 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
5178 | 5206 | ||
5179 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 5207 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
5180 | rem_reg_rules) { | 5208 | rem_reg_rules) { |
5181 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, | 5209 | r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, |
5182 | nla_data(nl_reg_rule), nla_len(nl_reg_rule), | 5210 | nla_data(nl_reg_rule), nla_len(nl_reg_rule), |
5183 | reg_rule_policy); | 5211 | reg_rule_policy); |
5212 | if (r) | ||
5213 | goto bad_reg; | ||
5184 | r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); | 5214 | r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); |
5185 | if (r) | 5215 | if (r) |
5186 | goto bad_reg; | 5216 | goto bad_reg; |
@@ -5443,6 +5473,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5443 | enum ieee80211_band band; | 5473 | enum ieee80211_band band; |
5444 | size_t ie_len; | 5474 | size_t ie_len; |
5445 | struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; | 5475 | struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1]; |
5476 | s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF; | ||
5446 | 5477 | ||
5447 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 5478 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || |
5448 | !rdev->ops->sched_scan_start) | 5479 | !rdev->ops->sched_scan_start) |
@@ -5477,11 +5508,40 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5477 | if (n_ssids > wiphy->max_sched_scan_ssids) | 5508 | if (n_ssids > wiphy->max_sched_scan_ssids) |
5478 | return -EINVAL; | 5509 | return -EINVAL; |
5479 | 5510 | ||
5480 | if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) | 5511 | /* |
5512 | * First, count the number of 'real' matchsets. Due to an issue with | ||
5513 | * the old implementation, matchsets containing only the RSSI attribute | ||
5514 | * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default' | ||
5515 | * RSSI for all matchsets, rather than their own matchset for reporting | ||
5516 | * all APs with a strong RSSI. This is needed to be compatible with | ||
5517 | * older userspace that treated a matchset with only the RSSI as the | ||
5518 | * global RSSI for all other matchsets - if there are other matchsets. | ||
5519 | */ | ||
5520 | if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) { | ||
5481 | nla_for_each_nested(attr, | 5521 | nla_for_each_nested(attr, |
5482 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 5522 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
5483 | tmp) | 5523 | tmp) { |
5484 | n_match_sets++; | 5524 | struct nlattr *rssi; |
5525 | |||
5526 | err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, | ||
5527 | nla_data(attr), nla_len(attr), | ||
5528 | nl80211_match_policy); | ||
5529 | if (err) | ||
5530 | return err; | ||
5531 | /* add other standalone attributes here */ | ||
5532 | if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) { | ||
5533 | n_match_sets++; | ||
5534 | continue; | ||
5535 | } | ||
5536 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
5537 | if (rssi) | ||
5538 | default_match_rssi = nla_get_s32(rssi); | ||
5539 | } | ||
5540 | } | ||
5541 | |||
5542 | /* However, if there's no other matchset, add the RSSI one */ | ||
5543 | if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF) | ||
5544 | n_match_sets = 1; | ||
5485 | 5545 | ||
5486 | if (n_match_sets > wiphy->max_match_sets) | 5546 | if (n_match_sets > wiphy->max_match_sets) |
5487 | return -EINVAL; | 5547 | return -EINVAL; |
@@ -5602,11 +5662,22 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5602 | tmp) { | 5662 | tmp) { |
5603 | struct nlattr *ssid, *rssi; | 5663 | struct nlattr *ssid, *rssi; |
5604 | 5664 | ||
5605 | nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, | 5665 | err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, |
5606 | nla_data(attr), nla_len(attr), | 5666 | nla_data(attr), nla_len(attr), |
5607 | nl80211_match_policy); | 5667 | nl80211_match_policy); |
5668 | if (err) | ||
5669 | goto out_free; | ||
5608 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; | 5670 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; |
5609 | if (ssid) { | 5671 | if (ssid) { |
5672 | if (WARN_ON(i >= n_match_sets)) { | ||
5673 | /* this indicates a programming error, | ||
5674 | * the loop above should have verified | ||
5675 | * things properly | ||
5676 | */ | ||
5677 | err = -EINVAL; | ||
5678 | goto out_free; | ||
5679 | } | ||
5680 | |||
5610 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { | 5681 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { |
5611 | err = -EINVAL; | 5682 | err = -EINVAL; |
5612 | goto out_free; | 5683 | goto out_free; |
@@ -5615,15 +5686,28 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5615 | nla_data(ssid), nla_len(ssid)); | 5686 | nla_data(ssid), nla_len(ssid)); |
5616 | request->match_sets[i].ssid.ssid_len = | 5687 | request->match_sets[i].ssid.ssid_len = |
5617 | nla_len(ssid); | 5688 | nla_len(ssid); |
5689 | /* special attribute - old implemenation w/a */ | ||
5690 | request->match_sets[i].rssi_thold = | ||
5691 | default_match_rssi; | ||
5692 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
5693 | if (rssi) | ||
5694 | request->match_sets[i].rssi_thold = | ||
5695 | nla_get_s32(rssi); | ||
5618 | } | 5696 | } |
5619 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
5620 | if (rssi) | ||
5621 | request->rssi_thold = nla_get_u32(rssi); | ||
5622 | else | ||
5623 | request->rssi_thold = | ||
5624 | NL80211_SCAN_RSSI_THOLD_OFF; | ||
5625 | i++; | 5697 | i++; |
5626 | } | 5698 | } |
5699 | |||
5700 | /* there was no other matchset, so the RSSI one is alone */ | ||
5701 | if (i == 0) | ||
5702 | request->match_sets[0].rssi_thold = default_match_rssi; | ||
5703 | |||
5704 | request->min_rssi_thold = INT_MAX; | ||
5705 | for (i = 0; i < n_match_sets; i++) | ||
5706 | request->min_rssi_thold = | ||
5707 | min(request->match_sets[i].rssi_thold, | ||
5708 | request->min_rssi_thold); | ||
5709 | } else { | ||
5710 | request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF; | ||
5627 | } | 5711 | } |
5628 | 5712 | ||
5629 | if (info->attrs[NL80211_ATTR_IE]) { | 5713 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -5719,7 +5803,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5719 | 5803 | ||
5720 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | 5804 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); |
5721 | if (!err) { | 5805 | if (!err) { |
5722 | wdev->channel = chandef.chan; | 5806 | wdev->chandef = chandef; |
5723 | wdev->cac_started = true; | 5807 | wdev->cac_started = true; |
5724 | wdev->cac_start_time = jiffies; | 5808 | wdev->cac_start_time = jiffies; |
5725 | } | 5809 | } |
@@ -5751,10 +5835,15 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5751 | 5835 | ||
5752 | /* useless if AP is not running */ | 5836 | /* useless if AP is not running */ |
5753 | if (!wdev->beacon_interval) | 5837 | if (!wdev->beacon_interval) |
5754 | return -EINVAL; | 5838 | return -ENOTCONN; |
5755 | break; | 5839 | break; |
5756 | case NL80211_IFTYPE_ADHOC: | 5840 | case NL80211_IFTYPE_ADHOC: |
5841 | if (!wdev->ssid_len) | ||
5842 | return -ENOTCONN; | ||
5843 | break; | ||
5757 | case NL80211_IFTYPE_MESH_POINT: | 5844 | case NL80211_IFTYPE_MESH_POINT: |
5845 | if (!wdev->mesh_id_len) | ||
5846 | return -ENOTCONN; | ||
5758 | break; | 5847 | break; |
5759 | default: | 5848 | default: |
5760 | return -EOPNOTSUPP; | 5849 | return -EOPNOTSUPP; |
@@ -6192,9 +6281,9 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
6192 | return -EOPNOTSUPP; | 6281 | return -EOPNOTSUPP; |
6193 | 6282 | ||
6194 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 6283 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
6195 | chan = ieee80211_get_channel(&rdev->wiphy, | 6284 | chan = nl80211_get_valid_chan(&rdev->wiphy, |
6196 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 6285 | info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
6197 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) | 6286 | if (!chan) |
6198 | return -EINVAL; | 6287 | return -EINVAL; |
6199 | 6288 | ||
6200 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 6289 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
@@ -6347,9 +6436,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
6347 | 6436 | ||
6348 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 6437 | bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
6349 | 6438 | ||
6350 | chan = ieee80211_get_channel(&rdev->wiphy, | 6439 | chan = nl80211_get_valid_chan(&rdev->wiphy, |
6351 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 6440 | info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
6352 | if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) | 6441 | if (!chan) |
6353 | return -EINVAL; | 6442 | return -EINVAL; |
6354 | 6443 | ||
6355 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 6444 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
@@ -6985,6 +7074,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
6985 | 7074 | ||
6986 | if (info->attrs[NL80211_ATTR_MAC]) | 7075 | if (info->attrs[NL80211_ATTR_MAC]) |
6987 | connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | 7076 | connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); |
7077 | else if (info->attrs[NL80211_ATTR_MAC_HINT]) | ||
7078 | connect.bssid_hint = | ||
7079 | nla_data(info->attrs[NL80211_ATTR_MAC_HINT]); | ||
6988 | connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 7080 | connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
6989 | connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 7081 | connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
6990 | 7082 | ||
@@ -7003,11 +7095,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
7003 | } | 7095 | } |
7004 | 7096 | ||
7005 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 7097 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
7006 | connect.channel = | 7098 | connect.channel = nl80211_get_valid_chan( |
7007 | ieee80211_get_channel(wiphy, | 7099 | wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
7008 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | 7100 | if (!connect.channel) |
7009 | if (!connect.channel || | 7101 | return -EINVAL; |
7010 | connect.channel->flags & IEEE80211_CHAN_DISABLED) | 7102 | } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) { |
7103 | connect.channel_hint = nl80211_get_valid_chan( | ||
7104 | wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]); | ||
7105 | if (!connect.channel_hint) | ||
7011 | return -EINVAL; | 7106 | return -EINVAL; |
7012 | } | 7107 | } |
7013 | 7108 | ||
@@ -7421,6 +7516,7 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { | |||
7421 | [NL80211_TXRATE_HT] = { .type = NLA_BINARY, | 7516 | [NL80211_TXRATE_HT] = { .type = NLA_BINARY, |
7422 | .len = NL80211_MAX_SUPP_HT_RATES }, | 7517 | .len = NL80211_MAX_SUPP_HT_RATES }, |
7423 | [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, | 7518 | [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)}, |
7519 | [NL80211_TXRATE_GI] = { .type = NLA_U8 }, | ||
7424 | }; | 7520 | }; |
7425 | 7521 | ||
7426 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | 7522 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, |
@@ -7467,16 +7563,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
7467 | * directly to the enum ieee80211_band values used in cfg80211. | 7563 | * directly to the enum ieee80211_band values used in cfg80211. |
7468 | */ | 7564 | */ |
7469 | BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); | 7565 | BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8); |
7470 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | 7566 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) { |
7471 | { | ||
7472 | enum ieee80211_band band = nla_type(tx_rates); | 7567 | enum ieee80211_band band = nla_type(tx_rates); |
7568 | int err; | ||
7569 | |||
7473 | if (band < 0 || band >= IEEE80211_NUM_BANDS) | 7570 | if (band < 0 || band >= IEEE80211_NUM_BANDS) |
7474 | return -EINVAL; | 7571 | return -EINVAL; |
7475 | sband = rdev->wiphy.bands[band]; | 7572 | sband = rdev->wiphy.bands[band]; |
7476 | if (sband == NULL) | 7573 | if (sband == NULL) |
7477 | return -EINVAL; | 7574 | return -EINVAL; |
7478 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | 7575 | err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), |
7479 | nla_len(tx_rates), nl80211_txattr_policy); | 7576 | nla_len(tx_rates), nl80211_txattr_policy); |
7577 | if (err) | ||
7578 | return err; | ||
7480 | if (tb[NL80211_TXRATE_LEGACY]) { | 7579 | if (tb[NL80211_TXRATE_LEGACY]) { |
7481 | mask.control[band].legacy = rateset_to_mask( | 7580 | mask.control[band].legacy = rateset_to_mask( |
7482 | sband, | 7581 | sband, |
@@ -7501,6 +7600,12 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
7501 | mask.control[band].vht_mcs)) | 7600 | mask.control[band].vht_mcs)) |
7502 | return -EINVAL; | 7601 | return -EINVAL; |
7503 | } | 7602 | } |
7603 | if (tb[NL80211_TXRATE_GI]) { | ||
7604 | mask.control[band].gi = | ||
7605 | nla_get_u8(tb[NL80211_TXRATE_GI]); | ||
7606 | if (mask.control[band].gi > NL80211_TXRATE_FORCE_LGI) | ||
7607 | return -EINVAL; | ||
7608 | } | ||
7504 | 7609 | ||
7505 | if (mask.control[band].legacy == 0) { | 7610 | if (mask.control[band].legacy == 0) { |
7506 | /* don't allow empty legacy rates if HT or VHT | 7611 | /* don't allow empty legacy rates if HT or VHT |
@@ -7777,8 +7882,8 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) | |||
7777 | return err; | 7882 | return err; |
7778 | } | 7883 | } |
7779 | 7884 | ||
7780 | static struct nla_policy | 7885 | static const struct nla_policy |
7781 | nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | 7886 | nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { |
7782 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | 7887 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, |
7783 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | 7888 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, |
7784 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | 7889 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, |
@@ -11107,7 +11212,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
11107 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | 11212 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) |
11108 | return; | 11213 | return; |
11109 | 11214 | ||
11110 | wdev->channel = chandef->chan; | 11215 | wdev->chandef = *chandef; |
11216 | wdev->preset_chandef = *chandef; | ||
11111 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | 11217 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); |
11112 | } | 11218 | } |
11113 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | 11219 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); |
@@ -11621,6 +11727,35 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp) | |||
11621 | } | 11727 | } |
11622 | EXPORT_SYMBOL(cfg80211_crit_proto_stopped); | 11728 | EXPORT_SYMBOL(cfg80211_crit_proto_stopped); |
11623 | 11729 | ||
11730 | void nl80211_send_ap_stopped(struct wireless_dev *wdev) | ||
11731 | { | ||
11732 | struct wiphy *wiphy = wdev->wiphy; | ||
11733 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
11734 | struct sk_buff *msg; | ||
11735 | void *hdr; | ||
11736 | |||
11737 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
11738 | if (!msg) | ||
11739 | return; | ||
11740 | |||
11741 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP); | ||
11742 | if (!hdr) | ||
11743 | goto out; | ||
11744 | |||
11745 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
11746 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) || | ||
11747 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
11748 | goto out; | ||
11749 | |||
11750 | genlmsg_end(msg, hdr); | ||
11751 | |||
11752 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0, | ||
11753 | NL80211_MCGRP_MLME, GFP_KERNEL); | ||
11754 | return; | ||
11755 | out: | ||
11756 | nlmsg_free(msg); | ||
11757 | } | ||
11758 | |||
11624 | /* initialisation/exit functions */ | 11759 | /* initialisation/exit functions */ |
11625 | 11760 | ||
11626 | int nl80211_init(void) | 11761 | int nl80211_init(void) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 75799746d845..1e6df9630f42 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
74 | enum nl80211_radar_event event, | 74 | enum nl80211_radar_event event, |
75 | struct net_device *netdev, gfp_t gfp); | 75 | struct net_device *netdev, gfp_t gfp); |
76 | 76 | ||
77 | void nl80211_send_ap_stopped(struct wireless_dev *wdev); | ||
78 | |||
77 | void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); | 79 | void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); |
78 | 80 | ||
79 | #endif /* __NET_WIRELESS_NL80211_H */ | 81 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 9b897fca7487..27c5253e7a61 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -91,7 +91,7 @@ static struct regulatory_request __rcu *last_request = | |||
91 | /* To trigger userspace events */ | 91 | /* To trigger userspace events */ |
92 | static struct platform_device *reg_pdev; | 92 | static struct platform_device *reg_pdev; |
93 | 93 | ||
94 | static struct device_type reg_device_type = { | 94 | static const struct device_type reg_device_type = { |
95 | .uevent = reg_device_uevent, | 95 | .uevent = reg_device_uevent, |
96 | }; | 96 | }; |
97 | 97 | ||
@@ -522,6 +522,77 @@ bool reg_is_valid_request(const char *alpha2) | |||
522 | return alpha2_equal(lr->alpha2, alpha2); | 522 | return alpha2_equal(lr->alpha2, alpha2); |
523 | } | 523 | } |
524 | 524 | ||
525 | static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy) | ||
526 | { | ||
527 | struct regulatory_request *lr = get_last_request(); | ||
528 | |||
529 | /* | ||
530 | * Follow the driver's regulatory domain, if present, unless a country | ||
531 | * IE has been processed or a user wants to help complaince further | ||
532 | */ | ||
533 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
534 | lr->initiator != NL80211_REGDOM_SET_BY_USER && | ||
535 | wiphy->regd) | ||
536 | return get_wiphy_regdom(wiphy); | ||
537 | |||
538 | return get_cfg80211_regdom(); | ||
539 | } | ||
540 | |||
541 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | ||
542 | const struct ieee80211_reg_rule *rule) | ||
543 | { | ||
544 | const struct ieee80211_freq_range *freq_range = &rule->freq_range; | ||
545 | const struct ieee80211_freq_range *freq_range_tmp; | ||
546 | const struct ieee80211_reg_rule *tmp; | ||
547 | u32 start_freq, end_freq, idx, no; | ||
548 | |||
549 | for (idx = 0; idx < rd->n_reg_rules; idx++) | ||
550 | if (rule == &rd->reg_rules[idx]) | ||
551 | break; | ||
552 | |||
553 | if (idx == rd->n_reg_rules) | ||
554 | return 0; | ||
555 | |||
556 | /* get start_freq */ | ||
557 | no = idx; | ||
558 | |||
559 | while (no) { | ||
560 | tmp = &rd->reg_rules[--no]; | ||
561 | freq_range_tmp = &tmp->freq_range; | ||
562 | |||
563 | if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz) | ||
564 | break; | ||
565 | |||
566 | if (freq_range_tmp->max_bandwidth_khz) | ||
567 | break; | ||
568 | |||
569 | freq_range = freq_range_tmp; | ||
570 | } | ||
571 | |||
572 | start_freq = freq_range->start_freq_khz; | ||
573 | |||
574 | /* get end_freq */ | ||
575 | freq_range = &rule->freq_range; | ||
576 | no = idx; | ||
577 | |||
578 | while (no < rd->n_reg_rules - 1) { | ||
579 | tmp = &rd->reg_rules[++no]; | ||
580 | freq_range_tmp = &tmp->freq_range; | ||
581 | |||
582 | if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz) | ||
583 | break; | ||
584 | |||
585 | if (freq_range_tmp->max_bandwidth_khz) | ||
586 | break; | ||
587 | |||
588 | freq_range = freq_range_tmp; | ||
589 | } | ||
590 | |||
591 | end_freq = freq_range->end_freq_khz; | ||
592 | |||
593 | return end_freq - start_freq; | ||
594 | } | ||
595 | |||
525 | /* Sanity check on a regulatory rule */ | 596 | /* Sanity check on a regulatory rule */ |
526 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) | 597 | static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) |
527 | { | 598 | { |
@@ -630,7 +701,9 @@ reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1, | |||
630 | * Helper for regdom_intersect(), this does the real | 701 | * Helper for regdom_intersect(), this does the real |
631 | * mathematical intersection fun | 702 | * mathematical intersection fun |
632 | */ | 703 | */ |
633 | static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, | 704 | static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, |
705 | const struct ieee80211_regdomain *rd2, | ||
706 | const struct ieee80211_reg_rule *rule1, | ||
634 | const struct ieee80211_reg_rule *rule2, | 707 | const struct ieee80211_reg_rule *rule2, |
635 | struct ieee80211_reg_rule *intersected_rule) | 708 | struct ieee80211_reg_rule *intersected_rule) |
636 | { | 709 | { |
@@ -638,7 +711,7 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, | |||
638 | struct ieee80211_freq_range *freq_range; | 711 | struct ieee80211_freq_range *freq_range; |
639 | const struct ieee80211_power_rule *power_rule1, *power_rule2; | 712 | const struct ieee80211_power_rule *power_rule1, *power_rule2; |
640 | struct ieee80211_power_rule *power_rule; | 713 | struct ieee80211_power_rule *power_rule; |
641 | u32 freq_diff; | 714 | u32 freq_diff, max_bandwidth1, max_bandwidth2; |
642 | 715 | ||
643 | freq_range1 = &rule1->freq_range; | 716 | freq_range1 = &rule1->freq_range; |
644 | freq_range2 = &rule2->freq_range; | 717 | freq_range2 = &rule2->freq_range; |
@@ -652,8 +725,24 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1, | |||
652 | freq_range2->start_freq_khz); | 725 | freq_range2->start_freq_khz); |
653 | freq_range->end_freq_khz = min(freq_range1->end_freq_khz, | 726 | freq_range->end_freq_khz = min(freq_range1->end_freq_khz, |
654 | freq_range2->end_freq_khz); | 727 | freq_range2->end_freq_khz); |
655 | freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz, | 728 | |
656 | freq_range2->max_bandwidth_khz); | 729 | max_bandwidth1 = freq_range1->max_bandwidth_khz; |
730 | max_bandwidth2 = freq_range2->max_bandwidth_khz; | ||
731 | |||
732 | /* | ||
733 | * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set | ||
734 | * output bandwidth as 0 (auto calculation). Next we will | ||
735 | * calculate this correctly in handle_channel function. | ||
736 | * In other case calculate output bandwidth here. | ||
737 | */ | ||
738 | if (max_bandwidth1 || max_bandwidth2) { | ||
739 | if (!max_bandwidth1) | ||
740 | max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); | ||
741 | if (!max_bandwidth2) | ||
742 | max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); | ||
743 | } | ||
744 | |||
745 | freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2); | ||
657 | 746 | ||
658 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; | 747 | freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; |
659 | if (freq_range->max_bandwidth_khz > freq_diff) | 748 | if (freq_range->max_bandwidth_khz > freq_diff) |
@@ -713,7 +802,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
713 | rule1 = &rd1->reg_rules[x]; | 802 | rule1 = &rd1->reg_rules[x]; |
714 | for (y = 0; y < rd2->n_reg_rules; y++) { | 803 | for (y = 0; y < rd2->n_reg_rules; y++) { |
715 | rule2 = &rd2->reg_rules[y]; | 804 | rule2 = &rd2->reg_rules[y]; |
716 | if (!reg_rules_intersect(rule1, rule2, &dummy_rule)) | 805 | if (!reg_rules_intersect(rd1, rd2, rule1, rule2, |
806 | &dummy_rule)) | ||
717 | num_rules++; | 807 | num_rules++; |
718 | } | 808 | } |
719 | } | 809 | } |
@@ -738,7 +828,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
738 | * a memcpy() | 828 | * a memcpy() |
739 | */ | 829 | */ |
740 | intersected_rule = &rd->reg_rules[rule_idx]; | 830 | intersected_rule = &rd->reg_rules[rule_idx]; |
741 | r = reg_rules_intersect(rule1, rule2, intersected_rule); | 831 | r = reg_rules_intersect(rd1, rd2, rule1, rule2, |
832 | intersected_rule); | ||
742 | /* | 833 | /* |
743 | * No need to memset here the intersected rule here as | 834 | * No need to memset here the intersected rule here as |
744 | * we're not using the stack anymore | 835 | * we're not using the stack anymore |
@@ -821,18 +912,8 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, | |||
821 | u32 center_freq) | 912 | u32 center_freq) |
822 | { | 913 | { |
823 | const struct ieee80211_regdomain *regd; | 914 | const struct ieee80211_regdomain *regd; |
824 | struct regulatory_request *lr = get_last_request(); | ||
825 | 915 | ||
826 | /* | 916 | regd = reg_get_regdomain(wiphy); |
827 | * Follow the driver's regulatory domain, if present, unless a country | ||
828 | * IE has been processed or a user wants to help complaince further | ||
829 | */ | ||
830 | if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
831 | lr->initiator != NL80211_REGDOM_SET_BY_USER && | ||
832 | wiphy->regd) | ||
833 | regd = get_wiphy_regdom(wiphy); | ||
834 | else | ||
835 | regd = get_cfg80211_regdom(); | ||
836 | 917 | ||
837 | return freq_reg_info_regd(wiphy, center_freq, regd); | 918 | return freq_reg_info_regd(wiphy, center_freq, regd); |
838 | } | 919 | } |
@@ -903,6 +984,8 @@ static void handle_channel(struct wiphy *wiphy, | |||
903 | const struct ieee80211_freq_range *freq_range = NULL; | 984 | const struct ieee80211_freq_range *freq_range = NULL; |
904 | struct wiphy *request_wiphy = NULL; | 985 | struct wiphy *request_wiphy = NULL; |
905 | struct regulatory_request *lr = get_last_request(); | 986 | struct regulatory_request *lr = get_last_request(); |
987 | const struct ieee80211_regdomain *regd; | ||
988 | u32 max_bandwidth_khz; | ||
906 | 989 | ||
907 | request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | 990 | request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); |
908 | 991 | ||
@@ -944,11 +1027,18 @@ static void handle_channel(struct wiphy *wiphy, | |||
944 | power_rule = ®_rule->power_rule; | 1027 | power_rule = ®_rule->power_rule; |
945 | freq_range = ®_rule->freq_range; | 1028 | freq_range = ®_rule->freq_range; |
946 | 1029 | ||
947 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | 1030 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
1031 | /* Check if auto calculation requested */ | ||
1032 | if (!max_bandwidth_khz) { | ||
1033 | regd = reg_get_regdomain(wiphy); | ||
1034 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); | ||
1035 | } | ||
1036 | |||
1037 | if (max_bandwidth_khz < MHZ_TO_KHZ(40)) | ||
948 | bw_flags = IEEE80211_CHAN_NO_HT40; | 1038 | bw_flags = IEEE80211_CHAN_NO_HT40; |
949 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) | 1039 | if (max_bandwidth_khz < MHZ_TO_KHZ(80)) |
950 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; | 1040 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; |
951 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) | 1041 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
952 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | 1042 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
953 | 1043 | ||
954 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 1044 | if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
@@ -1334,6 +1424,7 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1334 | const struct ieee80211_reg_rule *reg_rule = NULL; | 1424 | const struct ieee80211_reg_rule *reg_rule = NULL; |
1335 | const struct ieee80211_power_rule *power_rule = NULL; | 1425 | const struct ieee80211_power_rule *power_rule = NULL; |
1336 | const struct ieee80211_freq_range *freq_range = NULL; | 1426 | const struct ieee80211_freq_range *freq_range = NULL; |
1427 | u32 max_bandwidth_khz; | ||
1337 | 1428 | ||
1338 | reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), | 1429 | reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), |
1339 | regd); | 1430 | regd); |
@@ -1351,11 +1442,16 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1351 | power_rule = ®_rule->power_rule; | 1442 | power_rule = ®_rule->power_rule; |
1352 | freq_range = ®_rule->freq_range; | 1443 | freq_range = ®_rule->freq_range; |
1353 | 1444 | ||
1354 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | 1445 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
1446 | /* Check if auto calculation requested */ | ||
1447 | if (!max_bandwidth_khz) | ||
1448 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); | ||
1449 | |||
1450 | if (max_bandwidth_khz < MHZ_TO_KHZ(40)) | ||
1355 | bw_flags = IEEE80211_CHAN_NO_HT40; | 1451 | bw_flags = IEEE80211_CHAN_NO_HT40; |
1356 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80)) | 1452 | if (max_bandwidth_khz < MHZ_TO_KHZ(80)) |
1357 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; | 1453 | bw_flags |= IEEE80211_CHAN_NO_80MHZ; |
1358 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160)) | 1454 | if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
1359 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; | 1455 | bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
1360 | 1456 | ||
1361 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1457 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
@@ -1683,17 +1779,9 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1683 | struct wiphy *wiphy = NULL; | 1779 | struct wiphy *wiphy = NULL; |
1684 | enum reg_request_treatment treatment; | 1780 | enum reg_request_treatment treatment; |
1685 | 1781 | ||
1686 | if (WARN_ON(!reg_request->alpha2)) | ||
1687 | return; | ||
1688 | |||
1689 | if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) | 1782 | if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) |
1690 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | 1783 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); |
1691 | 1784 | ||
1692 | if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) { | ||
1693 | kfree(reg_request); | ||
1694 | return; | ||
1695 | } | ||
1696 | |||
1697 | switch (reg_request->initiator) { | 1785 | switch (reg_request->initiator) { |
1698 | case NL80211_REGDOM_SET_BY_CORE: | 1786 | case NL80211_REGDOM_SET_BY_CORE: |
1699 | reg_process_hint_core(reg_request); | 1787 | reg_process_hint_core(reg_request); |
@@ -1703,23 +1791,33 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
1703 | if (treatment == REG_REQ_OK || | 1791 | if (treatment == REG_REQ_OK || |
1704 | treatment == REG_REQ_ALREADY_SET) | 1792 | treatment == REG_REQ_ALREADY_SET) |
1705 | return; | 1793 | return; |
1706 | schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); | 1794 | queue_delayed_work(system_power_efficient_wq, |
1795 | ®_timeout, msecs_to_jiffies(3142)); | ||
1707 | return; | 1796 | return; |
1708 | case NL80211_REGDOM_SET_BY_DRIVER: | 1797 | case NL80211_REGDOM_SET_BY_DRIVER: |
1798 | if (!wiphy) | ||
1799 | goto out_free; | ||
1709 | treatment = reg_process_hint_driver(wiphy, reg_request); | 1800 | treatment = reg_process_hint_driver(wiphy, reg_request); |
1710 | break; | 1801 | break; |
1711 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | 1802 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: |
1803 | if (!wiphy) | ||
1804 | goto out_free; | ||
1712 | treatment = reg_process_hint_country_ie(wiphy, reg_request); | 1805 | treatment = reg_process_hint_country_ie(wiphy, reg_request); |
1713 | break; | 1806 | break; |
1714 | default: | 1807 | default: |
1715 | WARN(1, "invalid initiator %d\n", reg_request->initiator); | 1808 | WARN(1, "invalid initiator %d\n", reg_request->initiator); |
1716 | return; | 1809 | goto out_free; |
1717 | } | 1810 | } |
1718 | 1811 | ||
1719 | /* This is required so that the orig_* parameters are saved */ | 1812 | /* This is required so that the orig_* parameters are saved */ |
1720 | if (treatment == REG_REQ_ALREADY_SET && wiphy && | 1813 | if (treatment == REG_REQ_ALREADY_SET && wiphy && |
1721 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) | 1814 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) |
1722 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 1815 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
1816 | |||
1817 | return; | ||
1818 | |||
1819 | out_free: | ||
1820 | kfree(reg_request); | ||
1723 | } | 1821 | } |
1724 | 1822 | ||
1725 | /* | 1823 | /* |
@@ -2147,6 +2245,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
2147 | const struct ieee80211_reg_rule *reg_rule = NULL; | 2245 | const struct ieee80211_reg_rule *reg_rule = NULL; |
2148 | const struct ieee80211_freq_range *freq_range = NULL; | 2246 | const struct ieee80211_freq_range *freq_range = NULL; |
2149 | const struct ieee80211_power_rule *power_rule = NULL; | 2247 | const struct ieee80211_power_rule *power_rule = NULL; |
2248 | char bw[32]; | ||
2150 | 2249 | ||
2151 | pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); | 2250 | pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); |
2152 | 2251 | ||
@@ -2155,22 +2254,29 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
2155 | freq_range = ®_rule->freq_range; | 2254 | freq_range = ®_rule->freq_range; |
2156 | power_rule = ®_rule->power_rule; | 2255 | power_rule = ®_rule->power_rule; |
2157 | 2256 | ||
2257 | if (!freq_range->max_bandwidth_khz) | ||
2258 | snprintf(bw, 32, "%d KHz, AUTO", | ||
2259 | reg_get_max_bandwidth(rd, reg_rule)); | ||
2260 | else | ||
2261 | snprintf(bw, 32, "%d KHz", | ||
2262 | freq_range->max_bandwidth_khz); | ||
2263 | |||
2158 | /* | 2264 | /* |
2159 | * There may not be documentation for max antenna gain | 2265 | * There may not be documentation for max antenna gain |
2160 | * in certain regions | 2266 | * in certain regions |
2161 | */ | 2267 | */ |
2162 | if (power_rule->max_antenna_gain) | 2268 | if (power_rule->max_antenna_gain) |
2163 | pr_info(" (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n", | 2269 | pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n", |
2164 | freq_range->start_freq_khz, | 2270 | freq_range->start_freq_khz, |
2165 | freq_range->end_freq_khz, | 2271 | freq_range->end_freq_khz, |
2166 | freq_range->max_bandwidth_khz, | 2272 | bw, |
2167 | power_rule->max_antenna_gain, | 2273 | power_rule->max_antenna_gain, |
2168 | power_rule->max_eirp); | 2274 | power_rule->max_eirp); |
2169 | else | 2275 | else |
2170 | pr_info(" (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n", | 2276 | pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n", |
2171 | freq_range->start_freq_khz, | 2277 | freq_range->start_freq_khz, |
2172 | freq_range->end_freq_khz, | 2278 | freq_range->end_freq_khz, |
2173 | freq_range->max_bandwidth_khz, | 2279 | bw, |
2174 | power_rule->max_eirp); | 2280 | power_rule->max_eirp); |
2175 | } | 2281 | } |
2176 | } | 2282 | } |
@@ -2294,7 +2400,8 @@ static int reg_set_rd_driver(const struct ieee80211_regdomain *rd, | |||
2294 | 2400 | ||
2295 | request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); | 2401 | request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx); |
2296 | if (!request_wiphy) { | 2402 | if (!request_wiphy) { |
2297 | schedule_delayed_work(®_timeout, 0); | 2403 | queue_delayed_work(system_power_efficient_wq, |
2404 | ®_timeout, 0); | ||
2298 | return -ENODEV; | 2405 | return -ENODEV; |
2299 | } | 2406 | } |
2300 | 2407 | ||
@@ -2354,7 +2461,8 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd, | |||
2354 | 2461 | ||
2355 | request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); | 2462 | request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx); |
2356 | if (!request_wiphy) { | 2463 | if (!request_wiphy) { |
2357 | schedule_delayed_work(®_timeout, 0); | 2464 | queue_delayed_work(system_power_efficient_wq, |
2465 | ®_timeout, 0); | ||
2358 | return -ENODEV; | 2466 | return -ENODEV; |
2359 | } | 2467 | } |
2360 | 2468 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 02bd8f4b0921..18524617ab62 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -34,6 +34,8 @@ int __init regulatory_init(void); | |||
34 | void regulatory_exit(void); | 34 | void regulatory_exit(void); |
35 | 35 | ||
36 | int set_regdom(const struct ieee80211_regdomain *rd); | 36 | int set_regdom(const struct ieee80211_regdomain *rd); |
37 | unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | ||
38 | const struct ieee80211_reg_rule *rule); | ||
37 | 39 | ||
38 | bool reg_last_request_cell_base(void); | 40 | bool reg_last_request_cell_base(void); |
39 | 41 | ||
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index fbcc23edee54..5eaeed59db07 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -2278,11 +2278,6 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt, | |||
2278 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) | 2278 | TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr)) |
2279 | ); | 2279 | ); |
2280 | 2280 | ||
2281 | DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined, | ||
2282 | TP_PROTO(struct net_device *netdev, const u8 *addr), | ||
2283 | TP_ARGS(netdev, addr) | ||
2284 | ); | ||
2285 | |||
2286 | DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame, | 2281 | DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame, |
2287 | TP_PROTO(struct net_device *netdev, const u8 *addr), | 2282 | TP_PROTO(struct net_device *netdev, const u8 *addr), |
2288 | TP_ARGS(netdev, addr) | 2283 | TP_ARGS(netdev, addr) |
@@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_unexpected_4addr_frame, | |||
2293 | TP_ARGS(netdev, addr) | 2288 | TP_ARGS(netdev, addr) |
2294 | ); | 2289 | ); |
2295 | 2290 | ||
2291 | TRACE_EVENT(cfg80211_ibss_joined, | ||
2292 | TP_PROTO(struct net_device *netdev, const u8 *bssid, | ||
2293 | struct ieee80211_channel *channel), | ||
2294 | TP_ARGS(netdev, bssid, channel), | ||
2295 | TP_STRUCT__entry( | ||
2296 | NETDEV_ENTRY | ||
2297 | MAC_ENTRY(bssid) | ||
2298 | CHAN_ENTRY | ||
2299 | ), | ||
2300 | TP_fast_assign( | ||
2301 | NETDEV_ASSIGN; | ||
2302 | MAC_ASSIGN(bssid, bssid); | ||
2303 | CHAN_ASSIGN(channel); | ||
2304 | ), | ||
2305 | TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT, | ||
2306 | NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) | ||
2307 | ); | ||
2308 | |||
2296 | TRACE_EVENT(cfg80211_probe_status, | 2309 | TRACE_EVENT(cfg80211_probe_status, |
2297 | TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie, | 2310 | TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie, |
2298 | bool acked), | 2311 | bool acked), |
diff --git a/net/wireless/util.c b/net/wireless/util.c index d39c37104ae2..780b4546c9c7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) | |||
820 | ev->dc.reason, true); | 820 | ev->dc.reason, true); |
821 | break; | 821 | break; |
822 | case EVENT_IBSS_JOINED: | 822 | case EVENT_IBSS_JOINED: |
823 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); | 823 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid, |
824 | ev->ij.channel); | ||
824 | break; | 825 | break; |
825 | } | 826 | } |
826 | wdev_unlock(wdev); | 827 | wdev_unlock(wdev); |
@@ -1356,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
1356 | */ | 1357 | */ |
1357 | mutex_lock_nested(&wdev_iter->mtx, 1); | 1358 | mutex_lock_nested(&wdev_iter->mtx, 1); |
1358 | __acquire(wdev_iter->mtx); | 1359 | __acquire(wdev_iter->mtx); |
1359 | cfg80211_get_chan_state(wdev_iter, &ch, &chmode); | 1360 | cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect); |
1360 | wdev_unlock(wdev_iter); | 1361 | wdev_unlock(wdev_iter); |
1361 | 1362 | ||
1362 | switch (chmode) { | 1363 | switch (chmode) { |