diff options
Diffstat (limited to 'net')
37 files changed, 1194 insertions, 522 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e75d5c53e97b..ff090ef1ea2c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -428,11 +428,13 @@ void sta_set_rate_info_tx(struct sta_info *sta, | |||
| 428 | rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); | 428 | rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); |
| 429 | } | 429 | } |
| 430 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 430 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
| 431 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 431 | rinfo->bw = RATE_INFO_BW_40; |
| 432 | if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) | 432 | else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) |
| 433 | rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | 433 | rinfo->bw = RATE_INFO_BW_80; |
| 434 | if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) | 434 | else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) |
| 435 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 435 | rinfo->bw = RATE_INFO_BW_160; |
| 436 | else | ||
| 437 | rinfo->bw = RATE_INFO_BW_20; | ||
| 436 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) | 438 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) |
| 437 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; | 439 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; |
| 438 | } | 440 | } |
| @@ -459,16 +461,21 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) | |||
| 459 | rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); | 461 | rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); |
| 460 | } | 462 | } |
| 461 | 463 | ||
| 462 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) | ||
| 463 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
| 464 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) | 464 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) |
| 465 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; | 465 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; |
| 466 | if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80MHZ) | 466 | |
| 467 | rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | 467 | if (sta->last_rx_rate_flag & RX_FLAG_5MHZ) |
| 468 | if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80P80MHZ) | 468 | rinfo->bw = RATE_INFO_BW_5; |
| 469 | rinfo->flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | 469 | else if (sta->last_rx_rate_flag & RX_FLAG_10MHZ) |
| 470 | if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_160MHZ) | 470 | rinfo->bw = RATE_INFO_BW_10; |
| 471 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 471 | else if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) |
| 472 | rinfo->bw = RATE_INFO_BW_40; | ||
| 473 | else if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80MHZ) | ||
| 474 | rinfo->bw = RATE_INFO_BW_80; | ||
| 475 | else if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_160MHZ) | ||
| 476 | rinfo->bw = RATE_INFO_BW_160; | ||
| 477 | else | ||
| 478 | rinfo->bw = RATE_INFO_BW_20; | ||
| 472 | } | 479 | } |
| 473 | 480 | ||
| 474 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | 481 | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, |
| @@ -678,7 +685,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 678 | BSS_CHANGED_BEACON_ENABLED | | 685 | BSS_CHANGED_BEACON_ENABLED | |
| 679 | BSS_CHANGED_BEACON | | 686 | BSS_CHANGED_BEACON | |
| 680 | BSS_CHANGED_SSID | | 687 | BSS_CHANGED_SSID | |
| 681 | BSS_CHANGED_P2P_PS; | 688 | BSS_CHANGED_P2P_PS | |
| 689 | BSS_CHANGED_TXPOWER; | ||
| 682 | int err; | 690 | int err; |
| 683 | 691 | ||
| 684 | old = sdata_dereference(sdata->u.ap.beacon, sdata); | 692 | old = sdata_dereference(sdata->u.ap.beacon, sdata); |
| @@ -2556,7 +2564,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2556 | 2564 | ||
| 2557 | /* if there's one pending or we're scanning, queue this one */ | 2565 | /* if there's one pending or we're scanning, queue this one */ |
| 2558 | if (!list_empty(&local->roc_list) || | 2566 | if (!list_empty(&local->roc_list) || |
| 2559 | local->scanning || local->radar_detect_enabled) | 2567 | local->scanning || ieee80211_is_radar_required(local)) |
| 2560 | goto out_check_combine; | 2568 | goto out_check_combine; |
| 2561 | 2569 | ||
| 2562 | /* if not HW assist, just queue & schedule work */ | 2570 | /* if not HW assist, just queue & schedule work */ |
| @@ -3664,7 +3672,7 @@ static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev, | |||
| 3664 | * queues. | 3672 | * queues. |
| 3665 | */ | 3673 | */ |
| 3666 | synchronize_net(); | 3674 | synchronize_net(); |
| 3667 | ieee80211_flush_queues(local, sdata); | 3675 | ieee80211_flush_queues(local, sdata, false); |
| 3668 | 3676 | ||
| 3669 | /* restore the normal QoS parameters | 3677 | /* restore the normal QoS parameters |
| 3670 | * (unconditionally to avoid races) | 3678 | * (unconditionally to avoid races) |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index da1c12c34487..35b11e11e0c4 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -388,7 +388,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
| 388 | return NULL; | 388 | return NULL; |
| 389 | } | 389 | } |
| 390 | 390 | ||
| 391 | static bool ieee80211_is_radar_required(struct ieee80211_local *local) | 391 | bool ieee80211_is_radar_required(struct ieee80211_local *local) |
| 392 | { | 392 | { |
| 393 | struct ieee80211_sub_if_data *sdata; | 393 | struct ieee80211_sub_if_data *sdata; |
| 394 | 394 | ||
| @@ -406,6 +406,34 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local) | |||
| 406 | return false; | 406 | return false; |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | static bool | ||
| 410 | ieee80211_chanctx_radar_required(struct ieee80211_local *local, | ||
| 411 | struct ieee80211_chanctx *ctx) | ||
| 412 | { | ||
| 413 | struct ieee80211_chanctx_conf *conf = &ctx->conf; | ||
| 414 | struct ieee80211_sub_if_data *sdata; | ||
| 415 | bool required = false; | ||
| 416 | |||
| 417 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 418 | lockdep_assert_held(&local->mtx); | ||
| 419 | |||
| 420 | rcu_read_lock(); | ||
| 421 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 422 | if (!ieee80211_sdata_running(sdata)) | ||
| 423 | continue; | ||
| 424 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) | ||
| 425 | continue; | ||
| 426 | if (!sdata->radar_required) | ||
| 427 | continue; | ||
| 428 | |||
| 429 | required = true; | ||
| 430 | break; | ||
| 431 | } | ||
| 432 | rcu_read_unlock(); | ||
| 433 | |||
| 434 | return required; | ||
| 435 | } | ||
| 436 | |||
| 409 | static struct ieee80211_chanctx * | 437 | static struct ieee80211_chanctx * |
| 410 | ieee80211_alloc_chanctx(struct ieee80211_local *local, | 438 | ieee80211_alloc_chanctx(struct ieee80211_local *local, |
| 411 | const struct cfg80211_chan_def *chandef, | 439 | const struct cfg80211_chan_def *chandef, |
| @@ -425,7 +453,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local, | |||
| 425 | ctx->conf.rx_chains_static = 1; | 453 | ctx->conf.rx_chains_static = 1; |
| 426 | ctx->conf.rx_chains_dynamic = 1; | 454 | ctx->conf.rx_chains_dynamic = 1; |
| 427 | ctx->mode = mode; | 455 | ctx->mode = mode; |
| 428 | ctx->conf.radar_enabled = ieee80211_is_radar_required(local); | 456 | ctx->conf.radar_enabled = false; |
| 429 | ieee80211_recalc_chanctx_min_def(local, ctx); | 457 | ieee80211_recalc_chanctx_min_def(local, ctx); |
| 430 | 458 | ||
| 431 | return ctx; | 459 | return ctx; |
| @@ -567,16 +595,15 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local, | |||
| 567 | bool radar_enabled; | 595 | bool radar_enabled; |
| 568 | 596 | ||
| 569 | lockdep_assert_held(&local->chanctx_mtx); | 597 | lockdep_assert_held(&local->chanctx_mtx); |
| 570 | /* for setting local->radar_detect_enabled */ | 598 | /* for ieee80211_is_radar_required */ |
| 571 | lockdep_assert_held(&local->mtx); | 599 | lockdep_assert_held(&local->mtx); |
| 572 | 600 | ||
| 573 | radar_enabled = ieee80211_is_radar_required(local); | 601 | radar_enabled = ieee80211_chanctx_radar_required(local, chanctx); |
| 574 | 602 | ||
| 575 | if (radar_enabled == chanctx->conf.radar_enabled) | 603 | if (radar_enabled == chanctx->conf.radar_enabled) |
| 576 | return; | 604 | return; |
| 577 | 605 | ||
| 578 | chanctx->conf.radar_enabled = radar_enabled; | 606 | chanctx->conf.radar_enabled = radar_enabled; |
| 579 | local->radar_detect_enabled = chanctx->conf.radar_enabled; | ||
| 580 | 607 | ||
| 581 | if (!local->use_chanctx) { | 608 | if (!local->use_chanctx) { |
| 582 | local->hw.conf.radar_enabled = chanctx->conf.radar_enabled; | 609 | local->hw.conf.radar_enabled = chanctx->conf.radar_enabled; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 54a189f0393e..eeb0bbd69d98 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
| @@ -303,8 +303,6 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf, | |||
| 303 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); | 303 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); |
| 304 | if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) | 304 | if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) |
| 305 | sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); | 305 | sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); |
| 306 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | ||
| 307 | sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); | ||
| 308 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 306 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
| 309 | sf += scnprintf(buf + sf, mxln - sf, | 307 | sf += scnprintf(buf + sf, mxln - sf, |
| 310 | "REPORTS_TX_ACK_STATUS\n"); | 308 | "REPORTS_TX_ACK_STATUS\n"); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 2ebc9ead9695..fdeda17b8dd2 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -639,6 +639,21 @@ static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local, | |||
| 639 | trace_drv_return_void(local); | 639 | trace_drv_return_void(local); |
| 640 | } | 640 | } |
| 641 | 641 | ||
| 642 | static inline void drv_sta_statistics(struct ieee80211_local *local, | ||
| 643 | struct ieee80211_sub_if_data *sdata, | ||
| 644 | struct ieee80211_sta *sta, | ||
| 645 | struct station_info *sinfo) | ||
| 646 | { | ||
| 647 | sdata = get_bss_sdata(sdata); | ||
| 648 | if (!check_sdata_in_driver(sdata)) | ||
| 649 | return; | ||
| 650 | |||
| 651 | trace_drv_sta_statistics(local, sdata, sta); | ||
| 652 | if (local->ops->sta_statistics) | ||
| 653 | local->ops->sta_statistics(&local->hw, &sdata->vif, sta, sinfo); | ||
| 654 | trace_drv_return_void(local); | ||
| 655 | } | ||
| 656 | |||
| 642 | static inline int drv_conf_tx(struct ieee80211_local *local, | 657 | static inline int drv_conf_tx(struct ieee80211_local *local, |
| 643 | struct ieee80211_sub_if_data *sdata, u16 ac, | 658 | struct ieee80211_sub_if_data *sdata, u16 ac, |
| 644 | const struct ieee80211_tx_queue_params *params) | 659 | const struct ieee80211_tx_queue_params *params) |
| @@ -966,21 +981,6 @@ drv_allow_buffered_frames(struct ieee80211_local *local, | |||
| 966 | trace_drv_return_void(local); | 981 | trace_drv_return_void(local); |
| 967 | } | 982 | } |
| 968 | 983 | ||
| 969 | static inline int drv_get_rssi(struct ieee80211_local *local, | ||
| 970 | struct ieee80211_sub_if_data *sdata, | ||
| 971 | struct ieee80211_sta *sta, | ||
| 972 | s8 *rssi_dbm) | ||
| 973 | { | ||
| 974 | int ret; | ||
| 975 | |||
| 976 | might_sleep(); | ||
| 977 | |||
| 978 | ret = local->ops->get_rssi(&local->hw, &sdata->vif, sta, rssi_dbm); | ||
| 979 | trace_drv_get_rssi(local, sta, *rssi_dbm, ret); | ||
| 980 | |||
| 981 | return ret; | ||
| 982 | } | ||
| 983 | |||
| 984 | static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, | 984 | static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, |
| 985 | struct ieee80211_sub_if_data *sdata) | 985 | struct ieee80211_sub_if_data *sdata) |
| 986 | { | 986 | { |
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c index ebfc8091557b..52bcea6ad9e8 100644 --- a/net/mac80211/ethtool.c +++ b/net/mac80211/ethtool.c | |||
| @@ -117,16 +117,16 @@ static void ieee80211_get_stats(struct net_device *dev, | |||
| 117 | data[i++] = sta->sta_state; | 117 | data[i++] = sta->sta_state; |
| 118 | 118 | ||
| 119 | 119 | ||
| 120 | if (sinfo.filled & STATION_INFO_TX_BITRATE) | 120 | if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) |
| 121 | data[i] = 100000 * | 121 | data[i] = 100000 * |
| 122 | cfg80211_calculate_bitrate(&sinfo.txrate); | 122 | cfg80211_calculate_bitrate(&sinfo.txrate); |
| 123 | i++; | 123 | i++; |
| 124 | if (sinfo.filled & STATION_INFO_RX_BITRATE) | 124 | if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE)) |
| 125 | data[i] = 100000 * | 125 | data[i] = 100000 * |
| 126 | cfg80211_calculate_bitrate(&sinfo.rxrate); | 126 | cfg80211_calculate_bitrate(&sinfo.rxrate); |
| 127 | i++; | 127 | i++; |
| 128 | 128 | ||
| 129 | if (sinfo.filled & STATION_INFO_SIGNAL_AVG) | 129 | if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG)) |
| 130 | data[i] = (u8)sinfo.signal_avg; | 130 | data[i] = (u8)sinfo.signal_avg; |
| 131 | i++; | 131 | i++; |
| 132 | } else { | 132 | } else { |
| @@ -175,24 +175,24 @@ do_survey: | |||
| 175 | data[i++] = (u8)survey.noise; | 175 | data[i++] = (u8)survey.noise; |
| 176 | else | 176 | else |
| 177 | data[i++] = -1LL; | 177 | data[i++] = -1LL; |
| 178 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME) | 178 | if (survey.filled & SURVEY_INFO_TIME) |
| 179 | data[i++] = survey.channel_time; | 179 | data[i++] = survey.time; |
| 180 | else | 180 | else |
| 181 | data[i++] = -1LL; | 181 | data[i++] = -1LL; |
| 182 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY) | 182 | if (survey.filled & SURVEY_INFO_TIME_BUSY) |
| 183 | data[i++] = survey.channel_time_busy; | 183 | data[i++] = survey.time_busy; |
| 184 | else | 184 | else |
| 185 | data[i++] = -1LL; | 185 | data[i++] = -1LL; |
| 186 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) | 186 | if (survey.filled & SURVEY_INFO_TIME_EXT_BUSY) |
| 187 | data[i++] = survey.channel_time_ext_busy; | 187 | data[i++] = survey.time_ext_busy; |
| 188 | else | 188 | else |
| 189 | data[i++] = -1LL; | 189 | data[i++] = -1LL; |
| 190 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX) | 190 | if (survey.filled & SURVEY_INFO_TIME_RX) |
| 191 | data[i++] = survey.channel_time_rx; | 191 | data[i++] = survey.time_rx; |
| 192 | else | 192 | else |
| 193 | data[i++] = -1LL; | 193 | data[i++] = -1LL; |
| 194 | if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX) | 194 | if (survey.filled & SURVEY_INFO_TIME_TX) |
| 195 | data[i++] = survey.channel_time_tx; | 195 | data[i++] = survey.time_tx; |
| 196 | else | 196 | else |
| 197 | data[i++] = -1LL; | 197 | data[i++] = -1LL; |
| 198 | 198 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 509bc157ce55..b606b53a49a7 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -1069,9 +1069,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 1069 | } | 1069 | } |
| 1070 | 1070 | ||
| 1071 | if (sta && rates_updated) { | 1071 | if (sta && rates_updated) { |
| 1072 | drv_sta_rc_update(local, sdata, &sta->sta, | 1072 | u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; |
| 1073 | IEEE80211_RC_SUPP_RATES_CHANGED); | 1073 | u8 rx_nss = sta->sta.rx_nss; |
| 1074 | |||
| 1075 | /* Force rx_nss recalculation */ | ||
| 1076 | sta->sta.rx_nss = 0; | ||
| 1074 | rate_control_rate_init(sta); | 1077 | rate_control_rate_init(sta); |
| 1078 | if (sta->sta.rx_nss != rx_nss) | ||
| 1079 | changed |= IEEE80211_RC_NSS_CHANGED; | ||
| 1080 | |||
| 1081 | drv_sta_rc_update(local, sdata, &sta->sta, changed); | ||
| 1075 | } | 1082 | } |
| 1076 | 1083 | ||
| 1077 | rcu_read_unlock(); | 1084 | rcu_read_unlock(); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cc6e964d9837..156ea79e0157 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -1168,8 +1168,6 @@ struct ieee80211_local { | |||
| 1168 | /* wowlan is enabled -- don't reconfig on resume */ | 1168 | /* wowlan is enabled -- don't reconfig on resume */ |
| 1169 | bool wowlan; | 1169 | bool wowlan; |
| 1170 | 1170 | ||
| 1171 | /* DFS/radar detection is enabled */ | ||
| 1172 | bool radar_detect_enabled; | ||
| 1173 | struct work_struct radar_detected_work; | 1171 | struct work_struct radar_detected_work; |
| 1174 | 1172 | ||
| 1175 | /* number of RX chains the hardware has */ | 1173 | /* number of RX chains the hardware has */ |
| @@ -1704,6 +1702,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 1704 | struct ieee80211_supported_band *sband, | 1702 | struct ieee80211_supported_band *sband, |
| 1705 | const struct ieee80211_vht_cap *vht_cap_ie, | 1703 | const struct ieee80211_vht_cap *vht_cap_ie, |
| 1706 | struct sta_info *sta); | 1704 | struct sta_info *sta); |
| 1705 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta); | ||
| 1707 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); | 1706 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); |
| 1708 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); | 1707 | void ieee80211_sta_set_rx_nss(struct sta_info *sta); |
| 1709 | u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 1708 | u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
| @@ -1881,10 +1880,10 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
| 1881 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, | 1880 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, |
| 1882 | struct sk_buff_head *skbs); | 1881 | struct sk_buff_head *skbs); |
| 1883 | void ieee80211_flush_queues(struct ieee80211_local *local, | 1882 | void ieee80211_flush_queues(struct ieee80211_local *local, |
| 1884 | struct ieee80211_sub_if_data *sdata); | 1883 | struct ieee80211_sub_if_data *sdata, bool drop); |
| 1885 | void __ieee80211_flush_queues(struct ieee80211_local *local, | 1884 | void __ieee80211_flush_queues(struct ieee80211_local *local, |
| 1886 | struct ieee80211_sub_if_data *sdata, | 1885 | struct ieee80211_sub_if_data *sdata, |
| 1887 | unsigned int queues); | 1886 | unsigned int queues, bool drop); |
| 1888 | 1887 | ||
| 1889 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1888 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
| 1890 | u16 transaction, u16 auth_alg, u16 status, | 1889 | u16 transaction, u16 auth_alg, u16 status, |
| @@ -1981,6 +1980,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | |||
| 1981 | struct ieee80211_chanctx *chanctx); | 1980 | struct ieee80211_chanctx *chanctx); |
| 1982 | void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, | 1981 | void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local, |
| 1983 | struct ieee80211_chanctx *ctx); | 1982 | struct ieee80211_chanctx *ctx); |
| 1983 | bool ieee80211_is_radar_required(struct ieee80211_local *local); | ||
| 1984 | 1984 | ||
| 1985 | void ieee80211_dfs_cac_timer(unsigned long data); | 1985 | void ieee80211_dfs_cac_timer(unsigned long data); |
| 1986 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); | 1986 | void ieee80211_dfs_cac_timer_work(struct work_struct *work); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 417355390873..677422e11e07 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -93,7 +93,7 @@ static u32 __ieee80211_idle_on(struct ieee80211_local *local) | |||
| 93 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | 93 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) |
| 94 | return 0; | 94 | return 0; |
| 95 | 95 | ||
| 96 | ieee80211_flush_queues(local, NULL); | 96 | ieee80211_flush_queues(local, NULL, false); |
| 97 | 97 | ||
| 98 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | 98 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; |
| 99 | return IEEE80211_CONF_CHANGE_IDLE; | 99 | return IEEE80211_CONF_CHANGE_IDLE; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 0bb7038121ac..f8d9f0ee59bf 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -140,7 +140,8 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
| 140 | if (!ret) { | 140 | if (!ret) { |
| 141 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 141 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
| 142 | 142 | ||
| 143 | if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) | 143 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || |
| 144 | (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) | ||
| 144 | sdata->crypto_tx_tailroom_needed_cnt--; | 145 | sdata->crypto_tx_tailroom_needed_cnt--; |
| 145 | 146 | ||
| 146 | WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && | 147 | WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && |
| @@ -188,7 +189,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
| 188 | sta = key->sta; | 189 | sta = key->sta; |
| 189 | sdata = key->sdata; | 190 | sdata = key->sdata; |
| 190 | 191 | ||
| 191 | if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) | 192 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || |
| 193 | (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) | ||
| 192 | increment_tailroom_need_count(sdata); | 194 | increment_tailroom_need_count(sdata); |
| 193 | 195 | ||
| 194 | ret = drv_set_key(key->local, DISABLE_KEY, sdata, | 196 | ret = drv_set_key(key->local, DISABLE_KEY, sdata, |
| @@ -884,7 +886,8 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf) | |||
| 884 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 886 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { |
| 885 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 887 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
| 886 | 888 | ||
| 887 | if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) | 889 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || |
| 890 | (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) | ||
| 888 | increment_tailroom_need_count(key->sdata); | 891 | increment_tailroom_need_count(key->sdata); |
| 889 | } | 892 | } |
| 890 | 893 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 6ab99da38db9..d9ce33663c73 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -916,10 +916,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 916 | } | 916 | } |
| 917 | } | 917 | } |
| 918 | 918 | ||
| 919 | WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | ||
| 920 | && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), | ||
| 921 | "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); | ||
| 922 | |||
| 923 | /* | 919 | /* |
| 924 | * Calculate scan IE length -- we need this to alloc | 920 | * Calculate scan IE length -- we need this to alloc |
| 925 | * memory and to subtract from the driver limit. It | 921 | * memory and to subtract from the driver limit. It |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index b488e1859b18..fa94ca15ba95 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
| @@ -523,6 +523,13 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
| 523 | sdata->u.mesh.mshcfg.auto_open_plinks && | 523 | sdata->u.mesh.mshcfg.auto_open_plinks && |
| 524 | rssi_threshold_check(sdata, sta)) | 524 | rssi_threshold_check(sdata, sta)) |
| 525 | changed = mesh_plink_open(sta); | 525 | changed = mesh_plink_open(sta); |
| 526 | else if (sta->plink_state == NL80211_PLINK_LISTEN && | ||
| 527 | (sdata->u.mesh.user_mpm || | ||
| 528 | sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)) | ||
| 529 | cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, | ||
| 530 | elems->ie_start, | ||
| 531 | elems->total_len, | ||
| 532 | GFP_ATOMIC); | ||
| 526 | 533 | ||
| 527 | ieee80211_mps_frame_release(sta, elems); | 534 | ieee80211_mps_frame_release(sta, elems); |
| 528 | out: | 535 | out: |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2c36c4765f47..1875181ebd94 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -157,14 +157,18 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
| 157 | { | 157 | { |
| 158 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 158 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 159 | struct cfg80211_chan_def vht_chandef; | 159 | struct cfg80211_chan_def vht_chandef; |
| 160 | struct ieee80211_sta_ht_cap sta_ht_cap; | ||
| 160 | u32 ht_cfreq, ret; | 161 | u32 ht_cfreq, ret; |
| 161 | 162 | ||
| 163 | memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); | ||
| 164 | ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); | ||
| 165 | |||
| 162 | chandef->chan = channel; | 166 | chandef->chan = channel; |
| 163 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | 167 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; |
| 164 | chandef->center_freq1 = channel->center_freq; | 168 | chandef->center_freq1 = channel->center_freq; |
| 165 | chandef->center_freq2 = 0; | 169 | chandef->center_freq2 = 0; |
| 166 | 170 | ||
| 167 | if (!ht_cap || !ht_oper || !sband->ht_cap.ht_supported) { | 171 | if (!ht_cap || !ht_oper || !sta_ht_cap.ht_supported) { |
| 168 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | 172 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; |
| 169 | goto out; | 173 | goto out; |
| 170 | } | 174 | } |
| @@ -198,7 +202,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
| 198 | } | 202 | } |
| 199 | 203 | ||
| 200 | /* check 40 MHz support, if we have it */ | 204 | /* check 40 MHz support, if we have it */ |
| 201 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | 205 | if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { |
| 202 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 206 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
| 203 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 207 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
| 204 | chandef->width = NL80211_CHAN_WIDTH_40; | 208 | chandef->width = NL80211_CHAN_WIDTH_40; |
| @@ -1054,8 +1058,6 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) | |||
| 1054 | sdata->csa_block_tx = false; | 1058 | sdata->csa_block_tx = false; |
| 1055 | } | 1059 | } |
| 1056 | 1060 | ||
| 1057 | cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef); | ||
| 1058 | |||
| 1059 | sdata->vif.csa_active = false; | 1061 | sdata->vif.csa_active = false; |
| 1060 | ifmgd->csa_waiting_bcn = false; | 1062 | ifmgd->csa_waiting_bcn = false; |
| 1061 | 1063 | ||
| @@ -1067,6 +1069,8 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) | |||
| 1067 | &ifmgd->csa_connection_drop_work); | 1069 | &ifmgd->csa_connection_drop_work); |
| 1068 | return; | 1070 | return; |
| 1069 | } | 1071 | } |
| 1072 | |||
| 1073 | cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef); | ||
| 1070 | } | 1074 | } |
| 1071 | 1075 | ||
| 1072 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | 1076 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) |
| @@ -1284,8 +1288,11 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
| 1284 | country_ie_len -= 3; | 1288 | country_ie_len -= 3; |
| 1285 | } | 1289 | } |
| 1286 | 1290 | ||
| 1287 | if (have_chan_pwr) | 1291 | if (have_chan_pwr && pwr_constr_elem) |
| 1288 | *pwr_reduction = *pwr_constr_elem; | 1292 | *pwr_reduction = *pwr_constr_elem; |
| 1293 | else | ||
| 1294 | *pwr_reduction = 0; | ||
| 1295 | |||
| 1289 | return have_chan_pwr; | 1296 | return have_chan_pwr; |
| 1290 | } | 1297 | } |
| 1291 | 1298 | ||
| @@ -1314,10 +1321,11 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
| 1314 | int chan_pwr = 0, pwr_reduction_80211h = 0; | 1321 | int chan_pwr = 0, pwr_reduction_80211h = 0; |
| 1315 | int pwr_level_cisco, pwr_level_80211h; | 1322 | int pwr_level_cisco, pwr_level_80211h; |
| 1316 | int new_ap_level; | 1323 | int new_ap_level; |
| 1324 | __le16 capab = mgmt->u.probe_resp.capab_info; | ||
| 1317 | 1325 | ||
| 1318 | if (country_ie && pwr_constr_ie && | 1326 | if (country_ie && |
| 1319 | mgmt->u.probe_resp.capab_info & | 1327 | (capab & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT) || |
| 1320 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) { | 1328 | capab & cpu_to_le16(WLAN_CAPABILITY_RADIO_MEASURE))) { |
| 1321 | has_80211h_pwr = ieee80211_find_80211h_pwr_constr( | 1329 | has_80211h_pwr = ieee80211_find_80211h_pwr_constr( |
| 1322 | sdata, channel, country_ie, country_ie_len, | 1330 | sdata, channel, country_ie, country_ie_len, |
| 1323 | pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h); | 1331 | pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h); |
| @@ -1596,7 +1604,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
| 1596 | } else { | 1604 | } else { |
| 1597 | ieee80211_send_nullfunc(local, sdata, 1); | 1605 | ieee80211_send_nullfunc(local, sdata, 1); |
| 1598 | /* Flush to get the tx status of nullfunc frame */ | 1606 | /* Flush to get the tx status of nullfunc frame */ |
| 1599 | ieee80211_flush_queues(local, sdata); | 1607 | ieee80211_flush_queues(local, sdata, false); |
| 1600 | } | 1608 | } |
| 1601 | } | 1609 | } |
| 1602 | 1610 | ||
| @@ -2003,18 +2011,23 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 2003 | /* disable per-vif ps */ | 2011 | /* disable per-vif ps */ |
| 2004 | ieee80211_recalc_ps_vif(sdata); | 2012 | ieee80211_recalc_ps_vif(sdata); |
| 2005 | 2013 | ||
| 2006 | /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ | 2014 | /* |
| 2015 | * drop any frame before deauth/disassoc, this can be data or | ||
| 2016 | * management frame. Since we are disconnecting, we should not | ||
| 2017 | * insist sending these frames which can take time and delay | ||
| 2018 | * the disconnection and possible the roaming. | ||
| 2019 | */ | ||
| 2007 | if (tx) | 2020 | if (tx) |
| 2008 | ieee80211_flush_queues(local, sdata); | 2021 | ieee80211_flush_queues(local, sdata, true); |
| 2009 | 2022 | ||
| 2010 | /* deauthenticate/disassociate now */ | 2023 | /* deauthenticate/disassociate now */ |
| 2011 | if (tx || frame_buf) | 2024 | if (tx || frame_buf) |
| 2012 | ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, | 2025 | ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, |
| 2013 | reason, tx, frame_buf); | 2026 | reason, tx, frame_buf); |
| 2014 | 2027 | ||
| 2015 | /* flush out frame */ | 2028 | /* flush out frame - make sure the deauth was actually sent */ |
| 2016 | if (tx) | 2029 | if (tx) |
| 2017 | ieee80211_flush_queues(local, sdata); | 2030 | ieee80211_flush_queues(local, sdata, false); |
| 2018 | 2031 | ||
| 2019 | /* clear bssid only after building the needed mgmt frames */ | 2032 | /* clear bssid only after building the needed mgmt frames */ |
| 2020 | memset(ifmgd->bssid, 0, ETH_ALEN); | 2033 | memset(ifmgd->bssid, 0, ETH_ALEN); |
| @@ -2440,6 +2453,12 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | |||
| 2440 | sdata_assert_lock(sdata); | 2453 | sdata_assert_lock(sdata); |
| 2441 | 2454 | ||
| 2442 | if (!assoc) { | 2455 | if (!assoc) { |
| 2456 | /* | ||
| 2457 | * we are not authenticated yet, the only timer that could be | ||
| 2458 | * running is the timeout for the authentication response which | ||
| 2459 | * which is not relevant anymore. | ||
| 2460 | */ | ||
| 2461 | del_timer_sync(&sdata->u.mgd.timer); | ||
| 2443 | sta_info_destroy_addr(sdata, auth_data->bss->bssid); | 2462 | sta_info_destroy_addr(sdata, auth_data->bss->bssid); |
| 2444 | 2463 | ||
| 2445 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 2464 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
| @@ -2747,6 +2766,12 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, | |||
| 2747 | sdata_assert_lock(sdata); | 2766 | sdata_assert_lock(sdata); |
| 2748 | 2767 | ||
| 2749 | if (!assoc) { | 2768 | if (!assoc) { |
| 2769 | /* | ||
| 2770 | * we are not associated yet, the only timer that could be | ||
| 2771 | * running is the timeout for the association response which | ||
| 2772 | * which is not relevant anymore. | ||
| 2773 | */ | ||
| 2774 | del_timer_sync(&sdata->u.mgd.timer); | ||
| 2750 | sta_info_destroy_addr(sdata, assoc_data->bss->bssid); | 2775 | sta_info_destroy_addr(sdata, assoc_data->bss->bssid); |
| 2751 | 2776 | ||
| 2752 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 2777 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
| @@ -4197,9 +4222,13 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
| 4197 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 4222 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 4198 | struct ieee80211_bss *bss = (void *)cbss->priv; | 4223 | struct ieee80211_bss *bss = (void *)cbss->priv; |
| 4199 | struct sta_info *new_sta = NULL; | 4224 | struct sta_info *new_sta = NULL; |
| 4200 | bool have_sta = false; | 4225 | struct ieee80211_supported_band *sband; |
| 4226 | struct ieee80211_sta_ht_cap sta_ht_cap; | ||
| 4227 | bool have_sta = false, is_override = false; | ||
| 4201 | int err; | 4228 | int err; |
| 4202 | 4229 | ||
| 4230 | sband = local->hw.wiphy->bands[cbss->channel->band]; | ||
| 4231 | |||
| 4203 | if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) | 4232 | if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) |
| 4204 | return -EINVAL; | 4233 | return -EINVAL; |
| 4205 | 4234 | ||
| @@ -4214,25 +4243,32 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
| 4214 | if (!new_sta) | 4243 | if (!new_sta) |
| 4215 | return -ENOMEM; | 4244 | return -ENOMEM; |
| 4216 | } | 4245 | } |
| 4246 | |||
| 4247 | memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); | ||
| 4248 | ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); | ||
| 4249 | |||
| 4250 | is_override = (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) != | ||
| 4251 | (sband->ht_cap.cap & | ||
| 4252 | IEEE80211_HT_CAP_SUP_WIDTH_20_40); | ||
| 4253 | |||
| 4254 | if (new_sta || is_override) { | ||
| 4255 | err = ieee80211_prep_channel(sdata, cbss); | ||
| 4256 | if (err) { | ||
| 4257 | if (new_sta) | ||
| 4258 | sta_info_free(local, new_sta); | ||
| 4259 | return -EINVAL; | ||
| 4260 | } | ||
| 4261 | } | ||
| 4262 | |||
| 4217 | if (new_sta) { | 4263 | if (new_sta) { |
| 4218 | u32 rates = 0, basic_rates = 0; | 4264 | u32 rates = 0, basic_rates = 0; |
| 4219 | bool have_higher_than_11mbit; | 4265 | bool have_higher_than_11mbit; |
| 4220 | int min_rate = INT_MAX, min_rate_index = -1; | 4266 | int min_rate = INT_MAX, min_rate_index = -1; |
| 4221 | struct ieee80211_chanctx_conf *chanctx_conf; | 4267 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 4222 | struct ieee80211_supported_band *sband; | ||
| 4223 | const struct cfg80211_bss_ies *ies; | 4268 | const struct cfg80211_bss_ies *ies; |
| 4224 | int shift; | 4269 | int shift = ieee80211_vif_get_shift(&sdata->vif); |
| 4225 | u32 rate_flags; | 4270 | u32 rate_flags; |
| 4226 | 4271 | ||
| 4227 | sband = local->hw.wiphy->bands[cbss->channel->band]; | ||
| 4228 | |||
| 4229 | err = ieee80211_prep_channel(sdata, cbss); | ||
| 4230 | if (err) { | ||
| 4231 | sta_info_free(local, new_sta); | ||
| 4232 | return -EINVAL; | ||
| 4233 | } | ||
| 4234 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
| 4235 | |||
| 4236 | rcu_read_lock(); | 4272 | rcu_read_lock(); |
| 4237 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 4273 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 4238 | if (WARN_ON(!chanctx_conf)) { | 4274 | if (WARN_ON(!chanctx_conf)) { |
| @@ -4668,8 +4704,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 4668 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 4704 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
| 4669 | rcu_read_unlock(); | 4705 | rcu_read_unlock(); |
| 4670 | 4706 | ||
| 4707 | if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) && | ||
| 4708 | (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), | ||
| 4709 | "U-APSD not supported with HW_PS_NULLFUNC_STACK\n")) | ||
| 4710 | sdata->vif.driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD; | ||
| 4711 | |||
| 4671 | if (bss->wmm_used && bss->uapsd_supported && | 4712 | if (bss->wmm_used && bss->uapsd_supported && |
| 4672 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | 4713 | (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD)) { |
| 4673 | assoc_data->uapsd = true; | 4714 | assoc_data->uapsd = true; |
| 4674 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; | 4715 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; |
| 4675 | } else { | 4716 | } else { |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index ff20b2ebdb30..683f0e3cb124 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
| @@ -121,7 +121,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local) | |||
| 121 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, | 121 | ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP, |
| 122 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, | 122 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
| 123 | false); | 123 | false); |
| 124 | ieee80211_flush_queues(local, NULL); | 124 | ieee80211_flush_queues(local, NULL, false); |
| 125 | 125 | ||
| 126 | mutex_lock(&local->iflist_mtx); | 126 | mutex_lock(&local->iflist_mtx); |
| 127 | list_for_each_entry(sdata, &local->interfaces, list) { | 127 | list_for_each_entry(sdata, &local->interfaces, list) { |
| @@ -398,7 +398,7 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
| 398 | ieee80211_roc_notify_destroy(roc, !roc->abort); | 398 | ieee80211_roc_notify_destroy(roc, !roc->abort); |
| 399 | 399 | ||
| 400 | if (started && !on_channel) { | 400 | if (started && !on_channel) { |
| 401 | ieee80211_flush_queues(local, NULL); | 401 | ieee80211_flush_queues(local, NULL, false); |
| 402 | 402 | ||
| 403 | local->tmp_channel = NULL; | 403 | local->tmp_channel = NULL; |
| 404 | ieee80211_hw_config(local, 0); | 404 | ieee80211_hw_config(local, 0); |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 4c5192e0d66c..8c8c67819072 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -41,7 +41,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 41 | /* flush out all packets */ | 41 | /* flush out all packets */ |
| 42 | synchronize_net(); | 42 | synchronize_net(); |
| 43 | 43 | ||
| 44 | ieee80211_flush_queues(local, NULL); | 44 | ieee80211_flush_queues(local, NULL, true); |
| 45 | 45 | ||
| 46 | local->quiescing = true; | 46 | local->quiescing = true; |
| 47 | /* make quiescing visible to timers everywhere */ | 47 | /* make quiescing visible to timers everywhere */ |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index d51f6b1c549b..7c86a002df95 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
| @@ -263,12 +263,12 @@ static inline unsigned int | |||
| 263 | minstrel_get_retry_count(struct minstrel_rate *mr, | 263 | minstrel_get_retry_count(struct minstrel_rate *mr, |
| 264 | struct ieee80211_tx_info *info) | 264 | struct ieee80211_tx_info *info) |
| 265 | { | 265 | { |
| 266 | unsigned int retry = mr->adjusted_retry_count; | 266 | u8 retry = mr->adjusted_retry_count; |
| 267 | 267 | ||
| 268 | if (info->control.use_rts) | 268 | if (info->control.use_rts) |
| 269 | retry = max(2U, min(mr->stats.retry_count_rtscts, retry)); | 269 | retry = max_t(u8, 2, min(mr->stats.retry_count_rtscts, retry)); |
| 270 | else if (info->control.use_cts_prot) | 270 | else if (info->control.use_cts_prot) |
| 271 | retry = max(2U, min(mr->retry_count_cts, retry)); | 271 | retry = max_t(u8, 2, min(mr->retry_count_cts, retry)); |
| 272 | return retry; | 272 | return retry; |
| 273 | } | 273 | } |
| 274 | 274 | ||
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 97eca86a4af0..410efe620c57 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
| @@ -33,8 +33,8 @@ minstrel_ewma(int old, int new, int weight) | |||
| 33 | 33 | ||
| 34 | struct minstrel_rate_stats { | 34 | struct minstrel_rate_stats { |
| 35 | /* current / last sampling period attempts/success counters */ | 35 | /* current / last sampling period attempts/success counters */ |
| 36 | unsigned int attempts, last_attempts; | 36 | u16 attempts, last_attempts; |
| 37 | unsigned int success, last_success; | 37 | u16 success, last_success; |
| 38 | 38 | ||
| 39 | /* total attempts/success counters */ | 39 | /* total attempts/success counters */ |
| 40 | u64 att_hist, succ_hist; | 40 | u64 att_hist, succ_hist; |
| @@ -46,8 +46,8 @@ struct minstrel_rate_stats { | |||
| 46 | unsigned int cur_prob, probability; | 46 | unsigned int cur_prob, probability; |
| 47 | 47 | ||
| 48 | /* maximum retry counts */ | 48 | /* maximum retry counts */ |
| 49 | unsigned int retry_count; | 49 | u8 retry_count; |
| 50 | unsigned int retry_count_rtscts; | 50 | u8 retry_count_rtscts; |
| 51 | 51 | ||
| 52 | u8 sample_skipped; | 52 | u8 sample_skipped; |
| 53 | bool retry_updated; | 53 | bool retry_updated; |
| @@ -55,14 +55,15 @@ struct minstrel_rate_stats { | |||
| 55 | 55 | ||
| 56 | struct minstrel_rate { | 56 | struct minstrel_rate { |
| 57 | int bitrate; | 57 | int bitrate; |
| 58 | int rix; | 58 | |
| 59 | s8 rix; | ||
| 60 | u8 retry_count_cts; | ||
| 61 | u8 adjusted_retry_count; | ||
| 59 | 62 | ||
| 60 | unsigned int perfect_tx_time; | 63 | unsigned int perfect_tx_time; |
| 61 | unsigned int ack_time; | 64 | unsigned int ack_time; |
| 62 | 65 | ||
| 63 | int sample_limit; | 66 | int sample_limit; |
| 64 | unsigned int retry_count_cts; | ||
| 65 | unsigned int adjusted_retry_count; | ||
| 66 | 67 | ||
| 67 | struct minstrel_rate_stats stats; | 68 | struct minstrel_rate_stats stats; |
| 68 | }; | 69 | }; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 683b10f46505..3d79d498e7f6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -361,9 +361,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 361 | u16 known = local->hw.radiotap_vht_details; | 361 | u16 known = local->hw.radiotap_vht_details; |
| 362 | 362 | ||
| 363 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); | 363 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); |
| 364 | /* known field - how to handle 80+80? */ | ||
| 365 | if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) | ||
| 366 | known &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; | ||
| 367 | put_unaligned_le16(known, pos); | 364 | put_unaligned_le16(known, pos); |
| 368 | pos += 2; | 365 | pos += 2; |
| 369 | /* flags */ | 366 | /* flags */ |
| @@ -378,8 +375,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 378 | /* bandwidth */ | 375 | /* bandwidth */ |
| 379 | if (status->vht_flag & RX_VHT_FLAG_80MHZ) | 376 | if (status->vht_flag & RX_VHT_FLAG_80MHZ) |
| 380 | *pos++ = 4; | 377 | *pos++ = 4; |
| 381 | else if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) | ||
| 382 | *pos++ = 0; /* marked not known above */ | ||
| 383 | else if (status->vht_flag & RX_VHT_FLAG_160MHZ) | 378 | else if (status->vht_flag & RX_VHT_FLAG_160MHZ) |
| 384 | *pos++ = 11; | 379 | *pos++ = 11; |
| 385 | else if (status->flag & RX_FLAG_40MHZ) | 380 | else if (status->flag & RX_FLAG_40MHZ) |
| @@ -2314,6 +2309,15 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
| 2314 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | 2309 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) |
| 2315 | return RX_DROP_MONITOR; | 2310 | return RX_DROP_MONITOR; |
| 2316 | 2311 | ||
| 2312 | if (rx->sta) { | ||
| 2313 | /* The security index has the same property as needed | ||
| 2314 | * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS | ||
| 2315 | * for non-QoS-data frames. Here we know it's a data | ||
| 2316 | * frame, so count MSDUs. | ||
| 2317 | */ | ||
| 2318 | rx->sta->rx_msdu[rx->security_idx]++; | ||
| 2319 | } | ||
| 2320 | |||
| 2317 | /* | 2321 | /* |
| 2318 | * Send unexpected-4addr-frame event to hostapd. For older versions, | 2322 | * Send unexpected-4addr-frame event to hostapd. For older versions, |
| 2319 | * also drop the frame to cooked monitor interfaces. | 2323 | * also drop the frame to cooked monitor interfaces. |
| @@ -2598,7 +2602,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2598 | case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { | 2602 | case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { |
| 2599 | struct ieee80211_supported_band *sband; | 2603 | struct ieee80211_supported_band *sband; |
| 2600 | u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; | 2604 | u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; |
| 2601 | enum ieee80211_sta_rx_bandwidth new_bw; | 2605 | enum ieee80211_sta_rx_bandwidth max_bw, new_bw; |
| 2602 | 2606 | ||
| 2603 | /* If it doesn't support 40 MHz it can't change ... */ | 2607 | /* If it doesn't support 40 MHz it can't change ... */ |
| 2604 | if (!(rx->sta->sta.ht_cap.cap & | 2608 | if (!(rx->sta->sta.ht_cap.cap & |
| @@ -2606,13 +2610,18 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2606 | goto handled; | 2610 | goto handled; |
| 2607 | 2611 | ||
| 2608 | if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) | 2612 | if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) |
| 2609 | new_bw = IEEE80211_STA_RX_BW_20; | 2613 | max_bw = IEEE80211_STA_RX_BW_20; |
| 2610 | else | 2614 | else |
| 2611 | new_bw = ieee80211_sta_cur_vht_bw(rx->sta); | 2615 | max_bw = ieee80211_sta_cap_rx_bw(rx->sta); |
| 2616 | |||
| 2617 | /* set cur_max_bandwidth and recalc sta bw */ | ||
| 2618 | rx->sta->cur_max_bandwidth = max_bw; | ||
| 2619 | new_bw = ieee80211_sta_cur_vht_bw(rx->sta); | ||
| 2612 | 2620 | ||
| 2613 | if (rx->sta->sta.bandwidth == new_bw) | 2621 | if (rx->sta->sta.bandwidth == new_bw) |
| 2614 | goto handled; | 2622 | goto handled; |
| 2615 | 2623 | ||
| 2624 | rx->sta->sta.bandwidth = new_bw; | ||
| 2616 | sband = rx->local->hw.wiphy->bands[status->band]; | 2625 | sband = rx->local->hw.wiphy->bands[status->band]; |
| 2617 | 2626 | ||
| 2618 | rate_control_rate_update(local, sband, rx->sta, | 2627 | rate_control_rate_update(local, sband, rx->sta, |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index ae842678b629..7807fa42ed3f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -416,7 +416,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local, | |||
| 416 | ieee80211_offchannel_stop_vifs(local); | 416 | ieee80211_offchannel_stop_vifs(local); |
| 417 | 417 | ||
| 418 | /* ensure nullfunc is transmitted before leaving operating channel */ | 418 | /* ensure nullfunc is transmitted before leaving operating channel */ |
| 419 | ieee80211_flush_queues(local, NULL); | 419 | ieee80211_flush_queues(local, NULL, false); |
| 420 | 420 | ||
| 421 | ieee80211_configure_filter(local); | 421 | ieee80211_configure_filter(local); |
| 422 | 422 | ||
| @@ -432,7 +432,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local, | |||
| 432 | static bool ieee80211_can_scan(struct ieee80211_local *local, | 432 | static bool ieee80211_can_scan(struct ieee80211_local *local, |
| 433 | struct ieee80211_sub_if_data *sdata) | 433 | struct ieee80211_sub_if_data *sdata) |
| 434 | { | 434 | { |
| 435 | if (local->radar_detect_enabled) | 435 | if (ieee80211_is_radar_required(local)) |
| 436 | return false; | 436 | return false; |
| 437 | 437 | ||
| 438 | if (!list_empty(&local->roc_list)) | 438 | if (!list_empty(&local->roc_list)) |
| @@ -505,7 +505,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 505 | 505 | ||
| 506 | lockdep_assert_held(&local->mtx); | 506 | lockdep_assert_held(&local->mtx); |
| 507 | 507 | ||
| 508 | if (local->scan_req) | 508 | if (local->scan_req || ieee80211_is_radar_required(local)) |
| 509 | return -EBUSY; | 509 | return -EBUSY; |
| 510 | 510 | ||
| 511 | if (!ieee80211_can_scan(local, sdata)) { | 511 | if (!ieee80211_can_scan(local, sdata)) { |
| @@ -805,7 +805,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local, | |||
| 805 | ieee80211_offchannel_stop_vifs(local); | 805 | ieee80211_offchannel_stop_vifs(local); |
| 806 | 806 | ||
| 807 | if (local->ops->flush) { | 807 | if (local->ops->flush) { |
| 808 | ieee80211_flush_queues(local, NULL); | 808 | ieee80211_flush_queues(local, NULL, false); |
| 809 | *next_delay = 0; | 809 | *next_delay = 0; |
| 810 | } else | 810 | } else |
| 811 | *next_delay = HZ / 10; | 811 | *next_delay = HZ / 10; |
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index efeba56c913b..06e6ac8cc693 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
| @@ -34,19 +34,15 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, | |||
| 34 | struct cfg80211_chan_def new_vht_chandef = {}; | 34 | struct cfg80211_chan_def new_vht_chandef = {}; |
| 35 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; | 35 | const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; |
| 36 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; | 36 | const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie; |
| 37 | const struct ieee80211_ht_operation *ht_oper; | ||
| 38 | int secondary_channel_offset = -1; | 37 | int secondary_channel_offset = -1; |
| 39 | 38 | ||
| 40 | sec_chan_offs = elems->sec_chan_offs; | 39 | sec_chan_offs = elems->sec_chan_offs; |
| 41 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; | 40 | wide_bw_chansw_ie = elems->wide_bw_chansw_ie; |
| 42 | ht_oper = elems->ht_operation; | ||
| 43 | 41 | ||
| 44 | if (sta_flags & (IEEE80211_STA_DISABLE_HT | | 42 | if (sta_flags & (IEEE80211_STA_DISABLE_HT | |
| 45 | IEEE80211_STA_DISABLE_40MHZ)) { | 43 | IEEE80211_STA_DISABLE_40MHZ)) { |
| 46 | sec_chan_offs = NULL; | 44 | sec_chan_offs = NULL; |
| 47 | wide_bw_chansw_ie = NULL; | 45 | wide_bw_chansw_ie = NULL; |
| 48 | /* only used for bandwidth here */ | ||
| 49 | ht_oper = NULL; | ||
| 50 | } | 46 | } |
| 51 | 47 | ||
| 52 | if (sta_flags & IEEE80211_STA_DISABLE_VHT) | 48 | if (sta_flags & IEEE80211_STA_DISABLE_VHT) |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a42f5b2b024d..79383ef0c264 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -116,7 +116,6 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
| 116 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | 116 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); |
| 117 | 117 | ||
| 118 | atomic_dec(&ps->num_sta_ps); | 118 | atomic_dec(&ps->num_sta_ps); |
| 119 | sta_info_recalc_tim(sta); | ||
| 120 | } | 119 | } |
| 121 | 120 | ||
| 122 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 121 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
| @@ -625,7 +624,7 @@ static unsigned long ieee80211_tids_for_ac(int ac) | |||
| 625 | } | 624 | } |
| 626 | } | 625 | } |
| 627 | 626 | ||
| 628 | void sta_info_recalc_tim(struct sta_info *sta) | 627 | static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending) |
| 629 | { | 628 | { |
| 630 | struct ieee80211_local *local = sta->local; | 629 | struct ieee80211_local *local = sta->local; |
| 631 | struct ps_data *ps; | 630 | struct ps_data *ps; |
| @@ -667,6 +666,9 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
| 667 | if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1) | 666 | if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1) |
| 668 | ignore_for_tim = 0; | 667 | ignore_for_tim = 0; |
| 669 | 668 | ||
| 669 | if (ignore_pending) | ||
| 670 | ignore_for_tim = BIT(IEEE80211_NUM_ACS) - 1; | ||
| 671 | |||
| 670 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 672 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
| 671 | unsigned long tids; | 673 | unsigned long tids; |
| 672 | 674 | ||
| @@ -695,7 +697,7 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
| 695 | else | 697 | else |
| 696 | __bss_tim_clear(ps->tim, id); | 698 | __bss_tim_clear(ps->tim, id); |
| 697 | 699 | ||
| 698 | if (local->ops->set_tim) { | 700 | if (local->ops->set_tim && !WARN_ON(sta->dead)) { |
| 699 | local->tim_in_locked_section = true; | 701 | local->tim_in_locked_section = true; |
| 700 | drv_set_tim(local, &sta->sta, indicate_tim); | 702 | drv_set_tim(local, &sta->sta, indicate_tim); |
| 701 | local->tim_in_locked_section = false; | 703 | local->tim_in_locked_section = false; |
| @@ -705,6 +707,11 @@ out_unlock: | |||
| 705 | spin_unlock_bh(&local->tim_lock); | 707 | spin_unlock_bh(&local->tim_lock); |
| 706 | } | 708 | } |
| 707 | 709 | ||
| 710 | void sta_info_recalc_tim(struct sta_info *sta) | ||
| 711 | { | ||
| 712 | __sta_info_recalc_tim(sta, false); | ||
| 713 | } | ||
| 714 | |||
| 708 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) | 715 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) |
| 709 | { | 716 | { |
| 710 | struct ieee80211_tx_info *info; | 717 | struct ieee80211_tx_info *info; |
| @@ -874,6 +881,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta) | |||
| 874 | { | 881 | { |
| 875 | struct ieee80211_local *local = sta->local; | 882 | struct ieee80211_local *local = sta->local; |
| 876 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 883 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 884 | struct station_info sinfo = {}; | ||
| 877 | int ret; | 885 | int ret; |
| 878 | 886 | ||
| 879 | /* | 887 | /* |
| @@ -887,6 +895,9 @@ static void __sta_info_destroy_part2(struct sta_info *sta) | |||
| 887 | /* now keys can no longer be reached */ | 895 | /* now keys can no longer be reached */ |
| 888 | ieee80211_free_sta_keys(local, sta); | 896 | ieee80211_free_sta_keys(local, sta); |
| 889 | 897 | ||
| 898 | /* disable TIM bit - last chance to tell driver */ | ||
| 899 | __sta_info_recalc_tim(sta, true); | ||
| 900 | |||
| 890 | sta->dead = true; | 901 | sta->dead = true; |
| 891 | 902 | ||
| 892 | local->num_sta--; | 903 | local->num_sta--; |
| @@ -908,7 +919,8 @@ static void __sta_info_destroy_part2(struct sta_info *sta) | |||
| 908 | 919 | ||
| 909 | sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); | 920 | sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); |
| 910 | 921 | ||
| 911 | cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); | 922 | sta_set_sinfo(sta, &sinfo); |
| 923 | cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
| 912 | 924 | ||
| 913 | rate_control_remove_sta_debugfs(sta); | 925 | rate_control_remove_sta_debugfs(sta); |
| 914 | ieee80211_sta_debugfs_remove(sta); | 926 | ieee80211_sta_debugfs_remove(sta); |
| @@ -1243,10 +1255,11 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
| 1243 | * ends the poll/service period. | 1255 | * ends the poll/service period. |
| 1244 | */ | 1256 | */ |
| 1245 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | | 1257 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | |
| 1246 | IEEE80211_TX_CTL_PS_RESPONSE | | ||
| 1247 | IEEE80211_TX_STATUS_EOSP | | 1258 | IEEE80211_TX_STATUS_EOSP | |
| 1248 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1259 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
| 1249 | 1260 | ||
| 1261 | info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; | ||
| 1262 | |||
| 1250 | if (call_driver) | 1263 | if (call_driver) |
| 1251 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, | 1264 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, |
| 1252 | reason, false); | 1265 | reason, false); |
| @@ -1395,8 +1408,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, | |||
| 1395 | * STA may still remain is PS mode after this frame | 1408 | * STA may still remain is PS mode after this frame |
| 1396 | * exchange. | 1409 | * exchange. |
| 1397 | */ | 1410 | */ |
| 1398 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER | | 1411 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; |
| 1399 | IEEE80211_TX_CTL_PS_RESPONSE; | 1412 | info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; |
| 1400 | 1413 | ||
| 1401 | /* | 1414 | /* |
| 1402 | * Use MoreData flag to indicate whether there are | 1415 | * Use MoreData flag to indicate whether there are |
| @@ -1743,7 +1756,6 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
| 1743 | struct ieee80211_local *local = sdata->local; | 1756 | struct ieee80211_local *local = sdata->local; |
| 1744 | struct rate_control_ref *ref = NULL; | 1757 | struct rate_control_ref *ref = NULL; |
| 1745 | struct timespec uptime; | 1758 | struct timespec uptime; |
| 1746 | u64 packets = 0; | ||
| 1747 | u32 thr = 0; | 1759 | u32 thr = 0; |
| 1748 | int i, ac; | 1760 | int i, ac; |
| 1749 | 1761 | ||
| @@ -1752,49 +1764,76 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
| 1752 | 1764 | ||
| 1753 | sinfo->generation = sdata->local->sta_generation; | 1765 | sinfo->generation = sdata->local->sta_generation; |
| 1754 | 1766 | ||
| 1755 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 1767 | drv_sta_statistics(local, sdata, &sta->sta, sinfo); |
| 1756 | STATION_INFO_RX_BYTES64 | | 1768 | |
| 1757 | STATION_INFO_TX_BYTES64 | | 1769 | sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME) | |
| 1758 | STATION_INFO_RX_PACKETS | | 1770 | BIT(NL80211_STA_INFO_STA_FLAGS) | |
| 1759 | STATION_INFO_TX_PACKETS | | 1771 | BIT(NL80211_STA_INFO_BSS_PARAM) | |
| 1760 | STATION_INFO_TX_RETRIES | | 1772 | BIT(NL80211_STA_INFO_CONNECTED_TIME) | |
| 1761 | STATION_INFO_TX_FAILED | | 1773 | BIT(NL80211_STA_INFO_RX_DROP_MISC) | |
| 1762 | STATION_INFO_TX_BITRATE | | 1774 | BIT(NL80211_STA_INFO_BEACON_LOSS); |
| 1763 | STATION_INFO_RX_BITRATE | | ||
| 1764 | STATION_INFO_RX_DROP_MISC | | ||
| 1765 | STATION_INFO_BSS_PARAM | | ||
| 1766 | STATION_INFO_CONNECTED_TIME | | ||
| 1767 | STATION_INFO_STA_FLAGS | | ||
| 1768 | STATION_INFO_BEACON_LOSS_COUNT; | ||
| 1769 | 1775 | ||
| 1770 | ktime_get_ts(&uptime); | 1776 | ktime_get_ts(&uptime); |
| 1771 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | 1777 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; |
| 1772 | |||
| 1773 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 1778 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
| 1774 | sinfo->tx_bytes = 0; | 1779 | |
| 1775 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 1780 | if (!(sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES64) | |
| 1776 | sinfo->tx_bytes += sta->tx_bytes[ac]; | 1781 | BIT(NL80211_STA_INFO_TX_BYTES)))) { |
| 1777 | packets += sta->tx_packets[ac]; | 1782 | sinfo->tx_bytes = 0; |
| 1783 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
| 1784 | sinfo->tx_bytes += sta->tx_bytes[ac]; | ||
| 1785 | sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64); | ||
| 1786 | } | ||
| 1787 | |||
| 1788 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_PACKETS))) { | ||
| 1789 | sinfo->tx_packets = 0; | ||
| 1790 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | ||
| 1791 | sinfo->tx_packets += sta->tx_packets[ac]; | ||
| 1792 | sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); | ||
| 1793 | } | ||
| 1794 | |||
| 1795 | if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) | | ||
| 1796 | BIT(NL80211_STA_INFO_RX_BYTES)))) { | ||
| 1797 | sinfo->rx_bytes = sta->rx_bytes; | ||
| 1798 | sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); | ||
| 1799 | } | ||
| 1800 | |||
| 1801 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_PACKETS))) { | ||
| 1802 | sinfo->rx_packets = sta->rx_packets; | ||
| 1803 | sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_RETRIES))) { | ||
| 1807 | sinfo->tx_retries = sta->tx_retry_count; | ||
| 1808 | sinfo->filled |= BIT(NL80211_STA_INFO_TX_RETRIES); | ||
| 1778 | } | 1809 | } |
| 1779 | sinfo->tx_packets = packets; | 1810 | |
| 1780 | sinfo->rx_bytes = sta->rx_bytes; | 1811 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_FAILED))) { |
| 1781 | sinfo->rx_packets = sta->rx_packets; | 1812 | sinfo->tx_failed = sta->tx_retry_failed; |
| 1782 | sinfo->tx_retries = sta->tx_retry_count; | 1813 | sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); |
| 1783 | sinfo->tx_failed = sta->tx_retry_failed; | 1814 | } |
| 1815 | |||
| 1784 | sinfo->rx_dropped_misc = sta->rx_dropped; | 1816 | sinfo->rx_dropped_misc = sta->rx_dropped; |
| 1785 | sinfo->beacon_loss_count = sta->beacon_loss_count; | 1817 | sinfo->beacon_loss_count = sta->beacon_loss_count; |
| 1786 | 1818 | ||
| 1787 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | 1819 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || |
| 1788 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | 1820 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { |
| 1789 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | 1821 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL))) { |
| 1790 | if (!local->ops->get_rssi || | ||
| 1791 | drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) | ||
| 1792 | sinfo->signal = (s8)sta->last_signal; | 1822 | sinfo->signal = (s8)sta->last_signal; |
| 1793 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | 1823 | sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); |
| 1824 | } | ||
| 1825 | |||
| 1826 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) { | ||
| 1827 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
| 1828 | sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG); | ||
| 1829 | } | ||
| 1794 | } | 1830 | } |
| 1795 | if (sta->chains) { | 1831 | |
| 1796 | sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | | 1832 | if (sta->chains && |
| 1797 | STATION_INFO_CHAIN_SIGNAL_AVG; | 1833 | !(sinfo->filled & (BIT(NL80211_STA_INFO_CHAIN_SIGNAL) | |
| 1834 | BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) { | ||
| 1835 | sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL) | | ||
| 1836 | BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG); | ||
| 1798 | 1837 | ||
| 1799 | sinfo->chains = sta->chains; | 1838 | sinfo->chains = sta->chains; |
| 1800 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { | 1839 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { |
| @@ -1804,23 +1843,61 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
| 1804 | } | 1843 | } |
| 1805 | } | 1844 | } |
| 1806 | 1845 | ||
| 1807 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | 1846 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))) { |
| 1808 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | 1847 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); |
| 1848 | sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE))) { | ||
| 1852 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | ||
| 1853 | sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); | ||
| 1854 | } | ||
| 1855 | |||
| 1856 | sinfo->filled |= BIT(NL80211_STA_INFO_TID_STATS); | ||
| 1857 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { | ||
| 1858 | struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i]; | ||
| 1859 | |||
| 1860 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) { | ||
| 1861 | tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU); | ||
| 1862 | tidstats->rx_msdu = sta->rx_msdu[i]; | ||
| 1863 | } | ||
| 1864 | |||
| 1865 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) { | ||
| 1866 | tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU); | ||
| 1867 | tidstats->tx_msdu = sta->tx_msdu[i]; | ||
| 1868 | } | ||
| 1869 | |||
| 1870 | if (!(tidstats->filled & | ||
| 1871 | BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) && | ||
| 1872 | local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | ||
| 1873 | tidstats->filled |= | ||
| 1874 | BIT(NL80211_TID_STATS_TX_MSDU_RETRIES); | ||
| 1875 | tidstats->tx_msdu_retries = sta->tx_msdu_retries[i]; | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | if (!(tidstats->filled & | ||
| 1879 | BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) && | ||
| 1880 | local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | ||
| 1881 | tidstats->filled |= | ||
| 1882 | BIT(NL80211_TID_STATS_TX_MSDU_FAILED); | ||
| 1883 | tidstats->tx_msdu_failed = sta->tx_msdu_failed[i]; | ||
| 1884 | } | ||
| 1885 | } | ||
| 1809 | 1886 | ||
| 1810 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 1887 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 1811 | #ifdef CONFIG_MAC80211_MESH | 1888 | #ifdef CONFIG_MAC80211_MESH |
| 1812 | sinfo->filled |= STATION_INFO_LLID | | 1889 | sinfo->filled |= BIT(NL80211_STA_INFO_LLID) | |
| 1813 | STATION_INFO_PLID | | 1890 | BIT(NL80211_STA_INFO_PLID) | |
| 1814 | STATION_INFO_PLINK_STATE | | 1891 | BIT(NL80211_STA_INFO_PLINK_STATE) | |
| 1815 | STATION_INFO_LOCAL_PM | | 1892 | BIT(NL80211_STA_INFO_LOCAL_PM) | |
| 1816 | STATION_INFO_PEER_PM | | 1893 | BIT(NL80211_STA_INFO_PEER_PM) | |
| 1817 | STATION_INFO_NONPEER_PM; | 1894 | BIT(NL80211_STA_INFO_NONPEER_PM); |
| 1818 | 1895 | ||
| 1819 | sinfo->llid = sta->llid; | 1896 | sinfo->llid = sta->llid; |
| 1820 | sinfo->plid = sta->plid; | 1897 | sinfo->plid = sta->plid; |
| 1821 | sinfo->plink_state = sta->plink_state; | 1898 | sinfo->plink_state = sta->plink_state; |
| 1822 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | 1899 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { |
| 1823 | sinfo->filled |= STATION_INFO_T_OFFSET; | 1900 | sinfo->filled |= BIT(NL80211_STA_INFO_T_OFFSET); |
| 1824 | sinfo->t_offset = sta->t_offset; | 1901 | sinfo->t_offset = sta->t_offset; |
| 1825 | } | 1902 | } |
| 1826 | sinfo->local_pm = sta->local_pm; | 1903 | sinfo->local_pm = sta->local_pm; |
| @@ -1869,7 +1946,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
| 1869 | thr = drv_get_expected_throughput(local, &sta->sta); | 1946 | thr = drv_get_expected_throughput(local, &sta->sta); |
| 1870 | 1947 | ||
| 1871 | if (thr != 0) { | 1948 | if (thr != 0) { |
| 1872 | sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; | 1949 | sinfo->filled |= BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT); |
| 1873 | sinfo->expected_throughput = thr; | 1950 | sinfo->expected_throughput = thr; |
| 1874 | } | 1951 | } |
| 1875 | } | 1952 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4f052bb2a5ad..925e68fe64c7 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
| @@ -346,6 +346,14 @@ struct ieee80211_tx_latency_stat { | |||
| 346 | * @cipher_scheme: optional cipher scheme for this station | 346 | * @cipher_scheme: optional cipher scheme for this station |
| 347 | * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed | 347 | * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed |
| 348 | * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) | 348 | * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) |
| 349 | * @tx_msdu: MSDUs transmitted to this station, using IEEE80211_NUM_TID | ||
| 350 | * entry for non-QoS frames | ||
| 351 | * @tx_msdu_retries: MSDU retries for transmissions to to this station, | ||
| 352 | * using IEEE80211_NUM_TID entry for non-QoS frames | ||
| 353 | * @tx_msdu_failed: MSDU failures for transmissions to to this station, | ||
| 354 | * using IEEE80211_NUM_TID entry for non-QoS frames | ||
| 355 | * @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID | ||
| 356 | * entry for non-QoS frames | ||
| 349 | */ | 357 | */ |
| 350 | struct sta_info { | 358 | struct sta_info { |
| 351 | /* General information, mostly static */ | 359 | /* General information, mostly static */ |
| @@ -416,6 +424,10 @@ struct sta_info { | |||
| 416 | u32 last_rx_rate_vht_flag; | 424 | u32 last_rx_rate_vht_flag; |
| 417 | u8 last_rx_rate_vht_nss; | 425 | u8 last_rx_rate_vht_nss; |
| 418 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; | 426 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; |
| 427 | u64 tx_msdu[IEEE80211_NUM_TIDS + 1]; | ||
| 428 | u64 tx_msdu_retries[IEEE80211_NUM_TIDS + 1]; | ||
| 429 | u64 tx_msdu_failed[IEEE80211_NUM_TIDS + 1]; | ||
| 430 | u64 rx_msdu[IEEE80211_NUM_TIDS + 1]; | ||
| 419 | 431 | ||
| 420 | /* | 432 | /* |
| 421 | * Aggregation information, locked with lock. | 433 | * Aggregation information, locked with lock. |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index bb146f377ee4..e679b7c9b160 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
| @@ -664,13 +664,15 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw, | |||
| 664 | struct ieee80211_supported_band *sband; | 664 | struct ieee80211_supported_band *sband; |
| 665 | int retry_count; | 665 | int retry_count; |
| 666 | int rates_idx; | 666 | int rates_idx; |
| 667 | bool acked; | 667 | bool acked, noack_success; |
| 668 | 668 | ||
| 669 | rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); | 669 | rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); |
| 670 | 670 | ||
| 671 | sband = hw->wiphy->bands[info->band]; | 671 | sband = hw->wiphy->bands[info->band]; |
| 672 | 672 | ||
| 673 | acked = !!(info->flags & IEEE80211_TX_STAT_ACK); | 673 | acked = !!(info->flags & IEEE80211_TX_STAT_ACK); |
| 674 | noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED); | ||
| 675 | |||
| 674 | if (pubsta) { | 676 | if (pubsta) { |
| 675 | struct sta_info *sta; | 677 | struct sta_info *sta; |
| 676 | 678 | ||
| @@ -696,7 +698,7 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw, | |||
| 696 | rate_control_tx_status_noskb(local, sband, sta, info); | 698 | rate_control_tx_status_noskb(local, sband, sta, info); |
| 697 | } | 699 | } |
| 698 | 700 | ||
| 699 | if (acked) { | 701 | if (acked || noack_success) { |
| 700 | local->dot11TransmittedFrameCount++; | 702 | local->dot11TransmittedFrameCount++; |
| 701 | if (!pubsta) | 703 | if (!pubsta) |
| 702 | local->dot11MulticastTransmittedFrameCount++; | 704 | local->dot11MulticastTransmittedFrameCount++; |
| @@ -728,6 +730,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 728 | struct ieee80211_bar *bar; | 730 | struct ieee80211_bar *bar; |
| 729 | int rtap_len; | 731 | int rtap_len; |
| 730 | int shift = 0; | 732 | int shift = 0; |
| 733 | int tid = IEEE80211_NUM_TIDS; | ||
| 731 | 734 | ||
| 732 | rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); | 735 | rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); |
| 733 | 736 | ||
| @@ -771,7 +774,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 771 | 774 | ||
| 772 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && | 775 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && |
| 773 | (ieee80211_is_data_qos(fc))) { | 776 | (ieee80211_is_data_qos(fc))) { |
| 774 | u16 tid, ssn; | 777 | u16 ssn; |
| 775 | u8 *qc; | 778 | u8 *qc; |
| 776 | 779 | ||
| 777 | qc = ieee80211_get_qos_ctl(hdr); | 780 | qc = ieee80211_get_qos_ctl(hdr); |
| @@ -780,10 +783,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 780 | & IEEE80211_SCTL_SEQ); | 783 | & IEEE80211_SCTL_SEQ); |
| 781 | ieee80211_send_bar(&sta->sdata->vif, hdr->addr1, | 784 | ieee80211_send_bar(&sta->sdata->vif, hdr->addr1, |
| 782 | tid, ssn); | 785 | tid, ssn); |
| 786 | } else if (ieee80211_is_data_qos(fc)) { | ||
| 787 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
| 788 | |||
| 789 | tid = qc[0] & 0xf; | ||
| 783 | } | 790 | } |
| 784 | 791 | ||
| 785 | if (!acked && ieee80211_is_back_req(fc)) { | 792 | if (!acked && ieee80211_is_back_req(fc)) { |
| 786 | u16 tid, control; | 793 | u16 control; |
| 787 | 794 | ||
| 788 | /* | 795 | /* |
| 789 | * BAR failed, store the last SSN and retry sending | 796 | * BAR failed, store the last SSN and retry sending |
| @@ -811,6 +818,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 811 | if (!acked) | 818 | if (!acked) |
| 812 | sta->tx_retry_failed++; | 819 | sta->tx_retry_failed++; |
| 813 | sta->tx_retry_count += retry_count; | 820 | sta->tx_retry_count += retry_count; |
| 821 | |||
| 822 | if (ieee80211_is_data_present(fc)) { | ||
| 823 | if (!acked) | ||
| 824 | sta->tx_msdu_failed[tid]++; | ||
| 825 | sta->tx_msdu_retries[tid] += retry_count; | ||
| 826 | } | ||
| 814 | } | 827 | } |
| 815 | 828 | ||
| 816 | rate_control_tx_status(local, sband, sta, skb); | 829 | rate_control_tx_status(local, sband, sta, skb); |
| @@ -856,10 +869,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 856 | * Fragments are passed to low-level drivers as separate skbs, so these | 869 | * Fragments are passed to low-level drivers as separate skbs, so these |
| 857 | * are actually fragments, not frames. Update frame counters only for | 870 | * are actually fragments, not frames. Update frame counters only for |
| 858 | * the first fragment of the frame. */ | 871 | * the first fragment of the frame. */ |
| 859 | if (info->flags & IEEE80211_TX_STAT_ACK) { | 872 | if ((info->flags & IEEE80211_TX_STAT_ACK) || |
| 873 | (info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) { | ||
| 860 | if (ieee80211_is_first_frag(hdr->seq_ctrl)) { | 874 | if (ieee80211_is_first_frag(hdr->seq_ctrl)) { |
| 861 | local->dot11TransmittedFrameCount++; | 875 | local->dot11TransmittedFrameCount++; |
| 862 | if (is_multicast_ether_addr(hdr->addr1)) | 876 | if (is_multicast_ether_addr(ieee80211_get_DA(hdr))) |
| 863 | local->dot11MulticastTransmittedFrameCount++; | 877 | local->dot11MulticastTransmittedFrameCount++; |
| 864 | if (retry_count > 0) | 878 | if (retry_count > 0) |
| 865 | local->dot11RetryCount++; | 879 | local->dot11RetryCount++; |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 55ddd77b865d..917088dfd696 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
| @@ -68,17 +68,24 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata, | |||
| 68 | ch = ieee80211_get_channel(sdata->local->hw.wiphy, i); | 68 | ch = ieee80211_get_channel(sdata->local->hw.wiphy, i); |
| 69 | if (ch) { | 69 | if (ch) { |
| 70 | /* we will be active on the channel */ | 70 | /* we will be active on the channel */ |
| 71 | u32 flags = IEEE80211_CHAN_DISABLED | | ||
| 72 | IEEE80211_CHAN_NO_IR; | ||
| 73 | cfg80211_chandef_create(&chandef, ch, | 71 | cfg80211_chandef_create(&chandef, ch, |
| 74 | NL80211_CHAN_HT20); | 72 | NL80211_CHAN_NO_HT); |
| 75 | if (cfg80211_chandef_usable(sdata->local->hw.wiphy, | 73 | if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy, |
| 76 | &chandef, flags)) { | 74 | &chandef, |
| 75 | sdata->wdev.iftype)) { | ||
| 77 | ch_cnt++; | 76 | ch_cnt++; |
| 77 | /* | ||
| 78 | * check if the next channel is also part of | ||
| 79 | * this allowed range | ||
| 80 | */ | ||
| 78 | continue; | 81 | continue; |
| 79 | } | 82 | } |
| 80 | } | 83 | } |
| 81 | 84 | ||
| 85 | /* | ||
| 86 | * we've reached the end of a range, with allowed channels | ||
| 87 | * found | ||
| 88 | */ | ||
| 82 | if (ch_cnt) { | 89 | if (ch_cnt) { |
| 83 | u8 *pos = skb_put(skb, 2); | 90 | u8 *pos = skb_put(skb, 2); |
| 84 | *pos++ = ieee80211_frequency_to_channel(subband_start); | 91 | *pos++ = ieee80211_frequency_to_channel(subband_start); |
| @@ -89,6 +96,15 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata, | |||
| 89 | } | 96 | } |
| 90 | } | 97 | } |
| 91 | 98 | ||
| 99 | /* all channels in the requested range are allowed - add them here */ | ||
| 100 | if (ch_cnt) { | ||
| 101 | u8 *pos = skb_put(skb, 2); | ||
| 102 | *pos++ = ieee80211_frequency_to_channel(subband_start); | ||
| 103 | *pos++ = ch_cnt; | ||
| 104 | |||
| 105 | subband_cnt++; | ||
| 106 | } | ||
| 107 | |||
| 92 | return subband_cnt; | 108 | return subband_cnt; |
| 93 | } | 109 | } |
| 94 | 110 | ||
| @@ -912,7 +928,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
| 912 | rcu_read_unlock(); | 928 | rcu_read_unlock(); |
| 913 | } | 929 | } |
| 914 | 930 | ||
| 915 | ieee80211_flush_queues(local, sdata); | 931 | ieee80211_flush_queues(local, sdata, false); |
| 916 | 932 | ||
| 917 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 933 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
| 918 | dialog_token, status_code, | 934 | dialog_token, status_code, |
| @@ -952,7 +968,7 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, | |||
| 952 | */ | 968 | */ |
| 953 | ieee80211_stop_vif_queues(local, sdata, | 969 | ieee80211_stop_vif_queues(local, sdata, |
| 954 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); | 970 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); |
| 955 | ieee80211_flush_queues(local, sdata); | 971 | ieee80211_flush_queues(local, sdata, false); |
| 956 | 972 | ||
| 957 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 973 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
| 958 | dialog_token, status_code, | 974 | dialog_token, status_code, |
| @@ -1098,7 +1114,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
| 1098 | */ | 1114 | */ |
| 1099 | tasklet_kill(&local->tx_pending_tasklet); | 1115 | tasklet_kill(&local->tx_pending_tasklet); |
| 1100 | /* flush a potentially queued teardown packet */ | 1116 | /* flush a potentially queued teardown packet */ |
| 1101 | ieee80211_flush_queues(local, sdata); | 1117 | ieee80211_flush_queues(local, sdata, false); |
| 1102 | 1118 | ||
| 1103 | ret = sta_info_destroy_addr(sdata, peer); | 1119 | ret = sta_info_destroy_addr(sdata, peer); |
| 1104 | break; | 1120 | break; |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 8e461a02c6a8..263a9561eb26 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
| @@ -825,6 +825,13 @@ DECLARE_EVENT_CLASS(sta_event, | |||
| 825 | ) | 825 | ) |
| 826 | ); | 826 | ); |
| 827 | 827 | ||
| 828 | DEFINE_EVENT(sta_event, drv_sta_statistics, | ||
| 829 | TP_PROTO(struct ieee80211_local *local, | ||
| 830 | struct ieee80211_sub_if_data *sdata, | ||
| 831 | struct ieee80211_sta *sta), | ||
| 832 | TP_ARGS(local, sdata, sta) | ||
| 833 | ); | ||
| 834 | |||
| 828 | DEFINE_EVENT(sta_event, drv_sta_add, | 835 | DEFINE_EVENT(sta_event, drv_sta_add, |
| 829 | TP_PROTO(struct ieee80211_local *local, | 836 | TP_PROTO(struct ieee80211_local *local, |
| 830 | struct ieee80211_sub_if_data *sdata, | 837 | struct ieee80211_sub_if_data *sdata, |
| @@ -1329,32 +1336,6 @@ DEFINE_EVENT(release_evt, drv_allow_buffered_frames, | |||
| 1329 | TP_ARGS(local, sta, tids, num_frames, reason, more_data) | 1336 | TP_ARGS(local, sta, tids, num_frames, reason, more_data) |
| 1330 | ); | 1337 | ); |
| 1331 | 1338 | ||
| 1332 | TRACE_EVENT(drv_get_rssi, | ||
| 1333 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta, | ||
| 1334 | s8 rssi, int ret), | ||
| 1335 | |||
| 1336 | TP_ARGS(local, sta, rssi, ret), | ||
| 1337 | |||
| 1338 | TP_STRUCT__entry( | ||
| 1339 | LOCAL_ENTRY | ||
| 1340 | STA_ENTRY | ||
| 1341 | __field(s8, rssi) | ||
| 1342 | __field(int, ret) | ||
| 1343 | ), | ||
| 1344 | |||
| 1345 | TP_fast_assign( | ||
| 1346 | LOCAL_ASSIGN; | ||
| 1347 | STA_ASSIGN; | ||
| 1348 | __entry->rssi = rssi; | ||
| 1349 | __entry->ret = ret; | ||
| 1350 | ), | ||
| 1351 | |||
| 1352 | TP_printk( | ||
| 1353 | LOCAL_PR_FMT STA_PR_FMT " rssi:%d ret:%d", | ||
| 1354 | LOCAL_PR_ARG, STA_PR_ARG, __entry->rssi, __entry->ret | ||
| 1355 | ) | ||
| 1356 | ); | ||
| 1357 | |||
| 1358 | DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, | 1339 | DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, |
| 1359 | TP_PROTO(struct ieee80211_local *local, | 1340 | TP_PROTO(struct ieee80211_local *local, |
| 1360 | struct ieee80211_sub_if_data *sdata), | 1341 | struct ieee80211_sub_if_data *sdata), |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 058686a721a1..02ed6f60629a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -815,6 +815,8 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
| 815 | /* for pure STA mode without beacons, we can do it */ | 815 | /* for pure STA mode without beacons, we can do it */ |
| 816 | hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); | 816 | hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); |
| 817 | tx->sdata->sequence_number += 0x10; | 817 | tx->sdata->sequence_number += 0x10; |
| 818 | if (tx->sta) | ||
| 819 | tx->sta->tx_msdu[IEEE80211_NUM_TIDS]++; | ||
| 818 | return TX_CONTINUE; | 820 | return TX_CONTINUE; |
| 819 | } | 821 | } |
| 820 | 822 | ||
| @@ -831,6 +833,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
| 831 | qc = ieee80211_get_qos_ctl(hdr); | 833 | qc = ieee80211_get_qos_ctl(hdr); |
| 832 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; | 834 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; |
| 833 | seq = &tx->sta->tid_seq[tid]; | 835 | seq = &tx->sta->tid_seq[tid]; |
| 836 | tx->sta->tx_msdu[tid]++; | ||
| 834 | 837 | ||
| 835 | hdr->seq_ctrl = cpu_to_le16(*seq); | 838 | hdr->seq_ctrl = cpu_to_le16(*seq); |
| 836 | 839 | ||
| @@ -3152,7 +3155,7 @@ int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid) | |||
| 3152 | } | 3155 | } |
| 3153 | 3156 | ||
| 3154 | queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]); | 3157 | queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]); |
| 3155 | __ieee80211_flush_queues(local, sdata, queues); | 3158 | __ieee80211_flush_queues(local, sdata, queues, false); |
| 3156 | 3159 | ||
| 3157 | sta->reserved_tid = tid; | 3160 | sta->reserved_tid = tid; |
| 3158 | 3161 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 974ebe70f5b0..fbd37d43dfce 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -578,7 +578,7 @@ ieee80211_get_vif_queues(struct ieee80211_local *local, | |||
| 578 | 578 | ||
| 579 | void __ieee80211_flush_queues(struct ieee80211_local *local, | 579 | void __ieee80211_flush_queues(struct ieee80211_local *local, |
| 580 | struct ieee80211_sub_if_data *sdata, | 580 | struct ieee80211_sub_if_data *sdata, |
| 581 | unsigned int queues) | 581 | unsigned int queues, bool drop) |
| 582 | { | 582 | { |
| 583 | if (!local->ops->flush) | 583 | if (!local->ops->flush) |
| 584 | return; | 584 | return; |
| @@ -594,7 +594,7 @@ void __ieee80211_flush_queues(struct ieee80211_local *local, | |||
| 594 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 594 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
| 595 | false); | 595 | false); |
| 596 | 596 | ||
| 597 | drv_flush(local, sdata, queues, false); | 597 | drv_flush(local, sdata, queues, drop); |
| 598 | 598 | ||
| 599 | ieee80211_wake_queues_by_reason(&local->hw, queues, | 599 | ieee80211_wake_queues_by_reason(&local->hw, queues, |
| 600 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 600 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
| @@ -602,9 +602,9 @@ void __ieee80211_flush_queues(struct ieee80211_local *local, | |||
| 602 | } | 602 | } |
| 603 | 603 | ||
| 604 | void ieee80211_flush_queues(struct ieee80211_local *local, | 604 | void ieee80211_flush_queues(struct ieee80211_local *local, |
| 605 | struct ieee80211_sub_if_data *sdata) | 605 | struct ieee80211_sub_if_data *sdata, bool drop) |
| 606 | { | 606 | { |
| 607 | __ieee80211_flush_queues(local, sdata, 0); | 607 | __ieee80211_flush_queues(local, sdata, 0, drop); |
| 608 | } | 608 | } |
| 609 | 609 | ||
| 610 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | 610 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, |
| @@ -1470,10 +1470,12 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, | |||
| 1470 | 1470 | ||
| 1471 | /* Check if any channel in this sband supports at least 80 MHz */ | 1471 | /* Check if any channel in this sband supports at least 80 MHz */ |
| 1472 | for (i = 0; i < sband->n_channels; i++) { | 1472 | for (i = 0; i < sband->n_channels; i++) { |
| 1473 | if (!(sband->channels[i].flags & IEEE80211_CHAN_NO_80MHZ)) { | 1473 | if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | |
| 1474 | have_80mhz = true; | 1474 | IEEE80211_CHAN_NO_80MHZ)) |
| 1475 | break; | 1475 | continue; |
| 1476 | } | 1476 | |
| 1477 | have_80mhz = true; | ||
| 1478 | break; | ||
| 1477 | } | 1479 | } |
| 1478 | 1480 | ||
| 1479 | if (sband->vht_cap.vht_supported && have_80mhz) { | 1481 | if (sband->vht_cap.vht_supported && have_80mhz) { |
| @@ -1735,6 +1737,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1735 | struct cfg80211_sched_scan_request *sched_scan_req; | 1737 | struct cfg80211_sched_scan_request *sched_scan_req; |
| 1736 | bool sched_scan_stopped = false; | 1738 | bool sched_scan_stopped = false; |
| 1737 | 1739 | ||
| 1740 | /* nothing to do if HW shouldn't run */ | ||
| 1741 | if (!local->open_count) | ||
| 1742 | goto wake_up; | ||
| 1743 | |||
| 1738 | #ifdef CONFIG_PM | 1744 | #ifdef CONFIG_PM |
| 1739 | if (local->suspended) | 1745 | if (local->suspended) |
| 1740 | local->resuming = true; | 1746 | local->resuming = true; |
| @@ -1756,9 +1762,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1756 | reconfig_due_to_wowlan = true; | 1762 | reconfig_due_to_wowlan = true; |
| 1757 | } | 1763 | } |
| 1758 | #endif | 1764 | #endif |
| 1759 | /* everything else happens only if HW was up & running */ | ||
| 1760 | if (!local->open_count) | ||
| 1761 | goto wake_up; | ||
| 1762 | 1765 | ||
| 1763 | /* | 1766 | /* |
| 1764 | * Upon resume hardware can sometimes be goofy due to | 1767 | * Upon resume hardware can sometimes be goofy due to |
| @@ -2042,7 +2045,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 2042 | * If this is for hw restart things are still running. | 2045 | * If this is for hw restart things are still running. |
| 2043 | * We may want to change that later, however. | 2046 | * We may want to change that later, however. |
| 2044 | */ | 2047 | */ |
| 2045 | if (!local->suspended || reconfig_due_to_wowlan) | 2048 | if (local->open_count && (!local->suspended || reconfig_due_to_wowlan)) |
| 2046 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART); | 2049 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART); |
| 2047 | 2050 | ||
| 2048 | if (!local->suspended) | 2051 | if (!local->suspended) |
| @@ -2054,7 +2057,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 2054 | mb(); | 2057 | mb(); |
| 2055 | local->resuming = false; | 2058 | local->resuming = false; |
| 2056 | 2059 | ||
| 2057 | if (!reconfig_due_to_wowlan) | 2060 | if (local->open_count && !reconfig_due_to_wowlan) |
| 2058 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); | 2061 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); |
| 2059 | 2062 | ||
| 2060 | list_for_each_entry(sdata, &local->interfaces, list) { | 2063 | list_for_each_entry(sdata, &local->interfaces, list) { |
| @@ -2538,7 +2541,9 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
| 2538 | ri.mcs = status->rate_idx; | 2541 | ri.mcs = status->rate_idx; |
| 2539 | ri.flags |= RATE_INFO_FLAGS_MCS; | 2542 | ri.flags |= RATE_INFO_FLAGS_MCS; |
| 2540 | if (status->flag & RX_FLAG_40MHZ) | 2543 | if (status->flag & RX_FLAG_40MHZ) |
| 2541 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 2544 | ri.bw = RATE_INFO_BW_40; |
| 2545 | else | ||
| 2546 | ri.bw = RATE_INFO_BW_20; | ||
| 2542 | if (status->flag & RX_FLAG_SHORT_GI) | 2547 | if (status->flag & RX_FLAG_SHORT_GI) |
| 2543 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | 2548 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; |
| 2544 | } else if (status->flag & RX_FLAG_VHT) { | 2549 | } else if (status->flag & RX_FLAG_VHT) { |
| @@ -2546,13 +2551,13 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
| 2546 | ri.mcs = status->rate_idx; | 2551 | ri.mcs = status->rate_idx; |
| 2547 | ri.nss = status->vht_nss; | 2552 | ri.nss = status->vht_nss; |
| 2548 | if (status->flag & RX_FLAG_40MHZ) | 2553 | if (status->flag & RX_FLAG_40MHZ) |
| 2549 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 2554 | ri.bw = RATE_INFO_BW_40; |
| 2550 | if (status->vht_flag & RX_VHT_FLAG_80MHZ) | 2555 | else if (status->vht_flag & RX_VHT_FLAG_80MHZ) |
| 2551 | ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | 2556 | ri.bw = RATE_INFO_BW_80; |
| 2552 | if (status->vht_flag & RX_VHT_FLAG_80P80MHZ) | 2557 | else if (status->vht_flag & RX_VHT_FLAG_160MHZ) |
| 2553 | ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | 2558 | ri.bw = RATE_INFO_BW_160; |
| 2554 | if (status->vht_flag & RX_VHT_FLAG_160MHZ) | 2559 | else |
| 2555 | ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | 2560 | ri.bw = RATE_INFO_BW_20; |
| 2556 | if (status->flag & RX_FLAG_SHORT_GI) | 2561 | if (status->flag & RX_FLAG_SHORT_GI) |
| 2557 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | 2562 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; |
| 2558 | } else { | 2563 | } else { |
| @@ -2560,10 +2565,15 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | |||
| 2560 | int shift = 0; | 2565 | int shift = 0; |
| 2561 | int bitrate; | 2566 | int bitrate; |
| 2562 | 2567 | ||
| 2563 | if (status->flag & RX_FLAG_10MHZ) | 2568 | if (status->flag & RX_FLAG_10MHZ) { |
| 2564 | shift = 1; | 2569 | shift = 1; |
| 2565 | if (status->flag & RX_FLAG_5MHZ) | 2570 | ri.bw = RATE_INFO_BW_10; |
| 2571 | } else if (status->flag & RX_FLAG_5MHZ) { | ||
| 2566 | shift = 2; | 2572 | shift = 2; |
| 2573 | ri.bw = RATE_INFO_BW_5; | ||
| 2574 | } else { | ||
| 2575 | ri.bw = RATE_INFO_BW_20; | ||
| 2576 | } | ||
| 2567 | 2577 | ||
| 2568 | sband = local->hw.wiphy->bands[status->band]; | 2578 | sband = local->hw.wiphy->bands[status->band]; |
| 2569 | bitrate = sband->bitrates[status->rate_idx].bitrate; | 2579 | bitrate = sband->bitrates[status->rate_idx].bitrate; |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index bc9e8fc48785..85f9596da07b 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
| @@ -269,51 +269,54 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
| 269 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); | 269 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) | 272 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) |
| 273 | { | 273 | { |
| 274 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 274 | struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; |
| 275 | u32 cap = sta->sta.vht_cap.cap; | 275 | u32 cap_width; |
| 276 | enum ieee80211_sta_rx_bandwidth bw; | ||
| 277 | 276 | ||
| 278 | if (!sta->sta.vht_cap.vht_supported) { | 277 | if (!vht_cap->vht_supported) |
| 279 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | 278 | return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? |
| 280 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | 279 | IEEE80211_STA_RX_BW_40 : |
| 281 | goto check_max; | 280 | IEEE80211_STA_RX_BW_20; |
| 282 | } | ||
| 283 | 281 | ||
| 284 | switch (sdata->vif.bss_conf.chandef.width) { | 282 | cap_width = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; |
| 285 | default: | 283 | |
| 286 | WARN_ON_ONCE(1); | 284 | if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ || |
| 287 | /* fall through */ | 285 | cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) |
| 286 | return IEEE80211_STA_RX_BW_160; | ||
| 287 | |||
| 288 | return IEEE80211_STA_RX_BW_80; | ||
| 289 | } | ||
| 290 | |||
| 291 | static enum ieee80211_sta_rx_bandwidth | ||
| 292 | ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width) | ||
| 293 | { | ||
| 294 | switch (width) { | ||
| 288 | case NL80211_CHAN_WIDTH_20_NOHT: | 295 | case NL80211_CHAN_WIDTH_20_NOHT: |
| 289 | case NL80211_CHAN_WIDTH_20: | 296 | case NL80211_CHAN_WIDTH_20: |
| 290 | bw = IEEE80211_STA_RX_BW_20; | 297 | return IEEE80211_STA_RX_BW_20; |
| 291 | break; | ||
| 292 | case NL80211_CHAN_WIDTH_40: | 298 | case NL80211_CHAN_WIDTH_40: |
| 293 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | 299 | return IEEE80211_STA_RX_BW_40; |
| 294 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | 300 | case NL80211_CHAN_WIDTH_80: |
| 295 | break; | 301 | return IEEE80211_STA_RX_BW_80; |
| 296 | case NL80211_CHAN_WIDTH_160: | 302 | case NL80211_CHAN_WIDTH_160: |
| 297 | if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == | ||
| 298 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) { | ||
| 299 | bw = IEEE80211_STA_RX_BW_160; | ||
| 300 | break; | ||
| 301 | } | ||
| 302 | /* fall through */ | ||
| 303 | case NL80211_CHAN_WIDTH_80P80: | 303 | case NL80211_CHAN_WIDTH_80P80: |
| 304 | if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == | 304 | return IEEE80211_STA_RX_BW_160; |
| 305 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) { | 305 | default: |
| 306 | bw = IEEE80211_STA_RX_BW_160; | 306 | WARN_ON_ONCE(1); |
| 307 | break; | 307 | return IEEE80211_STA_RX_BW_20; |
| 308 | } | ||
| 309 | /* fall through */ | ||
| 310 | case NL80211_CHAN_WIDTH_80: | ||
| 311 | bw = IEEE80211_STA_RX_BW_80; | ||
| 312 | } | 308 | } |
| 309 | } | ||
| 310 | |||
| 311 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) | ||
| 312 | { | ||
| 313 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 314 | enum ieee80211_sta_rx_bandwidth bw; | ||
| 315 | |||
| 316 | bw = ieee80211_chan_width_to_rx_bw(sdata->vif.bss_conf.chandef.width); | ||
| 317 | bw = min(bw, ieee80211_sta_cap_rx_bw(sta)); | ||
| 318 | bw = min(bw, sta->cur_max_bandwidth); | ||
| 313 | 319 | ||
| 314 | check_max: | ||
| 315 | if (bw > sta->cur_max_bandwidth) | ||
| 316 | bw = sta->cur_max_bandwidth; | ||
| 317 | return bw; | 320 | return bw; |
| 318 | } | 321 | } |
| 319 | 322 | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 53dda7728f86..3af0ecf1cc16 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -320,6 +320,20 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) | |||
| 320 | rtnl_unlock(); | 320 | rtnl_unlock(); |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | static void cfg80211_sched_scan_stop_wk(struct work_struct *work) | ||
| 324 | { | ||
| 325 | struct cfg80211_registered_device *rdev; | ||
| 326 | |||
| 327 | rdev = container_of(work, struct cfg80211_registered_device, | ||
| 328 | sched_scan_stop_wk); | ||
| 329 | |||
| 330 | rtnl_lock(); | ||
| 331 | |||
| 332 | __cfg80211_stop_sched_scan(rdev, false); | ||
| 333 | |||
| 334 | rtnl_unlock(); | ||
| 335 | } | ||
| 336 | |||
| 323 | /* exported functions */ | 337 | /* exported functions */ |
| 324 | 338 | ||
| 325 | struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, | 339 | struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, |
| @@ -406,6 +420,7 @@ use_default_name: | |||
| 406 | INIT_LIST_HEAD(&rdev->destroy_list); | 420 | INIT_LIST_HEAD(&rdev->destroy_list); |
| 407 | spin_lock_init(&rdev->destroy_list_lock); | 421 | spin_lock_init(&rdev->destroy_list_lock); |
| 408 | INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); | 422 | INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); |
| 423 | INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk); | ||
| 409 | 424 | ||
| 410 | #ifdef CONFIG_CFG80211_DEFAULT_PS | 425 | #ifdef CONFIG_CFG80211_DEFAULT_PS |
| 411 | rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; | 426 | rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; |
| @@ -560,6 +575,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 560 | BIT(NL80211_IFTYPE_MONITOR))) | 575 | BIT(NL80211_IFTYPE_MONITOR))) |
| 561 | wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; | 576 | wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; |
| 562 | 577 | ||
| 578 | if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) && | ||
| 579 | (wiphy->regulatory_flags & | ||
| 580 | (REGULATORY_CUSTOM_REG | | ||
| 581 | REGULATORY_STRICT_REG | | ||
| 582 | REGULATORY_COUNTRY_IE_FOLLOW_POWER | | ||
| 583 | REGULATORY_COUNTRY_IE_IGNORE)))) | ||
| 584 | return -EINVAL; | ||
| 585 | |||
| 563 | if (WARN_ON(wiphy->coalesce && | 586 | if (WARN_ON(wiphy->coalesce && |
| 564 | (!wiphy->coalesce->n_rules || | 587 | (!wiphy->coalesce->n_rules || |
| 565 | !wiphy->coalesce->n_patterns) && | 588 | !wiphy->coalesce->n_patterns) && |
| @@ -778,6 +801,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
| 778 | flush_work(&rdev->event_work); | 801 | flush_work(&rdev->event_work); |
| 779 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); | 802 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); |
| 780 | flush_work(&rdev->destroy_work); | 803 | flush_work(&rdev->destroy_work); |
| 804 | flush_work(&rdev->sched_scan_stop_wk); | ||
| 781 | 805 | ||
| 782 | #ifdef CONFIG_PM | 806 | #ifdef CONFIG_PM |
| 783 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) | 807 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) |
| @@ -858,6 +882,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
| 858 | struct wireless_dev *wdev) | 882 | struct wireless_dev *wdev) |
| 859 | { | 883 | { |
| 860 | struct net_device *dev = wdev->netdev; | 884 | struct net_device *dev = wdev->netdev; |
| 885 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
| 861 | 886 | ||
| 862 | ASSERT_RTNL(); | 887 | ASSERT_RTNL(); |
| 863 | ASSERT_WDEV_LOCK(wdev); | 888 | ASSERT_WDEV_LOCK(wdev); |
| @@ -868,7 +893,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
| 868 | break; | 893 | break; |
| 869 | case NL80211_IFTYPE_P2P_CLIENT: | 894 | case NL80211_IFTYPE_P2P_CLIENT: |
| 870 | case NL80211_IFTYPE_STATION: | 895 | case NL80211_IFTYPE_STATION: |
| 871 | if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) | 896 | sched_scan_req = rtnl_dereference(rdev->sched_scan_req); |
| 897 | if (sched_scan_req && dev == sched_scan_req->dev) | ||
| 872 | __cfg80211_stop_sched_scan(rdev, false); | 898 | __cfg80211_stop_sched_scan(rdev, false); |
| 873 | 899 | ||
| 874 | #ifdef CONFIG_CFG80211_WEXT | 900 | #ifdef CONFIG_CFG80211_WEXT |
| @@ -943,6 +969,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 943 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 969 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
| 944 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 970 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 945 | struct cfg80211_registered_device *rdev; | 971 | struct cfg80211_registered_device *rdev; |
| 972 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
| 946 | 973 | ||
| 947 | if (!wdev) | 974 | if (!wdev) |
| 948 | return NOTIFY_DONE; | 975 | return NOTIFY_DONE; |
| @@ -1007,8 +1034,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
| 1007 | ___cfg80211_scan_done(rdev, false); | 1034 | ___cfg80211_scan_done(rdev, false); |
| 1008 | } | 1035 | } |
| 1009 | 1036 | ||
| 1010 | if (WARN_ON(rdev->sched_scan_req && | 1037 | sched_scan_req = rtnl_dereference(rdev->sched_scan_req); |
| 1011 | rdev->sched_scan_req->dev == wdev->netdev)) { | 1038 | if (WARN_ON(sched_scan_req && |
| 1039 | sched_scan_req->dev == wdev->netdev)) { | ||
| 1012 | __cfg80211_stop_sched_scan(rdev, false); | 1040 | __cfg80211_stop_sched_scan(rdev, false); |
| 1013 | } | 1041 | } |
| 1014 | 1042 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index faa5b1609aae..801cd49c5a0c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -36,6 +36,13 @@ struct cfg80211_registered_device { | |||
| 36 | * the country on the country IE changed. */ | 36 | * the country on the country IE changed. */ |
| 37 | char country_ie_alpha2[2]; | 37 | char country_ie_alpha2[2]; |
| 38 | 38 | ||
| 39 | /* | ||
| 40 | * the driver requests the regulatory core to set this regulatory | ||
| 41 | * domain as the wiphy's. Only used for %REGULATORY_WIPHY_SELF_MANAGED | ||
| 42 | * devices using the regulatory_set_wiphy_regd() API | ||
| 43 | */ | ||
| 44 | const struct ieee80211_regdomain *requested_regd; | ||
| 45 | |||
| 39 | /* If a Country IE has been received this tells us the environment | 46 | /* If a Country IE has been received this tells us the environment |
| 40 | * which its telling us its in. This defaults to ENVIRON_ANY */ | 47 | * which its telling us its in. This defaults to ENVIRON_ANY */ |
| 41 | enum environment_cap env; | 48 | enum environment_cap env; |
| @@ -63,7 +70,7 @@ struct cfg80211_registered_device { | |||
| 63 | u32 bss_generation; | 70 | u32 bss_generation; |
| 64 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | 71 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ |
| 65 | struct sk_buff *scan_msg; | 72 | struct sk_buff *scan_msg; |
| 66 | struct cfg80211_sched_scan_request *sched_scan_req; | 73 | struct cfg80211_sched_scan_request __rcu *sched_scan_req; |
| 67 | unsigned long suspend_at; | 74 | unsigned long suspend_at; |
| 68 | struct work_struct scan_done_wk; | 75 | struct work_struct scan_done_wk; |
| 69 | struct work_struct sched_scan_results_wk; | 76 | struct work_struct sched_scan_results_wk; |
| @@ -84,6 +91,8 @@ struct cfg80211_registered_device { | |||
| 84 | struct list_head destroy_list; | 91 | struct list_head destroy_list; |
| 85 | struct work_struct destroy_work; | 92 | struct work_struct destroy_work; |
| 86 | 93 | ||
| 94 | struct work_struct sched_scan_stop_wk; | ||
| 95 | |||
| 87 | /* must be last because of the way we do wiphy_priv(), | 96 | /* must be last because of the way we do wiphy_priv(), |
| 88 | * and it should at least be aligned to NETDEV_ALIGN */ | 97 | * and it should at least be aligned to NETDEV_ALIGN */ |
| 89 | struct wiphy wiphy __aligned(NETDEV_ALIGN); | 98 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7ca4b5133123..c5661c5ad8f3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -59,13 +59,13 @@ enum nl80211_multicast_groups { | |||
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | static const struct genl_multicast_group nl80211_mcgrps[] = { | 61 | static const struct genl_multicast_group nl80211_mcgrps[] = { |
| 62 | [NL80211_MCGRP_CONFIG] = { .name = "config", }, | 62 | [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG }, |
| 63 | [NL80211_MCGRP_SCAN] = { .name = "scan", }, | 63 | [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN }, |
| 64 | [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, | 64 | [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG }, |
| 65 | [NL80211_MCGRP_MLME] = { .name = "mlme", }, | 65 | [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME }, |
| 66 | [NL80211_MCGRP_VENDOR] = { .name = "vendor", }, | 66 | [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR }, |
| 67 | #ifdef CONFIG_NL80211_TESTMODE | 67 | #ifdef CONFIG_NL80211_TESTMODE |
| 68 | [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } | 68 | [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE } |
| 69 | #endif | 69 | #endif |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| @@ -396,6 +396,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
| 396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, | 396 | [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 }, |
| 397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, | 397 | [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 }, |
| 398 | [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, | 398 | [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN }, |
| 399 | [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG }, | ||
| 399 | }; | 400 | }; |
| 400 | 401 | ||
| 401 | /* policy for the key attributes */ | 402 | /* policy for the key attributes */ |
| @@ -1087,6 +1088,11 @@ static int nl80211_send_wowlan(struct sk_buff *msg, | |||
| 1087 | return -ENOBUFS; | 1088 | return -ENOBUFS; |
| 1088 | } | 1089 | } |
| 1089 | 1090 | ||
| 1091 | if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) && | ||
| 1092 | nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT, | ||
| 1093 | rdev->wiphy.wowlan->max_nd_match_sets)) | ||
| 1094 | return -ENOBUFS; | ||
| 1095 | |||
| 1090 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) | 1096 | if (large && nl80211_send_wowlan_tcp_caps(rdev, msg)) |
| 1091 | return -ENOBUFS; | 1097 | return -ENOBUFS; |
| 1092 | 1098 | ||
| @@ -1701,6 +1707,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
| 1701 | rdev->wiphy.max_num_csa_counters)) | 1707 | rdev->wiphy.max_num_csa_counters)) |
| 1702 | goto nla_put_failure; | 1708 | goto nla_put_failure; |
| 1703 | 1709 | ||
| 1710 | if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
| 1711 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
| 1712 | goto nla_put_failure; | ||
| 1713 | |||
| 1714 | if (nla_put(msg, NL80211_ATTR_EXT_FEATURES, | ||
| 1715 | sizeof(rdev->wiphy.ext_features), | ||
| 1716 | rdev->wiphy.ext_features)) | ||
| 1717 | goto nla_put_failure; | ||
| 1718 | |||
| 1704 | /* done */ | 1719 | /* done */ |
| 1705 | state->split_start = 0; | 1720 | state->split_start = 0; |
| 1706 | break; | 1721 | break; |
| @@ -3563,6 +3578,7 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
| 3563 | struct nlattr *rate; | 3578 | struct nlattr *rate; |
| 3564 | u32 bitrate; | 3579 | u32 bitrate; |
| 3565 | u16 bitrate_compat; | 3580 | u16 bitrate_compat; |
| 3581 | enum nl80211_attrs rate_flg; | ||
| 3566 | 3582 | ||
| 3567 | rate = nla_nest_start(msg, attr); | 3583 | rate = nla_nest_start(msg, attr); |
| 3568 | if (!rate) | 3584 | if (!rate) |
| @@ -3579,12 +3595,36 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
| 3579 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) | 3595 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) |
| 3580 | return false; | 3596 | return false; |
| 3581 | 3597 | ||
| 3598 | switch (info->bw) { | ||
| 3599 | case RATE_INFO_BW_5: | ||
| 3600 | rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH; | ||
| 3601 | break; | ||
| 3602 | case RATE_INFO_BW_10: | ||
| 3603 | rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH; | ||
| 3604 | break; | ||
| 3605 | default: | ||
| 3606 | WARN_ON(1); | ||
| 3607 | /* fall through */ | ||
| 3608 | case RATE_INFO_BW_20: | ||
| 3609 | rate_flg = 0; | ||
| 3610 | break; | ||
| 3611 | case RATE_INFO_BW_40: | ||
| 3612 | rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH; | ||
| 3613 | break; | ||
| 3614 | case RATE_INFO_BW_80: | ||
| 3615 | rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH; | ||
| 3616 | break; | ||
| 3617 | case RATE_INFO_BW_160: | ||
| 3618 | rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH; | ||
| 3619 | break; | ||
| 3620 | } | ||
| 3621 | |||
| 3622 | if (rate_flg && nla_put_flag(msg, rate_flg)) | ||
| 3623 | return false; | ||
| 3624 | |||
| 3582 | if (info->flags & RATE_INFO_FLAGS_MCS) { | 3625 | if (info->flags & RATE_INFO_FLAGS_MCS) { |
| 3583 | if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) | 3626 | if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) |
| 3584 | return false; | 3627 | return false; |
| 3585 | if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH && | ||
| 3586 | nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) | ||
| 3587 | return false; | ||
| 3588 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && | 3628 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && |
| 3589 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) | 3629 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) |
| 3590 | return false; | 3630 | return false; |
| @@ -3593,18 +3633,6 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
| 3593 | return false; | 3633 | return false; |
| 3594 | if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss)) | 3634 | if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss)) |
| 3595 | return false; | 3635 | return false; |
| 3596 | if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH && | ||
| 3597 | nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) | ||
| 3598 | return false; | ||
| 3599 | if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH && | ||
| 3600 | nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH)) | ||
| 3601 | return false; | ||
| 3602 | if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH && | ||
| 3603 | nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH)) | ||
| 3604 | return false; | ||
| 3605 | if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH && | ||
| 3606 | nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH)) | ||
| 3607 | return false; | ||
| 3608 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && | 3636 | if (info->flags & RATE_INFO_FLAGS_SHORT_GI && |
| 3609 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) | 3637 | nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) |
| 3610 | return false; | 3638 | return false; |
| @@ -3640,8 +3668,8 @@ static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal, | |||
| 3640 | return true; | 3668 | return true; |
| 3641 | } | 3669 | } |
| 3642 | 3670 | ||
| 3643 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | 3671 | static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, |
| 3644 | int flags, | 3672 | u32 seq, int flags, |
| 3645 | struct cfg80211_registered_device *rdev, | 3673 | struct cfg80211_registered_device *rdev, |
| 3646 | struct net_device *dev, | 3674 | struct net_device *dev, |
| 3647 | const u8 *mac_addr, struct station_info *sinfo) | 3675 | const u8 *mac_addr, struct station_info *sinfo) |
| @@ -3649,7 +3677,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
| 3649 | void *hdr; | 3677 | void *hdr; |
| 3650 | struct nlattr *sinfoattr, *bss_param; | 3678 | struct nlattr *sinfoattr, *bss_param; |
| 3651 | 3679 | ||
| 3652 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION); | 3680 | hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); |
| 3653 | if (!hdr) | 3681 | if (!hdr) |
| 3654 | return -1; | 3682 | return -1; |
| 3655 | 3683 | ||
| @@ -3661,115 +3689,77 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
| 3661 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 3689 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
| 3662 | if (!sinfoattr) | 3690 | if (!sinfoattr) |
| 3663 | goto nla_put_failure; | 3691 | goto nla_put_failure; |
| 3664 | if ((sinfo->filled & STATION_INFO_CONNECTED_TIME) && | 3692 | |
| 3665 | nla_put_u32(msg, NL80211_STA_INFO_CONNECTED_TIME, | 3693 | #define PUT_SINFO(attr, memb, type) do { \ |
| 3666 | sinfo->connected_time)) | 3694 | if (sinfo->filled & BIT(NL80211_STA_INFO_ ## attr) && \ |
| 3667 | goto nla_put_failure; | 3695 | nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \ |
| 3668 | if ((sinfo->filled & STATION_INFO_INACTIVE_TIME) && | 3696 | sinfo->memb)) \ |
| 3669 | nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME, | 3697 | goto nla_put_failure; \ |
| 3670 | sinfo->inactive_time)) | 3698 | } while (0) |
| 3671 | goto nla_put_failure; | 3699 | |
| 3672 | if ((sinfo->filled & (STATION_INFO_RX_BYTES | | 3700 | PUT_SINFO(CONNECTED_TIME, connected_time, u32); |
| 3673 | STATION_INFO_RX_BYTES64)) && | 3701 | PUT_SINFO(INACTIVE_TIME, inactive_time, u32); |
| 3702 | |||
| 3703 | if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) | | ||
| 3704 | BIT(NL80211_STA_INFO_RX_BYTES64)) && | ||
| 3674 | nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES, | 3705 | nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES, |
| 3675 | (u32)sinfo->rx_bytes)) | 3706 | (u32)sinfo->rx_bytes)) |
| 3676 | goto nla_put_failure; | 3707 | goto nla_put_failure; |
| 3677 | if ((sinfo->filled & (STATION_INFO_TX_BYTES | | 3708 | |
| 3678 | STATION_INFO_TX_BYTES64)) && | 3709 | if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) | |
| 3710 | BIT(NL80211_STA_INFO_TX_BYTES64)) && | ||
| 3679 | nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, | 3711 | nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES, |
| 3680 | (u32)sinfo->tx_bytes)) | 3712 | (u32)sinfo->tx_bytes)) |
| 3681 | goto nla_put_failure; | 3713 | goto nla_put_failure; |
| 3682 | if ((sinfo->filled & STATION_INFO_RX_BYTES64) && | 3714 | |
| 3683 | nla_put_u64(msg, NL80211_STA_INFO_RX_BYTES64, | 3715 | PUT_SINFO(RX_BYTES64, rx_bytes, u64); |
| 3684 | sinfo->rx_bytes)) | 3716 | PUT_SINFO(TX_BYTES64, tx_bytes, u64); |
| 3685 | goto nla_put_failure; | 3717 | PUT_SINFO(LLID, llid, u16); |
| 3686 | if ((sinfo->filled & STATION_INFO_TX_BYTES64) && | 3718 | PUT_SINFO(PLID, plid, u16); |
| 3687 | nla_put_u64(msg, NL80211_STA_INFO_TX_BYTES64, | 3719 | PUT_SINFO(PLINK_STATE, plink_state, u8); |
| 3688 | sinfo->tx_bytes)) | 3720 | |
| 3689 | goto nla_put_failure; | ||
| 3690 | if ((sinfo->filled & STATION_INFO_LLID) && | ||
| 3691 | nla_put_u16(msg, NL80211_STA_INFO_LLID, sinfo->llid)) | ||
| 3692 | goto nla_put_failure; | ||
| 3693 | if ((sinfo->filled & STATION_INFO_PLID) && | ||
| 3694 | nla_put_u16(msg, NL80211_STA_INFO_PLID, sinfo->plid)) | ||
| 3695 | goto nla_put_failure; | ||
| 3696 | if ((sinfo->filled & STATION_INFO_PLINK_STATE) && | ||
| 3697 | nla_put_u8(msg, NL80211_STA_INFO_PLINK_STATE, | ||
| 3698 | sinfo->plink_state)) | ||
| 3699 | goto nla_put_failure; | ||
| 3700 | switch (rdev->wiphy.signal_type) { | 3721 | switch (rdev->wiphy.signal_type) { |
| 3701 | case CFG80211_SIGNAL_TYPE_MBM: | 3722 | case CFG80211_SIGNAL_TYPE_MBM: |
| 3702 | if ((sinfo->filled & STATION_INFO_SIGNAL) && | 3723 | PUT_SINFO(SIGNAL, signal, u8); |
| 3703 | nla_put_u8(msg, NL80211_STA_INFO_SIGNAL, | 3724 | PUT_SINFO(SIGNAL_AVG, signal_avg, u8); |
| 3704 | sinfo->signal)) | ||
| 3705 | goto nla_put_failure; | ||
| 3706 | if ((sinfo->filled & STATION_INFO_SIGNAL_AVG) && | ||
| 3707 | nla_put_u8(msg, NL80211_STA_INFO_SIGNAL_AVG, | ||
| 3708 | sinfo->signal_avg)) | ||
| 3709 | goto nla_put_failure; | ||
| 3710 | break; | 3725 | break; |
| 3711 | default: | 3726 | default: |
| 3712 | break; | 3727 | break; |
| 3713 | } | 3728 | } |
| 3714 | if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) { | 3729 | if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) { |
| 3715 | if (!nl80211_put_signal(msg, sinfo->chains, | 3730 | if (!nl80211_put_signal(msg, sinfo->chains, |
| 3716 | sinfo->chain_signal, | 3731 | sinfo->chain_signal, |
| 3717 | NL80211_STA_INFO_CHAIN_SIGNAL)) | 3732 | NL80211_STA_INFO_CHAIN_SIGNAL)) |
| 3718 | goto nla_put_failure; | 3733 | goto nla_put_failure; |
| 3719 | } | 3734 | } |
| 3720 | if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) { | 3735 | if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) { |
| 3721 | if (!nl80211_put_signal(msg, sinfo->chains, | 3736 | if (!nl80211_put_signal(msg, sinfo->chains, |
| 3722 | sinfo->chain_signal_avg, | 3737 | sinfo->chain_signal_avg, |
| 3723 | NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) | 3738 | NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) |
| 3724 | goto nla_put_failure; | 3739 | goto nla_put_failure; |
| 3725 | } | 3740 | } |
| 3726 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | 3741 | if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) { |
| 3727 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, | 3742 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, |
| 3728 | NL80211_STA_INFO_TX_BITRATE)) | 3743 | NL80211_STA_INFO_TX_BITRATE)) |
| 3729 | goto nla_put_failure; | 3744 | goto nla_put_failure; |
| 3730 | } | 3745 | } |
| 3731 | if (sinfo->filled & STATION_INFO_RX_BITRATE) { | 3746 | if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) { |
| 3732 | if (!nl80211_put_sta_rate(msg, &sinfo->rxrate, | 3747 | if (!nl80211_put_sta_rate(msg, &sinfo->rxrate, |
| 3733 | NL80211_STA_INFO_RX_BITRATE)) | 3748 | NL80211_STA_INFO_RX_BITRATE)) |
| 3734 | goto nla_put_failure; | 3749 | goto nla_put_failure; |
| 3735 | } | 3750 | } |
| 3736 | if ((sinfo->filled & STATION_INFO_RX_PACKETS) && | 3751 | |
| 3737 | nla_put_u32(msg, NL80211_STA_INFO_RX_PACKETS, | 3752 | PUT_SINFO(RX_PACKETS, rx_packets, u32); |
| 3738 | sinfo->rx_packets)) | 3753 | PUT_SINFO(TX_PACKETS, tx_packets, u32); |
| 3739 | goto nla_put_failure; | 3754 | PUT_SINFO(TX_RETRIES, tx_retries, u32); |
| 3740 | if ((sinfo->filled & STATION_INFO_TX_PACKETS) && | 3755 | PUT_SINFO(TX_FAILED, tx_failed, u32); |
| 3741 | nla_put_u32(msg, NL80211_STA_INFO_TX_PACKETS, | 3756 | PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32); |
| 3742 | sinfo->tx_packets)) | 3757 | PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32); |
| 3743 | goto nla_put_failure; | 3758 | PUT_SINFO(LOCAL_PM, local_pm, u32); |
| 3744 | if ((sinfo->filled & STATION_INFO_TX_RETRIES) && | 3759 | PUT_SINFO(PEER_PM, peer_pm, u32); |
| 3745 | nla_put_u32(msg, NL80211_STA_INFO_TX_RETRIES, | 3760 | PUT_SINFO(NONPEER_PM, nonpeer_pm, u32); |
| 3746 | sinfo->tx_retries)) | 3761 | |
| 3747 | goto nla_put_failure; | 3762 | if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) { |
| 3748 | if ((sinfo->filled & STATION_INFO_TX_FAILED) && | ||
| 3749 | nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED, | ||
| 3750 | sinfo->tx_failed)) | ||
| 3751 | goto nla_put_failure; | ||
| 3752 | if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) && | ||
| 3753 | nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT, | ||
| 3754 | sinfo->expected_throughput)) | ||
| 3755 | goto nla_put_failure; | ||
| 3756 | if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) && | ||
| 3757 | nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS, | ||
| 3758 | sinfo->beacon_loss_count)) | ||
| 3759 | goto nla_put_failure; | ||
| 3760 | if ((sinfo->filled & STATION_INFO_LOCAL_PM) && | ||
| 3761 | nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM, | ||
| 3762 | sinfo->local_pm)) | ||
| 3763 | goto nla_put_failure; | ||
| 3764 | if ((sinfo->filled & STATION_INFO_PEER_PM) && | ||
| 3765 | nla_put_u32(msg, NL80211_STA_INFO_PEER_PM, | ||
| 3766 | sinfo->peer_pm)) | ||
| 3767 | goto nla_put_failure; | ||
| 3768 | if ((sinfo->filled & STATION_INFO_NONPEER_PM) && | ||
| 3769 | nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM, | ||
| 3770 | sinfo->nonpeer_pm)) | ||
| 3771 | goto nla_put_failure; | ||
| 3772 | if (sinfo->filled & STATION_INFO_BSS_PARAM) { | ||
| 3773 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); | 3763 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); |
| 3774 | if (!bss_param) | 3764 | if (!bss_param) |
| 3775 | goto nla_put_failure; | 3765 | goto nla_put_failure; |
| @@ -3788,18 +3778,62 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
| 3788 | 3778 | ||
| 3789 | nla_nest_end(msg, bss_param); | 3779 | nla_nest_end(msg, bss_param); |
| 3790 | } | 3780 | } |
| 3791 | if ((sinfo->filled & STATION_INFO_STA_FLAGS) && | 3781 | if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) && |
| 3792 | nla_put(msg, NL80211_STA_INFO_STA_FLAGS, | 3782 | nla_put(msg, NL80211_STA_INFO_STA_FLAGS, |
| 3793 | sizeof(struct nl80211_sta_flag_update), | 3783 | sizeof(struct nl80211_sta_flag_update), |
| 3794 | &sinfo->sta_flags)) | 3784 | &sinfo->sta_flags)) |
| 3795 | goto nla_put_failure; | 3785 | goto nla_put_failure; |
| 3796 | if ((sinfo->filled & STATION_INFO_T_OFFSET) && | 3786 | |
| 3797 | nla_put_u64(msg, NL80211_STA_INFO_T_OFFSET, | 3787 | PUT_SINFO(T_OFFSET, t_offset, u64); |
| 3798 | sinfo->t_offset)) | 3788 | PUT_SINFO(RX_DROP_MISC, rx_dropped_misc, u64); |
| 3799 | goto nla_put_failure; | 3789 | PUT_SINFO(BEACON_RX, rx_beacon, u64); |
| 3790 | PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8); | ||
| 3791 | |||
| 3792 | #undef PUT_SINFO | ||
| 3793 | |||
| 3794 | if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) { | ||
| 3795 | struct nlattr *tidsattr; | ||
| 3796 | int tid; | ||
| 3797 | |||
| 3798 | tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS); | ||
| 3799 | if (!tidsattr) | ||
| 3800 | goto nla_put_failure; | ||
| 3801 | |||
| 3802 | for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) { | ||
| 3803 | struct cfg80211_tid_stats *tidstats; | ||
| 3804 | struct nlattr *tidattr; | ||
| 3805 | |||
| 3806 | tidstats = &sinfo->pertid[tid]; | ||
| 3807 | |||
| 3808 | if (!tidstats->filled) | ||
| 3809 | continue; | ||
| 3810 | |||
| 3811 | tidattr = nla_nest_start(msg, tid + 1); | ||
| 3812 | if (!tidattr) | ||
| 3813 | goto nla_put_failure; | ||
| 3814 | |||
| 3815 | #define PUT_TIDVAL(attr, memb, type) do { \ | ||
| 3816 | if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \ | ||
| 3817 | nla_put_ ## type(msg, NL80211_TID_STATS_ ## attr, \ | ||
| 3818 | tidstats->memb)) \ | ||
| 3819 | goto nla_put_failure; \ | ||
| 3820 | } while (0) | ||
| 3821 | |||
| 3822 | PUT_TIDVAL(RX_MSDU, rx_msdu, u64); | ||
| 3823 | PUT_TIDVAL(TX_MSDU, tx_msdu, u64); | ||
| 3824 | PUT_TIDVAL(TX_MSDU_RETRIES, tx_msdu_retries, u64); | ||
| 3825 | PUT_TIDVAL(TX_MSDU_FAILED, tx_msdu_failed, u64); | ||
| 3826 | |||
| 3827 | #undef PUT_TIDVAL | ||
| 3828 | nla_nest_end(msg, tidattr); | ||
| 3829 | } | ||
| 3830 | |||
| 3831 | nla_nest_end(msg, tidsattr); | ||
| 3832 | } | ||
| 3833 | |||
| 3800 | nla_nest_end(msg, sinfoattr); | 3834 | nla_nest_end(msg, sinfoattr); |
| 3801 | 3835 | ||
| 3802 | if ((sinfo->filled & STATION_INFO_ASSOC_REQ_IES) && | 3836 | if (sinfo->assoc_req_ies_len && |
| 3803 | nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, | 3837 | nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, |
| 3804 | sinfo->assoc_req_ies)) | 3838 | sinfo->assoc_req_ies)) |
| 3805 | goto nla_put_failure; | 3839 | goto nla_put_failure; |
| @@ -3844,7 +3878,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
| 3844 | if (err) | 3878 | if (err) |
| 3845 | goto out_err; | 3879 | goto out_err; |
| 3846 | 3880 | ||
| 3847 | if (nl80211_send_station(skb, | 3881 | if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION, |
| 3848 | NETLINK_CB(cb->skb).portid, | 3882 | NETLINK_CB(cb->skb).portid, |
| 3849 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3883 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 3850 | rdev, wdev->netdev, mac_addr, | 3884 | rdev, wdev->netdev, mac_addr, |
| @@ -3891,7 +3925,8 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
| 3891 | if (!msg) | 3925 | if (!msg) |
| 3892 | return -ENOMEM; | 3926 | return -ENOMEM; |
| 3893 | 3927 | ||
| 3894 | if (nl80211_send_station(msg, info->snd_portid, info->snd_seq, 0, | 3928 | if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, |
| 3929 | info->snd_portid, info->snd_seq, 0, | ||
| 3895 | rdev, dev, mac_addr, &sinfo) < 0) { | 3930 | rdev, dev, mac_addr, &sinfo) < 0) { |
| 3896 | nlmsg_free(msg); | 3931 | nlmsg_free(msg); |
| 3897 | return -ENOBUFS; | 3932 | return -ENOBUFS; |
| @@ -5327,42 +5362,20 @@ static int nl80211_update_mesh_config(struct sk_buff *skb, | |||
| 5327 | return err; | 5362 | return err; |
| 5328 | } | 5363 | } |
| 5329 | 5364 | ||
| 5330 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 5365 | static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom, |
| 5366 | struct sk_buff *msg) | ||
| 5331 | { | 5367 | { |
| 5332 | const struct ieee80211_regdomain *regdom; | ||
| 5333 | struct sk_buff *msg; | ||
| 5334 | void *hdr = NULL; | ||
| 5335 | struct nlattr *nl_reg_rules; | 5368 | struct nlattr *nl_reg_rules; |
| 5336 | unsigned int i; | 5369 | unsigned int i; |
| 5337 | 5370 | ||
| 5338 | if (!cfg80211_regdomain) | ||
| 5339 | return -EINVAL; | ||
| 5340 | |||
| 5341 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 5342 | if (!msg) | ||
| 5343 | return -ENOBUFS; | ||
| 5344 | |||
| 5345 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
| 5346 | NL80211_CMD_GET_REG); | ||
| 5347 | if (!hdr) | ||
| 5348 | goto put_failure; | ||
| 5349 | |||
| 5350 | if (reg_last_request_cell_base() && | ||
| 5351 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
| 5352 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
| 5353 | goto nla_put_failure; | ||
| 5354 | |||
| 5355 | rcu_read_lock(); | ||
| 5356 | regdom = rcu_dereference(cfg80211_regdomain); | ||
| 5357 | |||
| 5358 | if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) || | 5371 | if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) || |
| 5359 | (regdom->dfs_region && | 5372 | (regdom->dfs_region && |
| 5360 | nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region))) | 5373 | nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region))) |
| 5361 | goto nla_put_failure_rcu; | 5374 | goto nla_put_failure; |
| 5362 | 5375 | ||
| 5363 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 5376 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
| 5364 | if (!nl_reg_rules) | 5377 | if (!nl_reg_rules) |
| 5365 | goto nla_put_failure_rcu; | 5378 | goto nla_put_failure; |
| 5366 | 5379 | ||
| 5367 | for (i = 0; i < regdom->n_reg_rules; i++) { | 5380 | for (i = 0; i < regdom->n_reg_rules; i++) { |
| 5368 | struct nlattr *nl_reg_rule; | 5381 | struct nlattr *nl_reg_rule; |
| @@ -5377,7 +5390,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
| 5377 | 5390 | ||
| 5378 | nl_reg_rule = nla_nest_start(msg, i); | 5391 | nl_reg_rule = nla_nest_start(msg, i); |
| 5379 | if (!nl_reg_rule) | 5392 | if (!nl_reg_rule) |
| 5380 | goto nla_put_failure_rcu; | 5393 | goto nla_put_failure; |
| 5381 | 5394 | ||
| 5382 | max_bandwidth_khz = freq_range->max_bandwidth_khz; | 5395 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
| 5383 | if (!max_bandwidth_khz) | 5396 | if (!max_bandwidth_khz) |
| @@ -5398,13 +5411,74 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
| 5398 | power_rule->max_eirp) || | 5411 | power_rule->max_eirp) || |
| 5399 | nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME, | 5412 | nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME, |
| 5400 | reg_rule->dfs_cac_ms)) | 5413 | reg_rule->dfs_cac_ms)) |
| 5401 | goto nla_put_failure_rcu; | 5414 | goto nla_put_failure; |
| 5402 | 5415 | ||
| 5403 | nla_nest_end(msg, nl_reg_rule); | 5416 | nla_nest_end(msg, nl_reg_rule); |
| 5404 | } | 5417 | } |
| 5405 | rcu_read_unlock(); | ||
| 5406 | 5418 | ||
| 5407 | nla_nest_end(msg, nl_reg_rules); | 5419 | nla_nest_end(msg, nl_reg_rules); |
| 5420 | return 0; | ||
| 5421 | |||
| 5422 | nla_put_failure: | ||
| 5423 | return -EMSGSIZE; | ||
| 5424 | } | ||
| 5425 | |||
| 5426 | static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info) | ||
| 5427 | { | ||
| 5428 | const struct ieee80211_regdomain *regdom = NULL; | ||
| 5429 | struct cfg80211_registered_device *rdev; | ||
| 5430 | struct wiphy *wiphy = NULL; | ||
| 5431 | struct sk_buff *msg; | ||
| 5432 | void *hdr; | ||
| 5433 | |||
| 5434 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 5435 | if (!msg) | ||
| 5436 | return -ENOBUFS; | ||
| 5437 | |||
| 5438 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
| 5439 | NL80211_CMD_GET_REG); | ||
| 5440 | if (!hdr) | ||
| 5441 | goto put_failure; | ||
| 5442 | |||
| 5443 | if (info->attrs[NL80211_ATTR_WIPHY]) { | ||
| 5444 | bool self_managed; | ||
| 5445 | |||
| 5446 | rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); | ||
| 5447 | if (IS_ERR(rdev)) { | ||
| 5448 | nlmsg_free(msg); | ||
| 5449 | return PTR_ERR(rdev); | ||
| 5450 | } | ||
| 5451 | |||
| 5452 | wiphy = &rdev->wiphy; | ||
| 5453 | self_managed = wiphy->regulatory_flags & | ||
| 5454 | REGULATORY_WIPHY_SELF_MANAGED; | ||
| 5455 | regdom = get_wiphy_regdom(wiphy); | ||
| 5456 | |||
| 5457 | /* a self-managed-reg device must have a private regdom */ | ||
| 5458 | if (WARN_ON(!regdom && self_managed)) { | ||
| 5459 | nlmsg_free(msg); | ||
| 5460 | return -EINVAL; | ||
| 5461 | } | ||
| 5462 | |||
| 5463 | if (regdom && | ||
| 5464 | nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy))) | ||
| 5465 | goto nla_put_failure; | ||
| 5466 | } | ||
| 5467 | |||
| 5468 | if (!wiphy && reg_last_request_cell_base() && | ||
| 5469 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
| 5470 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
| 5471 | goto nla_put_failure; | ||
| 5472 | |||
| 5473 | rcu_read_lock(); | ||
| 5474 | |||
| 5475 | if (!regdom) | ||
| 5476 | regdom = rcu_dereference(cfg80211_regdomain); | ||
| 5477 | |||
| 5478 | if (nl80211_put_regdom(regdom, msg)) | ||
| 5479 | goto nla_put_failure_rcu; | ||
| 5480 | |||
| 5481 | rcu_read_unlock(); | ||
| 5408 | 5482 | ||
| 5409 | genlmsg_end(msg, hdr); | 5483 | genlmsg_end(msg, hdr); |
| 5410 | return genlmsg_reply(msg, info); | 5484 | return genlmsg_reply(msg, info); |
| @@ -5418,6 +5492,83 @@ put_failure: | |||
| 5418 | return -EMSGSIZE; | 5492 | return -EMSGSIZE; |
| 5419 | } | 5493 | } |
| 5420 | 5494 | ||
| 5495 | static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb, | ||
| 5496 | u32 seq, int flags, struct wiphy *wiphy, | ||
| 5497 | const struct ieee80211_regdomain *regdom) | ||
| 5498 | { | ||
| 5499 | void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags, | ||
| 5500 | NL80211_CMD_GET_REG); | ||
| 5501 | |||
| 5502 | if (!hdr) | ||
| 5503 | return -1; | ||
| 5504 | |||
| 5505 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); | ||
| 5506 | |||
| 5507 | if (nl80211_put_regdom(regdom, msg)) | ||
| 5508 | goto nla_put_failure; | ||
| 5509 | |||
| 5510 | if (!wiphy && reg_last_request_cell_base() && | ||
| 5511 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
| 5512 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
| 5513 | goto nla_put_failure; | ||
| 5514 | |||
| 5515 | if (wiphy && | ||
| 5516 | nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy))) | ||
| 5517 | goto nla_put_failure; | ||
| 5518 | |||
| 5519 | if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
| 5520 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
| 5521 | goto nla_put_failure; | ||
| 5522 | |||
| 5523 | return genlmsg_end(msg, hdr); | ||
| 5524 | |||
| 5525 | nla_put_failure: | ||
| 5526 | genlmsg_cancel(msg, hdr); | ||
| 5527 | return -EMSGSIZE; | ||
| 5528 | } | ||
| 5529 | |||
| 5530 | static int nl80211_get_reg_dump(struct sk_buff *skb, | ||
| 5531 | struct netlink_callback *cb) | ||
| 5532 | { | ||
| 5533 | const struct ieee80211_regdomain *regdom = NULL; | ||
| 5534 | struct cfg80211_registered_device *rdev; | ||
| 5535 | int err, reg_idx, start = cb->args[2]; | ||
| 5536 | |||
| 5537 | rtnl_lock(); | ||
| 5538 | |||
| 5539 | if (cfg80211_regdomain && start == 0) { | ||
| 5540 | err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq, | ||
| 5541 | NLM_F_MULTI, NULL, | ||
| 5542 | rtnl_dereference(cfg80211_regdomain)); | ||
| 5543 | if (err < 0) | ||
| 5544 | goto out_err; | ||
| 5545 | } | ||
| 5546 | |||
| 5547 | /* the global regdom is idx 0 */ | ||
| 5548 | reg_idx = 1; | ||
| 5549 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
| 5550 | regdom = get_wiphy_regdom(&rdev->wiphy); | ||
| 5551 | if (!regdom) | ||
| 5552 | continue; | ||
| 5553 | |||
| 5554 | if (++reg_idx <= start) | ||
| 5555 | continue; | ||
| 5556 | |||
| 5557 | err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq, | ||
| 5558 | NLM_F_MULTI, &rdev->wiphy, regdom); | ||
| 5559 | if (err < 0) { | ||
| 5560 | reg_idx--; | ||
| 5561 | break; | ||
| 5562 | } | ||
| 5563 | } | ||
| 5564 | |||
| 5565 | cb->args[2] = reg_idx; | ||
| 5566 | err = skb->len; | ||
| 5567 | out_err: | ||
| 5568 | rtnl_unlock(); | ||
| 5569 | return err; | ||
| 5570 | } | ||
| 5571 | |||
| 5421 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | 5572 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) |
| 5422 | { | 5573 | { |
| 5423 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; | 5574 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; |
| @@ -6069,6 +6220,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
| 6069 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6220 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 6070 | struct net_device *dev = info->user_ptr[1]; | 6221 | struct net_device *dev = info->user_ptr[1]; |
| 6071 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 6222 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 6223 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
| 6072 | int err; | 6224 | int err; |
| 6073 | 6225 | ||
| 6074 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 6226 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || |
| @@ -6078,27 +6230,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
| 6078 | if (rdev->sched_scan_req) | 6230 | if (rdev->sched_scan_req) |
| 6079 | return -EINPROGRESS; | 6231 | return -EINPROGRESS; |
| 6080 | 6232 | ||
| 6081 | rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, | 6233 | sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, |
| 6082 | info->attrs); | 6234 | info->attrs); |
| 6083 | err = PTR_ERR_OR_ZERO(rdev->sched_scan_req); | 6235 | |
| 6236 | err = PTR_ERR_OR_ZERO(sched_scan_req); | ||
| 6084 | if (err) | 6237 | if (err) |
| 6085 | goto out_err; | 6238 | goto out_err; |
| 6086 | 6239 | ||
| 6087 | err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req); | 6240 | err = rdev_sched_scan_start(rdev, dev, sched_scan_req); |
| 6088 | if (err) | 6241 | if (err) |
| 6089 | goto out_free; | 6242 | goto out_free; |
| 6090 | 6243 | ||
| 6091 | rdev->sched_scan_req->dev = dev; | 6244 | sched_scan_req->dev = dev; |
| 6092 | rdev->sched_scan_req->wiphy = &rdev->wiphy; | 6245 | sched_scan_req->wiphy = &rdev->wiphy; |
| 6246 | |||
| 6247 | if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) | ||
| 6248 | sched_scan_req->owner_nlportid = info->snd_portid; | ||
| 6249 | |||
| 6250 | rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req); | ||
| 6093 | 6251 | ||
| 6094 | nl80211_send_sched_scan(rdev, dev, | 6252 | nl80211_send_sched_scan(rdev, dev, |
| 6095 | NL80211_CMD_START_SCHED_SCAN); | 6253 | NL80211_CMD_START_SCHED_SCAN); |
| 6096 | return 0; | 6254 | return 0; |
| 6097 | 6255 | ||
| 6098 | out_free: | 6256 | out_free: |
| 6099 | kfree(rdev->sched_scan_req); | 6257 | kfree(sched_scan_req); |
| 6100 | out_err: | 6258 | out_err: |
| 6101 | rdev->sched_scan_req = NULL; | ||
| 6102 | return err; | 6259 | return err; |
| 6103 | } | 6260 | } |
| 6104 | 6261 | ||
| @@ -6481,12 +6638,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 6481 | } | 6638 | } |
| 6482 | 6639 | ||
| 6483 | static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | 6640 | static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, |
| 6484 | int flags, struct net_device *dev, | 6641 | int flags, struct net_device *dev, |
| 6485 | struct survey_info *survey) | 6642 | bool allow_radio_stats, |
| 6643 | struct survey_info *survey) | ||
| 6486 | { | 6644 | { |
| 6487 | void *hdr; | 6645 | void *hdr; |
| 6488 | struct nlattr *infoattr; | 6646 | struct nlattr *infoattr; |
| 6489 | 6647 | ||
| 6648 | /* skip radio stats if userspace didn't request them */ | ||
| 6649 | if (!survey->channel && !allow_radio_stats) | ||
| 6650 | return 0; | ||
| 6651 | |||
| 6490 | hdr = nl80211hdr_put(msg, portid, seq, flags, | 6652 | hdr = nl80211hdr_put(msg, portid, seq, flags, |
| 6491 | NL80211_CMD_NEW_SURVEY_RESULTS); | 6653 | NL80211_CMD_NEW_SURVEY_RESULTS); |
| 6492 | if (!hdr) | 6654 | if (!hdr) |
| @@ -6499,7 +6661,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
| 6499 | if (!infoattr) | 6661 | if (!infoattr) |
| 6500 | goto nla_put_failure; | 6662 | goto nla_put_failure; |
| 6501 | 6663 | ||
| 6502 | if (nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY, | 6664 | if (survey->channel && |
| 6665 | nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY, | ||
| 6503 | survey->channel->center_freq)) | 6666 | survey->channel->center_freq)) |
| 6504 | goto nla_put_failure; | 6667 | goto nla_put_failure; |
| 6505 | 6668 | ||
| @@ -6509,25 +6672,29 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
| 6509 | if ((survey->filled & SURVEY_INFO_IN_USE) && | 6672 | if ((survey->filled & SURVEY_INFO_IN_USE) && |
| 6510 | nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE)) | 6673 | nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE)) |
| 6511 | goto nla_put_failure; | 6674 | goto nla_put_failure; |
| 6512 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME) && | 6675 | if ((survey->filled & SURVEY_INFO_TIME) && |
| 6513 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME, | 6676 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME, |
| 6514 | survey->channel_time)) | 6677 | survey->time)) |
| 6678 | goto nla_put_failure; | ||
| 6679 | if ((survey->filled & SURVEY_INFO_TIME_BUSY) && | ||
| 6680 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_BUSY, | ||
| 6681 | survey->time_busy)) | ||
| 6515 | goto nla_put_failure; | 6682 | goto nla_put_failure; |
| 6516 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) && | 6683 | if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) && |
| 6517 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, | 6684 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY, |
| 6518 | survey->channel_time_busy)) | 6685 | survey->time_ext_busy)) |
| 6519 | goto nla_put_failure; | 6686 | goto nla_put_failure; |
| 6520 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) && | 6687 | if ((survey->filled & SURVEY_INFO_TIME_RX) && |
| 6521 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, | 6688 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_RX, |
| 6522 | survey->channel_time_ext_busy)) | 6689 | survey->time_rx)) |
| 6523 | goto nla_put_failure; | 6690 | goto nla_put_failure; |
| 6524 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) && | 6691 | if ((survey->filled & SURVEY_INFO_TIME_TX) && |
| 6525 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX, | 6692 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_TX, |
| 6526 | survey->channel_time_rx)) | 6693 | survey->time_tx)) |
| 6527 | goto nla_put_failure; | 6694 | goto nla_put_failure; |
| 6528 | if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) && | 6695 | if ((survey->filled & SURVEY_INFO_TIME_SCAN) && |
| 6529 | nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX, | 6696 | nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_SCAN, |
| 6530 | survey->channel_time_tx)) | 6697 | survey->time_scan)) |
| 6531 | goto nla_put_failure; | 6698 | goto nla_put_failure; |
| 6532 | 6699 | ||
| 6533 | nla_nest_end(msg, infoattr); | 6700 | nla_nest_end(msg, infoattr); |
| @@ -6539,19 +6706,22 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | |||
| 6539 | return -EMSGSIZE; | 6706 | return -EMSGSIZE; |
| 6540 | } | 6707 | } |
| 6541 | 6708 | ||
| 6542 | static int nl80211_dump_survey(struct sk_buff *skb, | 6709 | static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb) |
| 6543 | struct netlink_callback *cb) | ||
| 6544 | { | 6710 | { |
| 6545 | struct survey_info survey; | 6711 | struct survey_info survey; |
| 6546 | struct cfg80211_registered_device *rdev; | 6712 | struct cfg80211_registered_device *rdev; |
| 6547 | struct wireless_dev *wdev; | 6713 | struct wireless_dev *wdev; |
| 6548 | int survey_idx = cb->args[2]; | 6714 | int survey_idx = cb->args[2]; |
| 6549 | int res; | 6715 | int res; |
| 6716 | bool radio_stats; | ||
| 6550 | 6717 | ||
| 6551 | res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); | 6718 | res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); |
| 6552 | if (res) | 6719 | if (res) |
| 6553 | return res; | 6720 | return res; |
| 6554 | 6721 | ||
| 6722 | /* prepare_wdev_dump parsed the attributes */ | ||
| 6723 | radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS]; | ||
| 6724 | |||
| 6555 | if (!wdev->netdev) { | 6725 | if (!wdev->netdev) { |
| 6556 | res = -EINVAL; | 6726 | res = -EINVAL; |
| 6557 | goto out_err; | 6727 | goto out_err; |
| @@ -6569,13 +6739,9 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
| 6569 | if (res) | 6739 | if (res) |
| 6570 | goto out_err; | 6740 | goto out_err; |
| 6571 | 6741 | ||
| 6572 | /* Survey without a channel doesn't make sense */ | 6742 | /* don't send disabled channels, but do send non-channel data */ |
| 6573 | if (!survey.channel) { | 6743 | if (survey.channel && |
| 6574 | res = -EINVAL; | 6744 | survey.channel->flags & IEEE80211_CHAN_DISABLED) { |
| 6575 | goto out; | ||
| 6576 | } | ||
| 6577 | |||
| 6578 | if (survey.channel->flags & IEEE80211_CHAN_DISABLED) { | ||
| 6579 | survey_idx++; | 6745 | survey_idx++; |
| 6580 | continue; | 6746 | continue; |
| 6581 | } | 6747 | } |
| @@ -6583,7 +6749,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
| 6583 | if (nl80211_send_survey(skb, | 6749 | if (nl80211_send_survey(skb, |
| 6584 | NETLINK_CB(cb->skb).portid, | 6750 | NETLINK_CB(cb->skb).portid, |
| 6585 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 6751 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
| 6586 | wdev->netdev, &survey) < 0) | 6752 | wdev->netdev, radio_stats, &survey) < 0) |
| 6587 | goto out; | 6753 | goto out; |
| 6588 | survey_idx++; | 6754 | survey_idx++; |
| 6589 | } | 6755 | } |
| @@ -8599,6 +8765,48 @@ static int nl80211_send_wowlan_tcp(struct sk_buff *msg, | |||
| 8599 | return 0; | 8765 | return 0; |
| 8600 | } | 8766 | } |
| 8601 | 8767 | ||
| 8768 | static int nl80211_send_wowlan_nd(struct sk_buff *msg, | ||
| 8769 | struct cfg80211_sched_scan_request *req) | ||
| 8770 | { | ||
| 8771 | struct nlattr *nd, *freqs, *matches, *match; | ||
| 8772 | int i; | ||
| 8773 | |||
| 8774 | if (!req) | ||
| 8775 | return 0; | ||
| 8776 | |||
| 8777 | nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT); | ||
| 8778 | if (!nd) | ||
| 8779 | return -ENOBUFS; | ||
| 8780 | |||
| 8781 | if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval)) | ||
| 8782 | return -ENOBUFS; | ||
| 8783 | |||
| 8784 | freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); | ||
| 8785 | if (!freqs) | ||
| 8786 | return -ENOBUFS; | ||
| 8787 | |||
| 8788 | for (i = 0; i < req->n_channels; i++) | ||
| 8789 | nla_put_u32(msg, i, req->channels[i]->center_freq); | ||
| 8790 | |||
| 8791 | nla_nest_end(msg, freqs); | ||
| 8792 | |||
| 8793 | if (req->n_match_sets) { | ||
| 8794 | matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH); | ||
| 8795 | for (i = 0; i < req->n_match_sets; i++) { | ||
| 8796 | match = nla_nest_start(msg, i); | ||
| 8797 | nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID, | ||
| 8798 | req->match_sets[i].ssid.ssid_len, | ||
| 8799 | req->match_sets[i].ssid.ssid); | ||
| 8800 | nla_nest_end(msg, match); | ||
| 8801 | } | ||
| 8802 | nla_nest_end(msg, matches); | ||
| 8803 | } | ||
| 8804 | |||
| 8805 | nla_nest_end(msg, nd); | ||
| 8806 | |||
| 8807 | return 0; | ||
| 8808 | } | ||
| 8809 | |||
| 8602 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 8810 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
| 8603 | { | 8811 | { |
| 8604 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8812 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| @@ -8656,6 +8864,11 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
| 8656 | rdev->wiphy.wowlan_config->tcp)) | 8864 | rdev->wiphy.wowlan_config->tcp)) |
| 8657 | goto nla_put_failure; | 8865 | goto nla_put_failure; |
| 8658 | 8866 | ||
| 8867 | if (nl80211_send_wowlan_nd( | ||
| 8868 | msg, | ||
| 8869 | rdev->wiphy.wowlan_config->nd_config)) | ||
| 8870 | goto nla_put_failure; | ||
| 8871 | |||
| 8659 | nla_nest_end(msg, nl_wowlan); | 8872 | nla_nest_end(msg, nl_wowlan); |
| 8660 | } | 8873 | } |
| 8661 | 8874 | ||
| @@ -10225,7 +10438,8 @@ static const struct genl_ops nl80211_ops[] = { | |||
| 10225 | }, | 10438 | }, |
| 10226 | { | 10439 | { |
| 10227 | .cmd = NL80211_CMD_GET_REG, | 10440 | .cmd = NL80211_CMD_GET_REG, |
| 10228 | .doit = nl80211_get_reg, | 10441 | .doit = nl80211_get_reg_do, |
| 10442 | .dumpit = nl80211_get_reg_dump, | ||
| 10229 | .policy = nl80211_policy, | 10443 | .policy = nl80211_policy, |
| 10230 | .internal_flags = NL80211_FLAG_NEED_RTNL, | 10444 | .internal_flags = NL80211_FLAG_NEED_RTNL, |
| 10231 | /* can be retrieved by unprivileged users */ | 10445 | /* can be retrieved by unprivileged users */ |
| @@ -10939,25 +11153,9 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |||
| 10939 | NL80211_MCGRP_SCAN, GFP_KERNEL); | 11153 | NL80211_MCGRP_SCAN, GFP_KERNEL); |
| 10940 | } | 11154 | } |
| 10941 | 11155 | ||
| 10942 | /* | 11156 | static bool nl80211_reg_change_event_fill(struct sk_buff *msg, |
| 10943 | * This can happen on global regulatory changes or device specific settings | 11157 | struct regulatory_request *request) |
| 10944 | * based on custom world regulatory domains. | ||
| 10945 | */ | ||
| 10946 | void nl80211_send_reg_change_event(struct regulatory_request *request) | ||
| 10947 | { | 11158 | { |
| 10948 | struct sk_buff *msg; | ||
| 10949 | void *hdr; | ||
| 10950 | |||
| 10951 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 10952 | if (!msg) | ||
| 10953 | return; | ||
| 10954 | |||
| 10955 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE); | ||
| 10956 | if (!hdr) { | ||
| 10957 | nlmsg_free(msg); | ||
| 10958 | return; | ||
| 10959 | } | ||
| 10960 | |||
| 10961 | /* Userspace can always count this one always being set */ | 11159 | /* Userspace can always count this one always being set */ |
| 10962 | if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator)) | 11160 | if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator)) |
| 10963 | goto nla_put_failure; | 11161 | goto nla_put_failure; |
| @@ -10983,8 +11181,46 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) | |||
| 10983 | goto nla_put_failure; | 11181 | goto nla_put_failure; |
| 10984 | } | 11182 | } |
| 10985 | 11183 | ||
| 10986 | if (request->wiphy_idx != WIPHY_IDX_INVALID && | 11184 | if (request->wiphy_idx != WIPHY_IDX_INVALID) { |
| 10987 | nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx)) | 11185 | struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx); |
| 11186 | |||
| 11187 | if (wiphy && | ||
| 11188 | nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx)) | ||
| 11189 | goto nla_put_failure; | ||
| 11190 | |||
| 11191 | if (wiphy && | ||
| 11192 | wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && | ||
| 11193 | nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG)) | ||
| 11194 | goto nla_put_failure; | ||
| 11195 | } | ||
| 11196 | |||
| 11197 | return true; | ||
| 11198 | |||
| 11199 | nla_put_failure: | ||
| 11200 | return false; | ||
| 11201 | } | ||
| 11202 | |||
| 11203 | /* | ||
| 11204 | * This can happen on global regulatory changes or device specific settings | ||
| 11205 | * based on custom regulatory domains. | ||
| 11206 | */ | ||
| 11207 | void nl80211_common_reg_change_event(enum nl80211_commands cmd_id, | ||
| 11208 | struct regulatory_request *request) | ||
| 11209 | { | ||
| 11210 | struct sk_buff *msg; | ||
| 11211 | void *hdr; | ||
| 11212 | |||
| 11213 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 11214 | if (!msg) | ||
| 11215 | return; | ||
| 11216 | |||
| 11217 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id); | ||
| 11218 | if (!hdr) { | ||
| 11219 | nlmsg_free(msg); | ||
| 11220 | return; | ||
| 11221 | } | ||
| 11222 | |||
| 11223 | if (nl80211_reg_change_event_fill(msg, request) == false) | ||
| 10988 | goto nla_put_failure; | 11224 | goto nla_put_failure; |
| 10989 | 11225 | ||
| 10990 | genlmsg_end(msg, hdr); | 11226 | genlmsg_end(msg, hdr); |
| @@ -11523,7 +11759,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
| 11523 | if (!msg) | 11759 | if (!msg) |
| 11524 | return; | 11760 | return; |
| 11525 | 11761 | ||
| 11526 | if (nl80211_send_station(msg, 0, 0, 0, | 11762 | if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0, |
| 11527 | rdev, dev, mac_addr, sinfo) < 0) { | 11763 | rdev, dev, mac_addr, sinfo) < 0) { |
| 11528 | nlmsg_free(msg); | 11764 | nlmsg_free(msg); |
| 11529 | return; | 11765 | return; |
| @@ -11534,12 +11770,16 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
| 11534 | } | 11770 | } |
| 11535 | EXPORT_SYMBOL(cfg80211_new_sta); | 11771 | EXPORT_SYMBOL(cfg80211_new_sta); |
| 11536 | 11772 | ||
| 11537 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | 11773 | void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr, |
| 11774 | struct station_info *sinfo, gfp_t gfp) | ||
| 11538 | { | 11775 | { |
| 11539 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 11776 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; |
| 11540 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 11777 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| 11541 | struct sk_buff *msg; | 11778 | struct sk_buff *msg; |
| 11542 | void *hdr; | 11779 | struct station_info empty_sinfo = {}; |
| 11780 | |||
| 11781 | if (!sinfo) | ||
| 11782 | sinfo = &empty_sinfo; | ||
| 11543 | 11783 | ||
| 11544 | trace_cfg80211_del_sta(dev, mac_addr); | 11784 | trace_cfg80211_del_sta(dev, mac_addr); |
| 11545 | 11785 | ||
| @@ -11547,27 +11787,16 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | |||
| 11547 | if (!msg) | 11787 | if (!msg) |
| 11548 | return; | 11788 | return; |
| 11549 | 11789 | ||
| 11550 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION); | 11790 | if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0, |
| 11551 | if (!hdr) { | 11791 | rdev, dev, mac_addr, sinfo) < 0) { |
| 11552 | nlmsg_free(msg); | 11792 | nlmsg_free(msg); |
| 11553 | return; | 11793 | return; |
| 11554 | } | 11794 | } |
| 11555 | 11795 | ||
| 11556 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | ||
| 11557 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr)) | ||
| 11558 | goto nla_put_failure; | ||
| 11559 | |||
| 11560 | genlmsg_end(msg, hdr); | ||
| 11561 | |||
| 11562 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | 11796 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, |
| 11563 | NL80211_MCGRP_MLME, gfp); | 11797 | NL80211_MCGRP_MLME, gfp); |
| 11564 | return; | ||
| 11565 | |||
| 11566 | nla_put_failure: | ||
| 11567 | genlmsg_cancel(msg, hdr); | ||
| 11568 | nlmsg_free(msg); | ||
| 11569 | } | 11798 | } |
| 11570 | EXPORT_SYMBOL(cfg80211_del_sta); | 11799 | EXPORT_SYMBOL(cfg80211_del_sta_sinfo); |
| 11571 | 11800 | ||
| 11572 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, | 11801 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, |
| 11573 | enum nl80211_connect_failed_reason reason, | 11802 | enum nl80211_connect_failed_reason reason, |
| @@ -12471,6 +12700,13 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
| 12471 | 12700 | ||
| 12472 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 12701 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
| 12473 | bool schedule_destroy_work = false; | 12702 | bool schedule_destroy_work = false; |
| 12703 | bool schedule_scan_stop = false; | ||
| 12704 | struct cfg80211_sched_scan_request *sched_scan_req = | ||
| 12705 | rcu_dereference(rdev->sched_scan_req); | ||
| 12706 | |||
| 12707 | if (sched_scan_req && notify->portid && | ||
| 12708 | sched_scan_req->owner_nlportid == notify->portid) | ||
| 12709 | schedule_scan_stop = true; | ||
| 12474 | 12710 | ||
| 12475 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { | 12711 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { |
| 12476 | cfg80211_mlme_unregister_socket(wdev, notify->portid); | 12712 | cfg80211_mlme_unregister_socket(wdev, notify->portid); |
| @@ -12501,6 +12737,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
| 12501 | spin_unlock(&rdev->destroy_list_lock); | 12737 | spin_unlock(&rdev->destroy_list_lock); |
| 12502 | schedule_work(&rdev->destroy_work); | 12738 | schedule_work(&rdev->destroy_work); |
| 12503 | } | 12739 | } |
| 12740 | } else if (schedule_scan_stop) { | ||
| 12741 | sched_scan_req->owner_nlportid = 0; | ||
| 12742 | |||
| 12743 | if (rdev->ops->sched_scan_stop && | ||
| 12744 | rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | ||
| 12745 | schedule_work(&rdev->sched_scan_stop_wk); | ||
| 12504 | } | 12746 | } |
| 12505 | } | 12747 | } |
| 12506 | 12748 | ||
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 7ad70d6f0cc6..84d4edf1d545 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
| @@ -17,7 +17,21 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |||
| 17 | struct net_device *netdev, u32 cmd); | 17 | struct net_device *netdev, u32 cmd); |
| 18 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, | 18 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, |
| 19 | struct net_device *netdev); | 19 | struct net_device *netdev); |
| 20 | void nl80211_send_reg_change_event(struct regulatory_request *request); | 20 | void nl80211_common_reg_change_event(enum nl80211_commands cmd_id, |
| 21 | struct regulatory_request *request); | ||
| 22 | |||
| 23 | static inline void | ||
| 24 | nl80211_send_reg_change_event(struct regulatory_request *request) | ||
| 25 | { | ||
| 26 | nl80211_common_reg_change_event(NL80211_CMD_REG_CHANGE, request); | ||
| 27 | } | ||
| 28 | |||
| 29 | static inline void | ||
| 30 | nl80211_send_wiphy_reg_change_event(struct regulatory_request *request) | ||
| 31 | { | ||
| 32 | nl80211_common_reg_change_event(NL80211_CMD_WIPHY_REG_CHANGE, request); | ||
| 33 | } | ||
| 34 | |||
| 21 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, | 35 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, |
| 22 | struct net_device *netdev, | 36 | struct net_device *netdev, |
| 23 | const u8 *buf, size_t len, gfp_t gfp); | 37 | const u8 *buf, size_t len, gfp_t gfp); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7b8309840d4e..886cc7cb5566 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -109,7 +109,7 @@ static struct regulatory_request core_request_world = { | |||
| 109 | * protected by RTNL (and can be accessed with RCU protection) | 109 | * protected by RTNL (and can be accessed with RCU protection) |
| 110 | */ | 110 | */ |
| 111 | static struct regulatory_request __rcu *last_request = | 111 | static struct regulatory_request __rcu *last_request = |
| 112 | (void __rcu *)&core_request_world; | 112 | (void __force __rcu *)&core_request_world; |
| 113 | 113 | ||
| 114 | /* To trigger userspace events */ | 114 | /* To trigger userspace events */ |
| 115 | static struct platform_device *reg_pdev; | 115 | static struct platform_device *reg_pdev; |
| @@ -142,7 +142,7 @@ static const struct ieee80211_regdomain *get_cfg80211_regdom(void) | |||
| 142 | return rtnl_dereference(cfg80211_regdomain); | 142 | return rtnl_dereference(cfg80211_regdomain); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) | 145 | const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) |
| 146 | { | 146 | { |
| 147 | return rtnl_dereference(wiphy->regd); | 147 | return rtnl_dereference(wiphy->regd); |
| 148 | } | 148 | } |
| @@ -1307,6 +1307,9 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
| 1307 | { | 1307 | { |
| 1308 | struct regulatory_request *lr = get_last_request(); | 1308 | struct regulatory_request *lr = get_last_request(); |
| 1309 | 1309 | ||
| 1310 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
| 1311 | return true; | ||
| 1312 | |||
| 1310 | if (!lr) { | 1313 | if (!lr) { |
| 1311 | REG_DBG_PRINT("Ignoring regulatory request set by %s " | 1314 | REG_DBG_PRINT("Ignoring regulatory request set by %s " |
| 1312 | "since last_request is not set\n", | 1315 | "since last_request is not set\n", |
| @@ -1683,8 +1686,12 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
| 1683 | if (IS_ERR(reg_rule)) { | 1686 | if (IS_ERR(reg_rule)) { |
| 1684 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", | 1687 | REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n", |
| 1685 | chan->center_freq); | 1688 | chan->center_freq); |
| 1686 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; | 1689 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { |
| 1687 | chan->flags = chan->orig_flags; | 1690 | chan->flags |= IEEE80211_CHAN_DISABLED; |
| 1691 | } else { | ||
| 1692 | chan->orig_flags |= IEEE80211_CHAN_DISABLED; | ||
| 1693 | chan->flags = chan->orig_flags; | ||
| 1694 | } | ||
| 1688 | return; | 1695 | return; |
| 1689 | } | 1696 | } |
| 1690 | 1697 | ||
| @@ -1709,7 +1716,13 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
| 1709 | chan->dfs_state = NL80211_DFS_USABLE; | 1716 | chan->dfs_state = NL80211_DFS_USABLE; |
| 1710 | 1717 | ||
| 1711 | chan->beacon_found = false; | 1718 | chan->beacon_found = false; |
| 1712 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1719 | |
| 1720 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
| 1721 | chan->flags = chan->orig_flags | bw_flags | | ||
| 1722 | map_regdom_flags(reg_rule->flags); | ||
| 1723 | else | ||
| 1724 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | ||
| 1725 | |||
| 1713 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1726 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
| 1714 | chan->max_reg_power = chan->max_power = | 1727 | chan->max_reg_power = chan->max_power = |
| 1715 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1728 | (int) MBM_TO_DBM(power_rule->max_eirp); |
| @@ -2095,6 +2108,26 @@ out_free: | |||
| 2095 | reg_free_request(reg_request); | 2108 | reg_free_request(reg_request); |
| 2096 | } | 2109 | } |
| 2097 | 2110 | ||
| 2111 | static bool reg_only_self_managed_wiphys(void) | ||
| 2112 | { | ||
| 2113 | struct cfg80211_registered_device *rdev; | ||
| 2114 | struct wiphy *wiphy; | ||
| 2115 | bool self_managed_found = false; | ||
| 2116 | |||
| 2117 | ASSERT_RTNL(); | ||
| 2118 | |||
| 2119 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
| 2120 | wiphy = &rdev->wiphy; | ||
| 2121 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
| 2122 | self_managed_found = true; | ||
| 2123 | else | ||
| 2124 | return false; | ||
| 2125 | } | ||
| 2126 | |||
| 2127 | /* make sure at least one self-managed wiphy exists */ | ||
| 2128 | return self_managed_found; | ||
| 2129 | } | ||
| 2130 | |||
| 2098 | /* | 2131 | /* |
| 2099 | * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* | 2132 | * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* |
| 2100 | * Regulatory hints come on a first come first serve basis and we | 2133 | * Regulatory hints come on a first come first serve basis and we |
| @@ -2126,6 +2159,11 @@ static void reg_process_pending_hints(void) | |||
| 2126 | 2159 | ||
| 2127 | spin_unlock(®_requests_lock); | 2160 | spin_unlock(®_requests_lock); |
| 2128 | 2161 | ||
| 2162 | if (reg_only_self_managed_wiphys()) { | ||
| 2163 | reg_free_request(reg_request); | ||
| 2164 | return; | ||
| 2165 | } | ||
| 2166 | |||
| 2129 | reg_process_hint(reg_request); | 2167 | reg_process_hint(reg_request); |
| 2130 | } | 2168 | } |
| 2131 | 2169 | ||
| @@ -2153,11 +2191,52 @@ static void reg_process_pending_beacon_hints(void) | |||
| 2153 | spin_unlock_bh(®_pending_beacons_lock); | 2191 | spin_unlock_bh(®_pending_beacons_lock); |
| 2154 | } | 2192 | } |
| 2155 | 2193 | ||
| 2194 | static void reg_process_self_managed_hints(void) | ||
| 2195 | { | ||
| 2196 | struct cfg80211_registered_device *rdev; | ||
| 2197 | struct wiphy *wiphy; | ||
| 2198 | const struct ieee80211_regdomain *tmp; | ||
| 2199 | const struct ieee80211_regdomain *regd; | ||
| 2200 | enum ieee80211_band band; | ||
| 2201 | struct regulatory_request request = {}; | ||
| 2202 | |||
| 2203 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
| 2204 | wiphy = &rdev->wiphy; | ||
| 2205 | |||
| 2206 | spin_lock(®_requests_lock); | ||
| 2207 | regd = rdev->requested_regd; | ||
| 2208 | rdev->requested_regd = NULL; | ||
| 2209 | spin_unlock(®_requests_lock); | ||
| 2210 | |||
| 2211 | if (regd == NULL) | ||
| 2212 | continue; | ||
| 2213 | |||
| 2214 | tmp = get_wiphy_regdom(wiphy); | ||
| 2215 | rcu_assign_pointer(wiphy->regd, regd); | ||
| 2216 | rcu_free_regdom(tmp); | ||
| 2217 | |||
| 2218 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
| 2219 | handle_band_custom(wiphy, wiphy->bands[band], regd); | ||
| 2220 | |||
| 2221 | reg_process_ht_flags(wiphy); | ||
| 2222 | |||
| 2223 | request.wiphy_idx = get_wiphy_idx(wiphy); | ||
| 2224 | request.alpha2[0] = regd->alpha2[0]; | ||
| 2225 | request.alpha2[1] = regd->alpha2[1]; | ||
| 2226 | request.initiator = NL80211_REGDOM_SET_BY_DRIVER; | ||
| 2227 | |||
| 2228 | nl80211_send_wiphy_reg_change_event(&request); | ||
| 2229 | } | ||
| 2230 | |||
| 2231 | reg_check_channels(); | ||
| 2232 | } | ||
| 2233 | |||
| 2156 | static void reg_todo(struct work_struct *work) | 2234 | static void reg_todo(struct work_struct *work) |
| 2157 | { | 2235 | { |
| 2158 | rtnl_lock(); | 2236 | rtnl_lock(); |
| 2159 | reg_process_pending_hints(); | 2237 | reg_process_pending_hints(); |
| 2160 | reg_process_pending_beacon_hints(); | 2238 | reg_process_pending_beacon_hints(); |
| 2239 | reg_process_self_managed_hints(); | ||
| 2161 | rtnl_unlock(); | 2240 | rtnl_unlock(); |
| 2162 | } | 2241 | } |
| 2163 | 2242 | ||
| @@ -2438,6 +2517,8 @@ static void restore_regulatory_settings(bool reset_user) | |||
| 2438 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; | 2517 | world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; |
| 2439 | 2518 | ||
| 2440 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 2519 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
| 2520 | if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
| 2521 | continue; | ||
| 2441 | if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) | 2522 | if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) |
| 2442 | restore_custom_reg_settings(&rdev->wiphy); | 2523 | restore_custom_reg_settings(&rdev->wiphy); |
| 2443 | } | 2524 | } |
| @@ -2841,10 +2922,79 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2841 | return 0; | 2922 | return 0; |
| 2842 | } | 2923 | } |
| 2843 | 2924 | ||
| 2925 | static int __regulatory_set_wiphy_regd(struct wiphy *wiphy, | ||
| 2926 | struct ieee80211_regdomain *rd) | ||
| 2927 | { | ||
| 2928 | const struct ieee80211_regdomain *regd; | ||
| 2929 | const struct ieee80211_regdomain *prev_regd; | ||
| 2930 | struct cfg80211_registered_device *rdev; | ||
| 2931 | |||
| 2932 | if (WARN_ON(!wiphy || !rd)) | ||
| 2933 | return -EINVAL; | ||
| 2934 | |||
| 2935 | if (WARN(!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED), | ||
| 2936 | "wiphy should have REGULATORY_WIPHY_SELF_MANAGED\n")) | ||
| 2937 | return -EPERM; | ||
| 2938 | |||
| 2939 | if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) { | ||
| 2940 | print_regdomain_info(rd); | ||
| 2941 | return -EINVAL; | ||
| 2942 | } | ||
| 2943 | |||
| 2944 | regd = reg_copy_regd(rd); | ||
| 2945 | if (IS_ERR(regd)) | ||
| 2946 | return PTR_ERR(regd); | ||
| 2947 | |||
| 2948 | rdev = wiphy_to_rdev(wiphy); | ||
| 2949 | |||
| 2950 | spin_lock(®_requests_lock); | ||
| 2951 | prev_regd = rdev->requested_regd; | ||
| 2952 | rdev->requested_regd = regd; | ||
| 2953 | spin_unlock(®_requests_lock); | ||
| 2954 | |||
| 2955 | kfree(prev_regd); | ||
| 2956 | return 0; | ||
| 2957 | } | ||
| 2958 | |||
| 2959 | int regulatory_set_wiphy_regd(struct wiphy *wiphy, | ||
| 2960 | struct ieee80211_regdomain *rd) | ||
| 2961 | { | ||
| 2962 | int ret = __regulatory_set_wiphy_regd(wiphy, rd); | ||
| 2963 | |||
| 2964 | if (ret) | ||
| 2965 | return ret; | ||
| 2966 | |||
| 2967 | schedule_work(®_work); | ||
| 2968 | return 0; | ||
| 2969 | } | ||
| 2970 | EXPORT_SYMBOL(regulatory_set_wiphy_regd); | ||
| 2971 | |||
| 2972 | int regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy, | ||
| 2973 | struct ieee80211_regdomain *rd) | ||
| 2974 | { | ||
| 2975 | int ret; | ||
| 2976 | |||
| 2977 | ASSERT_RTNL(); | ||
| 2978 | |||
| 2979 | ret = __regulatory_set_wiphy_regd(wiphy, rd); | ||
| 2980 | if (ret) | ||
| 2981 | return ret; | ||
| 2982 | |||
| 2983 | /* process the request immediately */ | ||
| 2984 | reg_process_self_managed_hints(); | ||
| 2985 | return 0; | ||
| 2986 | } | ||
| 2987 | EXPORT_SYMBOL(regulatory_set_wiphy_regd_sync_rtnl); | ||
| 2988 | |||
| 2844 | void wiphy_regulatory_register(struct wiphy *wiphy) | 2989 | void wiphy_regulatory_register(struct wiphy *wiphy) |
| 2845 | { | 2990 | { |
| 2846 | struct regulatory_request *lr; | 2991 | struct regulatory_request *lr; |
| 2847 | 2992 | ||
| 2993 | /* self-managed devices ignore external hints */ | ||
| 2994 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) | ||
| 2995 | wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS | | ||
| 2996 | REGULATORY_COUNTRY_IE_IGNORE; | ||
| 2997 | |||
| 2848 | if (!reg_dev_ignore_cell_hint(wiphy)) | 2998 | if (!reg_dev_ignore_cell_hint(wiphy)) |
| 2849 | reg_num_devs_support_basehint++; | 2999 | reg_num_devs_support_basehint++; |
| 2850 | 3000 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 5e48031ccb9a..4b45d6e61d24 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
| @@ -38,6 +38,7 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, | |||
| 38 | const struct ieee80211_reg_rule *rule); | 38 | const struct ieee80211_reg_rule *rule); |
| 39 | 39 | ||
| 40 | bool reg_last_request_cell_base(void); | 40 | bool reg_last_request_cell_base(void); |
| 41 | const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy); | ||
| 41 | 42 | ||
| 42 | /** | 43 | /** |
| 43 | * regulatory_hint_found_beacon - hints a beacon was found on a channel | 44 | * regulatory_hint_found_beacon - hints a beacon was found on a channel |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index bda39f149810..c705c3e2b751 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
| @@ -257,7 +257,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) | |||
| 257 | 257 | ||
| 258 | rtnl_lock(); | 258 | rtnl_lock(); |
| 259 | 259 | ||
| 260 | request = rdev->sched_scan_req; | 260 | request = rtnl_dereference(rdev->sched_scan_req); |
| 261 | 261 | ||
| 262 | /* we don't have sched_scan_req anymore if the scan is stopping */ | 262 | /* we don't have sched_scan_req anymore if the scan is stopping */ |
| 263 | if (request) { | 263 | if (request) { |
| @@ -279,7 +279,8 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy) | |||
| 279 | { | 279 | { |
| 280 | trace_cfg80211_sched_scan_results(wiphy); | 280 | trace_cfg80211_sched_scan_results(wiphy); |
| 281 | /* ignore if we're not scanning */ | 281 | /* ignore if we're not scanning */ |
| 282 | if (wiphy_to_rdev(wiphy)->sched_scan_req) | 282 | |
| 283 | if (rcu_access_pointer(wiphy_to_rdev(wiphy)->sched_scan_req)) | ||
| 283 | queue_work(cfg80211_wq, | 284 | queue_work(cfg80211_wq, |
| 284 | &wiphy_to_rdev(wiphy)->sched_scan_results_wk); | 285 | &wiphy_to_rdev(wiphy)->sched_scan_results_wk); |
| 285 | } | 286 | } |
| @@ -308,6 +309,7 @@ EXPORT_SYMBOL(cfg80211_sched_scan_stopped); | |||
| 308 | int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | 309 | int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, |
| 309 | bool driver_initiated) | 310 | bool driver_initiated) |
| 310 | { | 311 | { |
| 312 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
| 311 | struct net_device *dev; | 313 | struct net_device *dev; |
| 312 | 314 | ||
| 313 | ASSERT_RTNL(); | 315 | ASSERT_RTNL(); |
| @@ -315,7 +317,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | |||
| 315 | if (!rdev->sched_scan_req) | 317 | if (!rdev->sched_scan_req) |
| 316 | return -ENOENT; | 318 | return -ENOENT; |
| 317 | 319 | ||
| 318 | dev = rdev->sched_scan_req->dev; | 320 | sched_scan_req = rtnl_dereference(rdev->sched_scan_req); |
| 321 | dev = sched_scan_req->dev; | ||
| 319 | 322 | ||
| 320 | if (!driver_initiated) { | 323 | if (!driver_initiated) { |
| 321 | int err = rdev_sched_scan_stop(rdev, dev); | 324 | int err = rdev_sched_scan_stop(rdev, dev); |
| @@ -325,8 +328,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | |||
| 325 | 328 | ||
| 326 | nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); | 329 | nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); |
| 327 | 330 | ||
| 328 | kfree(rdev->sched_scan_req); | 331 | RCU_INIT_POINTER(rdev->sched_scan_req, NULL); |
| 329 | rdev->sched_scan_req = NULL; | 332 | kfree_rcu(sched_scan_req, rcu_head); |
| 330 | 333 | ||
| 331 | return 0; | 334 | return 0; |
| 332 | } | 335 | } |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ad38910f7036..b17b3692f8c2 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
| @@ -1604,11 +1604,12 @@ TRACE_EVENT(rdev_return_int_survey_info, | |||
| 1604 | WIPHY_ENTRY | 1604 | WIPHY_ENTRY |
| 1605 | CHAN_ENTRY | 1605 | CHAN_ENTRY |
| 1606 | __field(int, ret) | 1606 | __field(int, ret) |
| 1607 | __field(u64, channel_time) | 1607 | __field(u64, time) |
| 1608 | __field(u64, channel_time_busy) | 1608 | __field(u64, time_busy) |
| 1609 | __field(u64, channel_time_ext_busy) | 1609 | __field(u64, time_ext_busy) |
| 1610 | __field(u64, channel_time_rx) | 1610 | __field(u64, time_rx) |
| 1611 | __field(u64, channel_time_tx) | 1611 | __field(u64, time_tx) |
| 1612 | __field(u64, time_scan) | ||
| 1612 | __field(u32, filled) | 1613 | __field(u32, filled) |
| 1613 | __field(s8, noise) | 1614 | __field(s8, noise) |
| 1614 | ), | 1615 | ), |
| @@ -1616,22 +1617,24 @@ TRACE_EVENT(rdev_return_int_survey_info, | |||
| 1616 | WIPHY_ASSIGN; | 1617 | WIPHY_ASSIGN; |
| 1617 | CHAN_ASSIGN(info->channel); | 1618 | CHAN_ASSIGN(info->channel); |
| 1618 | __entry->ret = ret; | 1619 | __entry->ret = ret; |
| 1619 | __entry->channel_time = info->channel_time; | 1620 | __entry->time = info->time; |
| 1620 | __entry->channel_time_busy = info->channel_time_busy; | 1621 | __entry->time_busy = info->time_busy; |
| 1621 | __entry->channel_time_ext_busy = info->channel_time_ext_busy; | 1622 | __entry->time_ext_busy = info->time_ext_busy; |
| 1622 | __entry->channel_time_rx = info->channel_time_rx; | 1623 | __entry->time_rx = info->time_rx; |
| 1623 | __entry->channel_time_tx = info->channel_time_tx; | 1624 | __entry->time_tx = info->time_tx; |
| 1625 | __entry->time_scan = info->time_scan; | ||
| 1624 | __entry->filled = info->filled; | 1626 | __entry->filled = info->filled; |
| 1625 | __entry->noise = info->noise; | 1627 | __entry->noise = info->noise; |
| 1626 | ), | 1628 | ), |
| 1627 | TP_printk(WIPHY_PR_FMT ", returned: %d, " CHAN_PR_FMT | 1629 | TP_printk(WIPHY_PR_FMT ", returned: %d, " CHAN_PR_FMT |
| 1628 | ", channel time: %llu, channel time busy: %llu, " | 1630 | ", channel time: %llu, channel time busy: %llu, " |
| 1629 | "channel time extension busy: %llu, channel time rx: %llu, " | 1631 | "channel time extension busy: %llu, channel time rx: %llu, " |
| 1630 | "channel time tx: %llu, filled: %u, noise: %d", | 1632 | "channel time tx: %llu, scan time: %llu, filled: %u, noise: %d", |
| 1631 | WIPHY_PR_ARG, __entry->ret, CHAN_PR_ARG, | 1633 | WIPHY_PR_ARG, __entry->ret, CHAN_PR_ARG, |
| 1632 | __entry->channel_time, __entry->channel_time_busy, | 1634 | __entry->time, __entry->time_busy, |
| 1633 | __entry->channel_time_ext_busy, __entry->channel_time_rx, | 1635 | __entry->time_ext_busy, __entry->time_rx, |
| 1634 | __entry->channel_time_tx, __entry->filled, __entry->noise) | 1636 | __entry->time_tx, __entry->time_scan, |
| 1637 | __entry->filled, __entry->noise) | ||
| 1635 | ); | 1638 | ); |
| 1636 | 1639 | ||
| 1637 | TRACE_EVENT(rdev_tdls_oper, | 1640 | TRACE_EVENT(rdev_tdls_oper, |
diff --git a/net/wireless/util.c b/net/wireless/util.c index d0ac795445b7..3535e8ade48f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -1073,10 +1073,24 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) | |||
| 1073 | if (WARN_ON_ONCE(rate->mcs > 9)) | 1073 | if (WARN_ON_ONCE(rate->mcs > 9)) |
| 1074 | return 0; | 1074 | return 0; |
| 1075 | 1075 | ||
| 1076 | idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH | | 1076 | switch (rate->bw) { |
| 1077 | RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 : | 1077 | case RATE_INFO_BW_160: |
| 1078 | rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 : | 1078 | idx = 3; |
| 1079 | rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0; | 1079 | break; |
| 1080 | case RATE_INFO_BW_80: | ||
| 1081 | idx = 2; | ||
| 1082 | break; | ||
| 1083 | case RATE_INFO_BW_40: | ||
| 1084 | idx = 1; | ||
| 1085 | break; | ||
| 1086 | case RATE_INFO_BW_5: | ||
| 1087 | case RATE_INFO_BW_10: | ||
| 1088 | default: | ||
| 1089 | WARN_ON(1); | ||
| 1090 | /* fall through */ | ||
| 1091 | case RATE_INFO_BW_20: | ||
| 1092 | idx = 0; | ||
| 1093 | } | ||
| 1080 | 1094 | ||
| 1081 | bitrate = base[idx][rate->mcs]; | 1095 | bitrate = base[idx][rate->mcs]; |
| 1082 | bitrate *= rate->nss; | 1096 | bitrate *= rate->nss; |
| @@ -1107,8 +1121,7 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) | |||
| 1107 | modulation = rate->mcs & 7; | 1121 | modulation = rate->mcs & 7; |
| 1108 | streams = (rate->mcs >> 3) + 1; | 1122 | streams = (rate->mcs >> 3) + 1; |
| 1109 | 1123 | ||
| 1110 | bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? | 1124 | bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000; |
| 1111 | 13500000 : 6500000; | ||
| 1112 | 1125 | ||
| 1113 | if (modulation < 4) | 1126 | if (modulation < 4) |
| 1114 | bitrate *= (modulation + 1); | 1127 | bitrate *= (modulation + 1); |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 0f47948c572f..5b24d39d7903 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
| @@ -1300,7 +1300,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev, | |||
| 1300 | if (err) | 1300 | if (err) |
| 1301 | return err; | 1301 | return err; |
| 1302 | 1302 | ||
| 1303 | if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) | 1303 | if (!(sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))) |
| 1304 | return -EOPNOTSUPP; | 1304 | return -EOPNOTSUPP; |
| 1305 | 1305 | ||
| 1306 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); | 1306 | rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate); |
| @@ -1340,7 +1340,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) | |||
| 1340 | 1340 | ||
| 1341 | switch (rdev->wiphy.signal_type) { | 1341 | switch (rdev->wiphy.signal_type) { |
| 1342 | case CFG80211_SIGNAL_TYPE_MBM: | 1342 | case CFG80211_SIGNAL_TYPE_MBM: |
| 1343 | if (sinfo.filled & STATION_INFO_SIGNAL) { | 1343 | if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) { |
| 1344 | int sig = sinfo.signal; | 1344 | int sig = sinfo.signal; |
| 1345 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | 1345 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
| 1346 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | 1346 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
| @@ -1354,7 +1354,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) | |||
| 1354 | break; | 1354 | break; |
| 1355 | } | 1355 | } |
| 1356 | case CFG80211_SIGNAL_TYPE_UNSPEC: | 1356 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
| 1357 | if (sinfo.filled & STATION_INFO_SIGNAL) { | 1357 | if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) { |
| 1358 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | 1358 | wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; |
| 1359 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | 1359 | wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; |
| 1360 | wstats.qual.level = sinfo.signal; | 1360 | wstats.qual.level = sinfo.signal; |
| @@ -1367,9 +1367,9 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) | |||
| 1367 | } | 1367 | } |
| 1368 | 1368 | ||
| 1369 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; | 1369 | wstats.qual.updated |= IW_QUAL_NOISE_INVALID; |
| 1370 | if (sinfo.filled & STATION_INFO_RX_DROP_MISC) | 1370 | if (sinfo.filled & BIT(NL80211_STA_INFO_RX_DROP_MISC)) |
| 1371 | wstats.discard.misc = sinfo.rx_dropped_misc; | 1371 | wstats.discard.misc = sinfo.rx_dropped_misc; |
| 1372 | if (sinfo.filled & STATION_INFO_TX_FAILED) | 1372 | if (sinfo.filled & BIT(NL80211_STA_INFO_TX_FAILED)) |
| 1373 | wstats.discard.retries = sinfo.tx_failed; | 1373 | wstats.discard.retries = sinfo.tx_failed; |
| 1374 | 1374 | ||
| 1375 | return &wstats; | 1375 | return &wstats; |
