diff options
Diffstat (limited to 'net')
34 files changed, 1779 insertions, 380 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 43dd7525bfcb..31fc2247bc37 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -395,9 +395,13 @@ void sta_set_rate_info_tx(struct sta_info *sta, | |||
395 | rinfo->nss = ieee80211_rate_get_vht_nss(rate); | 395 | rinfo->nss = ieee80211_rate_get_vht_nss(rate); |
396 | } else { | 396 | } else { |
397 | struct ieee80211_supported_band *sband; | 397 | struct ieee80211_supported_band *sband; |
398 | int shift = ieee80211_vif_get_shift(&sta->sdata->vif); | ||
399 | u16 brate; | ||
400 | |||
398 | sband = sta->local->hw.wiphy->bands[ | 401 | sband = sta->local->hw.wiphy->bands[ |
399 | ieee80211_get_sdata_band(sta->sdata)]; | 402 | ieee80211_get_sdata_band(sta->sdata)]; |
400 | rinfo->legacy = sband->bitrates[rate->idx].bitrate; | 403 | brate = sband->bitrates[rate->idx].bitrate; |
404 | rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); | ||
401 | } | 405 | } |
402 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 406 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
403 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 407 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
@@ -422,11 +426,13 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) | |||
422 | rinfo->mcs = sta->last_rx_rate_idx; | 426 | rinfo->mcs = sta->last_rx_rate_idx; |
423 | } else { | 427 | } else { |
424 | struct ieee80211_supported_band *sband; | 428 | struct ieee80211_supported_band *sband; |
429 | int shift = ieee80211_vif_get_shift(&sta->sdata->vif); | ||
430 | u16 brate; | ||
425 | 431 | ||
426 | sband = sta->local->hw.wiphy->bands[ | 432 | sband = sta->local->hw.wiphy->bands[ |
427 | ieee80211_get_sdata_band(sta->sdata)]; | 433 | ieee80211_get_sdata_band(sta->sdata)]; |
428 | rinfo->legacy = | 434 | brate = sband->bitrates[sta->last_rx_rate_idx].bitrate; |
429 | sband->bitrates[sta->last_rx_rate_idx].bitrate; | 435 | rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); |
430 | } | 436 | } |
431 | 437 | ||
432 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) | 438 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) |
@@ -856,8 +862,8 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
856 | return 0; | 862 | return 0; |
857 | } | 863 | } |
858 | 864 | ||
859 | static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | 865 | int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, |
860 | struct cfg80211_beacon_data *params) | 866 | struct cfg80211_beacon_data *params) |
861 | { | 867 | { |
862 | struct beacon_data *new, *old; | 868 | struct beacon_data *new, *old; |
863 | int new_head_len, new_tail_len; | 869 | int new_head_len, new_tail_len; |
@@ -1020,6 +1026,12 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
1020 | 1026 | ||
1021 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1027 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1022 | 1028 | ||
1029 | /* don't allow changing the beacon while CSA is in place - offset | ||
1030 | * of channel switch counter may change | ||
1031 | */ | ||
1032 | if (sdata->vif.csa_active) | ||
1033 | return -EBUSY; | ||
1034 | |||
1023 | old = rtnl_dereference(sdata->u.ap.beacon); | 1035 | old = rtnl_dereference(sdata->u.ap.beacon); |
1024 | if (!old) | 1036 | if (!old) |
1025 | return -ENOENT; | 1037 | return -ENOENT; |
@@ -1044,6 +1056,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1044 | return -ENOENT; | 1056 | return -ENOENT; |
1045 | old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); | 1057 | old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); |
1046 | 1058 | ||
1059 | /* abort any running channel switch */ | ||
1060 | sdata->vif.csa_active = false; | ||
1061 | cancel_work_sync(&sdata->csa_finalize_work); | ||
1062 | |||
1047 | /* turn off carrier for this interface and dependent VLANs */ | 1063 | /* turn off carrier for this interface and dependent VLANs */ |
1048 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1064 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
1049 | netif_carrier_off(vlan->dev); | 1065 | netif_carrier_off(vlan->dev); |
@@ -1192,8 +1208,6 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1192 | struct station_parameters *params) | 1208 | struct station_parameters *params) |
1193 | { | 1209 | { |
1194 | int ret = 0; | 1210 | int ret = 0; |
1195 | u32 rates; | ||
1196 | int i, j; | ||
1197 | struct ieee80211_supported_band *sband; | 1211 | struct ieee80211_supported_band *sband; |
1198 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1212 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
1199 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | 1213 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
@@ -1286,16 +1300,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1286 | sta->listen_interval = params->listen_interval; | 1300 | sta->listen_interval = params->listen_interval; |
1287 | 1301 | ||
1288 | if (params->supported_rates) { | 1302 | if (params->supported_rates) { |
1289 | rates = 0; | 1303 | ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef, |
1290 | 1304 | sband, params->supported_rates, | |
1291 | for (i = 0; i < params->supported_rates_len; i++) { | 1305 | params->supported_rates_len, |
1292 | int rate = (params->supported_rates[i] & 0x7f) * 5; | 1306 | &sta->sta.supp_rates[band]); |
1293 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1294 | if (sband->bitrates[j].bitrate == rate) | ||
1295 | rates |= BIT(j); | ||
1296 | } | ||
1297 | } | ||
1298 | sta->sta.supp_rates[band] = rates; | ||
1299 | } | 1307 | } |
1300 | 1308 | ||
1301 | if (params->ht_capa) | 1309 | if (params->ht_capa) |
@@ -1958,18 +1966,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1958 | } | 1966 | } |
1959 | 1967 | ||
1960 | if (params->basic_rates) { | 1968 | if (params->basic_rates) { |
1961 | int i, j; | 1969 | ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef, |
1962 | u32 rates = 0; | 1970 | wiphy->bands[band], |
1963 | struct ieee80211_supported_band *sband = wiphy->bands[band]; | 1971 | params->basic_rates, |
1964 | 1972 | params->basic_rates_len, | |
1965 | for (i = 0; i < params->basic_rates_len; i++) { | 1973 | &sdata->vif.bss_conf.basic_rates); |
1966 | int rate = (params->basic_rates[i] & 0x7f) * 5; | ||
1967 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1968 | if (sband->bitrates[j].bitrate == rate) | ||
1969 | rates |= BIT(j); | ||
1970 | } | ||
1971 | } | ||
1972 | sdata->vif.bss_conf.basic_rates = rates; | ||
1973 | changed |= BSS_CHANGED_BASIC_RATES; | 1974 | changed |= BSS_CHANGED_BASIC_RATES; |
1974 | } | 1975 | } |
1975 | 1976 | ||
@@ -2786,6 +2787,178 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, | |||
2786 | return 0; | 2787 | return 0; |
2787 | } | 2788 | } |
2788 | 2789 | ||
2790 | static struct cfg80211_beacon_data * | ||
2791 | cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) | ||
2792 | { | ||
2793 | struct cfg80211_beacon_data *new_beacon; | ||
2794 | u8 *pos; | ||
2795 | int len; | ||
2796 | |||
2797 | len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len + | ||
2798 | beacon->proberesp_ies_len + beacon->assocresp_ies_len + | ||
2799 | beacon->probe_resp_len; | ||
2800 | |||
2801 | new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL); | ||
2802 | if (!new_beacon) | ||
2803 | return NULL; | ||
2804 | |||
2805 | pos = (u8 *)(new_beacon + 1); | ||
2806 | if (beacon->head_len) { | ||
2807 | new_beacon->head_len = beacon->head_len; | ||
2808 | new_beacon->head = pos; | ||
2809 | memcpy(pos, beacon->head, beacon->head_len); | ||
2810 | pos += beacon->head_len; | ||
2811 | } | ||
2812 | if (beacon->tail_len) { | ||
2813 | new_beacon->tail_len = beacon->tail_len; | ||
2814 | new_beacon->tail = pos; | ||
2815 | memcpy(pos, beacon->tail, beacon->tail_len); | ||
2816 | pos += beacon->tail_len; | ||
2817 | } | ||
2818 | if (beacon->beacon_ies_len) { | ||
2819 | new_beacon->beacon_ies_len = beacon->beacon_ies_len; | ||
2820 | new_beacon->beacon_ies = pos; | ||
2821 | memcpy(pos, beacon->beacon_ies, beacon->beacon_ies_len); | ||
2822 | pos += beacon->beacon_ies_len; | ||
2823 | } | ||
2824 | if (beacon->proberesp_ies_len) { | ||
2825 | new_beacon->proberesp_ies_len = beacon->proberesp_ies_len; | ||
2826 | new_beacon->proberesp_ies = pos; | ||
2827 | memcpy(pos, beacon->proberesp_ies, beacon->proberesp_ies_len); | ||
2828 | pos += beacon->proberesp_ies_len; | ||
2829 | } | ||
2830 | if (beacon->assocresp_ies_len) { | ||
2831 | new_beacon->assocresp_ies_len = beacon->assocresp_ies_len; | ||
2832 | new_beacon->assocresp_ies = pos; | ||
2833 | memcpy(pos, beacon->assocresp_ies, beacon->assocresp_ies_len); | ||
2834 | pos += beacon->assocresp_ies_len; | ||
2835 | } | ||
2836 | if (beacon->probe_resp_len) { | ||
2837 | new_beacon->probe_resp_len = beacon->probe_resp_len; | ||
2838 | beacon->probe_resp = pos; | ||
2839 | memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); | ||
2840 | pos += beacon->probe_resp_len; | ||
2841 | } | ||
2842 | |||
2843 | return new_beacon; | ||
2844 | } | ||
2845 | |||
2846 | void ieee80211_csa_finalize_work(struct work_struct *work) | ||
2847 | { | ||
2848 | struct ieee80211_sub_if_data *sdata = | ||
2849 | container_of(work, struct ieee80211_sub_if_data, | ||
2850 | csa_finalize_work); | ||
2851 | struct ieee80211_local *local = sdata->local; | ||
2852 | int err, changed; | ||
2853 | |||
2854 | if (!ieee80211_sdata_running(sdata)) | ||
2855 | return; | ||
2856 | |||
2857 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) | ||
2858 | return; | ||
2859 | |||
2860 | sdata->radar_required = sdata->csa_radar_required; | ||
2861 | err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, | ||
2862 | &changed); | ||
2863 | if (WARN_ON(err < 0)) | ||
2864 | return; | ||
2865 | |||
2866 | err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); | ||
2867 | if (err < 0) | ||
2868 | return; | ||
2869 | |||
2870 | changed |= err; | ||
2871 | kfree(sdata->u.ap.next_beacon); | ||
2872 | sdata->u.ap.next_beacon = NULL; | ||
2873 | sdata->vif.csa_active = false; | ||
2874 | |||
2875 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
2876 | IEEE80211_MAX_QUEUE_MAP, | ||
2877 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
2878 | |||
2879 | ieee80211_bss_info_change_notify(sdata, changed); | ||
2880 | |||
2881 | cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); | ||
2882 | } | ||
2883 | |||
2884 | static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
2885 | struct cfg80211_csa_settings *params) | ||
2886 | { | ||
2887 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2888 | struct ieee80211_local *local = sdata->local; | ||
2889 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
2890 | struct ieee80211_chanctx *chanctx; | ||
2891 | int err, num_chanctx; | ||
2892 | |||
2893 | if (!list_empty(&local->roc_list) || local->scanning) | ||
2894 | return -EBUSY; | ||
2895 | |||
2896 | if (sdata->wdev.cac_started) | ||
2897 | return -EBUSY; | ||
2898 | |||
2899 | if (cfg80211_chandef_identical(¶ms->chandef, | ||
2900 | &sdata->vif.bss_conf.chandef)) | ||
2901 | return -EINVAL; | ||
2902 | |||
2903 | rcu_read_lock(); | ||
2904 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
2905 | if (!chanctx_conf) { | ||
2906 | rcu_read_unlock(); | ||
2907 | return -EBUSY; | ||
2908 | } | ||
2909 | |||
2910 | /* don't handle for multi-VIF cases */ | ||
2911 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); | ||
2912 | if (chanctx->refcount > 1) { | ||
2913 | rcu_read_unlock(); | ||
2914 | return -EBUSY; | ||
2915 | } | ||
2916 | num_chanctx = 0; | ||
2917 | list_for_each_entry_rcu(chanctx, &local->chanctx_list, list) | ||
2918 | num_chanctx++; | ||
2919 | rcu_read_unlock(); | ||
2920 | |||
2921 | if (num_chanctx > 1) | ||
2922 | return -EBUSY; | ||
2923 | |||
2924 | /* don't allow another channel switch if one is already active. */ | ||
2925 | if (sdata->vif.csa_active) | ||
2926 | return -EBUSY; | ||
2927 | |||
2928 | /* only handle AP for now. */ | ||
2929 | switch (sdata->vif.type) { | ||
2930 | case NL80211_IFTYPE_AP: | ||
2931 | break; | ||
2932 | default: | ||
2933 | return -EOPNOTSUPP; | ||
2934 | } | ||
2935 | |||
2936 | sdata->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after); | ||
2937 | if (!sdata->u.ap.next_beacon) | ||
2938 | return -ENOMEM; | ||
2939 | |||
2940 | sdata->csa_counter_offset_beacon = params->counter_offset_beacon; | ||
2941 | sdata->csa_counter_offset_presp = params->counter_offset_presp; | ||
2942 | sdata->csa_radar_required = params->radar_required; | ||
2943 | |||
2944 | if (params->block_tx) | ||
2945 | ieee80211_stop_queues_by_reason(&local->hw, | ||
2946 | IEEE80211_MAX_QUEUE_MAP, | ||
2947 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
2948 | |||
2949 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); | ||
2950 | if (err < 0) | ||
2951 | return err; | ||
2952 | |||
2953 | local->csa_chandef = params->chandef; | ||
2954 | sdata->vif.csa_active = true; | ||
2955 | |||
2956 | ieee80211_bss_info_change_notify(sdata, err); | ||
2957 | drv_channel_switch_beacon(sdata, ¶ms->chandef); | ||
2958 | |||
2959 | return 0; | ||
2960 | } | ||
2961 | |||
2789 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | 2962 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
2790 | struct ieee80211_channel *chan, bool offchan, | 2963 | struct ieee80211_channel *chan, bool offchan, |
2791 | unsigned int wait, const u8 *buf, size_t len, | 2964 | unsigned int wait, const u8 *buf, size_t len, |
@@ -3503,4 +3676,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
3503 | .get_et_strings = ieee80211_get_et_strings, | 3676 | .get_et_strings = ieee80211_get_et_strings, |
3504 | .get_channel = ieee80211_cfg_get_channel, | 3677 | .get_channel = ieee80211_cfg_get_channel, |
3505 | .start_radar_detection = ieee80211_start_radar_detection, | 3678 | .start_radar_detection = ieee80211_start_radar_detection, |
3679 | .channel_switch = ieee80211_channel_switch, | ||
3506 | }; | 3680 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 03e8d2e3270e..3a4764b2869e 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -410,6 +410,64 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
410 | return ret; | 410 | return ret; |
411 | } | 411 | } |
412 | 412 | ||
413 | int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
414 | const struct cfg80211_chan_def *chandef, | ||
415 | u32 *changed) | ||
416 | { | ||
417 | struct ieee80211_local *local = sdata->local; | ||
418 | struct ieee80211_chanctx_conf *conf; | ||
419 | struct ieee80211_chanctx *ctx; | ||
420 | int ret; | ||
421 | u32 chanctx_changed = 0; | ||
422 | |||
423 | /* should never be called if not performing a channel switch. */ | ||
424 | if (WARN_ON(!sdata->vif.csa_active)) | ||
425 | return -EINVAL; | ||
426 | |||
427 | if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
428 | IEEE80211_CHAN_DISABLED)) | ||
429 | return -EINVAL; | ||
430 | |||
431 | mutex_lock(&local->chanctx_mtx); | ||
432 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
433 | lockdep_is_held(&local->chanctx_mtx)); | ||
434 | if (!conf) { | ||
435 | ret = -EINVAL; | ||
436 | goto out; | ||
437 | } | ||
438 | |||
439 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
440 | if (ctx->refcount != 1) { | ||
441 | ret = -EINVAL; | ||
442 | goto out; | ||
443 | } | ||
444 | |||
445 | if (sdata->vif.bss_conf.chandef.width != chandef->width) { | ||
446 | chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH; | ||
447 | *changed |= BSS_CHANGED_BANDWIDTH; | ||
448 | } | ||
449 | |||
450 | sdata->vif.bss_conf.chandef = *chandef; | ||
451 | ctx->conf.def = *chandef; | ||
452 | |||
453 | chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL; | ||
454 | drv_change_chanctx(local, ctx, chanctx_changed); | ||
455 | |||
456 | if (!local->use_chanctx) { | ||
457 | local->_oper_chandef = *chandef; | ||
458 | ieee80211_hw_config(local, 0); | ||
459 | } | ||
460 | |||
461 | ieee80211_recalc_chanctx_chantype(local, ctx); | ||
462 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
463 | ieee80211_recalc_radar_chanctx(local, ctx); | ||
464 | |||
465 | ret = 0; | ||
466 | out: | ||
467 | mutex_unlock(&local->chanctx_mtx); | ||
468 | return ret; | ||
469 | } | ||
470 | |||
413 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | 471 | int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, |
414 | const struct cfg80211_chan_def *chandef, | 472 | const struct cfg80211_chan_def *chandef, |
415 | u32 *changed) | 473 | u32 *changed) |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 44e201d60a13..19c54a44ed47 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -455,6 +455,15 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
455 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); | 455 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); |
456 | DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); | 456 | DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); |
457 | 457 | ||
458 | if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) | ||
459 | debugfs_create_x32("driver_buffered_tids", 0400, | ||
460 | sta->debugfs.dir, | ||
461 | (u32 *)&sta->driver_buffered_tids); | ||
462 | else | ||
463 | debugfs_create_x64("driver_buffered_tids", 0400, | ||
464 | sta->debugfs.dir, | ||
465 | (u64 *)&sta->driver_buffered_tids); | ||
466 | |||
458 | drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); | 467 | drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); |
459 | } | 468 | } |
460 | 469 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index b931c96a596f..b3ea11f3d526 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -1072,4 +1072,17 @@ static inline void drv_ipv6_addr_change(struct ieee80211_local *local, | |||
1072 | } | 1072 | } |
1073 | #endif | 1073 | #endif |
1074 | 1074 | ||
1075 | static inline void | ||
1076 | drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata, | ||
1077 | struct cfg80211_chan_def *chandef) | ||
1078 | { | ||
1079 | struct ieee80211_local *local = sdata->local; | ||
1080 | |||
1081 | if (local->ops->channel_switch_beacon) { | ||
1082 | trace_drv_channel_switch_beacon(local, sdata, chandef); | ||
1083 | local->ops->channel_switch_beacon(&local->hw, &sdata->vif, | ||
1084 | chandef); | ||
1085 | } | ||
1086 | } | ||
1087 | |||
1075 | #endif /* __MAC80211_DRIVER_OPS */ | 1088 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index f83534f6a2ee..529bf58bc145 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -19,13 +19,14 @@ | |||
19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
20 | #include "rate.h" | 20 | #include "rate.h" |
21 | 21 | ||
22 | static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata, | 22 | static void __check_htcap_disable(struct ieee80211_ht_cap *ht_capa, |
23 | struct ieee80211_ht_cap *ht_capa_mask, | ||
23 | struct ieee80211_sta_ht_cap *ht_cap, | 24 | struct ieee80211_sta_ht_cap *ht_cap, |
24 | u16 flag) | 25 | u16 flag) |
25 | { | 26 | { |
26 | __le16 le_flag = cpu_to_le16(flag); | 27 | __le16 le_flag = cpu_to_le16(flag); |
27 | if (sdata->u.mgd.ht_capa_mask.cap_info & le_flag) { | 28 | if (ht_capa_mask->cap_info & le_flag) { |
28 | if (!(sdata->u.mgd.ht_capa.cap_info & le_flag)) | 29 | if (!(ht_capa->cap_info & le_flag)) |
29 | ht_cap->cap &= ~flag; | 30 | ht_cap->cap &= ~flag; |
30 | } | 31 | } |
31 | } | 32 | } |
@@ -33,13 +34,30 @@ static void __check_htcap_disable(struct ieee80211_sub_if_data *sdata, | |||
33 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 34 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
34 | struct ieee80211_sta_ht_cap *ht_cap) | 35 | struct ieee80211_sta_ht_cap *ht_cap) |
35 | { | 36 | { |
36 | u8 *scaps = (u8 *)(&sdata->u.mgd.ht_capa.mcs.rx_mask); | 37 | struct ieee80211_ht_cap *ht_capa, *ht_capa_mask; |
37 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); | 38 | u8 *scaps, *smask; |
38 | int i; | 39 | int i; |
39 | 40 | ||
40 | if (!ht_cap->ht_supported) | 41 | if (!ht_cap->ht_supported) |
41 | return; | 42 | return; |
42 | 43 | ||
44 | switch (sdata->vif.type) { | ||
45 | case NL80211_IFTYPE_STATION: | ||
46 | ht_capa = &sdata->u.mgd.ht_capa; | ||
47 | ht_capa_mask = &sdata->u.mgd.ht_capa_mask; | ||
48 | break; | ||
49 | case NL80211_IFTYPE_ADHOC: | ||
50 | ht_capa = &sdata->u.ibss.ht_capa; | ||
51 | ht_capa_mask = &sdata->u.ibss.ht_capa_mask; | ||
52 | break; | ||
53 | default: | ||
54 | WARN_ON_ONCE(1); | ||
55 | return; | ||
56 | } | ||
57 | |||
58 | scaps = (u8 *)(&ht_capa->mcs.rx_mask); | ||
59 | smask = (u8 *)(&ht_capa_mask->mcs.rx_mask); | ||
60 | |||
43 | /* NOTE: If you add more over-rides here, update register_hw | 61 | /* NOTE: If you add more over-rides here, update register_hw |
44 | * ht_capa_mod_msk logic in main.c as well. | 62 | * ht_capa_mod_msk logic in main.c as well. |
45 | * And, if this method can ever change ht_cap.ht_supported, fix | 63 | * And, if this method can ever change ht_cap.ht_supported, fix |
@@ -55,28 +73,32 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
55 | } | 73 | } |
56 | 74 | ||
57 | /* Force removal of HT-40 capabilities? */ | 75 | /* Force removal of HT-40 capabilities? */ |
58 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SUP_WIDTH_20_40); | 76 | __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, |
59 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_40); | 77 | IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
78 | __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, | ||
79 | IEEE80211_HT_CAP_SGI_40); | ||
60 | 80 | ||
61 | /* Allow user to disable SGI-20 (SGI-40 is handled above) */ | 81 | /* Allow user to disable SGI-20 (SGI-40 is handled above) */ |
62 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_SGI_20); | 82 | __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, |
83 | IEEE80211_HT_CAP_SGI_20); | ||
63 | 84 | ||
64 | /* Allow user to disable the max-AMSDU bit. */ | 85 | /* Allow user to disable the max-AMSDU bit. */ |
65 | __check_htcap_disable(sdata, ht_cap, IEEE80211_HT_CAP_MAX_AMSDU); | 86 | __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap, |
87 | IEEE80211_HT_CAP_MAX_AMSDU); | ||
66 | 88 | ||
67 | /* Allow user to decrease AMPDU factor */ | 89 | /* Allow user to decrease AMPDU factor */ |
68 | if (sdata->u.mgd.ht_capa_mask.ampdu_params_info & | 90 | if (ht_capa_mask->ampdu_params_info & |
69 | IEEE80211_HT_AMPDU_PARM_FACTOR) { | 91 | IEEE80211_HT_AMPDU_PARM_FACTOR) { |
70 | u8 n = sdata->u.mgd.ht_capa.ampdu_params_info | 92 | u8 n = ht_capa->ampdu_params_info & |
71 | & IEEE80211_HT_AMPDU_PARM_FACTOR; | 93 | IEEE80211_HT_AMPDU_PARM_FACTOR; |
72 | if (n < ht_cap->ampdu_factor) | 94 | if (n < ht_cap->ampdu_factor) |
73 | ht_cap->ampdu_factor = n; | 95 | ht_cap->ampdu_factor = n; |
74 | } | 96 | } |
75 | 97 | ||
76 | /* Allow the user to increase AMPDU density. */ | 98 | /* Allow the user to increase AMPDU density. */ |
77 | if (sdata->u.mgd.ht_capa_mask.ampdu_params_info & | 99 | if (ht_capa_mask->ampdu_params_info & |
78 | IEEE80211_HT_AMPDU_PARM_DENSITY) { | 100 | IEEE80211_HT_AMPDU_PARM_DENSITY) { |
79 | u8 n = (sdata->u.mgd.ht_capa.ampdu_params_info & | 101 | u8 n = (ht_capa->ampdu_params_info & |
80 | IEEE80211_HT_AMPDU_PARM_DENSITY) | 102 | IEEE80211_HT_AMPDU_PARM_DENSITY) |
81 | >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; | 103 | >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; |
82 | if (n > ht_cap->ampdu_density) | 104 | if (n > ht_cap->ampdu_density) |
@@ -112,7 +134,8 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
112 | * we advertised a restricted capability set to. Override | 134 | * we advertised a restricted capability set to. Override |
113 | * our own capabilities and then use those below. | 135 | * our own capabilities and then use those below. |
114 | */ | 136 | */ |
115 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 137 | if ((sdata->vif.type == NL80211_IFTYPE_STATION || |
138 | sdata->vif.type == NL80211_IFTYPE_ADHOC) && | ||
116 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | 139 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) |
117 | ieee80211_apply_htcap_overrides(sdata, &own_cap); | 140 | ieee80211_apply_htcap_overrides(sdata, &own_cap); |
118 | 141 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ea7b9c2c7e66..e08387cdc8fd 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | 31 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) |
32 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | 32 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) |
33 | #define IEEE80211_IBSS_RSN_INACTIVITY_LIMIT (10 * HZ) | ||
33 | 34 | ||
34 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 35 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
35 | 36 | ||
@@ -43,16 +44,18 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
43 | { | 44 | { |
44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 45 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
45 | struct ieee80211_local *local = sdata->local; | 46 | struct ieee80211_local *local = sdata->local; |
46 | int rates, i; | 47 | int rates_n = 0, i, ri; |
47 | struct ieee80211_mgmt *mgmt; | 48 | struct ieee80211_mgmt *mgmt; |
48 | u8 *pos; | 49 | u8 *pos; |
49 | struct ieee80211_supported_band *sband; | 50 | struct ieee80211_supported_band *sband; |
50 | struct cfg80211_bss *bss; | 51 | struct cfg80211_bss *bss; |
51 | u32 bss_change; | 52 | u32 bss_change, rate_flags, rates = 0, rates_added = 0; |
52 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
53 | struct cfg80211_chan_def chandef; | 53 | struct cfg80211_chan_def chandef; |
54 | enum nl80211_bss_scan_width scan_width; | ||
55 | bool have_higher_than_11mbit = false; | ||
54 | struct beacon_data *presp; | 56 | struct beacon_data *presp; |
55 | int frame_len; | 57 | int frame_len; |
58 | int shift; | ||
56 | 59 | ||
57 | sdata_assert_lock(sdata); | 60 | sdata_assert_lock(sdata); |
58 | 61 | ||
@@ -83,6 +86,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
83 | 86 | ||
84 | chandef = ifibss->chandef; | 87 | chandef = ifibss->chandef; |
85 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { | 88 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { |
89 | if (chandef.width == NL80211_CHAN_WIDTH_5 || | ||
90 | chandef.width == NL80211_CHAN_WIDTH_10 || | ||
91 | chandef.width == NL80211_CHAN_WIDTH_20_NOHT || | ||
92 | chandef.width == NL80211_CHAN_WIDTH_20) { | ||
93 | sdata_info(sdata, | ||
94 | "Failed to join IBSS, beacons forbidden\n"); | ||
95 | return; | ||
96 | } | ||
86 | chandef.width = NL80211_CHAN_WIDTH_20; | 97 | chandef.width = NL80211_CHAN_WIDTH_20; |
87 | chandef.center_freq1 = chan->center_freq; | 98 | chandef.center_freq1 = chan->center_freq; |
88 | } | 99 | } |
@@ -99,6 +110,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
99 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | 110 | memcpy(ifibss->bssid, bssid, ETH_ALEN); |
100 | 111 | ||
101 | sband = local->hw.wiphy->bands[chan->band]; | 112 | sband = local->hw.wiphy->bands[chan->band]; |
113 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
102 | 114 | ||
103 | /* Build IBSS probe response */ | 115 | /* Build IBSS probe response */ |
104 | frame_len = sizeof(struct ieee80211_hdr_3addr) + | 116 | frame_len = sizeof(struct ieee80211_hdr_3addr) + |
@@ -134,15 +146,33 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
134 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); | 146 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); |
135 | pos += ifibss->ssid_len; | 147 | pos += ifibss->ssid_len; |
136 | 148 | ||
137 | rates = min_t(int, 8, sband->n_bitrates); | 149 | rate_flags = ieee80211_chandef_rate_flags(&chandef); |
150 | for (i = 0; i < sband->n_bitrates; i++) { | ||
151 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
152 | continue; | ||
153 | if (sband->bitrates[i].bitrate > 110) | ||
154 | have_higher_than_11mbit = true; | ||
155 | |||
156 | rates |= BIT(i); | ||
157 | rates_n++; | ||
158 | } | ||
159 | |||
138 | *pos++ = WLAN_EID_SUPP_RATES; | 160 | *pos++ = WLAN_EID_SUPP_RATES; |
139 | *pos++ = rates; | 161 | *pos++ = min_t(int, 8, rates_n); |
140 | for (i = 0; i < rates; i++) { | 162 | for (ri = 0; ri < sband->n_bitrates; ri++) { |
141 | int rate = sband->bitrates[i].bitrate; | 163 | int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate, |
164 | 5 * (1 << shift)); | ||
142 | u8 basic = 0; | 165 | u8 basic = 0; |
143 | if (basic_rates & BIT(i)) | 166 | if (!(rates & BIT(ri))) |
167 | continue; | ||
168 | |||
169 | if (basic_rates & BIT(ri)) | ||
144 | basic = 0x80; | 170 | basic = 0x80; |
145 | *pos++ = basic | (u8) (rate / 5); | 171 | *pos++ = basic | (u8) rate; |
172 | if (++rates_added == 8) { | ||
173 | ri++; /* continue at next rate for EXT_SUPP_RATES */ | ||
174 | break; | ||
175 | } | ||
146 | } | 176 | } |
147 | 177 | ||
148 | if (sband->band == IEEE80211_BAND_2GHZ) { | 178 | if (sband->band == IEEE80211_BAND_2GHZ) { |
@@ -157,15 +187,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
157 | *pos++ = 0; | 187 | *pos++ = 0; |
158 | *pos++ = 0; | 188 | *pos++ = 0; |
159 | 189 | ||
160 | if (sband->n_bitrates > 8) { | 190 | /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */ |
191 | if (rates_n > 8) { | ||
161 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 192 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
162 | *pos++ = sband->n_bitrates - 8; | 193 | *pos++ = rates_n - 8; |
163 | for (i = 8; i < sband->n_bitrates; i++) { | 194 | for (; ri < sband->n_bitrates; ri++) { |
164 | int rate = sband->bitrates[i].bitrate; | 195 | int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate, |
196 | 5 * (1 << shift)); | ||
165 | u8 basic = 0; | 197 | u8 basic = 0; |
166 | if (basic_rates & BIT(i)) | 198 | if (!(rates & BIT(ri))) |
199 | continue; | ||
200 | |||
201 | if (basic_rates & BIT(ri)) | ||
167 | basic = 0x80; | 202 | basic = 0x80; |
168 | *pos++ = basic | (u8) (rate / 5); | 203 | *pos++ = basic | (u8) rate; |
169 | } | 204 | } |
170 | } | 205 | } |
171 | 206 | ||
@@ -179,8 +214,12 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
179 | chandef.width != NL80211_CHAN_WIDTH_5 && | 214 | chandef.width != NL80211_CHAN_WIDTH_5 && |
180 | chandef.width != NL80211_CHAN_WIDTH_10 && | 215 | chandef.width != NL80211_CHAN_WIDTH_10 && |
181 | sband->ht_cap.ht_supported) { | 216 | sband->ht_cap.ht_supported) { |
182 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, | 217 | struct ieee80211_sta_ht_cap ht_cap; |
183 | sband->ht_cap.cap); | 218 | |
219 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
220 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
221 | |||
222 | pos = ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); | ||
184 | /* | 223 | /* |
185 | * Note: According to 802.11n-2009 9.13.3.1, HT Protection | 224 | * Note: According to 802.11n-2009 9.13.3.1, HT Protection |
186 | * field and RIFS Mode are reserved in IBSS mode, therefore | 225 | * field and RIFS Mode are reserved in IBSS mode, therefore |
@@ -236,18 +275,26 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
236 | sdata->vif.bss_conf.use_short_slot = chan->band == IEEE80211_BAND_5GHZ; | 275 | sdata->vif.bss_conf.use_short_slot = chan->band == IEEE80211_BAND_5GHZ; |
237 | bss_change |= BSS_CHANGED_ERP_SLOT; | 276 | bss_change |= BSS_CHANGED_ERP_SLOT; |
238 | 277 | ||
278 | /* cf. IEEE 802.11 9.2.12 */ | ||
279 | if (chan->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) | ||
280 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
281 | else | ||
282 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
283 | |||
239 | sdata->vif.bss_conf.ibss_joined = true; | 284 | sdata->vif.bss_conf.ibss_joined = true; |
240 | sdata->vif.bss_conf.ibss_creator = creator; | 285 | sdata->vif.bss_conf.ibss_creator = creator; |
241 | ieee80211_bss_info_change_notify(sdata, bss_change); | 286 | ieee80211_bss_info_change_notify(sdata, bss_change); |
242 | 287 | ||
243 | ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); | 288 | ieee80211_set_wmm_default(sdata, true); |
244 | 289 | ||
245 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; | 290 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; |
246 | mod_timer(&ifibss->timer, | 291 | mod_timer(&ifibss->timer, |
247 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | 292 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); |
248 | 293 | ||
249 | bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, | 294 | scan_width = cfg80211_chandef_to_scan_width(&chandef); |
250 | mgmt, presp->head_len, 0, GFP_KERNEL); | 295 | bss = cfg80211_inform_bss_width_frame(local->hw.wiphy, chan, |
296 | scan_width, mgmt, | ||
297 | presp->head_len, 0, GFP_KERNEL); | ||
251 | cfg80211_put_bss(local->hw.wiphy, bss); | 298 | cfg80211_put_bss(local->hw.wiphy, bss); |
252 | netif_carrier_on(sdata->dev); | 299 | netif_carrier_on(sdata->dev); |
253 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); | 300 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); |
@@ -264,6 +311,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
264 | u16 beacon_int = cbss->beacon_interval; | 311 | u16 beacon_int = cbss->beacon_interval; |
265 | const struct cfg80211_bss_ies *ies; | 312 | const struct cfg80211_bss_ies *ies; |
266 | u64 tsf; | 313 | u64 tsf; |
314 | u32 rate_flags; | ||
315 | int shift; | ||
267 | 316 | ||
268 | sdata_assert_lock(sdata); | 317 | sdata_assert_lock(sdata); |
269 | 318 | ||
@@ -271,15 +320,24 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
271 | beacon_int = 10; | 320 | beacon_int = 10; |
272 | 321 | ||
273 | sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; | 322 | sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; |
323 | rate_flags = ieee80211_chandef_rate_flags(&sdata->u.ibss.chandef); | ||
324 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
274 | 325 | ||
275 | basic_rates = 0; | 326 | basic_rates = 0; |
276 | 327 | ||
277 | for (i = 0; i < bss->supp_rates_len; i++) { | 328 | for (i = 0; i < bss->supp_rates_len; i++) { |
278 | int rate = (bss->supp_rates[i] & 0x7f) * 5; | 329 | int rate = bss->supp_rates[i] & 0x7f; |
279 | bool is_basic = !!(bss->supp_rates[i] & 0x80); | 330 | bool is_basic = !!(bss->supp_rates[i] & 0x80); |
280 | 331 | ||
281 | for (j = 0; j < sband->n_bitrates; j++) { | 332 | for (j = 0; j < sband->n_bitrates; j++) { |
282 | if (sband->bitrates[j].bitrate == rate) { | 333 | int brate; |
334 | if ((rate_flags & sband->bitrates[j].flags) | ||
335 | != rate_flags) | ||
336 | continue; | ||
337 | |||
338 | brate = DIV_ROUND_UP(sband->bitrates[j].bitrate, | ||
339 | 5 * (1 << shift)); | ||
340 | if (brate == rate) { | ||
283 | if (is_basic) | 341 | if (is_basic) |
284 | basic_rates |= BIT(j); | 342 | basic_rates |= BIT(j); |
285 | break; | 343 | break; |
@@ -335,6 +393,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
335 | struct sta_info *sta; | 393 | struct sta_info *sta; |
336 | struct ieee80211_chanctx_conf *chanctx_conf; | 394 | struct ieee80211_chanctx_conf *chanctx_conf; |
337 | struct ieee80211_supported_band *sband; | 395 | struct ieee80211_supported_band *sband; |
396 | enum nl80211_bss_scan_width scan_width; | ||
338 | int band; | 397 | int band; |
339 | 398 | ||
340 | /* | 399 | /* |
@@ -363,6 +422,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
363 | if (WARN_ON_ONCE(!chanctx_conf)) | 422 | if (WARN_ON_ONCE(!chanctx_conf)) |
364 | return NULL; | 423 | return NULL; |
365 | band = chanctx_conf->def.chan->band; | 424 | band = chanctx_conf->def.chan->band; |
425 | scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); | ||
366 | rcu_read_unlock(); | 426 | rcu_read_unlock(); |
367 | 427 | ||
368 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); | 428 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); |
@@ -376,7 +436,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
376 | /* make sure mandatory rates are always added */ | 436 | /* make sure mandatory rates are always added */ |
377 | sband = local->hw.wiphy->bands[band]; | 437 | sband = local->hw.wiphy->bands[band]; |
378 | sta->sta.supp_rates[band] = supp_rates | | 438 | sta->sta.supp_rates[band] = supp_rates | |
379 | ieee80211_mandatory_rates(sband); | 439 | ieee80211_mandatory_rates(sband, scan_width); |
380 | 440 | ||
381 | return ieee80211_ibss_finish_sta(sta); | 441 | return ieee80211_ibss_finish_sta(sta); |
382 | } | 442 | } |
@@ -440,6 +500,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
440 | u64 beacon_timestamp, rx_timestamp; | 500 | u64 beacon_timestamp, rx_timestamp; |
441 | u32 supp_rates = 0; | 501 | u32 supp_rates = 0; |
442 | enum ieee80211_band band = rx_status->band; | 502 | enum ieee80211_band band = rx_status->band; |
503 | enum nl80211_bss_scan_width scan_width; | ||
443 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; | 504 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; |
444 | bool rates_updated = false; | 505 | bool rates_updated = false; |
445 | 506 | ||
@@ -461,16 +522,22 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
461 | sta = sta_info_get(sdata, mgmt->sa); | 522 | sta = sta_info_get(sdata, mgmt->sa); |
462 | 523 | ||
463 | if (elems->supp_rates) { | 524 | if (elems->supp_rates) { |
464 | supp_rates = ieee80211_sta_get_rates(local, elems, | 525 | supp_rates = ieee80211_sta_get_rates(sdata, elems, |
465 | band, NULL); | 526 | band, NULL); |
466 | if (sta) { | 527 | if (sta) { |
467 | u32 prev_rates; | 528 | u32 prev_rates; |
468 | 529 | ||
469 | prev_rates = sta->sta.supp_rates[band]; | 530 | prev_rates = sta->sta.supp_rates[band]; |
470 | /* make sure mandatory rates are always added */ | 531 | /* make sure mandatory rates are always added */ |
471 | sta->sta.supp_rates[band] = supp_rates | | 532 | scan_width = NL80211_BSS_CHAN_WIDTH_20; |
472 | ieee80211_mandatory_rates(sband); | 533 | if (rx_status->flag & RX_FLAG_5MHZ) |
534 | scan_width = NL80211_BSS_CHAN_WIDTH_5; | ||
535 | if (rx_status->flag & RX_FLAG_10MHZ) | ||
536 | scan_width = NL80211_BSS_CHAN_WIDTH_10; | ||
473 | 537 | ||
538 | sta->sta.supp_rates[band] = supp_rates | | ||
539 | ieee80211_mandatory_rates(sband, | ||
540 | scan_width); | ||
474 | if (sta->sta.supp_rates[band] != prev_rates) { | 541 | if (sta->sta.supp_rates[band] != prev_rates) { |
475 | ibss_dbg(sdata, | 542 | ibss_dbg(sdata, |
476 | "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", | 543 | "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", |
@@ -585,7 +652,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
585 | "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n", | 652 | "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n", |
586 | mgmt->bssid); | 653 | mgmt->bssid); |
587 | ieee80211_sta_join_ibss(sdata, bss); | 654 | ieee80211_sta_join_ibss(sdata, bss); |
588 | supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL); | 655 | supp_rates = ieee80211_sta_get_rates(sdata, elems, band, NULL); |
589 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, | 656 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
590 | supp_rates); | 657 | supp_rates); |
591 | rcu_read_unlock(); | 658 | rcu_read_unlock(); |
@@ -604,6 +671,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
604 | struct sta_info *sta; | 671 | struct sta_info *sta; |
605 | struct ieee80211_chanctx_conf *chanctx_conf; | 672 | struct ieee80211_chanctx_conf *chanctx_conf; |
606 | struct ieee80211_supported_band *sband; | 673 | struct ieee80211_supported_band *sband; |
674 | enum nl80211_bss_scan_width scan_width; | ||
607 | int band; | 675 | int band; |
608 | 676 | ||
609 | /* | 677 | /* |
@@ -629,6 +697,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
629 | return; | 697 | return; |
630 | } | 698 | } |
631 | band = chanctx_conf->def.chan->band; | 699 | band = chanctx_conf->def.chan->band; |
700 | scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); | ||
632 | rcu_read_unlock(); | 701 | rcu_read_unlock(); |
633 | 702 | ||
634 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 703 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); |
@@ -640,7 +709,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
640 | /* make sure mandatory rates are always added */ | 709 | /* make sure mandatory rates are always added */ |
641 | sband = local->hw.wiphy->bands[band]; | 710 | sband = local->hw.wiphy->bands[band]; |
642 | sta->sta.supp_rates[band] = supp_rates | | 711 | sta->sta.supp_rates[band] = supp_rates | |
643 | ieee80211_mandatory_rates(sband); | 712 | ieee80211_mandatory_rates(sband, scan_width); |
644 | 713 | ||
645 | spin_lock(&ifibss->incomplete_lock); | 714 | spin_lock(&ifibss->incomplete_lock); |
646 | list_add(&sta->list, &ifibss->incomplete_stations); | 715 | list_add(&sta->list, &ifibss->incomplete_stations); |
@@ -672,6 +741,33 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | |||
672 | return active; | 741 | return active; |
673 | } | 742 | } |
674 | 743 | ||
744 | static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) | ||
745 | { | ||
746 | struct ieee80211_local *local = sdata->local; | ||
747 | struct sta_info *sta, *tmp; | ||
748 | unsigned long exp_time = IEEE80211_IBSS_INACTIVITY_LIMIT; | ||
749 | unsigned long exp_rsn_time = IEEE80211_IBSS_RSN_INACTIVITY_LIMIT; | ||
750 | |||
751 | mutex_lock(&local->sta_mtx); | ||
752 | |||
753 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | ||
754 | if (sdata != sta->sdata) | ||
755 | continue; | ||
756 | |||
757 | if (time_after(jiffies, sta->last_rx + exp_time) || | ||
758 | (time_after(jiffies, sta->last_rx + exp_rsn_time) && | ||
759 | sta->sta_state != IEEE80211_STA_AUTHORIZED)) { | ||
760 | sta_dbg(sta->sdata, "expiring inactive %sSTA %pM\n", | ||
761 | sta->sta_state != IEEE80211_STA_AUTHORIZED ? | ||
762 | "not authorized " : "", sta->sta.addr); | ||
763 | |||
764 | WARN_ON(__sta_info_destroy(sta)); | ||
765 | } | ||
766 | } | ||
767 | |||
768 | mutex_unlock(&local->sta_mtx); | ||
769 | } | ||
770 | |||
675 | /* | 771 | /* |
676 | * This function is called with state == IEEE80211_IBSS_MLME_JOINED | 772 | * This function is called with state == IEEE80211_IBSS_MLME_JOINED |
677 | */ | 773 | */ |
@@ -679,13 +775,14 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | |||
679 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | 775 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) |
680 | { | 776 | { |
681 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 777 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
778 | enum nl80211_bss_scan_width scan_width; | ||
682 | 779 | ||
683 | sdata_assert_lock(sdata); | 780 | sdata_assert_lock(sdata); |
684 | 781 | ||
685 | mod_timer(&ifibss->timer, | 782 | mod_timer(&ifibss->timer, |
686 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | 783 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); |
687 | 784 | ||
688 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | 785 | ieee80211_ibss_sta_expire(sdata); |
689 | 786 | ||
690 | if (time_before(jiffies, ifibss->last_scan_completed + | 787 | if (time_before(jiffies, ifibss->last_scan_completed + |
691 | IEEE80211_IBSS_MERGE_INTERVAL)) | 788 | IEEE80211_IBSS_MERGE_INTERVAL)) |
@@ -700,8 +797,9 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
700 | sdata_info(sdata, | 797 | sdata_info(sdata, |
701 | "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); | 798 | "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); |
702 | 799 | ||
800 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); | ||
703 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, | 801 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, |
704 | NULL); | 802 | NULL, scan_width); |
705 | } | 803 | } |
706 | 804 | ||
707 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | 805 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) |
@@ -751,6 +849,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
751 | struct cfg80211_bss *cbss; | 849 | struct cfg80211_bss *cbss; |
752 | struct ieee80211_channel *chan = NULL; | 850 | struct ieee80211_channel *chan = NULL; |
753 | const u8 *bssid = NULL; | 851 | const u8 *bssid = NULL; |
852 | enum nl80211_bss_scan_width scan_width; | ||
754 | int active_ibss; | 853 | int active_ibss; |
755 | u16 capability; | 854 | u16 capability; |
756 | 855 | ||
@@ -799,8 +898,10 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
799 | IEEE80211_SCAN_INTERVAL)) { | 898 | IEEE80211_SCAN_INTERVAL)) { |
800 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); | 899 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); |
801 | 900 | ||
901 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); | ||
802 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, | 902 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, |
803 | ifibss->ssid_len, chan); | 903 | ifibss->ssid_len, chan, |
904 | scan_width); | ||
804 | } else { | 905 | } else { |
805 | int interval = IEEE80211_SCAN_INTERVAL; | 906 | int interval = IEEE80211_SCAN_INTERVAL; |
806 | 907 | ||
@@ -1020,6 +1121,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1020 | struct cfg80211_ibss_params *params) | 1121 | struct cfg80211_ibss_params *params) |
1021 | { | 1122 | { |
1022 | u32 changed = 0; | 1123 | u32 changed = 0; |
1124 | u32 rate_flags; | ||
1125 | struct ieee80211_supported_band *sband; | ||
1126 | int i; | ||
1023 | 1127 | ||
1024 | if (params->bssid) { | 1128 | if (params->bssid) { |
1025 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); | 1129 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); |
@@ -1030,6 +1134,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1030 | sdata->u.ibss.privacy = params->privacy; | 1134 | sdata->u.ibss.privacy = params->privacy; |
1031 | sdata->u.ibss.control_port = params->control_port; | 1135 | sdata->u.ibss.control_port = params->control_port; |
1032 | sdata->u.ibss.basic_rates = params->basic_rates; | 1136 | sdata->u.ibss.basic_rates = params->basic_rates; |
1137 | |||
1138 | /* fix basic_rates if channel does not support these rates */ | ||
1139 | rate_flags = ieee80211_chandef_rate_flags(¶ms->chandef); | ||
1140 | sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band]; | ||
1141 | for (i = 0; i < sband->n_bitrates; i++) { | ||
1142 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
1143 | sdata->u.ibss.basic_rates &= ~BIT(i); | ||
1144 | } | ||
1033 | memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, | 1145 | memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, |
1034 | sizeof(params->mcast_rate)); | 1146 | sizeof(params->mcast_rate)); |
1035 | 1147 | ||
@@ -1051,6 +1163,11 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1051 | memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len); | 1163 | memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len); |
1052 | sdata->u.ibss.ssid_len = params->ssid_len; | 1164 | sdata->u.ibss.ssid_len = params->ssid_len; |
1053 | 1165 | ||
1166 | memcpy(&sdata->u.ibss.ht_capa, ¶ms->ht_capa, | ||
1167 | sizeof(sdata->u.ibss.ht_capa)); | ||
1168 | memcpy(&sdata->u.ibss.ht_capa_mask, ¶ms->ht_capa_mask, | ||
1169 | sizeof(sdata->u.ibss.ht_capa_mask)); | ||
1170 | |||
1054 | /* | 1171 | /* |
1055 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is | 1172 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is |
1056 | * reserved, but an HT STA shall protect HT transmissions as though | 1173 | * reserved, but an HT STA shall protect HT transmissions as though |
@@ -1131,6 +1248,11 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1131 | presp = rcu_dereference_protected(ifibss->presp, | 1248 | presp = rcu_dereference_protected(ifibss->presp, |
1132 | lockdep_is_held(&sdata->wdev.mtx)); | 1249 | lockdep_is_held(&sdata->wdev.mtx)); |
1133 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | 1250 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); |
1251 | |||
1252 | /* on the next join, re-program HT parameters */ | ||
1253 | memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa)); | ||
1254 | memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask)); | ||
1255 | |||
1134 | sdata->vif.bss_conf.ibss_joined = false; | 1256 | sdata->vif.bss_conf.ibss_joined = false; |
1135 | sdata->vif.bss_conf.ibss_creator = false; | 1257 | sdata->vif.bss_conf.ibss_creator = false; |
1136 | sdata->vif.bss_conf.enable_beacon = false; | 1258 | sdata->vif.bss_conf.enable_beacon = false; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8412a303993a..e94c84050e9c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -259,6 +259,8 @@ struct ieee80211_if_ap { | |||
259 | struct beacon_data __rcu *beacon; | 259 | struct beacon_data __rcu *beacon; |
260 | struct probe_resp __rcu *probe_resp; | 260 | struct probe_resp __rcu *probe_resp; |
261 | 261 | ||
262 | /* to be used after channel switch. */ | ||
263 | struct cfg80211_beacon_data *next_beacon; | ||
262 | struct list_head vlans; | 264 | struct list_head vlans; |
263 | 265 | ||
264 | struct ps_data ps; | 266 | struct ps_data ps; |
@@ -509,6 +511,9 @@ struct ieee80211_if_ibss { | |||
509 | /* probe response/beacon for IBSS */ | 511 | /* probe response/beacon for IBSS */ |
510 | struct beacon_data __rcu *presp; | 512 | struct beacon_data __rcu *presp; |
511 | 513 | ||
514 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ | ||
515 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ | ||
516 | |||
512 | spinlock_t incomplete_lock; | 517 | spinlock_t incomplete_lock; |
513 | struct list_head incomplete_stations; | 518 | struct list_head incomplete_stations; |
514 | 519 | ||
@@ -713,6 +718,11 @@ struct ieee80211_sub_if_data { | |||
713 | 718 | ||
714 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; | 719 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; |
715 | 720 | ||
721 | struct work_struct csa_finalize_work; | ||
722 | int csa_counter_offset_beacon; | ||
723 | int csa_counter_offset_presp; | ||
724 | bool csa_radar_required; | ||
725 | |||
716 | /* used to reconfigure hardware SM PS */ | 726 | /* used to reconfigure hardware SM PS */ |
717 | struct work_struct recalc_smps; | 727 | struct work_struct recalc_smps; |
718 | 728 | ||
@@ -809,6 +819,34 @@ ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata) | |||
809 | return band; | 819 | return band; |
810 | } | 820 | } |
811 | 821 | ||
822 | static inline int | ||
823 | ieee80211_chandef_get_shift(struct cfg80211_chan_def *chandef) | ||
824 | { | ||
825 | switch (chandef->width) { | ||
826 | case NL80211_CHAN_WIDTH_5: | ||
827 | return 2; | ||
828 | case NL80211_CHAN_WIDTH_10: | ||
829 | return 1; | ||
830 | default: | ||
831 | return 0; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | static inline int | ||
836 | ieee80211_vif_get_shift(struct ieee80211_vif *vif) | ||
837 | { | ||
838 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
839 | int shift = 0; | ||
840 | |||
841 | rcu_read_lock(); | ||
842 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
843 | if (chanctx_conf) | ||
844 | shift = ieee80211_chandef_get_shift(&chanctx_conf->def); | ||
845 | rcu_read_unlock(); | ||
846 | |||
847 | return shift; | ||
848 | } | ||
849 | |||
812 | enum sdata_queue_type { | 850 | enum sdata_queue_type { |
813 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, | 851 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, |
814 | IEEE80211_SDATA_QUEUE_AGG_START = 1, | 852 | IEEE80211_SDATA_QUEUE_AGG_START = 1, |
@@ -1026,7 +1064,7 @@ struct ieee80211_local { | |||
1026 | struct cfg80211_ssid scan_ssid; | 1064 | struct cfg80211_ssid scan_ssid; |
1027 | struct cfg80211_scan_request *int_scan_req; | 1065 | struct cfg80211_scan_request *int_scan_req; |
1028 | struct cfg80211_scan_request *scan_req, *hw_scan_req; | 1066 | struct cfg80211_scan_request *scan_req, *hw_scan_req; |
1029 | struct ieee80211_channel *scan_channel; | 1067 | struct cfg80211_chan_def scan_chandef; |
1030 | enum ieee80211_band hw_scan_band; | 1068 | enum ieee80211_band hw_scan_band; |
1031 | int scan_channel_idx; | 1069 | int scan_channel_idx; |
1032 | int scan_ies_len; | 1070 | int scan_ies_len; |
@@ -1063,7 +1101,6 @@ struct ieee80211_local { | |||
1063 | u32 dot11TransmittedFrameCount; | 1101 | u32 dot11TransmittedFrameCount; |
1064 | 1102 | ||
1065 | #ifdef CONFIG_MAC80211_LEDS | 1103 | #ifdef CONFIG_MAC80211_LEDS |
1066 | int tx_led_counter, rx_led_counter; | ||
1067 | struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; | 1104 | struct led_trigger *tx_led, *rx_led, *assoc_led, *radio_led; |
1068 | struct tpt_led_trigger *tpt_led_trigger; | 1105 | struct tpt_led_trigger *tpt_led_trigger; |
1069 | char tx_led_name[32], rx_led_name[32], | 1106 | char tx_led_name[32], rx_led_name[32], |
@@ -1306,7 +1343,8 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1306 | void ieee80211_scan_work(struct work_struct *work); | 1343 | void ieee80211_scan_work(struct work_struct *work); |
1307 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | 1344 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, |
1308 | const u8 *ssid, u8 ssid_len, | 1345 | const u8 *ssid, u8 ssid_len, |
1309 | struct ieee80211_channel *chan); | 1346 | struct ieee80211_channel *chan, |
1347 | enum nl80211_bss_scan_width scan_width); | ||
1310 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 1348 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
1311 | struct cfg80211_scan_request *req); | 1349 | struct cfg80211_scan_request *req); |
1312 | void ieee80211_scan_cancel(struct ieee80211_local *local); | 1350 | void ieee80211_scan_cancel(struct ieee80211_local *local); |
@@ -1341,6 +1379,9 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free); | |||
1341 | void ieee80211_sw_roc_work(struct work_struct *work); | 1379 | void ieee80211_sw_roc_work(struct work_struct *work); |
1342 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); | 1380 | void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); |
1343 | 1381 | ||
1382 | /* channel switch handling */ | ||
1383 | void ieee80211_csa_finalize_work(struct work_struct *work); | ||
1384 | |||
1344 | /* interface handling */ | 1385 | /* interface handling */ |
1345 | int ieee80211_iface_init(void); | 1386 | int ieee80211_iface_init(void); |
1346 | void ieee80211_iface_exit(void); | 1387 | void ieee80211_iface_exit(void); |
@@ -1362,6 +1403,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local); | |||
1362 | 1403 | ||
1363 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | 1404 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); |
1364 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | 1405 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); |
1406 | int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, | ||
1407 | struct cfg80211_beacon_data *params); | ||
1365 | 1408 | ||
1366 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1409 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) |
1367 | { | 1410 | { |
@@ -1465,7 +1508,8 @@ extern void *mac80211_wiphy_privid; /* for wiphy privid */ | |||
1465 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | 1508 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, |
1466 | enum nl80211_iftype type); | 1509 | enum nl80211_iftype type); |
1467 | int ieee80211_frame_duration(enum ieee80211_band band, size_t len, | 1510 | int ieee80211_frame_duration(enum ieee80211_band band, size_t len, |
1468 | int rate, int erp, int short_preamble); | 1511 | int rate, int erp, int short_preamble, |
1512 | int shift); | ||
1469 | void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, | 1513 | void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, |
1470 | struct ieee80211_hdr *hdr, const u8 *tsc, | 1514 | struct ieee80211_hdr *hdr, const u8 *tsc, |
1471 | gfp_t gfp); | 1515 | gfp_t gfp); |
@@ -1569,7 +1613,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1569 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1613 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1570 | size_t buffer_len, const u8 *ie, size_t ie_len, | 1614 | size_t buffer_len, const u8 *ie, size_t ie_len, |
1571 | enum ieee80211_band band, u32 rate_mask, | 1615 | enum ieee80211_band band, u32 rate_mask, |
1572 | u8 channel); | 1616 | struct cfg80211_chan_def *chandef); |
1573 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1617 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1574 | u8 *dst, u32 ratemask, | 1618 | u8 *dst, u32 ratemask, |
1575 | struct ieee80211_channel *chan, | 1619 | struct ieee80211_channel *chan, |
@@ -1582,10 +1626,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1582 | u32 ratemask, bool directed, u32 tx_flags, | 1626 | u32 ratemask, bool directed, u32 tx_flags, |
1583 | struct ieee80211_channel *channel, bool scan); | 1627 | struct ieee80211_channel *channel, bool scan); |
1584 | 1628 | ||
1585 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 1629 | u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, |
1586 | const size_t supp_rates_len, | ||
1587 | const u8 *supp_rates); | ||
1588 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
1589 | struct ieee802_11_elems *elems, | 1630 | struct ieee802_11_elems *elems, |
1590 | enum ieee80211_band band, u32 *basic_rates); | 1631 | enum ieee80211_band band, u32 *basic_rates); |
1591 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | 1632 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, |
@@ -1602,6 +1643,9 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1602 | u16 prot_mode); | 1643 | u16 prot_mode); |
1603 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | 1644 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, |
1604 | u32 cap); | 1645 | u32 cap); |
1646 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, | ||
1647 | const struct ieee80211_supported_band *sband, | ||
1648 | const u8 *srates, int srates_len, u32 *rates); | ||
1605 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | 1649 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, |
1606 | struct sk_buff *skb, bool need_basic, | 1650 | struct sk_buff *skb, bool need_basic, |
1607 | enum ieee80211_band band); | 1651 | enum ieee80211_band band); |
@@ -1622,6 +1666,11 @@ int __must_check | |||
1622 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | 1666 | ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, |
1623 | const struct cfg80211_chan_def *chandef, | 1667 | const struct cfg80211_chan_def *chandef, |
1624 | u32 *changed); | 1668 | u32 *changed); |
1669 | /* NOTE: only use ieee80211_vif_change_channel() for channel switch */ | ||
1670 | int __must_check | ||
1671 | ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata, | ||
1672 | const struct cfg80211_chan_def *chandef, | ||
1673 | u32 *changed); | ||
1625 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); | 1674 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
1626 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); | 1675 | void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata); |
1627 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, | 1676 | void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index cc117591f678..7ca534bf4cea 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -54,7 +54,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | |||
54 | return false; | 54 | return false; |
55 | } | 55 | } |
56 | 56 | ||
57 | power = chanctx_conf->def.chan->max_power; | 57 | power = ieee80211_chandef_max_power(&chanctx_conf->def); |
58 | rcu_read_unlock(); | 58 | rcu_read_unlock(); |
59 | 59 | ||
60 | if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) | 60 | if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) |
@@ -274,6 +274,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
274 | if (iftype == NL80211_IFTYPE_ADHOC && | 274 | if (iftype == NL80211_IFTYPE_ADHOC && |
275 | nsdata->vif.type == NL80211_IFTYPE_ADHOC) | 275 | nsdata->vif.type == NL80211_IFTYPE_ADHOC) |
276 | return -EBUSY; | 276 | return -EBUSY; |
277 | /* | ||
278 | * will not add another interface while any channel | ||
279 | * switch is active. | ||
280 | */ | ||
281 | if (nsdata->vif.csa_active) | ||
282 | return -EBUSY; | ||
277 | 283 | ||
278 | /* | 284 | /* |
279 | * The remaining checks are only performed for interfaces | 285 | * The remaining checks are only performed for interfaces |
@@ -804,6 +810,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
804 | cancel_work_sync(&local->dynamic_ps_enable_work); | 810 | cancel_work_sync(&local->dynamic_ps_enable_work); |
805 | 811 | ||
806 | cancel_work_sync(&sdata->recalc_smps); | 812 | cancel_work_sync(&sdata->recalc_smps); |
813 | sdata->vif.csa_active = false; | ||
814 | cancel_work_sync(&sdata->csa_finalize_work); | ||
807 | 815 | ||
808 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); | 816 | cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); |
809 | 817 | ||
@@ -1267,6 +1275,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1267 | skb_queue_head_init(&sdata->skb_queue); | 1275 | skb_queue_head_init(&sdata->skb_queue); |
1268 | INIT_WORK(&sdata->work, ieee80211_iface_work); | 1276 | INIT_WORK(&sdata->work, ieee80211_iface_work); |
1269 | INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); | 1277 | INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); |
1278 | INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); | ||
1270 | 1279 | ||
1271 | switch (type) { | 1280 | switch (type) { |
1272 | case NL80211_IFTYPE_P2P_GO: | 1281 | case NL80211_IFTYPE_P2P_GO: |
diff --git a/net/mac80211/led.c b/net/mac80211/led.c index bcffa6903129..e2b836446af3 100644 --- a/net/mac80211/led.c +++ b/net/mac80211/led.c | |||
@@ -12,27 +12,22 @@ | |||
12 | #include <linux/export.h> | 12 | #include <linux/export.h> |
13 | #include "led.h" | 13 | #include "led.h" |
14 | 14 | ||
15 | #define MAC80211_BLINK_DELAY 50 /* ms */ | ||
16 | |||
15 | void ieee80211_led_rx(struct ieee80211_local *local) | 17 | void ieee80211_led_rx(struct ieee80211_local *local) |
16 | { | 18 | { |
19 | unsigned long led_delay = MAC80211_BLINK_DELAY; | ||
17 | if (unlikely(!local->rx_led)) | 20 | if (unlikely(!local->rx_led)) |
18 | return; | 21 | return; |
19 | if (local->rx_led_counter++ % 2 == 0) | 22 | led_trigger_blink_oneshot(local->rx_led, &led_delay, &led_delay, 0); |
20 | led_trigger_event(local->rx_led, LED_OFF); | ||
21 | else | ||
22 | led_trigger_event(local->rx_led, LED_FULL); | ||
23 | } | 23 | } |
24 | 24 | ||
25 | /* q is 1 if a packet was enqueued, 0 if it has been transmitted */ | 25 | void ieee80211_led_tx(struct ieee80211_local *local) |
26 | void ieee80211_led_tx(struct ieee80211_local *local, int q) | ||
27 | { | 26 | { |
27 | unsigned long led_delay = MAC80211_BLINK_DELAY; | ||
28 | if (unlikely(!local->tx_led)) | 28 | if (unlikely(!local->tx_led)) |
29 | return; | 29 | return; |
30 | /* not sure how this is supposed to work ... */ | 30 | led_trigger_blink_oneshot(local->tx_led, &led_delay, &led_delay, 0); |
31 | local->tx_led_counter += 2*q-1; | ||
32 | if (local->tx_led_counter % 2 == 0) | ||
33 | led_trigger_event(local->tx_led, LED_OFF); | ||
34 | else | ||
35 | led_trigger_event(local->tx_led, LED_FULL); | ||
36 | } | 31 | } |
37 | 32 | ||
38 | void ieee80211_led_assoc(struct ieee80211_local *local, bool associated) | 33 | void ieee80211_led_assoc(struct ieee80211_local *local, bool associated) |
diff --git a/net/mac80211/led.h b/net/mac80211/led.h index e0275d9befa8..89f4344f13b9 100644 --- a/net/mac80211/led.h +++ b/net/mac80211/led.h | |||
@@ -13,7 +13,7 @@ | |||
13 | 13 | ||
14 | #ifdef CONFIG_MAC80211_LEDS | 14 | #ifdef CONFIG_MAC80211_LEDS |
15 | void ieee80211_led_rx(struct ieee80211_local *local); | 15 | void ieee80211_led_rx(struct ieee80211_local *local); |
16 | void ieee80211_led_tx(struct ieee80211_local *local, int q); | 16 | void ieee80211_led_tx(struct ieee80211_local *local); |
17 | void ieee80211_led_assoc(struct ieee80211_local *local, | 17 | void ieee80211_led_assoc(struct ieee80211_local *local, |
18 | bool associated); | 18 | bool associated); |
19 | void ieee80211_led_radio(struct ieee80211_local *local, | 19 | void ieee80211_led_radio(struct ieee80211_local *local, |
@@ -27,7 +27,7 @@ void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local, | |||
27 | static inline void ieee80211_led_rx(struct ieee80211_local *local) | 27 | static inline void ieee80211_led_rx(struct ieee80211_local *local) |
28 | { | 28 | { |
29 | } | 29 | } |
30 | static inline void ieee80211_led_tx(struct ieee80211_local *local, int q) | 30 | static inline void ieee80211_led_tx(struct ieee80211_local *local) |
31 | { | 31 | { |
32 | } | 32 | } |
33 | static inline void ieee80211_led_assoc(struct ieee80211_local *local, | 33 | static inline void ieee80211_led_assoc(struct ieee80211_local *local, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 091088ac7890..25eb35b01938 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -102,17 +102,8 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) | |||
102 | 102 | ||
103 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; | 103 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; |
104 | 104 | ||
105 | if (local->scan_channel) { | 105 | if (local->scan_chandef.chan) { |
106 | chandef.chan = local->scan_channel; | 106 | chandef = local->scan_chandef; |
107 | /* If scanning on oper channel, use whatever channel-type | ||
108 | * is currently in use. | ||
109 | */ | ||
110 | if (chandef.chan == local->_oper_chandef.chan) { | ||
111 | chandef = local->_oper_chandef; | ||
112 | } else { | ||
113 | chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | ||
114 | chandef.center_freq1 = chandef.chan->center_freq; | ||
115 | } | ||
116 | } else if (local->tmp_channel) { | 107 | } else if (local->tmp_channel) { |
117 | chandef.chan = local->tmp_channel; | 108 | chandef.chan = local->tmp_channel; |
118 | chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | 109 | chandef.width = NL80211_CHAN_WIDTH_20_NOHT; |
@@ -151,7 +142,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) | |||
151 | changed |= IEEE80211_CONF_CHANGE_SMPS; | 142 | changed |= IEEE80211_CONF_CHANGE_SMPS; |
152 | } | 143 | } |
153 | 144 | ||
154 | power = chandef.chan->max_power; | 145 | power = ieee80211_chandef_max_power(&chandef); |
155 | 146 | ||
156 | rcu_read_lock(); | 147 | rcu_read_lock(); |
157 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 148 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 447f41bbe744..885a5f6e2c21 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -62,7 +62,6 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
62 | struct ieee802_11_elems *ie) | 62 | struct ieee802_11_elems *ie) |
63 | { | 63 | { |
64 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 64 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
65 | struct ieee80211_local *local = sdata->local; | ||
66 | u32 basic_rates = 0; | 65 | u32 basic_rates = 0; |
67 | struct cfg80211_chan_def sta_chan_def; | 66 | struct cfg80211_chan_def sta_chan_def; |
68 | 67 | ||
@@ -85,7 +84,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
85 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) | 84 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) |
86 | return false; | 85 | return false; |
87 | 86 | ||
88 | ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata), | 87 | ieee80211_sta_get_rates(sdata, ie, ieee80211_get_sdata_band(sdata), |
89 | &basic_rates); | 88 | &basic_rates); |
90 | 89 | ||
91 | if (sdata->vif.bss_conf.basic_rates != basic_rates) | 90 | if (sdata->vif.bss_conf.basic_rates != basic_rates) |
@@ -274,7 +273,9 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, | |||
274 | neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS); | 273 | neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS); |
275 | *pos++ = neighbors << 1; | 274 | *pos++ = neighbors << 1; |
276 | /* Mesh capability */ | 275 | /* Mesh capability */ |
277 | *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; | 276 | *pos = 0x00; |
277 | *pos |= ifmsh->mshcfg.dot11MeshForwarding ? | ||
278 | IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00; | ||
278 | *pos |= ifmsh->accepting_plinks ? | 279 | *pos |= ifmsh->accepting_plinks ? |
279 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 280 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
280 | /* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */ | 281 | /* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */ |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 02c05fa15c20..6b65d5055f5b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -379,7 +379,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
379 | u32 rates, basic_rates = 0, changed = 0; | 379 | u32 rates, basic_rates = 0, changed = 0; |
380 | 380 | ||
381 | sband = local->hw.wiphy->bands[band]; | 381 | sband = local->hw.wiphy->bands[band]; |
382 | rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates); | 382 | rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates); |
383 | 383 | ||
384 | spin_lock_bh(&sta->lock); | 384 | spin_lock_bh(&sta->lock); |
385 | sta->last_rx = jiffies; | 385 | sta->last_rx = jiffies; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ae31968d42d3..21bccd849b3f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -31,10 +31,12 @@ | |||
31 | #include "led.h" | 31 | #include "led.h" |
32 | 32 | ||
33 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | 33 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) |
34 | #define IEEE80211_AUTH_TIMEOUT_LONG (HZ / 2) | ||
34 | #define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10) | 35 | #define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10) |
35 | #define IEEE80211_AUTH_MAX_TRIES 3 | 36 | #define IEEE80211_AUTH_MAX_TRIES 3 |
36 | #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) | 37 | #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) |
37 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 38 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
39 | #define IEEE80211_ASSOC_TIMEOUT_LONG (HZ / 2) | ||
38 | #define IEEE80211_ASSOC_TIMEOUT_SHORT (HZ / 10) | 40 | #define IEEE80211_ASSOC_TIMEOUT_SHORT (HZ / 10) |
39 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 41 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
40 | 42 | ||
@@ -209,8 +211,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
209 | struct ieee80211_channel *channel, | 211 | struct ieee80211_channel *channel, |
210 | const struct ieee80211_ht_operation *ht_oper, | 212 | const struct ieee80211_ht_operation *ht_oper, |
211 | const struct ieee80211_vht_operation *vht_oper, | 213 | const struct ieee80211_vht_operation *vht_oper, |
212 | struct cfg80211_chan_def *chandef, bool verbose) | 214 | struct cfg80211_chan_def *chandef, bool tracking) |
213 | { | 215 | { |
216 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
214 | struct cfg80211_chan_def vht_chandef; | 217 | struct cfg80211_chan_def vht_chandef; |
215 | u32 ht_cfreq, ret; | 218 | u32 ht_cfreq, ret; |
216 | 219 | ||
@@ -229,7 +232,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
229 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | 232 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, |
230 | channel->band); | 233 | channel->band); |
231 | /* check that channel matches the right operating channel */ | 234 | /* check that channel matches the right operating channel */ |
232 | if (channel->center_freq != ht_cfreq) { | 235 | if (!tracking && channel->center_freq != ht_cfreq) { |
233 | /* | 236 | /* |
234 | * It's possible that some APs are confused here; | 237 | * It's possible that some APs are confused here; |
235 | * Netgear WNDR3700 sometimes reports 4 higher than | 238 | * Netgear WNDR3700 sometimes reports 4 higher than |
@@ -237,11 +240,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
237 | * since we look at probe response/beacon data here | 240 | * since we look at probe response/beacon data here |
238 | * it should be OK. | 241 | * it should be OK. |
239 | */ | 242 | */ |
240 | if (verbose) | 243 | sdata_info(sdata, |
241 | sdata_info(sdata, | 244 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", |
242 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | 245 | channel->center_freq, ht_cfreq, |
243 | channel->center_freq, ht_cfreq, | 246 | ht_oper->primary_chan, channel->band); |
244 | ht_oper->primary_chan, channel->band); | ||
245 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | 247 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; |
246 | goto out; | 248 | goto out; |
247 | } | 249 | } |
@@ -295,7 +297,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
295 | channel->band); | 297 | channel->band); |
296 | break; | 298 | break; |
297 | default: | 299 | default: |
298 | if (verbose) | 300 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
299 | sdata_info(sdata, | 301 | sdata_info(sdata, |
300 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", | 302 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", |
301 | vht_oper->chan_width); | 303 | vht_oper->chan_width); |
@@ -304,7 +306,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
304 | } | 306 | } |
305 | 307 | ||
306 | if (!cfg80211_chandef_valid(&vht_chandef)) { | 308 | if (!cfg80211_chandef_valid(&vht_chandef)) { |
307 | if (verbose) | 309 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
308 | sdata_info(sdata, | 310 | sdata_info(sdata, |
309 | "AP VHT information is invalid, disable VHT\n"); | 311 | "AP VHT information is invalid, disable VHT\n"); |
310 | ret = IEEE80211_STA_DISABLE_VHT; | 312 | ret = IEEE80211_STA_DISABLE_VHT; |
@@ -317,7 +319,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
317 | } | 319 | } |
318 | 320 | ||
319 | if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { | 321 | if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { |
320 | if (verbose) | 322 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
321 | sdata_info(sdata, | 323 | sdata_info(sdata, |
322 | "AP VHT information doesn't match HT, disable VHT\n"); | 324 | "AP VHT information doesn't match HT, disable VHT\n"); |
323 | ret = IEEE80211_STA_DISABLE_VHT; | 325 | ret = IEEE80211_STA_DISABLE_VHT; |
@@ -333,18 +335,27 @@ out: | |||
333 | if (ret & IEEE80211_STA_DISABLE_VHT) | 335 | if (ret & IEEE80211_STA_DISABLE_VHT) |
334 | vht_chandef = *chandef; | 336 | vht_chandef = *chandef; |
335 | 337 | ||
338 | /* | ||
339 | * Ignore the DISABLED flag when we're already connected and only | ||
340 | * tracking the APs beacon for bandwidth changes - otherwise we | ||
341 | * might get disconnected here if we connect to an AP, update our | ||
342 | * regulatory information based on the AP's country IE and the | ||
343 | * information we have is wrong/outdated and disables the channel | ||
344 | * that we're actually using for the connection to the AP. | ||
345 | */ | ||
336 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | 346 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, |
337 | IEEE80211_CHAN_DISABLED)) { | 347 | tracking ? 0 : |
348 | IEEE80211_CHAN_DISABLED)) { | ||
338 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { | 349 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { |
339 | ret = IEEE80211_STA_DISABLE_HT | | 350 | ret = IEEE80211_STA_DISABLE_HT | |
340 | IEEE80211_STA_DISABLE_VHT; | 351 | IEEE80211_STA_DISABLE_VHT; |
341 | goto out; | 352 | break; |
342 | } | 353 | } |
343 | 354 | ||
344 | ret |= chandef_downgrade(chandef); | 355 | ret |= chandef_downgrade(chandef); |
345 | } | 356 | } |
346 | 357 | ||
347 | if (chandef->width != vht_chandef.width && verbose) | 358 | if (chandef->width != vht_chandef.width && !tracking) |
348 | sdata_info(sdata, | 359 | sdata_info(sdata, |
349 | "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); | 360 | "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n"); |
350 | 361 | ||
@@ -384,7 +395,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
384 | 395 | ||
385 | /* calculate new channel (type) based on HT/VHT operation IEs */ | 396 | /* calculate new channel (type) based on HT/VHT operation IEs */ |
386 | flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper, | 397 | flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper, |
387 | vht_oper, &chandef, false); | 398 | vht_oper, &chandef, true); |
388 | 399 | ||
389 | /* | 400 | /* |
390 | * Downgrade the new channel if we associated with restricted | 401 | * Downgrade the new channel if we associated with restricted |
@@ -478,27 +489,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, | |||
478 | 489 | ||
479 | /* frame sending functions */ | 490 | /* frame sending functions */ |
480 | 491 | ||
481 | static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | ||
482 | struct ieee80211_supported_band *sband, | ||
483 | u32 *rates) | ||
484 | { | ||
485 | int i, j, count; | ||
486 | *rates = 0; | ||
487 | count = 0; | ||
488 | for (i = 0; i < supp_rates_len; i++) { | ||
489 | int rate = (supp_rates[i] & 0x7F) * 5; | ||
490 | |||
491 | for (j = 0; j < sband->n_bitrates; j++) | ||
492 | if (sband->bitrates[j].bitrate == rate) { | ||
493 | *rates |= BIT(j); | ||
494 | count++; | ||
495 | break; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | return count; | ||
500 | } | ||
501 | |||
502 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | 492 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, |
503 | struct sk_buff *skb, u8 ap_ht_param, | 493 | struct sk_buff *skb, u8 ap_ht_param, |
504 | struct ieee80211_supported_band *sband, | 494 | struct ieee80211_supported_band *sband, |
@@ -617,12 +607,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
617 | struct ieee80211_mgmt *mgmt; | 607 | struct ieee80211_mgmt *mgmt; |
618 | u8 *pos, qos_info; | 608 | u8 *pos, qos_info; |
619 | size_t offset = 0, noffset; | 609 | size_t offset = 0, noffset; |
620 | int i, count, rates_len, supp_rates_len; | 610 | int i, count, rates_len, supp_rates_len, shift; |
621 | u16 capab; | 611 | u16 capab; |
622 | struct ieee80211_supported_band *sband; | 612 | struct ieee80211_supported_band *sband; |
623 | struct ieee80211_chanctx_conf *chanctx_conf; | 613 | struct ieee80211_chanctx_conf *chanctx_conf; |
624 | struct ieee80211_channel *chan; | 614 | struct ieee80211_channel *chan; |
625 | u32 rates = 0; | 615 | u32 rate_flags, rates = 0; |
626 | 616 | ||
627 | sdata_assert_lock(sdata); | 617 | sdata_assert_lock(sdata); |
628 | 618 | ||
@@ -633,8 +623,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
633 | return; | 623 | return; |
634 | } | 624 | } |
635 | chan = chanctx_conf->def.chan; | 625 | chan = chanctx_conf->def.chan; |
626 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); | ||
636 | rcu_read_unlock(); | 627 | rcu_read_unlock(); |
637 | sband = local->hw.wiphy->bands[chan->band]; | 628 | sband = local->hw.wiphy->bands[chan->band]; |
629 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
638 | 630 | ||
639 | if (assoc_data->supp_rates_len) { | 631 | if (assoc_data->supp_rates_len) { |
640 | /* | 632 | /* |
@@ -643,17 +635,24 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
643 | * in the association request (e.g. D-Link DAP 1353 in | 635 | * in the association request (e.g. D-Link DAP 1353 in |
644 | * b-only mode)... | 636 | * b-only mode)... |
645 | */ | 637 | */ |
646 | rates_len = ieee80211_compatible_rates(assoc_data->supp_rates, | 638 | rates_len = ieee80211_parse_bitrates(&chanctx_conf->def, sband, |
647 | assoc_data->supp_rates_len, | 639 | assoc_data->supp_rates, |
648 | sband, &rates); | 640 | assoc_data->supp_rates_len, |
641 | &rates); | ||
649 | } else { | 642 | } else { |
650 | /* | 643 | /* |
651 | * In case AP not provide any supported rates information | 644 | * In case AP not provide any supported rates information |
652 | * before association, we send information element(s) with | 645 | * before association, we send information element(s) with |
653 | * all rates that we support. | 646 | * all rates that we support. |
654 | */ | 647 | */ |
655 | rates = ~0; | 648 | rates_len = 0; |
656 | rates_len = sband->n_bitrates; | 649 | for (i = 0; i < sband->n_bitrates; i++) { |
650 | if ((rate_flags & sband->bitrates[i].flags) | ||
651 | != rate_flags) | ||
652 | continue; | ||
653 | rates |= BIT(i); | ||
654 | rates_len++; | ||
655 | } | ||
657 | } | 656 | } |
658 | 657 | ||
659 | skb = alloc_skb(local->hw.extra_tx_headroom + | 658 | skb = alloc_skb(local->hw.extra_tx_headroom + |
@@ -730,8 +729,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
730 | count = 0; | 729 | count = 0; |
731 | for (i = 0; i < sband->n_bitrates; i++) { | 730 | for (i = 0; i < sband->n_bitrates; i++) { |
732 | if (BIT(i) & rates) { | 731 | if (BIT(i) & rates) { |
733 | int rate = sband->bitrates[i].bitrate; | 732 | int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, |
734 | *pos++ = (u8) (rate / 5); | 733 | 5 * (1 << shift)); |
734 | *pos++ = (u8) rate; | ||
735 | if (++count == 8) | 735 | if (++count == 8) |
736 | break; | 736 | break; |
737 | } | 737 | } |
@@ -744,8 +744,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
744 | 744 | ||
745 | for (i++; i < sband->n_bitrates; i++) { | 745 | for (i++; i < sband->n_bitrates; i++) { |
746 | if (BIT(i) & rates) { | 746 | if (BIT(i) & rates) { |
747 | int rate = sband->bitrates[i].bitrate; | 747 | int rate; |
748 | *pos++ = (u8) (rate / 5); | 748 | rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, |
749 | 5 * (1 << shift)); | ||
750 | *pos++ = (u8) rate; | ||
749 | } | 751 | } |
750 | } | 752 | } |
751 | } | 753 | } |
@@ -756,7 +758,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
756 | *pos++ = WLAN_EID_PWR_CAPABILITY; | 758 | *pos++ = WLAN_EID_PWR_CAPABILITY; |
757 | *pos++ = 2; | 759 | *pos++ = 2; |
758 | *pos++ = 0; /* min tx power */ | 760 | *pos++ = 0; /* min tx power */ |
759 | *pos++ = chan->max_power; /* max tx power */ | 761 | /* max tx power */ |
762 | *pos++ = ieee80211_chandef_max_power(&chanctx_conf->def); | ||
760 | 763 | ||
761 | /* 2. supported channels */ | 764 | /* 2. supported channels */ |
762 | /* TODO: get this in reg domain format */ | 765 | /* TODO: get this in reg domain format */ |
@@ -2432,15 +2435,16 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | |||
2432 | u8 *supp_rates, unsigned int supp_rates_len, | 2435 | u8 *supp_rates, unsigned int supp_rates_len, |
2433 | u32 *rates, u32 *basic_rates, | 2436 | u32 *rates, u32 *basic_rates, |
2434 | bool *have_higher_than_11mbit, | 2437 | bool *have_higher_than_11mbit, |
2435 | int *min_rate, int *min_rate_index) | 2438 | int *min_rate, int *min_rate_index, |
2439 | int shift, u32 rate_flags) | ||
2436 | { | 2440 | { |
2437 | int i, j; | 2441 | int i, j; |
2438 | 2442 | ||
2439 | for (i = 0; i < supp_rates_len; i++) { | 2443 | for (i = 0; i < supp_rates_len; i++) { |
2440 | int rate = (supp_rates[i] & 0x7f) * 5; | 2444 | int rate = supp_rates[i] & 0x7f; |
2441 | bool is_basic = !!(supp_rates[i] & 0x80); | 2445 | bool is_basic = !!(supp_rates[i] & 0x80); |
2442 | 2446 | ||
2443 | if (rate > 110) | 2447 | if ((rate * 5 * (1 << shift)) > 110) |
2444 | *have_higher_than_11mbit = true; | 2448 | *have_higher_than_11mbit = true; |
2445 | 2449 | ||
2446 | /* | 2450 | /* |
@@ -2456,12 +2460,20 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | |||
2456 | continue; | 2460 | continue; |
2457 | 2461 | ||
2458 | for (j = 0; j < sband->n_bitrates; j++) { | 2462 | for (j = 0; j < sband->n_bitrates; j++) { |
2459 | if (sband->bitrates[j].bitrate == rate) { | 2463 | struct ieee80211_rate *br; |
2464 | int brate; | ||
2465 | |||
2466 | br = &sband->bitrates[j]; | ||
2467 | if ((rate_flags & br->flags) != rate_flags) | ||
2468 | continue; | ||
2469 | |||
2470 | brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5); | ||
2471 | if (brate == rate) { | ||
2460 | *rates |= BIT(j); | 2472 | *rates |= BIT(j); |
2461 | if (is_basic) | 2473 | if (is_basic) |
2462 | *basic_rates |= BIT(j); | 2474 | *basic_rates |= BIT(j); |
2463 | if (rate < *min_rate) { | 2475 | if ((rate * 5) < *min_rate) { |
2464 | *min_rate = rate; | 2476 | *min_rate = rate * 5; |
2465 | *min_rate_index = j; | 2477 | *min_rate_index = j; |
2466 | } | 2478 | } |
2467 | break; | 2479 | break; |
@@ -3394,10 +3406,13 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3394 | 3406 | ||
3395 | if (tx_flags == 0) { | 3407 | if (tx_flags == 0) { |
3396 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 3408 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
3397 | ifmgd->auth_data->timeout_started = true; | 3409 | auth_data->timeout_started = true; |
3398 | run_again(sdata, auth_data->timeout); | 3410 | run_again(sdata, auth_data->timeout); |
3399 | } else { | 3411 | } else { |
3400 | auth_data->timeout_started = false; | 3412 | auth_data->timeout = |
3413 | round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG); | ||
3414 | auth_data->timeout_started = true; | ||
3415 | run_again(sdata, auth_data->timeout); | ||
3401 | } | 3416 | } |
3402 | 3417 | ||
3403 | return 0; | 3418 | return 0; |
@@ -3434,7 +3449,11 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) | |||
3434 | assoc_data->timeout_started = true; | 3449 | assoc_data->timeout_started = true; |
3435 | run_again(sdata, assoc_data->timeout); | 3450 | run_again(sdata, assoc_data->timeout); |
3436 | } else { | 3451 | } else { |
3437 | assoc_data->timeout_started = false; | 3452 | assoc_data->timeout = |
3453 | round_jiffies_up(jiffies + | ||
3454 | IEEE80211_ASSOC_TIMEOUT_LONG); | ||
3455 | assoc_data->timeout_started = true; | ||
3456 | run_again(sdata, assoc_data->timeout); | ||
3438 | } | 3457 | } |
3439 | 3458 | ||
3440 | return 0; | 3459 | return 0; |
@@ -3829,7 +3848,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | |||
3829 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, | 3848 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, |
3830 | cbss->channel, | 3849 | cbss->channel, |
3831 | ht_oper, vht_oper, | 3850 | ht_oper, vht_oper, |
3832 | &chandef, true); | 3851 | &chandef, false); |
3833 | 3852 | ||
3834 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), | 3853 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), |
3835 | local->rx_chains); | 3854 | local->rx_chains); |
@@ -3884,27 +3903,40 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3884 | if (!new_sta) | 3903 | if (!new_sta) |
3885 | return -ENOMEM; | 3904 | return -ENOMEM; |
3886 | } | 3905 | } |
3887 | |||
3888 | if (new_sta) { | 3906 | if (new_sta) { |
3889 | u32 rates = 0, basic_rates = 0; | 3907 | u32 rates = 0, basic_rates = 0; |
3890 | bool have_higher_than_11mbit; | 3908 | bool have_higher_than_11mbit; |
3891 | int min_rate = INT_MAX, min_rate_index = -1; | 3909 | int min_rate = INT_MAX, min_rate_index = -1; |
3910 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
3892 | struct ieee80211_supported_band *sband; | 3911 | struct ieee80211_supported_band *sband; |
3893 | const struct cfg80211_bss_ies *ies; | 3912 | const struct cfg80211_bss_ies *ies; |
3913 | int shift; | ||
3914 | u32 rate_flags; | ||
3894 | 3915 | ||
3895 | sband = local->hw.wiphy->bands[cbss->channel->band]; | 3916 | sband = local->hw.wiphy->bands[cbss->channel->band]; |
3896 | 3917 | ||
3897 | err = ieee80211_prep_channel(sdata, cbss); | 3918 | err = ieee80211_prep_channel(sdata, cbss); |
3898 | if (err) { | 3919 | if (err) { |
3899 | sta_info_free(local, new_sta); | 3920 | sta_info_free(local, new_sta); |
3900 | return err; | 3921 | return -EINVAL; |
3922 | } | ||
3923 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
3924 | |||
3925 | rcu_read_lock(); | ||
3926 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
3927 | if (WARN_ON(!chanctx_conf)) { | ||
3928 | rcu_read_unlock(); | ||
3929 | return -EINVAL; | ||
3901 | } | 3930 | } |
3931 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); | ||
3932 | rcu_read_unlock(); | ||
3902 | 3933 | ||
3903 | ieee80211_get_rates(sband, bss->supp_rates, | 3934 | ieee80211_get_rates(sband, bss->supp_rates, |
3904 | bss->supp_rates_len, | 3935 | bss->supp_rates_len, |
3905 | &rates, &basic_rates, | 3936 | &rates, &basic_rates, |
3906 | &have_higher_than_11mbit, | 3937 | &have_higher_than_11mbit, |
3907 | &min_rate, &min_rate_index); | 3938 | &min_rate, &min_rate_index, |
3939 | shift, rate_flags); | ||
3908 | 3940 | ||
3909 | /* | 3941 | /* |
3910 | * This used to be a workaround for basic rates missing | 3942 | * This used to be a workaround for basic rates missing |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 30d58d2d13e2..ba63ac851c2b 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -232,37 +232,28 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, | |||
232 | /* could not find a basic rate; use original selection */ | 232 | /* could not find a basic rate; use original selection */ |
233 | } | 233 | } |
234 | 234 | ||
235 | static inline s8 | 235 | static void __rate_control_send_low(struct ieee80211_hw *hw, |
236 | rate_lowest_non_cck_index(struct ieee80211_supported_band *sband, | 236 | struct ieee80211_supported_band *sband, |
237 | struct ieee80211_sta *sta) | 237 | struct ieee80211_sta *sta, |
238 | struct ieee80211_tx_info *info) | ||
238 | { | 239 | { |
239 | int i; | 240 | int i; |
241 | u32 rate_flags = | ||
242 | ieee80211_chandef_rate_flags(&hw->conf.chandef); | ||
240 | 243 | ||
244 | if ((sband->band == IEEE80211_BAND_2GHZ) && | ||
245 | (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)) | ||
246 | rate_flags |= IEEE80211_RATE_ERP_G; | ||
247 | |||
248 | info->control.rates[0].idx = 0; | ||
241 | for (i = 0; i < sband->n_bitrates; i++) { | 249 | for (i = 0; i < sband->n_bitrates; i++) { |
242 | struct ieee80211_rate *srate = &sband->bitrates[i]; | 250 | if (!rate_supported(sta, sband->band, i)) |
243 | if ((srate->bitrate == 10) || (srate->bitrate == 20) || | ||
244 | (srate->bitrate == 55) || (srate->bitrate == 110)) | ||
245 | continue; | 251 | continue; |
246 | 252 | ||
247 | if (rate_supported(sta, sband->band, i)) | 253 | info->control.rates[0].idx = i; |
248 | return i; | 254 | break; |
249 | } | 255 | } |
250 | 256 | WARN_ON_ONCE(i == sband->n_bitrates); | |
251 | /* No matching rate found */ | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static void __rate_control_send_low(struct ieee80211_hw *hw, | ||
256 | struct ieee80211_supported_band *sband, | ||
257 | struct ieee80211_sta *sta, | ||
258 | struct ieee80211_tx_info *info) | ||
259 | { | ||
260 | if ((sband->band != IEEE80211_BAND_2GHZ) || | ||
261 | !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)) | ||
262 | info->control.rates[0].idx = rate_lowest_index(sband, sta); | ||
263 | else | ||
264 | info->control.rates[0].idx = | ||
265 | rate_lowest_non_cck_index(sband, sta); | ||
266 | 257 | ||
267 | info->control.rates[0].count = | 258 | info->control.rates[0].count = |
268 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? | 259 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? |
@@ -585,6 +576,7 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, | |||
585 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; | 576 | u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN]; |
586 | bool has_mcs_mask; | 577 | bool has_mcs_mask; |
587 | u32 mask; | 578 | u32 mask; |
579 | u32 rate_flags; | ||
588 | int i; | 580 | int i; |
589 | 581 | ||
590 | /* | 582 | /* |
@@ -594,6 +586,12 @@ static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata, | |||
594 | */ | 586 | */ |
595 | mask = sdata->rc_rateidx_mask[info->band]; | 587 | mask = sdata->rc_rateidx_mask[info->band]; |
596 | has_mcs_mask = sdata->rc_has_mcs_mask[info->band]; | 588 | has_mcs_mask = sdata->rc_has_mcs_mask[info->band]; |
589 | rate_flags = | ||
590 | ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); | ||
591 | for (i = 0; i < sband->n_bitrates; i++) | ||
592 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
593 | mask &= ~BIT(i); | ||
594 | |||
597 | if (mask == (1 << sband->n_bitrates) - 1 && !has_mcs_mask) | 595 | if (mask == (1 << sband->n_bitrates) - 1 && !has_mcs_mask) |
598 | return; | 596 | return; |
599 | 597 | ||
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index d35a5dd3fb13..5dedc56c94db 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -66,11 +66,12 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
66 | } | 66 | } |
67 | 67 | ||
68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; | 68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; |
69 | rcu_read_unlock(); | ||
70 | 69 | ||
71 | ieee80211_sta_set_rx_nss(sta); | 70 | ieee80211_sta_set_rx_nss(sta); |
72 | 71 | ||
73 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 72 | ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, |
73 | priv_sta); | ||
74 | rcu_read_unlock(); | ||
74 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); | 75 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); |
75 | } | 76 | } |
76 | 77 | ||
@@ -81,10 +82,21 @@ static inline void rate_control_rate_update(struct ieee80211_local *local, | |||
81 | struct rate_control_ref *ref = local->rate_ctrl; | 82 | struct rate_control_ref *ref = local->rate_ctrl; |
82 | struct ieee80211_sta *ista = &sta->sta; | 83 | struct ieee80211_sta *ista = &sta->sta; |
83 | void *priv_sta = sta->rate_ctrl_priv; | 84 | void *priv_sta = sta->rate_ctrl_priv; |
85 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
86 | |||
87 | if (ref && ref->ops->rate_update) { | ||
88 | rcu_read_lock(); | ||
84 | 89 | ||
85 | if (ref && ref->ops->rate_update) | 90 | chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); |
86 | ref->ops->rate_update(ref->priv, sband, ista, | 91 | if (WARN_ON(!chanctx_conf)) { |
87 | priv_sta, changed); | 92 | rcu_read_unlock(); |
93 | return; | ||
94 | } | ||
95 | |||
96 | ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def, | ||
97 | ista, priv_sta, changed); | ||
98 | rcu_read_unlock(); | ||
99 | } | ||
88 | drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); | 100 | drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); |
89 | } | 101 | } |
90 | 102 | ||
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index e6512e2ffd20..8b5f7ef7c0c9 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -383,14 +383,18 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
383 | static void | 383 | static void |
384 | calc_rate_durations(enum ieee80211_band band, | 384 | calc_rate_durations(enum ieee80211_band band, |
385 | struct minstrel_rate *d, | 385 | struct minstrel_rate *d, |
386 | struct ieee80211_rate *rate) | 386 | struct ieee80211_rate *rate, |
387 | struct cfg80211_chan_def *chandef) | ||
387 | { | 388 | { |
388 | int erp = !!(rate->flags & IEEE80211_RATE_ERP_G); | 389 | int erp = !!(rate->flags & IEEE80211_RATE_ERP_G); |
390 | int shift = ieee80211_chandef_get_shift(chandef); | ||
389 | 391 | ||
390 | d->perfect_tx_time = ieee80211_frame_duration(band, 1200, | 392 | d->perfect_tx_time = ieee80211_frame_duration(band, 1200, |
391 | rate->bitrate, erp, 1); | 393 | DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1, |
394 | shift); | ||
392 | d->ack_time = ieee80211_frame_duration(band, 10, | 395 | d->ack_time = ieee80211_frame_duration(band, 10, |
393 | rate->bitrate, erp, 1); | 396 | DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1, |
397 | shift); | ||
394 | } | 398 | } |
395 | 399 | ||
396 | static void | 400 | static void |
@@ -418,21 +422,25 @@ init_sample_table(struct minstrel_sta_info *mi) | |||
418 | 422 | ||
419 | static void | 423 | static void |
420 | minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, | 424 | minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, |
421 | struct ieee80211_sta *sta, void *priv_sta) | 425 | struct cfg80211_chan_def *chandef, |
426 | struct ieee80211_sta *sta, void *priv_sta) | ||
422 | { | 427 | { |
423 | struct minstrel_sta_info *mi = priv_sta; | 428 | struct minstrel_sta_info *mi = priv_sta; |
424 | struct minstrel_priv *mp = priv; | 429 | struct minstrel_priv *mp = priv; |
425 | struct ieee80211_rate *ctl_rate; | 430 | struct ieee80211_rate *ctl_rate; |
426 | unsigned int i, n = 0; | 431 | unsigned int i, n = 0; |
427 | unsigned int t_slot = 9; /* FIXME: get real slot time */ | 432 | unsigned int t_slot = 9; /* FIXME: get real slot time */ |
433 | u32 rate_flags; | ||
428 | 434 | ||
429 | mi->sta = sta; | 435 | mi->sta = sta; |
430 | mi->lowest_rix = rate_lowest_index(sband, sta); | 436 | mi->lowest_rix = rate_lowest_index(sband, sta); |
431 | ctl_rate = &sband->bitrates[mi->lowest_rix]; | 437 | ctl_rate = &sband->bitrates[mi->lowest_rix]; |
432 | mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10, | 438 | mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10, |
433 | ctl_rate->bitrate, | 439 | ctl_rate->bitrate, |
434 | !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1); | 440 | !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1, |
441 | ieee80211_chandef_get_shift(chandef)); | ||
435 | 442 | ||
443 | rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); | ||
436 | memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate)); | 444 | memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate)); |
437 | mi->max_prob_rate = 0; | 445 | mi->max_prob_rate = 0; |
438 | 446 | ||
@@ -441,15 +449,22 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
441 | unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; | 449 | unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; |
442 | unsigned int tx_time_single; | 450 | unsigned int tx_time_single; |
443 | unsigned int cw = mp->cw_min; | 451 | unsigned int cw = mp->cw_min; |
452 | int shift; | ||
444 | 453 | ||
445 | if (!rate_supported(sta, sband->band, i)) | 454 | if (!rate_supported(sta, sband->band, i)) |
446 | continue; | 455 | continue; |
456 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
457 | continue; | ||
458 | |||
447 | n++; | 459 | n++; |
448 | memset(mr, 0, sizeof(*mr)); | 460 | memset(mr, 0, sizeof(*mr)); |
449 | 461 | ||
450 | mr->rix = i; | 462 | mr->rix = i; |
451 | mr->bitrate = sband->bitrates[i].bitrate / 5; | 463 | shift = ieee80211_chandef_get_shift(chandef); |
452 | calc_rate_durations(sband->band, mr, &sband->bitrates[i]); | 464 | mr->bitrate = DIV_ROUND_UP(sband->bitrates[i].bitrate, |
465 | (1 << shift) * 5); | ||
466 | calc_rate_durations(sband->band, mr, &sband->bitrates[i], | ||
467 | chandef); | ||
453 | 468 | ||
454 | /* calculate maximum number of retransmissions before | 469 | /* calculate maximum number of retransmissions before |
455 | * fallback (based on maximum segment size) */ | 470 | * fallback (based on maximum segment size) */ |
@@ -547,6 +562,7 @@ minstrel_init_cck_rates(struct minstrel_priv *mp) | |||
547 | { | 562 | { |
548 | static const int bitrates[4] = { 10, 20, 55, 110 }; | 563 | static const int bitrates[4] = { 10, 20, 55, 110 }; |
549 | struct ieee80211_supported_band *sband; | 564 | struct ieee80211_supported_band *sband; |
565 | u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); | ||
550 | int i, j; | 566 | int i, j; |
551 | 567 | ||
552 | sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; | 568 | sband = mp->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; |
@@ -559,6 +575,9 @@ minstrel_init_cck_rates(struct minstrel_priv *mp) | |||
559 | if (rate->flags & IEEE80211_RATE_ERP_G) | 575 | if (rate->flags & IEEE80211_RATE_ERP_G) |
560 | continue; | 576 | continue; |
561 | 577 | ||
578 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
579 | continue; | ||
580 | |||
562 | for (j = 0; j < ARRAY_SIZE(bitrates); j++) { | 581 | for (j = 0; j < ARRAY_SIZE(bitrates); j++) { |
563 | if (rate->bitrate != bitrates[j]) | 582 | if (rate->bitrate != bitrates[j]) |
564 | continue; | 583 | continue; |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index f5aed963b22e..61569425b723 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -844,6 +844,7 @@ minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
844 | 844 | ||
845 | static void | 845 | static void |
846 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | 846 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, |
847 | struct cfg80211_chan_def *chandef, | ||
847 | struct ieee80211_sta *sta, void *priv_sta) | 848 | struct ieee80211_sta *sta, void *priv_sta) |
848 | { | 849 | { |
849 | struct minstrel_priv *mp = priv; | 850 | struct minstrel_priv *mp = priv; |
@@ -869,8 +870,9 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
869 | mi->sta = sta; | 870 | mi->sta = sta; |
870 | mi->stats_update = jiffies; | 871 | mi->stats_update = jiffies; |
871 | 872 | ||
872 | ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1); | 873 | ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1, 0); |
873 | mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1) + ack_dur; | 874 | mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1, 0); |
875 | mi->overhead += ack_dur; | ||
874 | mi->overhead_rtscts = mi->overhead + 2 * ack_dur; | 876 | mi->overhead_rtscts = mi->overhead + 2 * ack_dur; |
875 | 877 | ||
876 | mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); | 878 | mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); |
@@ -939,22 +941,25 @@ use_legacy: | |||
939 | memset(&msp->legacy, 0, sizeof(msp->legacy)); | 941 | memset(&msp->legacy, 0, sizeof(msp->legacy)); |
940 | msp->legacy.r = msp->ratelist; | 942 | msp->legacy.r = msp->ratelist; |
941 | msp->legacy.sample_table = msp->sample_table; | 943 | msp->legacy.sample_table = msp->sample_table; |
942 | return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy); | 944 | return mac80211_minstrel.rate_init(priv, sband, chandef, sta, |
945 | &msp->legacy); | ||
943 | } | 946 | } |
944 | 947 | ||
945 | static void | 948 | static void |
946 | minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband, | 949 | minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband, |
950 | struct cfg80211_chan_def *chandef, | ||
947 | struct ieee80211_sta *sta, void *priv_sta) | 951 | struct ieee80211_sta *sta, void *priv_sta) |
948 | { | 952 | { |
949 | minstrel_ht_update_caps(priv, sband, sta, priv_sta); | 953 | minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta); |
950 | } | 954 | } |
951 | 955 | ||
952 | static void | 956 | static void |
953 | minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband, | 957 | minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband, |
958 | struct cfg80211_chan_def *chandef, | ||
954 | struct ieee80211_sta *sta, void *priv_sta, | 959 | struct ieee80211_sta *sta, void *priv_sta, |
955 | u32 changed) | 960 | u32 changed) |
956 | { | 961 | { |
957 | minstrel_ht_update_caps(priv, sband, sta, priv_sta); | 962 | minstrel_ht_update_caps(priv, sband, chandef, sta, priv_sta); |
958 | } | 963 | } |
959 | 964 | ||
960 | static void * | 965 | static void * |
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 502d3ecc4a79..958fad07b54c 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c | |||
@@ -293,6 +293,7 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, | |||
293 | 293 | ||
294 | static void | 294 | static void |
295 | rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, | 295 | rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, |
296 | struct cfg80211_chan_def *chandef, | ||
296 | struct ieee80211_sta *sta, void *priv_sta) | 297 | struct ieee80211_sta *sta, void *priv_sta) |
297 | { | 298 | { |
298 | struct rc_pid_sta_info *spinfo = priv_sta; | 299 | struct rc_pid_sta_info *spinfo = priv_sta; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2c5a79bd3777..6b85f95b9ba1 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -87,11 +87,13 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, | |||
87 | int len; | 87 | int len; |
88 | 88 | ||
89 | /* always present fields */ | 89 | /* always present fields */ |
90 | len = sizeof(struct ieee80211_radiotap_header) + 9; | 90 | len = sizeof(struct ieee80211_radiotap_header) + 8; |
91 | 91 | ||
92 | /* allocate extra bitmap */ | 92 | /* allocate extra bitmaps */ |
93 | if (status->vendor_radiotap_len) | 93 | if (status->vendor_radiotap_len) |
94 | len += 4; | 94 | len += 4; |
95 | if (status->chains) | ||
96 | len += 4 * hweight8(status->chains); | ||
95 | 97 | ||
96 | if (ieee80211_have_rx_timestamp(status)) { | 98 | if (ieee80211_have_rx_timestamp(status)) { |
97 | len = ALIGN(len, 8); | 99 | len = ALIGN(len, 8); |
@@ -100,6 +102,10 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, | |||
100 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 102 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
101 | len += 1; | 103 | len += 1; |
102 | 104 | ||
105 | /* antenna field, if we don't have per-chain info */ | ||
106 | if (!status->chains) | ||
107 | len += 1; | ||
108 | |||
103 | /* padding for RX_FLAGS if necessary */ | 109 | /* padding for RX_FLAGS if necessary */ |
104 | len = ALIGN(len, 2); | 110 | len = ALIGN(len, 2); |
105 | 111 | ||
@@ -116,6 +122,11 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, | |||
116 | len += 12; | 122 | len += 12; |
117 | } | 123 | } |
118 | 124 | ||
125 | if (status->chains) { | ||
126 | /* antenna and antenna signal fields */ | ||
127 | len += 2 * hweight8(status->chains); | ||
128 | } | ||
129 | |||
119 | if (status->vendor_radiotap_len) { | 130 | if (status->vendor_radiotap_len) { |
120 | if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) | 131 | if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) |
121 | status->vendor_radiotap_align = 1; | 132 | status->vendor_radiotap_align = 1; |
@@ -145,8 +156,12 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
145 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 156 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
146 | struct ieee80211_radiotap_header *rthdr; | 157 | struct ieee80211_radiotap_header *rthdr; |
147 | unsigned char *pos; | 158 | unsigned char *pos; |
159 | __le32 *it_present; | ||
160 | u32 it_present_val; | ||
148 | u16 rx_flags = 0; | 161 | u16 rx_flags = 0; |
149 | int mpdulen; | 162 | u16 channel_flags = 0; |
163 | int mpdulen, chain; | ||
164 | unsigned long chains = status->chains; | ||
150 | 165 | ||
151 | mpdulen = skb->len; | 166 | mpdulen = skb->len; |
152 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) | 167 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) |
@@ -154,25 +169,39 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
154 | 169 | ||
155 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); | 170 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); |
156 | memset(rthdr, 0, rtap_len); | 171 | memset(rthdr, 0, rtap_len); |
172 | it_present = &rthdr->it_present; | ||
157 | 173 | ||
158 | /* radiotap header, set always present flags */ | 174 | /* radiotap header, set always present flags */ |
159 | rthdr->it_present = | ||
160 | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
161 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
162 | (1 << IEEE80211_RADIOTAP_ANTENNA) | | ||
163 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | ||
164 | rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); | 175 | rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); |
176 | it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) | | ||
177 | BIT(IEEE80211_RADIOTAP_CHANNEL) | | ||
178 | BIT(IEEE80211_RADIOTAP_RX_FLAGS); | ||
165 | 179 | ||
166 | pos = (unsigned char *)(rthdr + 1); | 180 | if (!status->chains) |
181 | it_present_val |= BIT(IEEE80211_RADIOTAP_ANTENNA); | ||
182 | |||
183 | for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { | ||
184 | it_present_val |= | ||
185 | BIT(IEEE80211_RADIOTAP_EXT) | | ||
186 | BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE); | ||
187 | put_unaligned_le32(it_present_val, it_present); | ||
188 | it_present++; | ||
189 | it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) | | ||
190 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); | ||
191 | } | ||
167 | 192 | ||
168 | if (status->vendor_radiotap_len) { | 193 | if (status->vendor_radiotap_len) { |
169 | rthdr->it_present |= | 194 | it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | |
170 | cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) | | 195 | BIT(IEEE80211_RADIOTAP_EXT); |
171 | cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT)); | 196 | put_unaligned_le32(it_present_val, it_present); |
172 | put_unaligned_le32(status->vendor_radiotap_bitmap, pos); | 197 | it_present++; |
173 | pos += 4; | 198 | it_present_val = status->vendor_radiotap_bitmap; |
174 | } | 199 | } |
175 | 200 | ||
201 | put_unaligned_le32(it_present_val, it_present); | ||
202 | |||
203 | pos = (void *)(it_present + 1); | ||
204 | |||
176 | /* the order of the following fields is important */ | 205 | /* the order of the following fields is important */ |
177 | 206 | ||
178 | /* IEEE80211_RADIOTAP_TSFT */ | 207 | /* IEEE80211_RADIOTAP_TSFT */ |
@@ -207,28 +236,35 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
207 | */ | 236 | */ |
208 | *pos = 0; | 237 | *pos = 0; |
209 | } else { | 238 | } else { |
239 | int shift = 0; | ||
210 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); | 240 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); |
211 | *pos = rate->bitrate / 5; | 241 | if (status->flag & RX_FLAG_10MHZ) |
242 | shift = 1; | ||
243 | else if (status->flag & RX_FLAG_5MHZ) | ||
244 | shift = 2; | ||
245 | *pos = DIV_ROUND_UP(rate->bitrate, 5 * (1 << shift)); | ||
212 | } | 246 | } |
213 | pos++; | 247 | pos++; |
214 | 248 | ||
215 | /* IEEE80211_RADIOTAP_CHANNEL */ | 249 | /* IEEE80211_RADIOTAP_CHANNEL */ |
216 | put_unaligned_le16(status->freq, pos); | 250 | put_unaligned_le16(status->freq, pos); |
217 | pos += 2; | 251 | pos += 2; |
252 | if (status->flag & RX_FLAG_10MHZ) | ||
253 | channel_flags |= IEEE80211_CHAN_HALF; | ||
254 | else if (status->flag & RX_FLAG_5MHZ) | ||
255 | channel_flags |= IEEE80211_CHAN_QUARTER; | ||
256 | |||
218 | if (status->band == IEEE80211_BAND_5GHZ) | 257 | if (status->band == IEEE80211_BAND_5GHZ) |
219 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, | 258 | channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ; |
220 | pos); | ||
221 | else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) | 259 | else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) |
222 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, | 260 | channel_flags |= IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; |
223 | pos); | ||
224 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) | 261 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) |
225 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, | 262 | channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ; |
226 | pos); | ||
227 | else if (rate) | 263 | else if (rate) |
228 | put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, | 264 | channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ; |
229 | pos); | ||
230 | else | 265 | else |
231 | put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos); | 266 | channel_flags |= IEEE80211_CHAN_2GHZ; |
267 | put_unaligned_le16(channel_flags, pos); | ||
232 | pos += 2; | 268 | pos += 2; |
233 | 269 | ||
234 | /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ | 270 | /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ |
@@ -242,9 +278,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
242 | 278 | ||
243 | /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ | 279 | /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ |
244 | 280 | ||
245 | /* IEEE80211_RADIOTAP_ANTENNA */ | 281 | if (!status->chains) { |
246 | *pos = status->antenna; | 282 | /* IEEE80211_RADIOTAP_ANTENNA */ |
247 | pos++; | 283 | *pos = status->antenna; |
284 | pos++; | ||
285 | } | ||
248 | 286 | ||
249 | /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */ | 287 | /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */ |
250 | 288 | ||
@@ -341,6 +379,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
341 | pos += 2; | 379 | pos += 2; |
342 | } | 380 | } |
343 | 381 | ||
382 | for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) { | ||
383 | *pos++ = status->chain_signal[chain]; | ||
384 | *pos++ = chain; | ||
385 | } | ||
386 | |||
344 | if (status->vendor_radiotap_len) { | 387 | if (status->vendor_radiotap_len) { |
345 | /* ensure 2 byte alignment for the vendor field as required */ | 388 | /* ensure 2 byte alignment for the vendor field as required */ |
346 | if ((pos - (u8 *)rthdr) & 1) | 389 | if ((pos - (u8 *)rthdr) & 1) |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1b122a79b0d8..08afe74b98f4 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -66,6 +66,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
66 | struct cfg80211_bss *cbss; | 66 | struct cfg80211_bss *cbss; |
67 | struct ieee80211_bss *bss; | 67 | struct ieee80211_bss *bss; |
68 | int clen, srlen; | 68 | int clen, srlen; |
69 | enum nl80211_bss_scan_width scan_width; | ||
69 | s32 signal = 0; | 70 | s32 signal = 0; |
70 | 71 | ||
71 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 72 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
@@ -73,8 +74,15 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
73 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 74 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
74 | signal = (rx_status->signal * 100) / local->hw.max_signal; | 75 | signal = (rx_status->signal * 100) / local->hw.max_signal; |
75 | 76 | ||
76 | cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, | 77 | scan_width = NL80211_BSS_CHAN_WIDTH_20; |
77 | mgmt, len, signal, GFP_ATOMIC); | 78 | if (rx_status->flag & RX_FLAG_5MHZ) |
79 | scan_width = NL80211_BSS_CHAN_WIDTH_5; | ||
80 | if (rx_status->flag & RX_FLAG_10MHZ) | ||
81 | scan_width = NL80211_BSS_CHAN_WIDTH_10; | ||
82 | |||
83 | cbss = cfg80211_inform_bss_width_frame(local->hw.wiphy, channel, | ||
84 | scan_width, mgmt, len, signal, | ||
85 | GFP_ATOMIC); | ||
78 | if (!cbss) | 86 | if (!cbss) |
79 | return NULL; | 87 | return NULL; |
80 | 88 | ||
@@ -204,10 +212,29 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
204 | ieee80211_rx_bss_put(local, bss); | 212 | ieee80211_rx_bss_put(local, bss); |
205 | } | 213 | } |
206 | 214 | ||
215 | static void | ||
216 | ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef, | ||
217 | enum nl80211_bss_scan_width scan_width) | ||
218 | { | ||
219 | memset(chandef, 0, sizeof(*chandef)); | ||
220 | switch (scan_width) { | ||
221 | case NL80211_BSS_CHAN_WIDTH_5: | ||
222 | chandef->width = NL80211_CHAN_WIDTH_5; | ||
223 | break; | ||
224 | case NL80211_BSS_CHAN_WIDTH_10: | ||
225 | chandef->width = NL80211_CHAN_WIDTH_10; | ||
226 | break; | ||
227 | default: | ||
228 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
229 | break; | ||
230 | } | ||
231 | } | ||
232 | |||
207 | /* return false if no more work */ | 233 | /* return false if no more work */ |
208 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | 234 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) |
209 | { | 235 | { |
210 | struct cfg80211_scan_request *req = local->scan_req; | 236 | struct cfg80211_scan_request *req = local->scan_req; |
237 | struct cfg80211_chan_def chandef; | ||
211 | enum ieee80211_band band; | 238 | enum ieee80211_band band; |
212 | int i, ielen, n_chans; | 239 | int i, ielen, n_chans; |
213 | 240 | ||
@@ -229,11 +256,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
229 | } while (!n_chans); | 256 | } while (!n_chans); |
230 | 257 | ||
231 | local->hw_scan_req->n_channels = n_chans; | 258 | local->hw_scan_req->n_channels = n_chans; |
259 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); | ||
232 | 260 | ||
233 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, | 261 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, |
234 | local->hw_scan_ies_bufsize, | 262 | local->hw_scan_ies_bufsize, |
235 | req->ie, req->ie_len, band, | 263 | req->ie, req->ie_len, band, |
236 | req->rates[band], 0); | 264 | req->rates[band], &chandef); |
237 | local->hw_scan_req->ie_len = ielen; | 265 | local->hw_scan_req->ie_len = ielen; |
238 | local->hw_scan_req->no_cck = req->no_cck; | 266 | local->hw_scan_req->no_cck = req->no_cck; |
239 | 267 | ||
@@ -280,7 +308,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
280 | rcu_assign_pointer(local->scan_sdata, NULL); | 308 | rcu_assign_pointer(local->scan_sdata, NULL); |
281 | 309 | ||
282 | local->scanning = 0; | 310 | local->scanning = 0; |
283 | local->scan_channel = NULL; | 311 | local->scan_chandef.chan = NULL; |
284 | 312 | ||
285 | /* Set power back to normal operating levels. */ | 313 | /* Set power back to normal operating levels. */ |
286 | ieee80211_hw_config(local, 0); | 314 | ieee80211_hw_config(local, 0); |
@@ -615,11 +643,34 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
615 | { | 643 | { |
616 | int skip; | 644 | int skip; |
617 | struct ieee80211_channel *chan; | 645 | struct ieee80211_channel *chan; |
646 | enum nl80211_bss_scan_width oper_scan_width; | ||
618 | 647 | ||
619 | skip = 0; | 648 | skip = 0; |
620 | chan = local->scan_req->channels[local->scan_channel_idx]; | 649 | chan = local->scan_req->channels[local->scan_channel_idx]; |
621 | 650 | ||
622 | local->scan_channel = chan; | 651 | local->scan_chandef.chan = chan; |
652 | local->scan_chandef.center_freq1 = chan->center_freq; | ||
653 | local->scan_chandef.center_freq2 = 0; | ||
654 | switch (local->scan_req->scan_width) { | ||
655 | case NL80211_BSS_CHAN_WIDTH_5: | ||
656 | local->scan_chandef.width = NL80211_CHAN_WIDTH_5; | ||
657 | break; | ||
658 | case NL80211_BSS_CHAN_WIDTH_10: | ||
659 | local->scan_chandef.width = NL80211_CHAN_WIDTH_10; | ||
660 | break; | ||
661 | case NL80211_BSS_CHAN_WIDTH_20: | ||
662 | /* If scanning on oper channel, use whatever channel-type | ||
663 | * is currently in use. | ||
664 | */ | ||
665 | oper_scan_width = cfg80211_chandef_to_scan_width( | ||
666 | &local->_oper_chandef); | ||
667 | if (chan == local->_oper_chandef.chan && | ||
668 | oper_scan_width == local->scan_req->scan_width) | ||
669 | local->scan_chandef = local->_oper_chandef; | ||
670 | else | ||
671 | local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | ||
672 | break; | ||
673 | } | ||
623 | 674 | ||
624 | if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) | 675 | if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) |
625 | skip = 1; | 676 | skip = 1; |
@@ -659,7 +710,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local, | |||
659 | unsigned long *next_delay) | 710 | unsigned long *next_delay) |
660 | { | 711 | { |
661 | /* switch back to the operating channel */ | 712 | /* switch back to the operating channel */ |
662 | local->scan_channel = NULL; | 713 | local->scan_chandef.chan = NULL; |
663 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 714 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
664 | 715 | ||
665 | /* disable PS */ | 716 | /* disable PS */ |
@@ -801,7 +852,8 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
801 | 852 | ||
802 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | 853 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, |
803 | const u8 *ssid, u8 ssid_len, | 854 | const u8 *ssid, u8 ssid_len, |
804 | struct ieee80211_channel *chan) | 855 | struct ieee80211_channel *chan, |
856 | enum nl80211_bss_scan_width scan_width) | ||
805 | { | 857 | { |
806 | struct ieee80211_local *local = sdata->local; | 858 | struct ieee80211_local *local = sdata->local; |
807 | int ret = -EBUSY; | 859 | int ret = -EBUSY; |
@@ -851,6 +903,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, | |||
851 | 903 | ||
852 | local->int_scan_req->ssids = &local->scan_ssid; | 904 | local->int_scan_req->ssids = &local->scan_ssid; |
853 | local->int_scan_req->n_ssids = 1; | 905 | local->int_scan_req->n_ssids = 1; |
906 | local->int_scan_req->scan_width = scan_width; | ||
854 | memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); | 907 | memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); |
855 | local->int_scan_req->ssids[0].ssid_len = ssid_len; | 908 | local->int_scan_req->ssids[0].ssid_len = ssid_len; |
856 | 909 | ||
@@ -912,6 +965,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
912 | { | 965 | { |
913 | struct ieee80211_local *local = sdata->local; | 966 | struct ieee80211_local *local = sdata->local; |
914 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; | 967 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; |
968 | struct cfg80211_chan_def chandef; | ||
915 | int ret, i, iebufsz; | 969 | int ret, i, iebufsz; |
916 | 970 | ||
917 | iebufsz = 2 + IEEE80211_MAX_SSID_LEN + | 971 | iebufsz = 2 + IEEE80211_MAX_SSID_LEN + |
@@ -939,10 +993,12 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
939 | goto out_free; | 993 | goto out_free; |
940 | } | 994 | } |
941 | 995 | ||
996 | ieee80211_prepare_scan_chandef(&chandef, req->scan_width); | ||
997 | |||
942 | sched_scan_ies.len[i] = | 998 | sched_scan_ies.len[i] = |
943 | ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], | 999 | ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], |
944 | iebufsz, req->ie, req->ie_len, | 1000 | iebufsz, req->ie, req->ie_len, |
945 | i, (u32) -1, 0); | 1001 | i, (u32) -1, &chandef); |
946 | } | 1002 | } |
947 | 1003 | ||
948 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 1004 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 43439203f4e4..368837fe3b80 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -235,7 +235,8 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info) | |||
235 | 235 | ||
236 | /* IEEE80211_RADIOTAP_RATE rate */ | 236 | /* IEEE80211_RADIOTAP_RATE rate */ |
237 | if (info->status.rates[0].idx >= 0 && | 237 | if (info->status.rates[0].idx >= 0 && |
238 | !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) | 238 | !(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS | |
239 | IEEE80211_TX_RC_VHT_MCS))) | ||
239 | len += 2; | 240 | len += 2; |
240 | 241 | ||
241 | /* IEEE80211_RADIOTAP_TX_FLAGS */ | 242 | /* IEEE80211_RADIOTAP_TX_FLAGS */ |
@@ -244,17 +245,23 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info) | |||
244 | /* IEEE80211_RADIOTAP_DATA_RETRIES */ | 245 | /* IEEE80211_RADIOTAP_DATA_RETRIES */ |
245 | len += 1; | 246 | len += 1; |
246 | 247 | ||
247 | /* IEEE80211_TX_RC_MCS */ | 248 | /* IEEE80211_RADIOTAP_MCS |
248 | if (info->status.rates[0].idx >= 0 && | 249 | * IEEE80211_RADIOTAP_VHT */ |
249 | info->status.rates[0].flags & IEEE80211_TX_RC_MCS) | 250 | if (info->status.rates[0].idx >= 0) { |
250 | len += 3; | 251 | if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) |
252 | len += 3; | ||
253 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) | ||
254 | len = ALIGN(len, 2) + 12; | ||
255 | } | ||
251 | 256 | ||
252 | return len; | 257 | return len; |
253 | } | 258 | } |
254 | 259 | ||
255 | static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | 260 | static void |
256 | *sband, struct sk_buff *skb, | 261 | ieee80211_add_tx_radiotap_header(struct ieee80211_local *local, |
257 | int retry_count, int rtap_len) | 262 | struct ieee80211_supported_band *sband, |
263 | struct sk_buff *skb, int retry_count, | ||
264 | int rtap_len, int shift) | ||
258 | { | 265 | { |
259 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 266 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
260 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 267 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
@@ -279,9 +286,13 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
279 | 286 | ||
280 | /* IEEE80211_RADIOTAP_RATE */ | 287 | /* IEEE80211_RADIOTAP_RATE */ |
281 | if (info->status.rates[0].idx >= 0 && | 288 | if (info->status.rates[0].idx >= 0 && |
282 | !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) { | 289 | !(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS | |
290 | IEEE80211_TX_RC_VHT_MCS))) { | ||
291 | u16 rate; | ||
292 | |||
283 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); | 293 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); |
284 | *pos = sband->bitrates[info->status.rates[0].idx].bitrate / 5; | 294 | rate = sband->bitrates[info->status.rates[0].idx].bitrate; |
295 | *pos = DIV_ROUND_UP(rate, 5 * (1 << shift)); | ||
285 | /* padding for tx flags */ | 296 | /* padding for tx flags */ |
286 | pos += 2; | 297 | pos += 2; |
287 | } | 298 | } |
@@ -306,9 +317,12 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
306 | *pos = retry_count; | 317 | *pos = retry_count; |
307 | pos++; | 318 | pos++; |
308 | 319 | ||
309 | /* IEEE80211_TX_RC_MCS */ | 320 | if (info->status.rates[0].idx < 0) |
310 | if (info->status.rates[0].idx >= 0 && | 321 | return; |
311 | info->status.rates[0].flags & IEEE80211_TX_RC_MCS) { | 322 | |
323 | /* IEEE80211_RADIOTAP_MCS | ||
324 | * IEEE80211_RADIOTAP_VHT */ | ||
325 | if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) { | ||
312 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); | 326 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); |
313 | pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS | | 327 | pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS | |
314 | IEEE80211_RADIOTAP_MCS_HAVE_GI | | 328 | IEEE80211_RADIOTAP_MCS_HAVE_GI | |
@@ -321,8 +335,48 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
321 | pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF; | 335 | pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF; |
322 | pos[2] = info->status.rates[0].idx; | 336 | pos[2] = info->status.rates[0].idx; |
323 | pos += 3; | 337 | pos += 3; |
324 | } | 338 | } else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) { |
339 | u16 known = local->hw.radiotap_vht_details & | ||
340 | (IEEE80211_RADIOTAP_VHT_KNOWN_GI | | ||
341 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH); | ||
342 | |||
343 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); | ||
344 | |||
345 | /* required alignment from rthdr */ | ||
346 | pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2); | ||
325 | 347 | ||
348 | /* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */ | ||
349 | put_unaligned_le16(known, pos); | ||
350 | pos += 2; | ||
351 | |||
352 | /* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */ | ||
353 | if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) | ||
354 | *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; | ||
355 | pos++; | ||
356 | |||
357 | /* u8 bandwidth */ | ||
358 | if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
359 | *pos = 1; | ||
360 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH) | ||
361 | *pos = 4; | ||
362 | else if (info->status.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH) | ||
363 | *pos = 11; | ||
364 | else /* IEEE80211_TX_RC_{20_MHZ_WIDTH,FIXME:DUP_DATA} */ | ||
365 | *pos = 0; | ||
366 | pos++; | ||
367 | |||
368 | /* u8 mcs_nss[4] */ | ||
369 | *pos = (ieee80211_rate_get_vht_mcs(&info->status.rates[0]) << 4) | | ||
370 | ieee80211_rate_get_vht_nss(&info->status.rates[0]); | ||
371 | pos += 4; | ||
372 | |||
373 | /* u8 coding */ | ||
374 | pos++; | ||
375 | /* u8 group_id */ | ||
376 | pos++; | ||
377 | /* u16 partial_aid */ | ||
378 | pos += 2; | ||
379 | } | ||
326 | } | 380 | } |
327 | 381 | ||
328 | static void ieee80211_report_used_skb(struct ieee80211_local *local, | 382 | static void ieee80211_report_used_skb(struct ieee80211_local *local, |
@@ -424,6 +478,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
424 | bool acked; | 478 | bool acked; |
425 | struct ieee80211_bar *bar; | 479 | struct ieee80211_bar *bar; |
426 | int rtap_len; | 480 | int rtap_len; |
481 | int shift = 0; | ||
427 | 482 | ||
428 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 483 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
429 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | 484 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && |
@@ -458,6 +513,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
458 | if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr)) | 513 | if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr)) |
459 | continue; | 514 | continue; |
460 | 515 | ||
516 | shift = ieee80211_vif_get_shift(&sta->sdata->vif); | ||
517 | |||
461 | if (info->flags & IEEE80211_TX_STATUS_EOSP) | 518 | if (info->flags & IEEE80211_TX_STATUS_EOSP) |
462 | clear_sta_flag(sta, WLAN_STA_SP); | 519 | clear_sta_flag(sta, WLAN_STA_SP); |
463 | 520 | ||
@@ -557,7 +614,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
557 | 614 | ||
558 | rcu_read_unlock(); | 615 | rcu_read_unlock(); |
559 | 616 | ||
560 | ieee80211_led_tx(local, 0); | 617 | ieee80211_led_tx(local); |
561 | 618 | ||
562 | /* SNMP counters | 619 | /* SNMP counters |
563 | * Fragments are passed to low-level drivers as separate skbs, so these | 620 | * Fragments are passed to low-level drivers as separate skbs, so these |
@@ -624,7 +681,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
624 | dev_kfree_skb(skb); | 681 | dev_kfree_skb(skb); |
625 | return; | 682 | return; |
626 | } | 683 | } |
627 | ieee80211_add_tx_radiotap_header(sband, skb, retry_count, rtap_len); | 684 | ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count, |
685 | rtap_len, shift); | ||
628 | 686 | ||
629 | /* XXX: is this sufficient for BPF? */ | 687 | /* XXX: is this sufficient for BPF? */ |
630 | skb_set_mac_header(skb, 0); | 688 | skb_set_mac_header(skb, 0); |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index c215fafd7a2f..1aba645882bd 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1906,6 +1906,32 @@ TRACE_EVENT(api_radar_detected, | |||
1906 | ) | 1906 | ) |
1907 | ); | 1907 | ); |
1908 | 1908 | ||
1909 | TRACE_EVENT(drv_channel_switch_beacon, | ||
1910 | TP_PROTO(struct ieee80211_local *local, | ||
1911 | struct ieee80211_sub_if_data *sdata, | ||
1912 | struct cfg80211_chan_def *chandef), | ||
1913 | |||
1914 | TP_ARGS(local, sdata, chandef), | ||
1915 | |||
1916 | TP_STRUCT__entry( | ||
1917 | LOCAL_ENTRY | ||
1918 | VIF_ENTRY | ||
1919 | CHANDEF_ENTRY | ||
1920 | ), | ||
1921 | |||
1922 | TP_fast_assign( | ||
1923 | LOCAL_ASSIGN; | ||
1924 | VIF_ASSIGN; | ||
1925 | CHANDEF_ASSIGN(chandef); | ||
1926 | ), | ||
1927 | |||
1928 | TP_printk( | ||
1929 | LOCAL_PR_FMT VIF_PR_FMT " channel switch to " CHANDEF_PR_FMT, | ||
1930 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG | ||
1931 | ) | ||
1932 | ); | ||
1933 | |||
1934 | |||
1909 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 1935 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
1910 | #undef TRACE_SYSTEM | 1936 | #undef TRACE_SYSTEM |
1911 | #define TRACE_SYSTEM mac80211_msg | 1937 | #define TRACE_SYSTEM mac80211_msg |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4105d0ca963e..0e42322aa6b1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -40,12 +40,22 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
40 | struct sk_buff *skb, int group_addr, | 40 | struct sk_buff *skb, int group_addr, |
41 | int next_frag_len) | 41 | int next_frag_len) |
42 | { | 42 | { |
43 | int rate, mrate, erp, dur, i; | 43 | int rate, mrate, erp, dur, i, shift = 0; |
44 | struct ieee80211_rate *txrate; | 44 | struct ieee80211_rate *txrate; |
45 | struct ieee80211_local *local = tx->local; | 45 | struct ieee80211_local *local = tx->local; |
46 | struct ieee80211_supported_band *sband; | 46 | struct ieee80211_supported_band *sband; |
47 | struct ieee80211_hdr *hdr; | 47 | struct ieee80211_hdr *hdr; |
48 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 48 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
49 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
50 | u32 rate_flags = 0; | ||
51 | |||
52 | rcu_read_lock(); | ||
53 | chanctx_conf = rcu_dereference(tx->sdata->vif.chanctx_conf); | ||
54 | if (chanctx_conf) { | ||
55 | shift = ieee80211_chandef_get_shift(&chanctx_conf->def); | ||
56 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); | ||
57 | } | ||
58 | rcu_read_unlock(); | ||
49 | 59 | ||
50 | /* assume HW handles this */ | 60 | /* assume HW handles this */ |
51 | if (tx->rate.flags & IEEE80211_TX_RC_MCS) | 61 | if (tx->rate.flags & IEEE80211_TX_RC_MCS) |
@@ -122,8 +132,11 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
122 | if (r->bitrate > txrate->bitrate) | 132 | if (r->bitrate > txrate->bitrate) |
123 | break; | 133 | break; |
124 | 134 | ||
135 | if ((rate_flags & r->flags) != rate_flags) | ||
136 | continue; | ||
137 | |||
125 | if (tx->sdata->vif.bss_conf.basic_rates & BIT(i)) | 138 | if (tx->sdata->vif.bss_conf.basic_rates & BIT(i)) |
126 | rate = r->bitrate; | 139 | rate = DIV_ROUND_UP(r->bitrate, 1 << shift); |
127 | 140 | ||
128 | switch (sband->band) { | 141 | switch (sband->band) { |
129 | case IEEE80211_BAND_2GHZ: { | 142 | case IEEE80211_BAND_2GHZ: { |
@@ -150,7 +163,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
150 | if (rate == -1) { | 163 | if (rate == -1) { |
151 | /* No matching basic rate found; use highest suitable mandatory | 164 | /* No matching basic rate found; use highest suitable mandatory |
152 | * PHY rate */ | 165 | * PHY rate */ |
153 | rate = mrate; | 166 | rate = DIV_ROUND_UP(mrate, 1 << shift); |
154 | } | 167 | } |
155 | 168 | ||
156 | /* Don't calculate ACKs for QoS Frames with NoAck Policy set */ | 169 | /* Don't calculate ACKs for QoS Frames with NoAck Policy set */ |
@@ -162,7 +175,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
162 | * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up | 175 | * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up |
163 | * to closest integer */ | 176 | * to closest integer */ |
164 | dur = ieee80211_frame_duration(sband->band, 10, rate, erp, | 177 | dur = ieee80211_frame_duration(sband->band, 10, rate, erp, |
165 | tx->sdata->vif.bss_conf.use_short_preamble); | 178 | tx->sdata->vif.bss_conf.use_short_preamble, |
179 | shift); | ||
166 | 180 | ||
167 | if (next_frag_len) { | 181 | if (next_frag_len) { |
168 | /* Frame is fragmented: duration increases with time needed to | 182 | /* Frame is fragmented: duration increases with time needed to |
@@ -171,7 +185,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
171 | /* next fragment */ | 185 | /* next fragment */ |
172 | dur += ieee80211_frame_duration(sband->band, next_frag_len, | 186 | dur += ieee80211_frame_duration(sband->band, next_frag_len, |
173 | txrate->bitrate, erp, | 187 | txrate->bitrate, erp, |
174 | tx->sdata->vif.bss_conf.use_short_preamble); | 188 | tx->sdata->vif.bss_conf.use_short_preamble, |
189 | shift); | ||
175 | } | 190 | } |
176 | 191 | ||
177 | return cpu_to_le16(dur); | 192 | return cpu_to_le16(dur); |
@@ -1257,6 +1272,10 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1257 | 1272 | ||
1258 | switch (sdata->vif.type) { | 1273 | switch (sdata->vif.type) { |
1259 | case NL80211_IFTYPE_MONITOR: | 1274 | case NL80211_IFTYPE_MONITOR: |
1275 | if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) { | ||
1276 | vif = &sdata->vif; | ||
1277 | break; | ||
1278 | } | ||
1260 | sdata = rcu_dereference(local->monitor_sdata); | 1279 | sdata = rcu_dereference(local->monitor_sdata); |
1261 | if (sdata) { | 1280 | if (sdata) { |
1262 | vif = &sdata->vif; | 1281 | vif = &sdata->vif; |
@@ -1281,7 +1300,6 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1281 | txpending); | 1300 | txpending); |
1282 | 1301 | ||
1283 | ieee80211_tpt_led_trig_tx(local, fc, led_len); | 1302 | ieee80211_tpt_led_trig_tx(local, fc, led_len); |
1284 | ieee80211_led_tx(local, 1); | ||
1285 | 1303 | ||
1286 | WARN_ON_ONCE(!skb_queue_empty(skbs)); | 1304 | WARN_ON_ONCE(!skb_queue_empty(skbs)); |
1287 | 1305 | ||
@@ -2320,6 +2338,81 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
2320 | return 0; | 2338 | return 0; |
2321 | } | 2339 | } |
2322 | 2340 | ||
2341 | void ieee80211_csa_finish(struct ieee80211_vif *vif) | ||
2342 | { | ||
2343 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
2344 | |||
2345 | ieee80211_queue_work(&sdata->local->hw, | ||
2346 | &sdata->csa_finalize_work); | ||
2347 | } | ||
2348 | EXPORT_SYMBOL(ieee80211_csa_finish); | ||
2349 | |||
2350 | static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata, | ||
2351 | struct beacon_data *beacon) | ||
2352 | { | ||
2353 | struct probe_resp *resp; | ||
2354 | int counter_offset_beacon = sdata->csa_counter_offset_beacon; | ||
2355 | int counter_offset_presp = sdata->csa_counter_offset_presp; | ||
2356 | |||
2357 | /* warn if the driver did not check for/react to csa completeness */ | ||
2358 | if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0)) | ||
2359 | return; | ||
2360 | |||
2361 | ((u8 *)beacon->tail)[counter_offset_beacon]--; | ||
2362 | |||
2363 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
2364 | counter_offset_presp) { | ||
2365 | rcu_read_lock(); | ||
2366 | resp = rcu_dereference(sdata->u.ap.probe_resp); | ||
2367 | |||
2368 | /* if nl80211 accepted the offset, this should not happen. */ | ||
2369 | if (WARN_ON(!resp)) { | ||
2370 | rcu_read_unlock(); | ||
2371 | return; | ||
2372 | } | ||
2373 | resp->data[counter_offset_presp]--; | ||
2374 | rcu_read_unlock(); | ||
2375 | } | ||
2376 | } | ||
2377 | |||
2378 | bool ieee80211_csa_is_complete(struct ieee80211_vif *vif) | ||
2379 | { | ||
2380 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
2381 | struct beacon_data *beacon = NULL; | ||
2382 | u8 *beacon_data; | ||
2383 | size_t beacon_data_len; | ||
2384 | int counter_beacon = sdata->csa_counter_offset_beacon; | ||
2385 | int ret = false; | ||
2386 | |||
2387 | if (!ieee80211_sdata_running(sdata)) | ||
2388 | return false; | ||
2389 | |||
2390 | rcu_read_lock(); | ||
2391 | if (vif->type == NL80211_IFTYPE_AP) { | ||
2392 | struct ieee80211_if_ap *ap = &sdata->u.ap; | ||
2393 | |||
2394 | beacon = rcu_dereference(ap->beacon); | ||
2395 | if (WARN_ON(!beacon || !beacon->tail)) | ||
2396 | goto out; | ||
2397 | beacon_data = beacon->tail; | ||
2398 | beacon_data_len = beacon->tail_len; | ||
2399 | } else { | ||
2400 | WARN_ON(1); | ||
2401 | goto out; | ||
2402 | } | ||
2403 | |||
2404 | if (WARN_ON(counter_beacon > beacon_data_len)) | ||
2405 | goto out; | ||
2406 | |||
2407 | if (beacon_data[counter_beacon] == 0) | ||
2408 | ret = true; | ||
2409 | out: | ||
2410 | rcu_read_unlock(); | ||
2411 | |||
2412 | return ret; | ||
2413 | } | ||
2414 | EXPORT_SYMBOL(ieee80211_csa_is_complete); | ||
2415 | |||
2323 | struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | 2416 | struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, |
2324 | struct ieee80211_vif *vif, | 2417 | struct ieee80211_vif *vif, |
2325 | u16 *tim_offset, u16 *tim_length) | 2418 | u16 *tim_offset, u16 *tim_length) |
@@ -2350,6 +2443,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2350 | struct beacon_data *beacon = rcu_dereference(ap->beacon); | 2443 | struct beacon_data *beacon = rcu_dereference(ap->beacon); |
2351 | 2444 | ||
2352 | if (beacon) { | 2445 | if (beacon) { |
2446 | if (sdata->vif.csa_active) | ||
2447 | ieee80211_update_csa(sdata, beacon); | ||
2448 | |||
2353 | /* | 2449 | /* |
2354 | * headroom, head length, | 2450 | * headroom, head length, |
2355 | * tail length and maximum TIM length | 2451 | * tail length and maximum TIM length |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22654452a561..d23c5a705a68 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -107,7 +107,8 @@ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | |||
107 | } | 107 | } |
108 | 108 | ||
109 | int ieee80211_frame_duration(enum ieee80211_band band, size_t len, | 109 | int ieee80211_frame_duration(enum ieee80211_band band, size_t len, |
110 | int rate, int erp, int short_preamble) | 110 | int rate, int erp, int short_preamble, |
111 | int shift) | ||
111 | { | 112 | { |
112 | int dur; | 113 | int dur; |
113 | 114 | ||
@@ -118,6 +119,9 @@ int ieee80211_frame_duration(enum ieee80211_band band, size_t len, | |||
118 | * | 119 | * |
119 | * rate is in 100 kbps, so divident is multiplied by 10 in the | 120 | * rate is in 100 kbps, so divident is multiplied by 10 in the |
120 | * DIV_ROUND_UP() operations. | 121 | * DIV_ROUND_UP() operations. |
122 | * | ||
123 | * shift may be 2 for 5 MHz channels or 1 for 10 MHz channels, and | ||
124 | * is assumed to be 0 otherwise. | ||
121 | */ | 125 | */ |
122 | 126 | ||
123 | if (band == IEEE80211_BAND_5GHZ || erp) { | 127 | if (band == IEEE80211_BAND_5GHZ || erp) { |
@@ -130,13 +134,23 @@ int ieee80211_frame_duration(enum ieee80211_band band, size_t len, | |||
130 | * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext | 134 | * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext |
131 | * | 135 | * |
132 | * T_SYM = 4 usec | 136 | * T_SYM = 4 usec |
133 | * 802.11a - 17.5.2: aSIFSTime = 16 usec | 137 | * 802.11a - 18.5.2: aSIFSTime = 16 usec |
134 | * 802.11g - 19.8.4: aSIFSTime = 10 usec + | 138 | * 802.11g - 19.8.4: aSIFSTime = 10 usec + |
135 | * signal ext = 6 usec | 139 | * signal ext = 6 usec |
136 | */ | 140 | */ |
137 | dur = 16; /* SIFS + signal ext */ | 141 | dur = 16; /* SIFS + signal ext */ |
138 | dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ | 142 | dur += 16; /* IEEE 802.11-2012 18.3.2.4: T_PREAMBLE = 16 usec */ |
139 | dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ | 143 | dur += 4; /* IEEE 802.11-2012 18.3.2.4: T_SIGNAL = 4 usec */ |
144 | |||
145 | /* IEEE 802.11-2012 18.3.2.4: all values above are: | ||
146 | * * times 4 for 5 MHz | ||
147 | * * times 2 for 10 MHz | ||
148 | */ | ||
149 | dur *= 1 << shift; | ||
150 | |||
151 | /* rates should already consider the channel bandwidth, | ||
152 | * don't apply divisor again. | ||
153 | */ | ||
140 | dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, | 154 | dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, |
141 | 4 * rate); /* T_SYM x N_SYM */ | 155 | 4 * rate); /* T_SYM x N_SYM */ |
142 | } else { | 156 | } else { |
@@ -168,7 +182,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, | |||
168 | { | 182 | { |
169 | struct ieee80211_sub_if_data *sdata; | 183 | struct ieee80211_sub_if_data *sdata; |
170 | u16 dur; | 184 | u16 dur; |
171 | int erp; | 185 | int erp, shift = 0; |
172 | bool short_preamble = false; | 186 | bool short_preamble = false; |
173 | 187 | ||
174 | erp = 0; | 188 | erp = 0; |
@@ -177,10 +191,11 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, | |||
177 | short_preamble = sdata->vif.bss_conf.use_short_preamble; | 191 | short_preamble = sdata->vif.bss_conf.use_short_preamble; |
178 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 192 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) |
179 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 193 | erp = rate->flags & IEEE80211_RATE_ERP_G; |
194 | shift = ieee80211_vif_get_shift(vif); | ||
180 | } | 195 | } |
181 | 196 | ||
182 | dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp, | 197 | dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp, |
183 | short_preamble); | 198 | short_preamble, shift); |
184 | 199 | ||
185 | return cpu_to_le16(dur); | 200 | return cpu_to_le16(dur); |
186 | } | 201 | } |
@@ -194,7 +209,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | |||
194 | struct ieee80211_rate *rate; | 209 | struct ieee80211_rate *rate; |
195 | struct ieee80211_sub_if_data *sdata; | 210 | struct ieee80211_sub_if_data *sdata; |
196 | bool short_preamble; | 211 | bool short_preamble; |
197 | int erp; | 212 | int erp, shift = 0, bitrate; |
198 | u16 dur; | 213 | u16 dur; |
199 | struct ieee80211_supported_band *sband; | 214 | struct ieee80211_supported_band *sband; |
200 | 215 | ||
@@ -210,17 +225,20 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | |||
210 | short_preamble = sdata->vif.bss_conf.use_short_preamble; | 225 | short_preamble = sdata->vif.bss_conf.use_short_preamble; |
211 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 226 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) |
212 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 227 | erp = rate->flags & IEEE80211_RATE_ERP_G; |
228 | shift = ieee80211_vif_get_shift(vif); | ||
213 | } | 229 | } |
214 | 230 | ||
231 | bitrate = DIV_ROUND_UP(rate->bitrate, 1 << shift); | ||
232 | |||
215 | /* CTS duration */ | 233 | /* CTS duration */ |
216 | dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate, | 234 | dur = ieee80211_frame_duration(sband->band, 10, bitrate, |
217 | erp, short_preamble); | 235 | erp, short_preamble, shift); |
218 | /* Data frame duration */ | 236 | /* Data frame duration */ |
219 | dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate, | 237 | dur += ieee80211_frame_duration(sband->band, frame_len, bitrate, |
220 | erp, short_preamble); | 238 | erp, short_preamble, shift); |
221 | /* ACK duration */ | 239 | /* ACK duration */ |
222 | dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate, | 240 | dur += ieee80211_frame_duration(sband->band, 10, bitrate, |
223 | erp, short_preamble); | 241 | erp, short_preamble, shift); |
224 | 242 | ||
225 | return cpu_to_le16(dur); | 243 | return cpu_to_le16(dur); |
226 | } | 244 | } |
@@ -235,7 +253,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | |||
235 | struct ieee80211_rate *rate; | 253 | struct ieee80211_rate *rate; |
236 | struct ieee80211_sub_if_data *sdata; | 254 | struct ieee80211_sub_if_data *sdata; |
237 | bool short_preamble; | 255 | bool short_preamble; |
238 | int erp; | 256 | int erp, shift = 0, bitrate; |
239 | u16 dur; | 257 | u16 dur; |
240 | struct ieee80211_supported_band *sband; | 258 | struct ieee80211_supported_band *sband; |
241 | 259 | ||
@@ -250,15 +268,18 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | |||
250 | short_preamble = sdata->vif.bss_conf.use_short_preamble; | 268 | short_preamble = sdata->vif.bss_conf.use_short_preamble; |
251 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) | 269 | if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) |
252 | erp = rate->flags & IEEE80211_RATE_ERP_G; | 270 | erp = rate->flags & IEEE80211_RATE_ERP_G; |
271 | shift = ieee80211_vif_get_shift(vif); | ||
253 | } | 272 | } |
254 | 273 | ||
274 | bitrate = DIV_ROUND_UP(rate->bitrate, 1 << shift); | ||
275 | |||
255 | /* Data frame duration */ | 276 | /* Data frame duration */ |
256 | dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate, | 277 | dur = ieee80211_frame_duration(sband->band, frame_len, bitrate, |
257 | erp, short_preamble); | 278 | erp, short_preamble, shift); |
258 | if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { | 279 | if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) { |
259 | /* ACK duration */ | 280 | /* ACK duration */ |
260 | dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate, | 281 | dur += ieee80211_frame_duration(sband->band, 10, bitrate, |
261 | erp, short_preamble); | 282 | erp, short_preamble, shift); |
262 | } | 283 | } |
263 | 284 | ||
264 | return cpu_to_le16(dur); | 285 | return cpu_to_le16(dur); |
@@ -1052,32 +1073,6 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1052 | } | 1073 | } |
1053 | } | 1074 | } |
1054 | 1075 | ||
1055 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
1056 | const size_t supp_rates_len, | ||
1057 | const u8 *supp_rates) | ||
1058 | { | ||
1059 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
1060 | int i, have_higher_than_11mbit = 0; | ||
1061 | |||
1062 | /* cf. IEEE 802.11 9.2.12 */ | ||
1063 | for (i = 0; i < supp_rates_len; i++) | ||
1064 | if ((supp_rates[i] & 0x7f) * 5 > 110) | ||
1065 | have_higher_than_11mbit = 1; | ||
1066 | |||
1067 | rcu_read_lock(); | ||
1068 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
1069 | |||
1070 | if (chanctx_conf && | ||
1071 | chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ && | ||
1072 | have_higher_than_11mbit) | ||
1073 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
1074 | else | ||
1075 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
1076 | rcu_read_unlock(); | ||
1077 | |||
1078 | ieee80211_set_wmm_default(sdata, true); | ||
1079 | } | ||
1080 | |||
1081 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1076 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1082 | u16 transaction, u16 auth_alg, u16 status, | 1077 | u16 transaction, u16 auth_alg, u16 status, |
1083 | const u8 *extra, size_t extra_len, const u8 *da, | 1078 | const u8 *extra, size_t extra_len, const u8 *da, |
@@ -1162,7 +1157,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1162 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1157 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1163 | size_t buffer_len, const u8 *ie, size_t ie_len, | 1158 | size_t buffer_len, const u8 *ie, size_t ie_len, |
1164 | enum ieee80211_band band, u32 rate_mask, | 1159 | enum ieee80211_band band, u32 rate_mask, |
1165 | u8 channel) | 1160 | struct cfg80211_chan_def *chandef) |
1166 | { | 1161 | { |
1167 | struct ieee80211_supported_band *sband; | 1162 | struct ieee80211_supported_band *sband; |
1168 | u8 *pos = buffer, *end = buffer + buffer_len; | 1163 | u8 *pos = buffer, *end = buffer + buffer_len; |
@@ -1171,16 +1166,26 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1171 | u8 rates[32]; | 1166 | u8 rates[32]; |
1172 | int num_rates; | 1167 | int num_rates; |
1173 | int ext_rates_len; | 1168 | int ext_rates_len; |
1169 | int shift; | ||
1170 | u32 rate_flags; | ||
1174 | 1171 | ||
1175 | sband = local->hw.wiphy->bands[band]; | 1172 | sband = local->hw.wiphy->bands[band]; |
1176 | if (WARN_ON_ONCE(!sband)) | 1173 | if (WARN_ON_ONCE(!sband)) |
1177 | return 0; | 1174 | return 0; |
1178 | 1175 | ||
1176 | rate_flags = ieee80211_chandef_rate_flags(chandef); | ||
1177 | shift = ieee80211_chandef_get_shift(chandef); | ||
1178 | |||
1179 | num_rates = 0; | 1179 | num_rates = 0; |
1180 | for (i = 0; i < sband->n_bitrates; i++) { | 1180 | for (i = 0; i < sband->n_bitrates; i++) { |
1181 | if ((BIT(i) & rate_mask) == 0) | 1181 | if ((BIT(i) & rate_mask) == 0) |
1182 | continue; /* skip rate */ | 1182 | continue; /* skip rate */ |
1183 | rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5); | 1183 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) |
1184 | continue; | ||
1185 | |||
1186 | rates[num_rates++] = | ||
1187 | (u8) DIV_ROUND_UP(sband->bitrates[i].bitrate, | ||
1188 | (1 << shift) * 5); | ||
1184 | } | 1189 | } |
1185 | 1190 | ||
1186 | supp_rates_len = min_t(int, num_rates, 8); | 1191 | supp_rates_len = min_t(int, num_rates, 8); |
@@ -1220,12 +1225,13 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1220 | pos += ext_rates_len; | 1225 | pos += ext_rates_len; |
1221 | } | 1226 | } |
1222 | 1227 | ||
1223 | if (channel && sband->band == IEEE80211_BAND_2GHZ) { | 1228 | if (chandef->chan && sband->band == IEEE80211_BAND_2GHZ) { |
1224 | if (end - pos < 3) | 1229 | if (end - pos < 3) |
1225 | goto out_err; | 1230 | goto out_err; |
1226 | *pos++ = WLAN_EID_DS_PARAMS; | 1231 | *pos++ = WLAN_EID_DS_PARAMS; |
1227 | *pos++ = 1; | 1232 | *pos++ = 1; |
1228 | *pos++ = channel; | 1233 | *pos++ = ieee80211_frequency_to_channel( |
1234 | chandef->chan->center_freq); | ||
1229 | } | 1235 | } |
1230 | 1236 | ||
1231 | /* insert custom IEs that go before HT */ | 1237 | /* insert custom IEs that go before HT */ |
@@ -1290,9 +1296,9 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1290 | bool directed) | 1296 | bool directed) |
1291 | { | 1297 | { |
1292 | struct ieee80211_local *local = sdata->local; | 1298 | struct ieee80211_local *local = sdata->local; |
1299 | struct cfg80211_chan_def chandef; | ||
1293 | struct sk_buff *skb; | 1300 | struct sk_buff *skb; |
1294 | struct ieee80211_mgmt *mgmt; | 1301 | struct ieee80211_mgmt *mgmt; |
1295 | u8 chan_no; | ||
1296 | int ies_len; | 1302 | int ies_len; |
1297 | 1303 | ||
1298 | /* | 1304 | /* |
@@ -1300,10 +1306,11 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1300 | * in order to maximize the chance that we get a response. Some | 1306 | * in order to maximize the chance that we get a response. Some |
1301 | * badly-behaved APs don't respond when this parameter is included. | 1307 | * badly-behaved APs don't respond when this parameter is included. |
1302 | */ | 1308 | */ |
1309 | chandef.width = sdata->vif.bss_conf.chandef.width; | ||
1303 | if (directed) | 1310 | if (directed) |
1304 | chan_no = 0; | 1311 | chandef.chan = NULL; |
1305 | else | 1312 | else |
1306 | chan_no = ieee80211_frequency_to_channel(chan->center_freq); | 1313 | chandef.chan = chan; |
1307 | 1314 | ||
1308 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 1315 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
1309 | ssid, ssid_len, 100 + ie_len); | 1316 | ssid, ssid_len, 100 + ie_len); |
@@ -1313,7 +1320,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1313 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), | 1320 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), |
1314 | skb_tailroom(skb), | 1321 | skb_tailroom(skb), |
1315 | ie, ie_len, chan->band, | 1322 | ie, ie_len, chan->band, |
1316 | ratemask, chan_no); | 1323 | ratemask, &chandef); |
1317 | skb_put(skb, ies_len); | 1324 | skb_put(skb, ies_len); |
1318 | 1325 | ||
1319 | if (dst) { | 1326 | if (dst) { |
@@ -1347,16 +1354,19 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1347 | } | 1354 | } |
1348 | } | 1355 | } |
1349 | 1356 | ||
1350 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1357 | u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, |
1351 | struct ieee802_11_elems *elems, | 1358 | struct ieee802_11_elems *elems, |
1352 | enum ieee80211_band band, u32 *basic_rates) | 1359 | enum ieee80211_band band, u32 *basic_rates) |
1353 | { | 1360 | { |
1354 | struct ieee80211_supported_band *sband; | 1361 | struct ieee80211_supported_band *sband; |
1355 | struct ieee80211_rate *bitrates; | 1362 | struct ieee80211_rate *bitrates; |
1356 | size_t num_rates; | 1363 | size_t num_rates; |
1357 | u32 supp_rates; | 1364 | u32 supp_rates, rate_flags; |
1358 | int i, j; | 1365 | int i, j, shift; |
1359 | sband = local->hw.wiphy->bands[band]; | 1366 | sband = sdata->local->hw.wiphy->bands[band]; |
1367 | |||
1368 | rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); | ||
1369 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
1360 | 1370 | ||
1361 | if (WARN_ON(!sband)) | 1371 | if (WARN_ON(!sband)) |
1362 | return 1; | 1372 | return 1; |
@@ -1381,7 +1391,15 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
1381 | continue; | 1391 | continue; |
1382 | 1392 | ||
1383 | for (j = 0; j < num_rates; j++) { | 1393 | for (j = 0; j < num_rates; j++) { |
1384 | if (bitrates[j].bitrate == own_rate) { | 1394 | int brate; |
1395 | if ((rate_flags & sband->bitrates[j].flags) | ||
1396 | != rate_flags) | ||
1397 | continue; | ||
1398 | |||
1399 | brate = DIV_ROUND_UP(sband->bitrates[j].bitrate, | ||
1400 | 1 << shift); | ||
1401 | |||
1402 | if (brate == own_rate) { | ||
1385 | supp_rates |= BIT(j); | 1403 | supp_rates |= BIT(j); |
1386 | if (basic_rates && is_basic) | 1404 | if (basic_rates && is_basic) |
1387 | *basic_rates |= BIT(j); | 1405 | *basic_rates |= BIT(j); |
@@ -2004,18 +2022,56 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, | |||
2004 | cfg80211_chandef_create(chandef, control_chan, channel_type); | 2022 | cfg80211_chandef_create(chandef, control_chan, channel_type); |
2005 | } | 2023 | } |
2006 | 2024 | ||
2025 | int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef, | ||
2026 | const struct ieee80211_supported_band *sband, | ||
2027 | const u8 *srates, int srates_len, u32 *rates) | ||
2028 | { | ||
2029 | u32 rate_flags = ieee80211_chandef_rate_flags(chandef); | ||
2030 | int shift = ieee80211_chandef_get_shift(chandef); | ||
2031 | struct ieee80211_rate *br; | ||
2032 | int brate, rate, i, j, count = 0; | ||
2033 | |||
2034 | *rates = 0; | ||
2035 | |||
2036 | for (i = 0; i < srates_len; i++) { | ||
2037 | rate = srates[i] & 0x7f; | ||
2038 | |||
2039 | for (j = 0; j < sband->n_bitrates; j++) { | ||
2040 | br = &sband->bitrates[j]; | ||
2041 | if ((rate_flags & br->flags) != rate_flags) | ||
2042 | continue; | ||
2043 | |||
2044 | brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5); | ||
2045 | if (brate == rate) { | ||
2046 | *rates |= BIT(j); | ||
2047 | count++; | ||
2048 | break; | ||
2049 | } | ||
2050 | } | ||
2051 | } | ||
2052 | return count; | ||
2053 | } | ||
2054 | |||
2007 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | 2055 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, |
2008 | struct sk_buff *skb, bool need_basic, | 2056 | struct sk_buff *skb, bool need_basic, |
2009 | enum ieee80211_band band) | 2057 | enum ieee80211_band band) |
2010 | { | 2058 | { |
2011 | struct ieee80211_local *local = sdata->local; | 2059 | struct ieee80211_local *local = sdata->local; |
2012 | struct ieee80211_supported_band *sband; | 2060 | struct ieee80211_supported_band *sband; |
2013 | int rate; | 2061 | int rate, shift; |
2014 | u8 i, rates, *pos; | 2062 | u8 i, rates, *pos; |
2015 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; | 2063 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; |
2064 | u32 rate_flags; | ||
2016 | 2065 | ||
2066 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
2067 | rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); | ||
2017 | sband = local->hw.wiphy->bands[band]; | 2068 | sband = local->hw.wiphy->bands[band]; |
2018 | rates = sband->n_bitrates; | 2069 | rates = 0; |
2070 | for (i = 0; i < sband->n_bitrates; i++) { | ||
2071 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
2072 | continue; | ||
2073 | rates++; | ||
2074 | } | ||
2019 | if (rates > 8) | 2075 | if (rates > 8) |
2020 | rates = 8; | 2076 | rates = 8; |
2021 | 2077 | ||
@@ -2027,10 +2083,15 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
2027 | *pos++ = rates; | 2083 | *pos++ = rates; |
2028 | for (i = 0; i < rates; i++) { | 2084 | for (i = 0; i < rates; i++) { |
2029 | u8 basic = 0; | 2085 | u8 basic = 0; |
2086 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
2087 | continue; | ||
2088 | |||
2030 | if (need_basic && basic_rates & BIT(i)) | 2089 | if (need_basic && basic_rates & BIT(i)) |
2031 | basic = 0x80; | 2090 | basic = 0x80; |
2032 | rate = sband->bitrates[i].bitrate; | 2091 | rate = sband->bitrates[i].bitrate; |
2033 | *pos++ = basic | (u8) (rate / 5); | 2092 | rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, |
2093 | 5 * (1 << shift)); | ||
2094 | *pos++ = basic | (u8) rate; | ||
2034 | } | 2095 | } |
2035 | 2096 | ||
2036 | return 0; | 2097 | return 0; |
@@ -2042,12 +2103,22 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
2042 | { | 2103 | { |
2043 | struct ieee80211_local *local = sdata->local; | 2104 | struct ieee80211_local *local = sdata->local; |
2044 | struct ieee80211_supported_band *sband; | 2105 | struct ieee80211_supported_band *sband; |
2045 | int rate; | 2106 | int rate, skip, shift; |
2046 | u8 i, exrates, *pos; | 2107 | u8 i, exrates, *pos; |
2047 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; | 2108 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; |
2109 | u32 rate_flags; | ||
2110 | |||
2111 | rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); | ||
2112 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
2048 | 2113 | ||
2049 | sband = local->hw.wiphy->bands[band]; | 2114 | sband = local->hw.wiphy->bands[band]; |
2050 | exrates = sband->n_bitrates; | 2115 | exrates = 0; |
2116 | for (i = 0; i < sband->n_bitrates; i++) { | ||
2117 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
2118 | continue; | ||
2119 | exrates++; | ||
2120 | } | ||
2121 | |||
2051 | if (exrates > 8) | 2122 | if (exrates > 8) |
2052 | exrates -= 8; | 2123 | exrates -= 8; |
2053 | else | 2124 | else |
@@ -2060,12 +2131,19 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
2060 | pos = skb_put(skb, exrates + 2); | 2131 | pos = skb_put(skb, exrates + 2); |
2061 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 2132 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
2062 | *pos++ = exrates; | 2133 | *pos++ = exrates; |
2134 | skip = 0; | ||
2063 | for (i = 8; i < sband->n_bitrates; i++) { | 2135 | for (i = 8; i < sband->n_bitrates; i++) { |
2064 | u8 basic = 0; | 2136 | u8 basic = 0; |
2137 | if ((rate_flags & sband->bitrates[i].flags) | ||
2138 | != rate_flags) | ||
2139 | continue; | ||
2140 | if (skip++ < 8) | ||
2141 | continue; | ||
2065 | if (need_basic && basic_rates & BIT(i)) | 2142 | if (need_basic && basic_rates & BIT(i)) |
2066 | basic = 0x80; | 2143 | basic = 0x80; |
2067 | rate = sband->bitrates[i].bitrate; | 2144 | rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, |
2068 | *pos++ = basic | (u8) (rate / 5); | 2145 | 5 * (1 << shift)); |
2146 | *pos++ = basic | (u8) rate; | ||
2069 | } | 2147 | } |
2070 | } | 2148 | } |
2071 | return 0; | 2149 | return 0; |
@@ -2149,9 +2227,17 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
2149 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | 2227 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; |
2150 | } else { | 2228 | } else { |
2151 | struct ieee80211_supported_band *sband; | 2229 | struct ieee80211_supported_band *sband; |
2230 | int shift = 0; | ||
2231 | int bitrate; | ||
2232 | |||
2233 | if (status->flag & RX_FLAG_10MHZ) | ||
2234 | shift = 1; | ||
2235 | if (status->flag & RX_FLAG_5MHZ) | ||
2236 | shift = 2; | ||
2152 | 2237 | ||
2153 | sband = local->hw.wiphy->bands[status->band]; | 2238 | sband = local->hw.wiphy->bands[status->band]; |
2154 | ri.legacy = sband->bitrates[status->rate_idx].bitrate; | 2239 | bitrate = sband->bitrates[status->rate_idx].bitrate; |
2240 | ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift)); | ||
2155 | } | 2241 | } |
2156 | 2242 | ||
2157 | rate = cfg80211_calculate_bitrate(&ri); | 2243 | rate = cfg80211_calculate_bitrate(&ri); |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 4f9f216665e9..67153964aad2 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -462,6 +462,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
462 | return -EINVAL; | 462 | return -EINVAL; |
463 | #endif | 463 | #endif |
464 | 464 | ||
465 | if (WARN_ON(wiphy->coalesce && | ||
466 | (!wiphy->coalesce->n_rules || | ||
467 | !wiphy->coalesce->n_patterns) && | ||
468 | (!wiphy->coalesce->pattern_min_len || | ||
469 | wiphy->coalesce->pattern_min_len > | ||
470 | wiphy->coalesce->pattern_max_len))) | ||
471 | return -EINVAL; | ||
472 | |||
465 | if (WARN_ON(wiphy->ap_sme_capa && | 473 | if (WARN_ON(wiphy->ap_sme_capa && |
466 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) | 474 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) |
467 | return -EINVAL; | 475 | return -EINVAL; |
@@ -668,6 +676,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
668 | rdev_set_wakeup(rdev, false); | 676 | rdev_set_wakeup(rdev, false); |
669 | #endif | 677 | #endif |
670 | cfg80211_rdev_free_wowlan(rdev); | 678 | cfg80211_rdev_free_wowlan(rdev); |
679 | cfg80211_rdev_free_coalesce(rdev); | ||
671 | } | 680 | } |
672 | EXPORT_SYMBOL(wiphy_unregister); | 681 | EXPORT_SYMBOL(wiphy_unregister); |
673 | 682 | ||
@@ -765,6 +774,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
765 | cfg80211_leave_mesh(rdev, dev); | 774 | cfg80211_leave_mesh(rdev, dev); |
766 | break; | 775 | break; |
767 | case NL80211_IFTYPE_AP: | 776 | case NL80211_IFTYPE_AP: |
777 | case NL80211_IFTYPE_P2P_GO: | ||
768 | cfg80211_stop_ap(rdev, dev); | 778 | cfg80211_stop_ap(rdev, dev); |
769 | break; | 779 | break; |
770 | default: | 780 | default: |
diff --git a/net/wireless/core.h b/net/wireless/core.h index a6b45bf00f33..9ad43c619c54 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -79,6 +79,8 @@ struct cfg80211_registered_device { | |||
79 | /* netlink port which started critical protocol (0 means not started) */ | 79 | /* netlink port which started critical protocol (0 means not started) */ |
80 | u32 crit_proto_nlportid; | 80 | u32 crit_proto_nlportid; |
81 | 81 | ||
82 | struct cfg80211_coalesce *coalesce; | ||
83 | |||
82 | /* must be last because of the way we do wiphy_priv(), | 84 | /* must be last because of the way we do wiphy_priv(), |
83 | * and it should at least be aligned to NETDEV_ALIGN */ | 85 | * and it should at least be aligned to NETDEV_ALIGN */ |
84 | struct wiphy wiphy __aligned(NETDEV_ALIGN); | 86 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 30c49202ee4d..0553fd4d85ae 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -167,9 +167,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
167 | * basic rates | 167 | * basic rates |
168 | */ | 168 | */ |
169 | if (!setup->basic_rates) { | 169 | if (!setup->basic_rates) { |
170 | enum nl80211_bss_scan_width scan_width; | ||
170 | struct ieee80211_supported_band *sband = | 171 | struct ieee80211_supported_band *sband = |
171 | rdev->wiphy.bands[setup->chandef.chan->band]; | 172 | rdev->wiphy.bands[setup->chandef.chan->band]; |
172 | setup->basic_rates = ieee80211_mandatory_rates(sband); | 173 | scan_width = cfg80211_chandef_to_scan_width(&setup->chandef); |
174 | setup->basic_rates = ieee80211_mandatory_rates(sband, | ||
175 | scan_width); | ||
173 | } | 176 | } |
174 | 177 | ||
175 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) | 178 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 25d217d90807..adf1e98f4c3e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -349,6 +349,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
349 | [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY, | 349 | [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY, |
350 | .len = IEEE80211_MAX_DATA_LEN }, | 350 | .len = IEEE80211_MAX_DATA_LEN }, |
351 | [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 }, | 351 | [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 }, |
352 | [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 }, | ||
353 | [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG }, | ||
354 | [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED }, | ||
355 | [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 }, | ||
356 | [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 }, | ||
352 | }; | 357 | }; |
353 | 358 | ||
354 | /* policy for the key attributes */ | 359 | /* policy for the key attributes */ |
@@ -403,6 +408,14 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = { | |||
403 | [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 }, | 408 | [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 }, |
404 | }; | 409 | }; |
405 | 410 | ||
411 | /* policy for coalesce rule attributes */ | ||
412 | static const struct nla_policy | ||
413 | nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = { | ||
414 | [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 }, | ||
415 | [NL80211_ATTR_COALESCE_RULE_CONDITION] = { .type = NLA_U32 }, | ||
416 | [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED }, | ||
417 | }; | ||
418 | |||
406 | /* policy for GTK rekey offload attributes */ | 419 | /* policy for GTK rekey offload attributes */ |
407 | static const struct nla_policy | 420 | static const struct nla_policy |
408 | nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { | 421 | nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { |
@@ -441,10 +454,12 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | |||
441 | goto out_unlock; | 454 | goto out_unlock; |
442 | } | 455 | } |
443 | *rdev = wiphy_to_dev((*wdev)->wiphy); | 456 | *rdev = wiphy_to_dev((*wdev)->wiphy); |
444 | cb->args[0] = (*rdev)->wiphy_idx; | 457 | /* 0 is the first index - add 1 to parse only once */ |
458 | cb->args[0] = (*rdev)->wiphy_idx + 1; | ||
445 | cb->args[1] = (*wdev)->identifier; | 459 | cb->args[1] = (*wdev)->identifier; |
446 | } else { | 460 | } else { |
447 | struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]); | 461 | /* subtract the 1 again here */ |
462 | struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1); | ||
448 | struct wireless_dev *tmp; | 463 | struct wireless_dev *tmp; |
449 | 464 | ||
450 | if (!wiphy) { | 465 | if (!wiphy) { |
@@ -974,7 +989,7 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
974 | return -ENOBUFS; | 989 | return -ENOBUFS; |
975 | 990 | ||
976 | if (dev->wiphy.wowlan->n_patterns) { | 991 | if (dev->wiphy.wowlan->n_patterns) { |
977 | struct nl80211_wowlan_pattern_support pat = { | 992 | struct nl80211_pattern_support pat = { |
978 | .max_patterns = dev->wiphy.wowlan->n_patterns, | 993 | .max_patterns = dev->wiphy.wowlan->n_patterns, |
979 | .min_pattern_len = dev->wiphy.wowlan->pattern_min_len, | 994 | .min_pattern_len = dev->wiphy.wowlan->pattern_min_len, |
980 | .max_pattern_len = dev->wiphy.wowlan->pattern_max_len, | 995 | .max_pattern_len = dev->wiphy.wowlan->pattern_max_len, |
@@ -995,6 +1010,27 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
995 | } | 1010 | } |
996 | #endif | 1011 | #endif |
997 | 1012 | ||
1013 | static int nl80211_send_coalesce(struct sk_buff *msg, | ||
1014 | struct cfg80211_registered_device *dev) | ||
1015 | { | ||
1016 | struct nl80211_coalesce_rule_support rule; | ||
1017 | |||
1018 | if (!dev->wiphy.coalesce) | ||
1019 | return 0; | ||
1020 | |||
1021 | rule.max_rules = dev->wiphy.coalesce->n_rules; | ||
1022 | rule.max_delay = dev->wiphy.coalesce->max_delay; | ||
1023 | rule.pat.max_patterns = dev->wiphy.coalesce->n_patterns; | ||
1024 | rule.pat.min_pattern_len = dev->wiphy.coalesce->pattern_min_len; | ||
1025 | rule.pat.max_pattern_len = dev->wiphy.coalesce->pattern_max_len; | ||
1026 | rule.pat.max_pkt_offset = dev->wiphy.coalesce->max_pkt_offset; | ||
1027 | |||
1028 | if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule)) | ||
1029 | return -ENOBUFS; | ||
1030 | |||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
998 | static int nl80211_send_band_rateinfo(struct sk_buff *msg, | 1034 | static int nl80211_send_band_rateinfo(struct sk_buff *msg, |
999 | struct ieee80211_supported_band *sband) | 1035 | struct ieee80211_supported_band *sband) |
1000 | { | 1036 | { |
@@ -1393,6 +1429,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1393 | if (state->split) { | 1429 | if (state->split) { |
1394 | CMD(crit_proto_start, CRIT_PROTOCOL_START); | 1430 | CMD(crit_proto_start, CRIT_PROTOCOL_START); |
1395 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); | 1431 | CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); |
1432 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) | ||
1433 | CMD(channel_switch, CHANNEL_SWITCH); | ||
1396 | } | 1434 | } |
1397 | 1435 | ||
1398 | #ifdef CONFIG_NL80211_TESTMODE | 1436 | #ifdef CONFIG_NL80211_TESTMODE |
@@ -1513,6 +1551,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1513 | dev->wiphy.vht_capa_mod_mask)) | 1551 | dev->wiphy.vht_capa_mod_mask)) |
1514 | goto nla_put_failure; | 1552 | goto nla_put_failure; |
1515 | 1553 | ||
1554 | state->split_start++; | ||
1555 | break; | ||
1556 | case 10: | ||
1557 | if (nl80211_send_coalesce(msg, dev)) | ||
1558 | goto nla_put_failure; | ||
1559 | |||
1516 | /* done */ | 1560 | /* done */ |
1517 | state->split_start = 0; | 1561 | state->split_start = 0; |
1518 | break; | 1562 | break; |
@@ -5578,6 +5622,111 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5578 | return err; | 5622 | return err; |
5579 | } | 5623 | } |
5580 | 5624 | ||
5625 | static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | ||
5626 | { | ||
5627 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5628 | struct net_device *dev = info->user_ptr[1]; | ||
5629 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
5630 | struct cfg80211_csa_settings params; | ||
5631 | /* csa_attrs is defined static to avoid waste of stack size - this | ||
5632 | * function is called under RTNL lock, so this should not be a problem. | ||
5633 | */ | ||
5634 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; | ||
5635 | u8 radar_detect_width = 0; | ||
5636 | int err; | ||
5637 | |||
5638 | if (!rdev->ops->channel_switch || | ||
5639 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) | ||
5640 | return -EOPNOTSUPP; | ||
5641 | |||
5642 | /* may add IBSS support later */ | ||
5643 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
5644 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
5645 | return -EOPNOTSUPP; | ||
5646 | |||
5647 | memset(¶ms, 0, sizeof(params)); | ||
5648 | |||
5649 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | ||
5650 | !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]) | ||
5651 | return -EINVAL; | ||
5652 | |||
5653 | /* only important for AP, IBSS and mesh create IEs internally */ | ||
5654 | if (!info->attrs[NL80211_ATTR_CSA_IES]) | ||
5655 | return -EINVAL; | ||
5656 | |||
5657 | /* useless if AP is not running */ | ||
5658 | if (!wdev->beacon_interval) | ||
5659 | return -EINVAL; | ||
5660 | |||
5661 | params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); | ||
5662 | |||
5663 | err = nl80211_parse_beacon(info->attrs, ¶ms.beacon_after); | ||
5664 | if (err) | ||
5665 | return err; | ||
5666 | |||
5667 | err = nla_parse_nested(csa_attrs, NL80211_ATTR_MAX, | ||
5668 | info->attrs[NL80211_ATTR_CSA_IES], | ||
5669 | nl80211_policy); | ||
5670 | if (err) | ||
5671 | return err; | ||
5672 | |||
5673 | err = nl80211_parse_beacon(csa_attrs, ¶ms.beacon_csa); | ||
5674 | if (err) | ||
5675 | return err; | ||
5676 | |||
5677 | if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]) | ||
5678 | return -EINVAL; | ||
5679 | |||
5680 | params.counter_offset_beacon = | ||
5681 | nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]); | ||
5682 | if (params.counter_offset_beacon >= params.beacon_csa.tail_len) | ||
5683 | return -EINVAL; | ||
5684 | |||
5685 | /* sanity check - counters should be the same */ | ||
5686 | if (params.beacon_csa.tail[params.counter_offset_beacon] != | ||
5687 | params.count) | ||
5688 | return -EINVAL; | ||
5689 | |||
5690 | if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) { | ||
5691 | params.counter_offset_presp = | ||
5692 | nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]); | ||
5693 | if (params.counter_offset_presp >= | ||
5694 | params.beacon_csa.probe_resp_len) | ||
5695 | return -EINVAL; | ||
5696 | |||
5697 | if (params.beacon_csa.probe_resp[params.counter_offset_presp] != | ||
5698 | params.count) | ||
5699 | return -EINVAL; | ||
5700 | } | ||
5701 | |||
5702 | err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); | ||
5703 | if (err) | ||
5704 | return err; | ||
5705 | |||
5706 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) | ||
5707 | return -EINVAL; | ||
5708 | |||
5709 | err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); | ||
5710 | if (err < 0) { | ||
5711 | return err; | ||
5712 | } else if (err) { | ||
5713 | radar_detect_width = BIT(params.chandef.width); | ||
5714 | params.radar_required = true; | ||
5715 | } | ||
5716 | |||
5717 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
5718 | params.chandef.chan, | ||
5719 | CHAN_MODE_SHARED, | ||
5720 | radar_detect_width); | ||
5721 | if (err) | ||
5722 | return err; | ||
5723 | |||
5724 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) | ||
5725 | params.block_tx = true; | ||
5726 | |||
5727 | return rdev_channel_switch(rdev, dev, ¶ms); | ||
5728 | } | ||
5729 | |||
5581 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | 5730 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, |
5582 | u32 seq, int flags, | 5731 | u32 seq, int flags, |
5583 | struct cfg80211_registered_device *rdev, | 5732 | struct cfg80211_registered_device *rdev, |
@@ -5639,6 +5788,7 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | |||
5639 | goto nla_put_failure; | 5788 | goto nla_put_failure; |
5640 | if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) || | 5789 | if (nla_put_u16(msg, NL80211_BSS_CAPABILITY, res->capability) || |
5641 | nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) || | 5790 | nla_put_u32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq) || |
5791 | nla_put_u32(msg, NL80211_BSS_CHAN_WIDTH, res->scan_width) || | ||
5642 | nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO, | 5792 | nla_put_u32(msg, NL80211_BSS_SEEN_MS_AGO, |
5643 | jiffies_to_msecs(jiffies - intbss->ts))) | 5793 | jiffies_to_msecs(jiffies - intbss->ts))) |
5644 | goto nla_put_failure; | 5794 | goto nla_put_failure; |
@@ -6319,6 +6469,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
6319 | return -EINVAL; | 6469 | return -EINVAL; |
6320 | 6470 | ||
6321 | switch (ibss.chandef.width) { | 6471 | switch (ibss.chandef.width) { |
6472 | case NL80211_CHAN_WIDTH_5: | ||
6473 | case NL80211_CHAN_WIDTH_10: | ||
6322 | case NL80211_CHAN_WIDTH_20_NOHT: | 6474 | case NL80211_CHAN_WIDTH_20_NOHT: |
6323 | break; | 6475 | break; |
6324 | case NL80211_CHAN_WIDTH_20: | 6476 | case NL80211_CHAN_WIDTH_20: |
@@ -6346,6 +6498,19 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
6346 | return err; | 6498 | return err; |
6347 | } | 6499 | } |
6348 | 6500 | ||
6501 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
6502 | memcpy(&ibss.ht_capa_mask, | ||
6503 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]), | ||
6504 | sizeof(ibss.ht_capa_mask)); | ||
6505 | |||
6506 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | ||
6507 | if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
6508 | return -EINVAL; | ||
6509 | memcpy(&ibss.ht_capa, | ||
6510 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]), | ||
6511 | sizeof(ibss.ht_capa)); | ||
6512 | } | ||
6513 | |||
6349 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && | 6514 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && |
6350 | !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate, | 6515 | !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate, |
6351 | nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]))) | 6516 | nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]))) |
@@ -7593,12 +7758,11 @@ static int nl80211_send_wowlan_patterns(struct sk_buff *msg, | |||
7593 | if (!nl_pat) | 7758 | if (!nl_pat) |
7594 | return -ENOBUFS; | 7759 | return -ENOBUFS; |
7595 | pat_len = wowlan->patterns[i].pattern_len; | 7760 | pat_len = wowlan->patterns[i].pattern_len; |
7596 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, | 7761 | if (nla_put(msg, NL80211_PKTPAT_MASK, DIV_ROUND_UP(pat_len, 8), |
7597 | DIV_ROUND_UP(pat_len, 8), | ||
7598 | wowlan->patterns[i].mask) || | 7762 | wowlan->patterns[i].mask) || |
7599 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | 7763 | nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len, |
7600 | pat_len, wowlan->patterns[i].pattern) || | 7764 | wowlan->patterns[i].pattern) || |
7601 | nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET, | 7765 | nla_put_u32(msg, NL80211_PKTPAT_OFFSET, |
7602 | wowlan->patterns[i].pkt_offset)) | 7766 | wowlan->patterns[i].pkt_offset)) |
7603 | return -ENOBUFS; | 7767 | return -ENOBUFS; |
7604 | nla_nest_end(msg, nl_pat); | 7768 | nla_nest_end(msg, nl_pat); |
@@ -7939,7 +8103,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7939 | struct nlattr *pat; | 8103 | struct nlattr *pat; |
7940 | int n_patterns = 0; | 8104 | int n_patterns = 0; |
7941 | int rem, pat_len, mask_len, pkt_offset; | 8105 | int rem, pat_len, mask_len, pkt_offset; |
7942 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; | 8106 | struct nlattr *pat_tb[NUM_NL80211_PKTPAT]; |
7943 | 8107 | ||
7944 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | 8108 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], |
7945 | rem) | 8109 | rem) |
@@ -7958,26 +8122,25 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7958 | 8122 | ||
7959 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | 8123 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], |
7960 | rem) { | 8124 | rem) { |
7961 | nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT, | 8125 | nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), |
7962 | nla_data(pat), nla_len(pat), NULL); | 8126 | nla_len(pat), NULL); |
7963 | err = -EINVAL; | 8127 | err = -EINVAL; |
7964 | if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] || | 8128 | if (!pat_tb[NL80211_PKTPAT_MASK] || |
7965 | !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]) | 8129 | !pat_tb[NL80211_PKTPAT_PATTERN]) |
7966 | goto error; | 8130 | goto error; |
7967 | pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]); | 8131 | pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]); |
7968 | mask_len = DIV_ROUND_UP(pat_len, 8); | 8132 | mask_len = DIV_ROUND_UP(pat_len, 8); |
7969 | if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) != | 8133 | if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len) |
7970 | mask_len) | ||
7971 | goto error; | 8134 | goto error; |
7972 | if (pat_len > wowlan->pattern_max_len || | 8135 | if (pat_len > wowlan->pattern_max_len || |
7973 | pat_len < wowlan->pattern_min_len) | 8136 | pat_len < wowlan->pattern_min_len) |
7974 | goto error; | 8137 | goto error; |
7975 | 8138 | ||
7976 | if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]) | 8139 | if (!pat_tb[NL80211_PKTPAT_OFFSET]) |
7977 | pkt_offset = 0; | 8140 | pkt_offset = 0; |
7978 | else | 8141 | else |
7979 | pkt_offset = nla_get_u32( | 8142 | pkt_offset = nla_get_u32( |
7980 | pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]); | 8143 | pat_tb[NL80211_PKTPAT_OFFSET]); |
7981 | if (pkt_offset > wowlan->max_pkt_offset) | 8144 | if (pkt_offset > wowlan->max_pkt_offset) |
7982 | goto error; | 8145 | goto error; |
7983 | new_triggers.patterns[i].pkt_offset = pkt_offset; | 8146 | new_triggers.patterns[i].pkt_offset = pkt_offset; |
@@ -7991,11 +8154,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7991 | new_triggers.patterns[i].pattern = | 8154 | new_triggers.patterns[i].pattern = |
7992 | new_triggers.patterns[i].mask + mask_len; | 8155 | new_triggers.patterns[i].mask + mask_len; |
7993 | memcpy(new_triggers.patterns[i].mask, | 8156 | memcpy(new_triggers.patterns[i].mask, |
7994 | nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]), | 8157 | nla_data(pat_tb[NL80211_PKTPAT_MASK]), |
7995 | mask_len); | 8158 | mask_len); |
7996 | new_triggers.patterns[i].pattern_len = pat_len; | 8159 | new_triggers.patterns[i].pattern_len = pat_len; |
7997 | memcpy(new_triggers.patterns[i].pattern, | 8160 | memcpy(new_triggers.patterns[i].pattern, |
7998 | nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]), | 8161 | nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), |
7999 | pat_len); | 8162 | pat_len); |
8000 | i++; | 8163 | i++; |
8001 | } | 8164 | } |
@@ -8034,6 +8197,264 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
8034 | } | 8197 | } |
8035 | #endif | 8198 | #endif |
8036 | 8199 | ||
8200 | static int nl80211_send_coalesce_rules(struct sk_buff *msg, | ||
8201 | struct cfg80211_registered_device *rdev) | ||
8202 | { | ||
8203 | struct nlattr *nl_pats, *nl_pat, *nl_rule, *nl_rules; | ||
8204 | int i, j, pat_len; | ||
8205 | struct cfg80211_coalesce_rules *rule; | ||
8206 | |||
8207 | if (!rdev->coalesce->n_rules) | ||
8208 | return 0; | ||
8209 | |||
8210 | nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE); | ||
8211 | if (!nl_rules) | ||
8212 | return -ENOBUFS; | ||
8213 | |||
8214 | for (i = 0; i < rdev->coalesce->n_rules; i++) { | ||
8215 | nl_rule = nla_nest_start(msg, i + 1); | ||
8216 | if (!nl_rule) | ||
8217 | return -ENOBUFS; | ||
8218 | |||
8219 | rule = &rdev->coalesce->rules[i]; | ||
8220 | if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_DELAY, | ||
8221 | rule->delay)) | ||
8222 | return -ENOBUFS; | ||
8223 | |||
8224 | if (nla_put_u32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION, | ||
8225 | rule->condition)) | ||
8226 | return -ENOBUFS; | ||
8227 | |||
8228 | nl_pats = nla_nest_start(msg, | ||
8229 | NL80211_ATTR_COALESCE_RULE_PKT_PATTERN); | ||
8230 | if (!nl_pats) | ||
8231 | return -ENOBUFS; | ||
8232 | |||
8233 | for (j = 0; j < rule->n_patterns; j++) { | ||
8234 | nl_pat = nla_nest_start(msg, j + 1); | ||
8235 | if (!nl_pat) | ||
8236 | return -ENOBUFS; | ||
8237 | pat_len = rule->patterns[j].pattern_len; | ||
8238 | if (nla_put(msg, NL80211_PKTPAT_MASK, | ||
8239 | DIV_ROUND_UP(pat_len, 8), | ||
8240 | rule->patterns[j].mask) || | ||
8241 | nla_put(msg, NL80211_PKTPAT_PATTERN, pat_len, | ||
8242 | rule->patterns[j].pattern) || | ||
8243 | nla_put_u32(msg, NL80211_PKTPAT_OFFSET, | ||
8244 | rule->patterns[j].pkt_offset)) | ||
8245 | return -ENOBUFS; | ||
8246 | nla_nest_end(msg, nl_pat); | ||
8247 | } | ||
8248 | nla_nest_end(msg, nl_pats); | ||
8249 | nla_nest_end(msg, nl_rule); | ||
8250 | } | ||
8251 | nla_nest_end(msg, nl_rules); | ||
8252 | |||
8253 | return 0; | ||
8254 | } | ||
8255 | |||
8256 | static int nl80211_get_coalesce(struct sk_buff *skb, struct genl_info *info) | ||
8257 | { | ||
8258 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8259 | struct sk_buff *msg; | ||
8260 | void *hdr; | ||
8261 | |||
8262 | if (!rdev->wiphy.coalesce) | ||
8263 | return -EOPNOTSUPP; | ||
8264 | |||
8265 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
8266 | if (!msg) | ||
8267 | return -ENOMEM; | ||
8268 | |||
8269 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
8270 | NL80211_CMD_GET_COALESCE); | ||
8271 | if (!hdr) | ||
8272 | goto nla_put_failure; | ||
8273 | |||
8274 | if (rdev->coalesce && nl80211_send_coalesce_rules(msg, rdev)) | ||
8275 | goto nla_put_failure; | ||
8276 | |||
8277 | genlmsg_end(msg, hdr); | ||
8278 | return genlmsg_reply(msg, info); | ||
8279 | |||
8280 | nla_put_failure: | ||
8281 | nlmsg_free(msg); | ||
8282 | return -ENOBUFS; | ||
8283 | } | ||
8284 | |||
8285 | void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev) | ||
8286 | { | ||
8287 | struct cfg80211_coalesce *coalesce = rdev->coalesce; | ||
8288 | int i, j; | ||
8289 | struct cfg80211_coalesce_rules *rule; | ||
8290 | |||
8291 | if (!coalesce) | ||
8292 | return; | ||
8293 | |||
8294 | for (i = 0; i < coalesce->n_rules; i++) { | ||
8295 | rule = &coalesce->rules[i]; | ||
8296 | for (j = 0; j < rule->n_patterns; j++) | ||
8297 | kfree(rule->patterns[j].mask); | ||
8298 | kfree(rule->patterns); | ||
8299 | } | ||
8300 | kfree(coalesce->rules); | ||
8301 | kfree(coalesce); | ||
8302 | rdev->coalesce = NULL; | ||
8303 | } | ||
8304 | |||
8305 | static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev, | ||
8306 | struct nlattr *rule, | ||
8307 | struct cfg80211_coalesce_rules *new_rule) | ||
8308 | { | ||
8309 | int err, i; | ||
8310 | const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce; | ||
8311 | struct nlattr *tb[NUM_NL80211_ATTR_COALESCE_RULE], *pat; | ||
8312 | int rem, pat_len, mask_len, pkt_offset, n_patterns = 0; | ||
8313 | struct nlattr *pat_tb[NUM_NL80211_PKTPAT]; | ||
8314 | |||
8315 | err = nla_parse(tb, NL80211_ATTR_COALESCE_RULE_MAX, nla_data(rule), | ||
8316 | nla_len(rule), nl80211_coalesce_policy); | ||
8317 | if (err) | ||
8318 | return err; | ||
8319 | |||
8320 | if (tb[NL80211_ATTR_COALESCE_RULE_DELAY]) | ||
8321 | new_rule->delay = | ||
8322 | nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_DELAY]); | ||
8323 | if (new_rule->delay > coalesce->max_delay) | ||
8324 | return -EINVAL; | ||
8325 | |||
8326 | if (tb[NL80211_ATTR_COALESCE_RULE_CONDITION]) | ||
8327 | new_rule->condition = | ||
8328 | nla_get_u32(tb[NL80211_ATTR_COALESCE_RULE_CONDITION]); | ||
8329 | if (new_rule->condition != NL80211_COALESCE_CONDITION_MATCH && | ||
8330 | new_rule->condition != NL80211_COALESCE_CONDITION_NO_MATCH) | ||
8331 | return -EINVAL; | ||
8332 | |||
8333 | if (!tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN]) | ||
8334 | return -EINVAL; | ||
8335 | |||
8336 | nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN], | ||
8337 | rem) | ||
8338 | n_patterns++; | ||
8339 | if (n_patterns > coalesce->n_patterns) | ||
8340 | return -EINVAL; | ||
8341 | |||
8342 | new_rule->patterns = kcalloc(n_patterns, sizeof(new_rule->patterns[0]), | ||
8343 | GFP_KERNEL); | ||
8344 | if (!new_rule->patterns) | ||
8345 | return -ENOMEM; | ||
8346 | |||
8347 | new_rule->n_patterns = n_patterns; | ||
8348 | i = 0; | ||
8349 | |||
8350 | nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN], | ||
8351 | rem) { | ||
8352 | nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), | ||
8353 | nla_len(pat), NULL); | ||
8354 | if (!pat_tb[NL80211_PKTPAT_MASK] || | ||
8355 | !pat_tb[NL80211_PKTPAT_PATTERN]) | ||
8356 | return -EINVAL; | ||
8357 | pat_len = nla_len(pat_tb[NL80211_PKTPAT_PATTERN]); | ||
8358 | mask_len = DIV_ROUND_UP(pat_len, 8); | ||
8359 | if (nla_len(pat_tb[NL80211_PKTPAT_MASK]) != mask_len) | ||
8360 | return -EINVAL; | ||
8361 | if (pat_len > coalesce->pattern_max_len || | ||
8362 | pat_len < coalesce->pattern_min_len) | ||
8363 | return -EINVAL; | ||
8364 | |||
8365 | if (!pat_tb[NL80211_PKTPAT_OFFSET]) | ||
8366 | pkt_offset = 0; | ||
8367 | else | ||
8368 | pkt_offset = nla_get_u32(pat_tb[NL80211_PKTPAT_OFFSET]); | ||
8369 | if (pkt_offset > coalesce->max_pkt_offset) | ||
8370 | return -EINVAL; | ||
8371 | new_rule->patterns[i].pkt_offset = pkt_offset; | ||
8372 | |||
8373 | new_rule->patterns[i].mask = | ||
8374 | kmalloc(mask_len + pat_len, GFP_KERNEL); | ||
8375 | if (!new_rule->patterns[i].mask) | ||
8376 | return -ENOMEM; | ||
8377 | new_rule->patterns[i].pattern = | ||
8378 | new_rule->patterns[i].mask + mask_len; | ||
8379 | memcpy(new_rule->patterns[i].mask, | ||
8380 | nla_data(pat_tb[NL80211_PKTPAT_MASK]), mask_len); | ||
8381 | new_rule->patterns[i].pattern_len = pat_len; | ||
8382 | memcpy(new_rule->patterns[i].pattern, | ||
8383 | nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), pat_len); | ||
8384 | i++; | ||
8385 | } | ||
8386 | |||
8387 | return 0; | ||
8388 | } | ||
8389 | |||
8390 | static int nl80211_set_coalesce(struct sk_buff *skb, struct genl_info *info) | ||
8391 | { | ||
8392 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8393 | const struct wiphy_coalesce_support *coalesce = rdev->wiphy.coalesce; | ||
8394 | struct cfg80211_coalesce new_coalesce = {}; | ||
8395 | struct cfg80211_coalesce *n_coalesce; | ||
8396 | int err, rem_rule, n_rules = 0, i, j; | ||
8397 | struct nlattr *rule; | ||
8398 | struct cfg80211_coalesce_rules *tmp_rule; | ||
8399 | |||
8400 | if (!rdev->wiphy.coalesce || !rdev->ops->set_coalesce) | ||
8401 | return -EOPNOTSUPP; | ||
8402 | |||
8403 | if (!info->attrs[NL80211_ATTR_COALESCE_RULE]) { | ||
8404 | cfg80211_rdev_free_coalesce(rdev); | ||
8405 | rdev->ops->set_coalesce(&rdev->wiphy, NULL); | ||
8406 | return 0; | ||
8407 | } | ||
8408 | |||
8409 | nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE], | ||
8410 | rem_rule) | ||
8411 | n_rules++; | ||
8412 | if (n_rules > coalesce->n_rules) | ||
8413 | return -EINVAL; | ||
8414 | |||
8415 | new_coalesce.rules = kcalloc(n_rules, sizeof(new_coalesce.rules[0]), | ||
8416 | GFP_KERNEL); | ||
8417 | if (!new_coalesce.rules) | ||
8418 | return -ENOMEM; | ||
8419 | |||
8420 | new_coalesce.n_rules = n_rules; | ||
8421 | i = 0; | ||
8422 | |||
8423 | nla_for_each_nested(rule, info->attrs[NL80211_ATTR_COALESCE_RULE], | ||
8424 | rem_rule) { | ||
8425 | err = nl80211_parse_coalesce_rule(rdev, rule, | ||
8426 | &new_coalesce.rules[i]); | ||
8427 | if (err) | ||
8428 | goto error; | ||
8429 | |||
8430 | i++; | ||
8431 | } | ||
8432 | |||
8433 | err = rdev->ops->set_coalesce(&rdev->wiphy, &new_coalesce); | ||
8434 | if (err) | ||
8435 | goto error; | ||
8436 | |||
8437 | n_coalesce = kmemdup(&new_coalesce, sizeof(new_coalesce), GFP_KERNEL); | ||
8438 | if (!n_coalesce) { | ||
8439 | err = -ENOMEM; | ||
8440 | goto error; | ||
8441 | } | ||
8442 | cfg80211_rdev_free_coalesce(rdev); | ||
8443 | rdev->coalesce = n_coalesce; | ||
8444 | |||
8445 | return 0; | ||
8446 | error: | ||
8447 | for (i = 0; i < new_coalesce.n_rules; i++) { | ||
8448 | tmp_rule = &new_coalesce.rules[i]; | ||
8449 | for (j = 0; j < tmp_rule->n_patterns; j++) | ||
8450 | kfree(tmp_rule->patterns[j].mask); | ||
8451 | kfree(tmp_rule->patterns); | ||
8452 | } | ||
8453 | kfree(new_coalesce.rules); | ||
8454 | |||
8455 | return err; | ||
8456 | } | ||
8457 | |||
8037 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | 8458 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) |
8038 | { | 8459 | { |
8039 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8460 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -9041,7 +9462,30 @@ static struct genl_ops nl80211_ops[] = { | |||
9041 | .flags = GENL_ADMIN_PERM, | 9462 | .flags = GENL_ADMIN_PERM, |
9042 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | 9463 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
9043 | NL80211_FLAG_NEED_RTNL, | 9464 | NL80211_FLAG_NEED_RTNL, |
9044 | } | 9465 | }, |
9466 | { | ||
9467 | .cmd = NL80211_CMD_GET_COALESCE, | ||
9468 | .doit = nl80211_get_coalesce, | ||
9469 | .policy = nl80211_policy, | ||
9470 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
9471 | NL80211_FLAG_NEED_RTNL, | ||
9472 | }, | ||
9473 | { | ||
9474 | .cmd = NL80211_CMD_SET_COALESCE, | ||
9475 | .doit = nl80211_set_coalesce, | ||
9476 | .policy = nl80211_policy, | ||
9477 | .flags = GENL_ADMIN_PERM, | ||
9478 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
9479 | NL80211_FLAG_NEED_RTNL, | ||
9480 | }, | ||
9481 | { | ||
9482 | .cmd = NL80211_CMD_CHANNEL_SWITCH, | ||
9483 | .doit = nl80211_channel_switch, | ||
9484 | .policy = nl80211_policy, | ||
9485 | .flags = GENL_ADMIN_PERM, | ||
9486 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
9487 | NL80211_FLAG_NEED_RTNL, | ||
9488 | }, | ||
9045 | }; | 9489 | }; |
9046 | 9490 | ||
9047 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 9491 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index a4073e808c13..44341bf53cfc 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -74,4 +74,6 @@ 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 cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev); | ||
78 | |||
77 | #endif /* __NET_WIRELESS_NL80211_H */ | 79 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 9f15f0ac824d..de870d4d0bcc 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -923,4 +923,16 @@ static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev, | |||
923 | trace_rdev_return_void(&rdev->wiphy); | 923 | trace_rdev_return_void(&rdev->wiphy); |
924 | } | 924 | } |
925 | 925 | ||
926 | static inline int rdev_channel_switch(struct cfg80211_registered_device *rdev, | ||
927 | struct net_device *dev, | ||
928 | struct cfg80211_csa_settings *params) | ||
929 | { | ||
930 | int ret; | ||
931 | |||
932 | trace_rdev_channel_switch(&rdev->wiphy, dev, params); | ||
933 | ret = rdev->ops->channel_switch(&rdev->wiphy, dev, params); | ||
934 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
935 | return ret; | ||
936 | } | ||
937 | |||
926 | #endif /* __CFG80211_RDEV_OPS */ | 938 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index ae8c186b50d6..ad1e4068ce06 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -651,6 +651,8 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, | |||
651 | continue; | 651 | continue; |
652 | if (bss->pub.channel != new->pub.channel) | 652 | if (bss->pub.channel != new->pub.channel) |
653 | continue; | 653 | continue; |
654 | if (bss->pub.scan_width != new->pub.scan_width) | ||
655 | continue; | ||
654 | if (rcu_access_pointer(bss->pub.beacon_ies)) | 656 | if (rcu_access_pointer(bss->pub.beacon_ies)) |
655 | continue; | 657 | continue; |
656 | ies = rcu_access_pointer(bss->pub.ies); | 658 | ies = rcu_access_pointer(bss->pub.ies); |
@@ -870,11 +872,12 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, | |||
870 | 872 | ||
871 | /* Returned bss is reference counted and must be cleaned up appropriately. */ | 873 | /* Returned bss is reference counted and must be cleaned up appropriately. */ |
872 | struct cfg80211_bss* | 874 | struct cfg80211_bss* |
873 | cfg80211_inform_bss(struct wiphy *wiphy, | 875 | cfg80211_inform_bss_width(struct wiphy *wiphy, |
874 | struct ieee80211_channel *channel, | 876 | struct ieee80211_channel *channel, |
875 | const u8 *bssid, u64 tsf, u16 capability, | 877 | enum nl80211_bss_scan_width scan_width, |
876 | u16 beacon_interval, const u8 *ie, size_t ielen, | 878 | const u8 *bssid, u64 tsf, u16 capability, |
877 | s32 signal, gfp_t gfp) | 879 | u16 beacon_interval, const u8 *ie, size_t ielen, |
880 | s32 signal, gfp_t gfp) | ||
878 | { | 881 | { |
879 | struct cfg80211_bss_ies *ies; | 882 | struct cfg80211_bss_ies *ies; |
880 | struct cfg80211_internal_bss tmp = {}, *res; | 883 | struct cfg80211_internal_bss tmp = {}, *res; |
@@ -892,6 +895,7 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
892 | 895 | ||
893 | memcpy(tmp.pub.bssid, bssid, ETH_ALEN); | 896 | memcpy(tmp.pub.bssid, bssid, ETH_ALEN); |
894 | tmp.pub.channel = channel; | 897 | tmp.pub.channel = channel; |
898 | tmp.pub.scan_width = scan_width; | ||
895 | tmp.pub.signal = signal; | 899 | tmp.pub.signal = signal; |
896 | tmp.pub.beacon_interval = beacon_interval; | 900 | tmp.pub.beacon_interval = beacon_interval; |
897 | tmp.pub.capability = capability; | 901 | tmp.pub.capability = capability; |
@@ -924,14 +928,15 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
924 | /* cfg80211_bss_update gives us a referenced result */ | 928 | /* cfg80211_bss_update gives us a referenced result */ |
925 | return &res->pub; | 929 | return &res->pub; |
926 | } | 930 | } |
927 | EXPORT_SYMBOL(cfg80211_inform_bss); | 931 | EXPORT_SYMBOL(cfg80211_inform_bss_width); |
928 | 932 | ||
929 | /* Returned bss is reference counted and must be cleaned up appropriately. */ | 933 | /* Returned bss is reference counted and must be cleaned up appropriately. */ |
930 | struct cfg80211_bss * | 934 | struct cfg80211_bss * |
931 | cfg80211_inform_bss_frame(struct wiphy *wiphy, | 935 | cfg80211_inform_bss_width_frame(struct wiphy *wiphy, |
932 | struct ieee80211_channel *channel, | 936 | struct ieee80211_channel *channel, |
933 | struct ieee80211_mgmt *mgmt, size_t len, | 937 | enum nl80211_bss_scan_width scan_width, |
934 | s32 signal, gfp_t gfp) | 938 | struct ieee80211_mgmt *mgmt, size_t len, |
939 | s32 signal, gfp_t gfp) | ||
935 | { | 940 | { |
936 | struct cfg80211_internal_bss tmp = {}, *res; | 941 | struct cfg80211_internal_bss tmp = {}, *res; |
937 | struct cfg80211_bss_ies *ies; | 942 | struct cfg80211_bss_ies *ies; |
@@ -941,7 +946,8 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
941 | BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != | 946 | BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != |
942 | offsetof(struct ieee80211_mgmt, u.beacon.variable)); | 947 | offsetof(struct ieee80211_mgmt, u.beacon.variable)); |
943 | 948 | ||
944 | trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal); | 949 | trace_cfg80211_inform_bss_width_frame(wiphy, channel, scan_width, mgmt, |
950 | len, signal); | ||
945 | 951 | ||
946 | if (WARN_ON(!mgmt)) | 952 | if (WARN_ON(!mgmt)) |
947 | return NULL; | 953 | return NULL; |
@@ -976,6 +982,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
976 | 982 | ||
977 | memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN); | 983 | memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN); |
978 | tmp.pub.channel = channel; | 984 | tmp.pub.channel = channel; |
985 | tmp.pub.scan_width = scan_width; | ||
979 | tmp.pub.signal = signal; | 986 | tmp.pub.signal = signal; |
980 | tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); | 987 | tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); |
981 | tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); | 988 | tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); |
@@ -991,7 +998,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
991 | /* cfg80211_bss_update gives us a referenced result */ | 998 | /* cfg80211_bss_update gives us a referenced result */ |
992 | return &res->pub; | 999 | return &res->pub; |
993 | } | 1000 | } |
994 | EXPORT_SYMBOL(cfg80211_inform_bss_frame); | 1001 | EXPORT_SYMBOL(cfg80211_inform_bss_width_frame); |
995 | 1002 | ||
996 | void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | 1003 | void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) |
997 | { | 1004 | { |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index e1534baf2ebb..f0ebdcd394ef 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1841,6 +1841,39 @@ TRACE_EVENT(rdev_crit_proto_stop, | |||
1841 | WIPHY_PR_ARG, WDEV_PR_ARG) | 1841 | WIPHY_PR_ARG, WDEV_PR_ARG) |
1842 | ); | 1842 | ); |
1843 | 1843 | ||
1844 | TRACE_EVENT(rdev_channel_switch, | ||
1845 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
1846 | struct cfg80211_csa_settings *params), | ||
1847 | TP_ARGS(wiphy, netdev, params), | ||
1848 | TP_STRUCT__entry( | ||
1849 | WIPHY_ENTRY | ||
1850 | NETDEV_ENTRY | ||
1851 | CHAN_DEF_ENTRY | ||
1852 | __field(u16, counter_offset_beacon) | ||
1853 | __field(u16, counter_offset_presp) | ||
1854 | __field(bool, radar_required) | ||
1855 | __field(bool, block_tx) | ||
1856 | __field(u8, count) | ||
1857 | ), | ||
1858 | TP_fast_assign( | ||
1859 | WIPHY_ASSIGN; | ||
1860 | NETDEV_ASSIGN; | ||
1861 | CHAN_DEF_ASSIGN(¶ms->chandef); | ||
1862 | __entry->counter_offset_beacon = params->counter_offset_beacon; | ||
1863 | __entry->counter_offset_presp = params->counter_offset_presp; | ||
1864 | __entry->radar_required = params->radar_required; | ||
1865 | __entry->block_tx = params->block_tx; | ||
1866 | __entry->count = params->count; | ||
1867 | ), | ||
1868 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT | ||
1869 | ", block_tx: %d, count: %u, radar_required: %d" | ||
1870 | ", counter offsets (beacon/presp): %u/%u", | ||
1871 | WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG, | ||
1872 | __entry->block_tx, __entry->count, __entry->radar_required, | ||
1873 | __entry->counter_offset_beacon, | ||
1874 | __entry->counter_offset_presp) | ||
1875 | ); | ||
1876 | |||
1844 | /************************************************************* | 1877 | /************************************************************* |
1845 | * cfg80211 exported functions traces * | 1878 | * cfg80211 exported functions traces * |
1846 | *************************************************************/ | 1879 | *************************************************************/ |
@@ -2391,26 +2424,30 @@ TRACE_EVENT(cfg80211_get_bss, | |||
2391 | __entry->capa_mask, __entry->capa_val) | 2424 | __entry->capa_mask, __entry->capa_val) |
2392 | ); | 2425 | ); |
2393 | 2426 | ||
2394 | TRACE_EVENT(cfg80211_inform_bss_frame, | 2427 | TRACE_EVENT(cfg80211_inform_bss_width_frame, |
2395 | TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, | 2428 | TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, |
2429 | enum nl80211_bss_scan_width scan_width, | ||
2396 | struct ieee80211_mgmt *mgmt, size_t len, | 2430 | struct ieee80211_mgmt *mgmt, size_t len, |
2397 | s32 signal), | 2431 | s32 signal), |
2398 | TP_ARGS(wiphy, channel, mgmt, len, signal), | 2432 | TP_ARGS(wiphy, channel, scan_width, mgmt, len, signal), |
2399 | TP_STRUCT__entry( | 2433 | TP_STRUCT__entry( |
2400 | WIPHY_ENTRY | 2434 | WIPHY_ENTRY |
2401 | CHAN_ENTRY | 2435 | CHAN_ENTRY |
2436 | __field(enum nl80211_bss_scan_width, scan_width) | ||
2402 | __dynamic_array(u8, mgmt, len) | 2437 | __dynamic_array(u8, mgmt, len) |
2403 | __field(s32, signal) | 2438 | __field(s32, signal) |
2404 | ), | 2439 | ), |
2405 | TP_fast_assign( | 2440 | TP_fast_assign( |
2406 | WIPHY_ASSIGN; | 2441 | WIPHY_ASSIGN; |
2407 | CHAN_ASSIGN(channel); | 2442 | CHAN_ASSIGN(channel); |
2443 | __entry->scan_width = scan_width; | ||
2408 | if (mgmt) | 2444 | if (mgmt) |
2409 | memcpy(__get_dynamic_array(mgmt), mgmt, len); | 2445 | memcpy(__get_dynamic_array(mgmt), mgmt, len); |
2410 | __entry->signal = signal; | 2446 | __entry->signal = signal; |
2411 | ), | 2447 | ), |
2412 | TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "signal: %d", | 2448 | TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "(scan_width: %d) signal: %d", |
2413 | WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal) | 2449 | WIPHY_PR_ARG, CHAN_PR_ARG, __entry->scan_width, |
2450 | __entry->signal) | ||
2414 | ); | 2451 | ); |
2415 | 2452 | ||
2416 | DECLARE_EVENT_CLASS(cfg80211_bss_evt, | 2453 | DECLARE_EVENT_CLASS(cfg80211_bss_evt, |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 74458b7f61eb..ce090c1c5e4f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -33,7 +33,8 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | |||
33 | } | 33 | } |
34 | EXPORT_SYMBOL(ieee80211_get_response_rate); | 34 | EXPORT_SYMBOL(ieee80211_get_response_rate); |
35 | 35 | ||
36 | u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband) | 36 | u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband, |
37 | enum nl80211_bss_scan_width scan_width) | ||
37 | { | 38 | { |
38 | struct ieee80211_rate *bitrates; | 39 | struct ieee80211_rate *bitrates; |
39 | u32 mandatory_rates = 0; | 40 | u32 mandatory_rates = 0; |
@@ -43,10 +44,15 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband) | |||
43 | if (WARN_ON(!sband)) | 44 | if (WARN_ON(!sband)) |
44 | return 1; | 45 | return 1; |
45 | 46 | ||
46 | if (sband->band == IEEE80211_BAND_2GHZ) | 47 | if (sband->band == IEEE80211_BAND_2GHZ) { |
47 | mandatory_flag = IEEE80211_RATE_MANDATORY_B; | 48 | if (scan_width == NL80211_BSS_CHAN_WIDTH_5 || |
48 | else | 49 | scan_width == NL80211_BSS_CHAN_WIDTH_10) |
50 | mandatory_flag = IEEE80211_RATE_MANDATORY_G; | ||
51 | else | ||
52 | mandatory_flag = IEEE80211_RATE_MANDATORY_B; | ||
53 | } else { | ||
49 | mandatory_flag = IEEE80211_RATE_MANDATORY_A; | 54 | mandatory_flag = IEEE80211_RATE_MANDATORY_A; |
55 | } | ||
50 | 56 | ||
51 | bitrates = sband->bitrates; | 57 | bitrates = sband->bitrates; |
52 | for (i = 0; i < sband->n_bitrates; i++) | 58 | for (i = 0; i < sband->n_bitrates; i++) |