diff options
| author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-01-11 10:28:19 -0500 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-01-11 10:28:19 -0500 |
| commit | 734d1ece37fbf3d2ddfc71bc6c69e0fe35f02542 (patch) | |
| tree | c4805dd7e746b1feb9e09e9849f3245d0b2c0c6b /net/mac80211 | |
| parent | 216c82c6aba63eeb49d7654b448e0d47bea255bb (diff) | |
| parent | 9931faca02c604c22335f5a935a501bb2ace6e20 (diff) | |
Merge tag 'v3.8-rc3' into v4l_for_linus
Linux 3.8-rc3
* tag 'v3.8-rc3': (11110 commits)
Linux 3.8-rc3
mm: reinstante dropped pmd_trans_splitting() check
cred: Remove tgcred pointer from struct cred
drm/ttm: fix fence locking in ttm_buffer_object_transfer
ARM: clps711x: Fix bad merge of clockevents setup
ARM: highbank: save and restore L2 cache and GIC on suspend
ARM: highbank: add a power request clear
ARM: highbank: fix secondary boot and hotplug
ARM: highbank: fix typos with hignbank in power request functions
ARM: dts: fix highbank cpu mpidr values
ARM: dts: add device_type prop to cpu nodes on Calxeda platforms
drm/prime: drop reference on imported dma-buf come from gem
xen/netfront: improve truesize tracking
ARM: mx5: Fix MX53 flexcan2 clock
ARM: OMAP2+: am33xx-hwmod: Fix wrongly terminated am33xx_usbss_mpu_irqs array
sctp: fix Kconfig bug in default cookie hmac selection
EDAC: Cleanup device deregistering path
EDAC: Fix EDAC Kconfig menu
EDAC: Fix kernel panic on module unloading
ALSA: hda - add mute LED for HP Pavilion 17 (Realtek codec)
...
Diffstat (limited to 'net/mac80211')
41 files changed, 3180 insertions, 1449 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 63af25458fda..b4ecf267a34b 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
| @@ -248,7 +248,7 @@ config MAC80211_MHWMP_DEBUG | |||
| 248 | Do not select this option. | 248 | Do not select this option. |
| 249 | 249 | ||
| 250 | config MAC80211_MESH_SYNC_DEBUG | 250 | config MAC80211_MESH_SYNC_DEBUG |
| 251 | bool "Verbose mesh mesh synchronization debugging" | 251 | bool "Verbose mesh synchronization debugging" |
| 252 | depends on MAC80211_DEBUG_MENU | 252 | depends on MAC80211_DEBUG_MENU |
| 253 | depends on MAC80211_MESH | 253 | depends on MAC80211_MESH |
| 254 | ---help--- | 254 | ---help--- |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index a7dd110faafa..4911202334d9 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
| @@ -8,6 +8,7 @@ mac80211-y := \ | |||
| 8 | wpa.o \ | 8 | wpa.o \ |
| 9 | scan.o offchannel.o \ | 9 | scan.o offchannel.o \ |
| 10 | ht.o agg-tx.o agg-rx.o \ | 10 | ht.o agg-tx.o agg-rx.o \ |
| 11 | vht.o \ | ||
| 11 | ibss.o \ | 12 | ibss.o \ |
| 12 | iface.o \ | 13 | iface.o \ |
| 13 | rate.o \ | 14 | rate.o \ |
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index a04752e91023..537488cbf941 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <linux/crypto.h> | 12 | #include <linux/crypto.h> |
| 13 | #include <linux/export.h> | ||
| 13 | #include <linux/err.h> | 14 | #include <linux/err.h> |
| 14 | #include <crypto/aes.h> | 15 | #include <crypto/aes.h> |
| 15 | 16 | ||
| @@ -126,3 +127,20 @@ void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm) | |||
| 126 | { | 127 | { |
| 127 | crypto_free_cipher(tfm); | 128 | crypto_free_cipher(tfm); |
| 128 | } | 129 | } |
| 130 | |||
| 131 | void ieee80211_aes_cmac_calculate_k1_k2(struct ieee80211_key_conf *keyconf, | ||
| 132 | u8 *k1, u8 *k2) | ||
| 133 | { | ||
| 134 | u8 l[AES_BLOCK_SIZE] = {}; | ||
| 135 | struct ieee80211_key *key = | ||
| 136 | container_of(keyconf, struct ieee80211_key, conf); | ||
| 137 | |||
| 138 | crypto_cipher_encrypt_one(key->u.aes_cmac.tfm, l, l); | ||
| 139 | |||
| 140 | memcpy(k1, l, AES_BLOCK_SIZE); | ||
| 141 | gf_mulx(k1); | ||
| 142 | |||
| 143 | memcpy(k2, k1, AES_BLOCK_SIZE); | ||
| 144 | gf_mulx(k2); | ||
| 145 | } | ||
| 146 | EXPORT_SYMBOL(ieee80211_aes_cmac_calculate_k1_k2); | ||
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 186d9919b043..808338a1bce5 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
| @@ -118,7 +118,7 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap, | |||
| 118 | return; | 118 | return; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | for (i = 0; i < STA_TID_NUM; i++) | 121 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 122 | if (ba_rx_bitmap & BIT(i)) | 122 | if (ba_rx_bitmap & BIT(i)) |
| 123 | set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); | 123 | set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested); |
| 124 | 124 | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 3195a6307f50..eb9df22418f0 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
| @@ -445,10 +445,10 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
| 445 | 445 | ||
| 446 | trace_api_start_tx_ba_session(pubsta, tid); | 446 | trace_api_start_tx_ba_session(pubsta, tid); |
| 447 | 447 | ||
| 448 | if (WARN_ON(!local->ops->ampdu_action)) | 448 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) |
| 449 | return -EINVAL; | 449 | return -EINVAL; |
| 450 | 450 | ||
| 451 | if ((tid >= STA_TID_NUM) || | 451 | if ((tid >= IEEE80211_NUM_TIDS) || |
| 452 | !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) || | 452 | !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) || |
| 453 | (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) | 453 | (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) |
| 454 | return -EINVAL; | 454 | return -EINVAL; |
| @@ -605,9 +605,9 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) | |||
| 605 | 605 | ||
| 606 | trace_api_start_tx_ba_cb(sdata, ra, tid); | 606 | trace_api_start_tx_ba_cb(sdata, ra, tid); |
| 607 | 607 | ||
| 608 | if (tid >= STA_TID_NUM) { | 608 | if (tid >= IEEE80211_NUM_TIDS) { |
| 609 | ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", | 609 | ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", |
| 610 | tid, STA_TID_NUM); | 610 | tid, IEEE80211_NUM_TIDS); |
| 611 | return; | 611 | return; |
| 612 | } | 612 | } |
| 613 | 613 | ||
| @@ -687,7 +687,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
| 687 | if (!local->ops->ampdu_action) | 687 | if (!local->ops->ampdu_action) |
| 688 | return -EINVAL; | 688 | return -EINVAL; |
| 689 | 689 | ||
| 690 | if (tid >= STA_TID_NUM) | 690 | if (tid >= IEEE80211_NUM_TIDS) |
| 691 | return -EINVAL; | 691 | return -EINVAL; |
| 692 | 692 | ||
| 693 | spin_lock_bh(&sta->lock); | 693 | spin_lock_bh(&sta->lock); |
| @@ -722,9 +722,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) | |||
| 722 | 722 | ||
| 723 | trace_api_stop_tx_ba_cb(sdata, ra, tid); | 723 | trace_api_stop_tx_ba_cb(sdata, ra, tid); |
| 724 | 724 | ||
| 725 | if (tid >= STA_TID_NUM) { | 725 | if (tid >= IEEE80211_NUM_TIDS) { |
| 726 | ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", | 726 | ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", |
| 727 | tid, STA_TID_NUM); | 727 | tid, IEEE80211_NUM_TIDS); |
| 728 | return; | 728 | return; |
| 729 | } | 729 | } |
| 730 | 730 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7371f676cf41..5c61677487cf 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -370,29 +370,64 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, | |||
| 370 | return 0; | 370 | return 0; |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx) | ||
| 374 | { | ||
| 375 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { | ||
| 376 | struct ieee80211_supported_band *sband; | ||
| 377 | sband = sta->local->hw.wiphy->bands[ | ||
| 378 | sta->local->oper_channel->band]; | ||
| 379 | rate->legacy = sband->bitrates[idx].bitrate; | ||
| 380 | } else | ||
| 381 | rate->mcs = idx; | ||
| 382 | } | ||
| 383 | |||
| 384 | void sta_set_rate_info_tx(struct sta_info *sta, | 373 | void sta_set_rate_info_tx(struct sta_info *sta, |
| 385 | const struct ieee80211_tx_rate *rate, | 374 | const struct ieee80211_tx_rate *rate, |
| 386 | struct rate_info *rinfo) | 375 | struct rate_info *rinfo) |
| 387 | { | 376 | { |
| 388 | rinfo->flags = 0; | 377 | rinfo->flags = 0; |
| 389 | if (rate->flags & IEEE80211_TX_RC_MCS) | 378 | if (rate->flags & IEEE80211_TX_RC_MCS) { |
| 390 | rinfo->flags |= RATE_INFO_FLAGS_MCS; | 379 | rinfo->flags |= RATE_INFO_FLAGS_MCS; |
| 380 | rinfo->mcs = rate->idx; | ||
| 381 | } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { | ||
| 382 | rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS; | ||
| 383 | rinfo->mcs = ieee80211_rate_get_vht_mcs(rate); | ||
| 384 | rinfo->nss = ieee80211_rate_get_vht_nss(rate); | ||
| 385 | } else { | ||
| 386 | struct ieee80211_supported_band *sband; | ||
| 387 | sband = sta->local->hw.wiphy->bands[ | ||
| 388 | ieee80211_get_sdata_band(sta->sdata)]; | ||
| 389 | rinfo->legacy = sband->bitrates[rate->idx].bitrate; | ||
| 390 | } | ||
| 391 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 391 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
| 392 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 392 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
| 393 | if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) | ||
| 394 | rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | ||
| 395 | if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) | ||
| 396 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | ||
| 393 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) | 397 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) |
| 394 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; | 398 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; |
| 395 | rate_idx_to_bitrate(rinfo, sta, rate->idx); | 399 | } |
| 400 | |||
| 401 | void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) | ||
| 402 | { | ||
| 403 | rinfo->flags = 0; | ||
| 404 | |||
| 405 | if (sta->last_rx_rate_flag & RX_FLAG_HT) { | ||
| 406 | rinfo->flags |= RATE_INFO_FLAGS_MCS; | ||
| 407 | rinfo->mcs = sta->last_rx_rate_idx; | ||
| 408 | } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) { | ||
| 409 | rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS; | ||
| 410 | rinfo->nss = sta->last_rx_rate_vht_nss; | ||
| 411 | rinfo->mcs = sta->last_rx_rate_idx; | ||
| 412 | } else { | ||
| 413 | struct ieee80211_supported_band *sband; | ||
| 414 | |||
| 415 | sband = sta->local->hw.wiphy->bands[ | ||
| 416 | ieee80211_get_sdata_band(sta->sdata)]; | ||
| 417 | rinfo->legacy = | ||
| 418 | sband->bitrates[sta->last_rx_rate_idx].bitrate; | ||
| 419 | } | ||
| 420 | |||
| 421 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) | ||
| 422 | rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
| 423 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) | ||
| 424 | rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
| 425 | if (sta->last_rx_rate_flag & RX_FLAG_80MHZ) | ||
| 426 | rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | ||
| 427 | if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ) | ||
| 428 | rinfo->flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | ||
| 429 | if (sta->last_rx_rate_flag & RX_FLAG_160MHZ) | ||
| 430 | rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | ||
| 396 | } | 431 | } |
| 397 | 432 | ||
| 398 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 433 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
| @@ -441,15 +476,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
| 441 | } | 476 | } |
| 442 | 477 | ||
| 443 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | 478 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); |
| 444 | 479 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | |
| 445 | sinfo->rxrate.flags = 0; | ||
| 446 | if (sta->last_rx_rate_flag & RX_FLAG_HT) | ||
| 447 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; | ||
| 448 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) | ||
| 449 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
| 450 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) | ||
| 451 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
| 452 | rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx); | ||
| 453 | 480 | ||
| 454 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 481 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 455 | #ifdef CONFIG_MAC80211_MESH | 482 | #ifdef CONFIG_MAC80211_MESH |
| @@ -532,6 +559,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, | |||
| 532 | u64 *data) | 559 | u64 *data) |
| 533 | { | 560 | { |
| 534 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 561 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 562 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 563 | struct ieee80211_channel *channel; | ||
| 535 | struct sta_info *sta; | 564 | struct sta_info *sta; |
| 536 | struct ieee80211_local *local = sdata->local; | 565 | struct ieee80211_local *local = sdata->local; |
| 537 | struct station_info sinfo; | 566 | struct station_info sinfo; |
| @@ -607,19 +636,26 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, | |||
| 607 | do_survey: | 636 | do_survey: |
| 608 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; | 637 | i = STA_STATS_LEN - STA_STATS_SURVEY_LEN; |
| 609 | /* Get survey stats for current channel */ | 638 | /* Get survey stats for current channel */ |
| 610 | q = 0; | 639 | survey.filled = 0; |
| 611 | while (true) { | ||
| 612 | survey.filled = 0; | ||
| 613 | if (drv_get_survey(local, q, &survey) != 0) { | ||
| 614 | survey.filled = 0; | ||
| 615 | break; | ||
| 616 | } | ||
| 617 | 640 | ||
| 618 | if (survey.channel && | 641 | rcu_read_lock(); |
| 619 | (local->oper_channel->center_freq == | 642 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 620 | survey.channel->center_freq)) | 643 | if (chanctx_conf) |
| 621 | break; | 644 | channel = chanctx_conf->def.chan; |
| 622 | q++; | 645 | else |
| 646 | channel = NULL; | ||
| 647 | rcu_read_unlock(); | ||
| 648 | |||
| 649 | if (channel) { | ||
| 650 | q = 0; | ||
| 651 | do { | ||
| 652 | survey.filled = 0; | ||
| 653 | if (drv_get_survey(local, q, &survey) != 0) { | ||
| 654 | survey.filled = 0; | ||
| 655 | break; | ||
| 656 | } | ||
| 657 | q++; | ||
| 658 | } while (channel != survey.channel); | ||
| 623 | } | 659 | } |
| 624 | 660 | ||
| 625 | if (survey.filled) | 661 | if (survey.filled) |
| @@ -724,47 +760,37 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 724 | return ret; | 760 | return ret; |
| 725 | } | 761 | } |
| 726 | 762 | ||
| 727 | static int ieee80211_set_channel(struct wiphy *wiphy, | 763 | static int ieee80211_set_monitor_channel(struct wiphy *wiphy, |
| 728 | struct net_device *netdev, | 764 | struct cfg80211_chan_def *chandef) |
| 729 | struct ieee80211_channel *chan, | ||
| 730 | enum nl80211_channel_type channel_type) | ||
| 731 | { | 765 | { |
| 732 | struct ieee80211_local *local = wiphy_priv(wiphy); | 766 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 733 | struct ieee80211_sub_if_data *sdata = NULL; | 767 | struct ieee80211_sub_if_data *sdata; |
| 734 | 768 | int ret = 0; | |
| 735 | if (netdev) | ||
| 736 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); | ||
| 737 | |||
| 738 | switch (ieee80211_get_channel_mode(local, NULL)) { | ||
| 739 | case CHAN_MODE_HOPPING: | ||
| 740 | return -EBUSY; | ||
| 741 | case CHAN_MODE_FIXED: | ||
| 742 | if (local->oper_channel != chan || | ||
| 743 | (!sdata && local->_oper_channel_type != channel_type)) | ||
| 744 | return -EBUSY; | ||
| 745 | if (!sdata && local->_oper_channel_type == channel_type) | ||
| 746 | return 0; | ||
| 747 | break; | ||
| 748 | case CHAN_MODE_UNDEFINED: | ||
| 749 | break; | ||
| 750 | } | ||
| 751 | 769 | ||
| 752 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) | 770 | if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) |
| 753 | return -EBUSY; | 771 | return 0; |
| 754 | 772 | ||
| 755 | local->oper_channel = chan; | 773 | mutex_lock(&local->iflist_mtx); |
| 774 | if (local->use_chanctx) { | ||
| 775 | sdata = rcu_dereference_protected( | ||
| 776 | local->monitor_sdata, | ||
| 777 | lockdep_is_held(&local->iflist_mtx)); | ||
| 778 | if (sdata) { | ||
| 779 | ieee80211_vif_release_channel(sdata); | ||
| 780 | ret = ieee80211_vif_use_channel(sdata, chandef, | ||
| 781 | IEEE80211_CHANCTX_EXCLUSIVE); | ||
| 782 | } | ||
| 783 | } else if (local->open_count == local->monitors) { | ||
| 784 | local->_oper_channel = chandef->chan; | ||
| 785 | local->_oper_channel_type = cfg80211_get_chandef_type(chandef); | ||
| 786 | ieee80211_hw_config(local, 0); | ||
| 787 | } | ||
| 756 | 788 | ||
| 757 | /* auto-detects changes */ | 789 | if (ret == 0) |
| 758 | ieee80211_hw_config(local, 0); | 790 | local->monitor_chandef = *chandef; |
| 791 | mutex_unlock(&local->iflist_mtx); | ||
| 759 | 792 | ||
| 760 | return 0; | 793 | return ret; |
| 761 | } | ||
| 762 | |||
| 763 | static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | ||
| 764 | struct ieee80211_channel *chan, | ||
| 765 | enum nl80211_channel_type channel_type) | ||
| 766 | { | ||
| 767 | return ieee80211_set_channel(wiphy, NULL, chan, channel_type); | ||
| 768 | } | 794 | } |
| 769 | 795 | ||
| 770 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | 796 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, |
| @@ -872,15 +898,20 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 872 | u32 changed = BSS_CHANGED_BEACON_INT | | 898 | u32 changed = BSS_CHANGED_BEACON_INT | |
| 873 | BSS_CHANGED_BEACON_ENABLED | | 899 | BSS_CHANGED_BEACON_ENABLED | |
| 874 | BSS_CHANGED_BEACON | | 900 | BSS_CHANGED_BEACON | |
| 875 | BSS_CHANGED_SSID; | 901 | BSS_CHANGED_SSID | |
| 902 | BSS_CHANGED_P2P_PS; | ||
| 876 | int err; | 903 | int err; |
| 877 | 904 | ||
| 878 | old = rtnl_dereference(sdata->u.ap.beacon); | 905 | old = rtnl_dereference(sdata->u.ap.beacon); |
| 879 | if (old) | 906 | if (old) |
| 880 | return -EALREADY; | 907 | return -EALREADY; |
| 881 | 908 | ||
| 882 | err = ieee80211_set_channel(wiphy, dev, params->channel, | 909 | /* TODO: make hostapd tell us what it wants */ |
| 883 | params->channel_type); | 910 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 911 | sdata->needed_rx_chains = sdata->local->rx_chains; | ||
| 912 | |||
| 913 | err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, | ||
| 914 | IEEE80211_CHANCTX_SHARED); | ||
| 884 | if (err) | 915 | if (err) |
| 885 | return err; | 916 | return err; |
| 886 | 917 | ||
| @@ -907,11 +938,23 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
| 907 | sdata->vif.bss_conf.hidden_ssid = | 938 | sdata->vif.bss_conf.hidden_ssid = |
| 908 | (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); | 939 | (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); |
| 909 | 940 | ||
| 941 | sdata->vif.bss_conf.p2p_ctwindow = params->p2p_ctwindow; | ||
| 942 | sdata->vif.bss_conf.p2p_oppps = params->p2p_opp_ps; | ||
| 943 | |||
| 910 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon); | 944 | err = ieee80211_assign_beacon(sdata, ¶ms->beacon); |
| 911 | if (err < 0) | 945 | if (err < 0) |
| 912 | return err; | 946 | return err; |
| 913 | changed |= err; | 947 | changed |= err; |
| 914 | 948 | ||
| 949 | err = drv_start_ap(sdata->local, sdata); | ||
| 950 | if (err) { | ||
| 951 | old = rtnl_dereference(sdata->u.ap.beacon); | ||
| 952 | if (old) | ||
| 953 | kfree_rcu(old, rcu_head); | ||
| 954 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | ||
| 955 | return err; | ||
| 956 | } | ||
| 957 | |||
| 915 | ieee80211_bss_info_change_notify(sdata, changed); | 958 | ieee80211_bss_info_change_notify(sdata, changed); |
| 916 | 959 | ||
| 917 | netif_carrier_on(dev); | 960 | netif_carrier_on(dev); |
| @@ -943,26 +986,40 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
| 943 | 986 | ||
| 944 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | 987 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) |
| 945 | { | 988 | { |
| 946 | struct ieee80211_sub_if_data *sdata, *vlan; | 989 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 947 | struct beacon_data *old; | 990 | struct ieee80211_sub_if_data *vlan; |
| 948 | 991 | struct ieee80211_local *local = sdata->local; | |
| 949 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 992 | struct beacon_data *old_beacon; |
| 993 | struct probe_resp *old_probe_resp; | ||
| 950 | 994 | ||
| 951 | old = rtnl_dereference(sdata->u.ap.beacon); | 995 | old_beacon = rtnl_dereference(sdata->u.ap.beacon); |
| 952 | if (!old) | 996 | if (!old_beacon) |
| 953 | return -ENOENT; | 997 | return -ENOENT; |
| 998 | old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); | ||
| 954 | 999 | ||
| 1000 | /* turn off carrier for this interface and dependent VLANs */ | ||
| 955 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1001 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
| 956 | netif_carrier_off(vlan->dev); | 1002 | netif_carrier_off(vlan->dev); |
| 957 | netif_carrier_off(dev); | 1003 | netif_carrier_off(dev); |
| 958 | 1004 | ||
| 1005 | /* remove beacon and probe response */ | ||
| 959 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | 1006 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); |
| 1007 | RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | ||
| 1008 | kfree_rcu(old_beacon, rcu_head); | ||
| 1009 | if (old_probe_resp) | ||
| 1010 | kfree_rcu(old_probe_resp, rcu_head); | ||
| 960 | 1011 | ||
| 961 | kfree_rcu(old, rcu_head); | 1012 | sta_info_flush(local, sdata); |
| 962 | |||
| 963 | sta_info_flush(sdata->local, sdata); | ||
| 964 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 1013 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
| 965 | 1014 | ||
| 1015 | drv_stop_ap(sdata->local, sdata); | ||
| 1016 | |||
| 1017 | /* free all potentially still buffered bcast frames */ | ||
| 1018 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); | ||
| 1019 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | ||
| 1020 | |||
| 1021 | ieee80211_vif_release_channel(sdata); | ||
| 1022 | |||
| 966 | return 0; | 1023 | return 0; |
| 967 | } | 1024 | } |
| 968 | 1025 | ||
| @@ -1019,9 +1076,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
| 1019 | int i, j; | 1076 | int i, j; |
| 1020 | struct ieee80211_supported_band *sband; | 1077 | struct ieee80211_supported_band *sband; |
| 1021 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1078 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 1079 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
| 1022 | u32 mask, set; | 1080 | u32 mask, set; |
| 1023 | 1081 | ||
| 1024 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 1082 | sband = local->hw.wiphy->bands[band]; |
| 1025 | 1083 | ||
| 1026 | mask = params->sta_flags_mask; | 1084 | mask = params->sta_flags_mask; |
| 1027 | set = params->sta_flags_set; | 1085 | set = params->sta_flags_set; |
| @@ -1136,7 +1194,7 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
| 1136 | rates |= BIT(j); | 1194 | rates |= BIT(j); |
| 1137 | } | 1195 | } |
| 1138 | } | 1196 | } |
| 1139 | sta->sta.supp_rates[local->oper_channel->band] = rates; | 1197 | sta->sta.supp_rates[band] = rates; |
| 1140 | } | 1198 | } |
| 1141 | 1199 | ||
| 1142 | if (params->ht_capa) | 1200 | if (params->ht_capa) |
| @@ -1144,6 +1202,11 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
| 1144 | params->ht_capa, | 1202 | params->ht_capa, |
| 1145 | &sta->sta.ht_cap); | 1203 | &sta->sta.ht_cap); |
| 1146 | 1204 | ||
| 1205 | if (params->vht_capa) | ||
| 1206 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | ||
| 1207 | params->vht_capa, | ||
| 1208 | &sta->sta.vht_cap); | ||
| 1209 | |||
| 1147 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 1210 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 1148 | #ifdef CONFIG_MAC80211_MESH | 1211 | #ifdef CONFIG_MAC80211_MESH |
| 1149 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) | 1212 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) |
| @@ -1664,8 +1727,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | |||
| 1664 | if (err) | 1727 | if (err) |
| 1665 | return err; | 1728 | return err; |
| 1666 | 1729 | ||
| 1667 | err = ieee80211_set_channel(wiphy, dev, setup->channel, | 1730 | /* can mesh use other SMPS modes? */ |
| 1668 | setup->channel_type); | 1731 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 1732 | sdata->needed_rx_chains = sdata->local->rx_chains; | ||
| 1733 | |||
| 1734 | err = ieee80211_vif_use_channel(sdata, &setup->chandef, | ||
| 1735 | IEEE80211_CHANCTX_SHARED); | ||
| 1669 | if (err) | 1736 | if (err) |
| 1670 | return err; | 1737 | return err; |
| 1671 | 1738 | ||
| @@ -1679,6 +1746,7 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | |||
| 1679 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1746 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 1680 | 1747 | ||
| 1681 | ieee80211_stop_mesh(sdata); | 1748 | ieee80211_stop_mesh(sdata); |
| 1749 | ieee80211_vif_release_channel(sdata); | ||
| 1682 | 1750 | ||
| 1683 | return 0; | 1751 | return 0; |
| 1684 | } | 1752 | } |
| @@ -1688,10 +1756,14 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
| 1688 | struct net_device *dev, | 1756 | struct net_device *dev, |
| 1689 | struct bss_parameters *params) | 1757 | struct bss_parameters *params) |
| 1690 | { | 1758 | { |
| 1691 | struct ieee80211_sub_if_data *sdata; | 1759 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 1760 | enum ieee80211_band band; | ||
| 1692 | u32 changed = 0; | 1761 | u32 changed = 0; |
| 1693 | 1762 | ||
| 1694 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1763 | if (!rtnl_dereference(sdata->u.ap.beacon)) |
| 1764 | return -ENOENT; | ||
| 1765 | |||
| 1766 | band = ieee80211_get_sdata_band(sdata); | ||
| 1695 | 1767 | ||
| 1696 | if (params->use_cts_prot >= 0) { | 1768 | if (params->use_cts_prot >= 0) { |
| 1697 | sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; | 1769 | sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; |
| @@ -1704,7 +1776,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
| 1704 | } | 1776 | } |
| 1705 | 1777 | ||
| 1706 | if (!sdata->vif.bss_conf.use_short_slot && | 1778 | if (!sdata->vif.bss_conf.use_short_slot && |
| 1707 | sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) { | 1779 | band == IEEE80211_BAND_5GHZ) { |
| 1708 | sdata->vif.bss_conf.use_short_slot = true; | 1780 | sdata->vif.bss_conf.use_short_slot = true; |
| 1709 | changed |= BSS_CHANGED_ERP_SLOT; | 1781 | changed |= BSS_CHANGED_ERP_SLOT; |
| 1710 | } | 1782 | } |
| @@ -1718,9 +1790,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
| 1718 | if (params->basic_rates) { | 1790 | if (params->basic_rates) { |
| 1719 | int i, j; | 1791 | int i, j; |
| 1720 | u32 rates = 0; | 1792 | u32 rates = 0; |
| 1721 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1793 | struct ieee80211_supported_band *sband = wiphy->bands[band]; |
| 1722 | struct ieee80211_supported_band *sband = | ||
| 1723 | wiphy->bands[local->oper_channel->band]; | ||
| 1724 | 1794 | ||
| 1725 | for (i = 0; i < params->basic_rates_len; i++) { | 1795 | for (i = 0; i < params->basic_rates_len; i++) { |
| 1726 | int rate = (params->basic_rates[i] & 0x7f) * 5; | 1796 | int rate = (params->basic_rates[i] & 0x7f) * 5; |
| @@ -1746,6 +1816,16 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
| 1746 | changed |= BSS_CHANGED_HT; | 1816 | changed |= BSS_CHANGED_HT; |
| 1747 | } | 1817 | } |
| 1748 | 1818 | ||
| 1819 | if (params->p2p_ctwindow >= 0) { | ||
| 1820 | sdata->vif.bss_conf.p2p_ctwindow = params->p2p_ctwindow; | ||
| 1821 | changed |= BSS_CHANGED_P2P_PS; | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | if (params->p2p_opp_ps >= 0) { | ||
| 1825 | sdata->vif.bss_conf.p2p_oppps = params->p2p_opp_ps; | ||
| 1826 | changed |= BSS_CHANGED_P2P_PS; | ||
| 1827 | } | ||
| 1828 | |||
| 1749 | ieee80211_bss_info_change_notify(sdata, changed); | 1829 | ieee80211_bss_info_change_notify(sdata, changed); |
| 1750 | 1830 | ||
| 1751 | return 0; | 1831 | return 0; |
| @@ -1829,7 +1909,16 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
| 1829 | * beaconing hasn't been configured yet | 1909 | * beaconing hasn't been configured yet |
| 1830 | */ | 1910 | */ |
| 1831 | case NL80211_IFTYPE_AP: | 1911 | case NL80211_IFTYPE_AP: |
| 1832 | if (sdata->u.ap.beacon) | 1912 | /* |
| 1913 | * If the scan has been forced (and the driver supports | ||
| 1914 | * forcing), don't care about being beaconing already. | ||
| 1915 | * This will create problems to the attached stations (e.g. all | ||
| 1916 | * the frames sent while scanning on other channel will be | ||
| 1917 | * lost) | ||
| 1918 | */ | ||
| 1919 | if (sdata->u.ap.beacon && | ||
| 1920 | (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || | ||
| 1921 | !(req->flags & NL80211_SCAN_FLAG_AP))) | ||
| 1833 | return -EOPNOTSUPP; | 1922 | return -EOPNOTSUPP; |
| 1834 | break; | 1923 | break; |
| 1835 | default: | 1924 | default: |
| @@ -1872,20 +1961,6 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | |||
| 1872 | static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | 1961 | static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, |
| 1873 | struct cfg80211_assoc_request *req) | 1962 | struct cfg80211_assoc_request *req) |
| 1874 | { | 1963 | { |
| 1875 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
| 1876 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1877 | |||
| 1878 | switch (ieee80211_get_channel_mode(local, sdata)) { | ||
| 1879 | case CHAN_MODE_HOPPING: | ||
| 1880 | return -EBUSY; | ||
| 1881 | case CHAN_MODE_FIXED: | ||
| 1882 | if (local->oper_channel == req->bss->channel) | ||
| 1883 | break; | ||
| 1884 | return -EBUSY; | ||
| 1885 | case CHAN_MODE_UNDEFINED: | ||
| 1886 | break; | ||
| 1887 | } | ||
| 1888 | |||
| 1889 | return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); | 1964 | return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); |
| 1890 | } | 1965 | } |
| 1891 | 1966 | ||
| @@ -1904,30 +1979,22 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, | |||
| 1904 | static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | 1979 | static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, |
| 1905 | struct cfg80211_ibss_params *params) | 1980 | struct cfg80211_ibss_params *params) |
| 1906 | { | 1981 | { |
| 1907 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1982 | return ieee80211_ibss_join(IEEE80211_DEV_TO_SUB_IF(dev), params); |
| 1908 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1909 | |||
| 1910 | switch (ieee80211_get_channel_mode(local, sdata)) { | ||
| 1911 | case CHAN_MODE_HOPPING: | ||
| 1912 | return -EBUSY; | ||
| 1913 | case CHAN_MODE_FIXED: | ||
| 1914 | if (!params->channel_fixed) | ||
| 1915 | return -EBUSY; | ||
| 1916 | if (local->oper_channel == params->channel) | ||
| 1917 | break; | ||
| 1918 | return -EBUSY; | ||
| 1919 | case CHAN_MODE_UNDEFINED: | ||
| 1920 | break; | ||
| 1921 | } | ||
| 1922 | |||
| 1923 | return ieee80211_ibss_join(sdata, params); | ||
| 1924 | } | 1983 | } |
| 1925 | 1984 | ||
| 1926 | static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | 1985 | static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) |
| 1927 | { | 1986 | { |
| 1987 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | ||
| 1988 | } | ||
| 1989 | |||
| 1990 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, | ||
| 1991 | int rate[IEEE80211_NUM_BANDS]) | ||
| 1992 | { | ||
| 1928 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1993 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 1929 | 1994 | ||
| 1930 | return ieee80211_ibss_leave(sdata); | 1995 | memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate)); |
| 1996 | |||
| 1997 | return 0; | ||
| 1931 | } | 1998 | } |
| 1932 | 1999 | ||
| 1933 | static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | 2000 | static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) |
| @@ -1956,10 +2023,16 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
| 1956 | return err; | 2023 | return err; |
| 1957 | } | 2024 | } |
| 1958 | 2025 | ||
| 1959 | if (changed & WIPHY_PARAM_RETRY_SHORT) | 2026 | if (changed & WIPHY_PARAM_RETRY_SHORT) { |
| 2027 | if (wiphy->retry_short > IEEE80211_MAX_TX_RETRY) | ||
| 2028 | return -EINVAL; | ||
| 1960 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 2029 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
| 1961 | if (changed & WIPHY_PARAM_RETRY_LONG) | 2030 | } |
| 2031 | if (changed & WIPHY_PARAM_RETRY_LONG) { | ||
| 2032 | if (wiphy->retry_long > IEEE80211_MAX_TX_RETRY) | ||
| 2033 | return -EINVAL; | ||
| 1962 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 2034 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
| 2035 | } | ||
| 1963 | if (changed & | 2036 | if (changed & |
| 1964 | (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) | 2037 | (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) |
| 1965 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); | 2038 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); |
| @@ -1968,41 +2041,65 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
| 1968 | } | 2041 | } |
| 1969 | 2042 | ||
| 1970 | static int ieee80211_set_tx_power(struct wiphy *wiphy, | 2043 | static int ieee80211_set_tx_power(struct wiphy *wiphy, |
| 2044 | struct wireless_dev *wdev, | ||
| 1971 | enum nl80211_tx_power_setting type, int mbm) | 2045 | enum nl80211_tx_power_setting type, int mbm) |
| 1972 | { | 2046 | { |
| 1973 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2047 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 1974 | struct ieee80211_channel *chan = local->oper_channel; | 2048 | struct ieee80211_sub_if_data *sdata; |
| 1975 | u32 changes = 0; | 2049 | |
| 2050 | if (wdev) { | ||
| 2051 | sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
| 2052 | |||
| 2053 | switch (type) { | ||
| 2054 | case NL80211_TX_POWER_AUTOMATIC: | ||
| 2055 | sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL; | ||
| 2056 | break; | ||
| 2057 | case NL80211_TX_POWER_LIMITED: | ||
| 2058 | case NL80211_TX_POWER_FIXED: | ||
| 2059 | if (mbm < 0 || (mbm % 100)) | ||
| 2060 | return -EOPNOTSUPP; | ||
| 2061 | sdata->user_power_level = MBM_TO_DBM(mbm); | ||
| 2062 | break; | ||
| 2063 | } | ||
| 2064 | |||
| 2065 | ieee80211_recalc_txpower(sdata); | ||
| 2066 | |||
| 2067 | return 0; | ||
| 2068 | } | ||
| 1976 | 2069 | ||
| 1977 | switch (type) { | 2070 | switch (type) { |
| 1978 | case NL80211_TX_POWER_AUTOMATIC: | 2071 | case NL80211_TX_POWER_AUTOMATIC: |
| 1979 | local->user_power_level = -1; | 2072 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; |
| 1980 | break; | 2073 | break; |
| 1981 | case NL80211_TX_POWER_LIMITED: | 2074 | case NL80211_TX_POWER_LIMITED: |
| 1982 | if (mbm < 0 || (mbm % 100)) | ||
| 1983 | return -EOPNOTSUPP; | ||
| 1984 | local->user_power_level = MBM_TO_DBM(mbm); | ||
| 1985 | break; | ||
| 1986 | case NL80211_TX_POWER_FIXED: | 2075 | case NL80211_TX_POWER_FIXED: |
| 1987 | if (mbm < 0 || (mbm % 100)) | 2076 | if (mbm < 0 || (mbm % 100)) |
| 1988 | return -EOPNOTSUPP; | 2077 | return -EOPNOTSUPP; |
| 1989 | /* TODO: move to cfg80211 when it knows the channel */ | ||
| 1990 | if (MBM_TO_DBM(mbm) > chan->max_power) | ||
| 1991 | return -EINVAL; | ||
| 1992 | local->user_power_level = MBM_TO_DBM(mbm); | 2078 | local->user_power_level = MBM_TO_DBM(mbm); |
| 1993 | break; | 2079 | break; |
| 1994 | } | 2080 | } |
| 1995 | 2081 | ||
| 1996 | ieee80211_hw_config(local, changes); | 2082 | mutex_lock(&local->iflist_mtx); |
| 2083 | list_for_each_entry(sdata, &local->interfaces, list) | ||
| 2084 | sdata->user_power_level = local->user_power_level; | ||
| 2085 | list_for_each_entry(sdata, &local->interfaces, list) | ||
| 2086 | ieee80211_recalc_txpower(sdata); | ||
| 2087 | mutex_unlock(&local->iflist_mtx); | ||
| 1997 | 2088 | ||
| 1998 | return 0; | 2089 | return 0; |
| 1999 | } | 2090 | } |
| 2000 | 2091 | ||
| 2001 | static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) | 2092 | static int ieee80211_get_tx_power(struct wiphy *wiphy, |
| 2093 | struct wireless_dev *wdev, | ||
| 2094 | int *dbm) | ||
| 2002 | { | 2095 | { |
| 2003 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2096 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 2097 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
| 2004 | 2098 | ||
| 2005 | *dbm = local->hw.conf.power_level; | 2099 | if (!local->use_chanctx) |
| 2100 | *dbm = local->hw.conf.power_level; | ||
| 2101 | else | ||
| 2102 | *dbm = sdata->vif.bss_conf.txpower; | ||
| 2006 | 2103 | ||
| 2007 | return 0; | 2104 | return 0; |
| 2008 | } | 2105 | } |
| @@ -2067,13 +2164,12 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
| 2067 | 2164 | ||
| 2068 | /* | 2165 | /* |
| 2069 | * If not associated, or current association is not an HT | 2166 | * If not associated, or current association is not an HT |
| 2070 | * association, there's no need to send an action frame. | 2167 | * association, there's no need to do anything, just store |
| 2168 | * the new value until we associate. | ||
| 2071 | */ | 2169 | */ |
| 2072 | if (!sdata->u.mgd.associated || | 2170 | if (!sdata->u.mgd.associated || |
| 2073 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) { | 2171 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 2074 | ieee80211_recalc_smps(sdata->local); | ||
| 2075 | return 0; | 2172 | return 0; |
| 2076 | } | ||
| 2077 | 2173 | ||
| 2078 | ap = sdata->u.mgd.associated->bssid; | 2174 | ap = sdata->u.mgd.associated->bssid; |
| 2079 | 2175 | ||
| @@ -2179,7 +2275,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
| 2179 | static int ieee80211_start_roc_work(struct ieee80211_local *local, | 2275 | static int ieee80211_start_roc_work(struct ieee80211_local *local, |
| 2180 | struct ieee80211_sub_if_data *sdata, | 2276 | struct ieee80211_sub_if_data *sdata, |
| 2181 | struct ieee80211_channel *channel, | 2277 | struct ieee80211_channel *channel, |
| 2182 | enum nl80211_channel_type channel_type, | ||
| 2183 | unsigned int duration, u64 *cookie, | 2278 | unsigned int duration, u64 *cookie, |
| 2184 | struct sk_buff *txskb) | 2279 | struct sk_buff *txskb) |
| 2185 | { | 2280 | { |
| @@ -2189,12 +2284,14 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2189 | 2284 | ||
| 2190 | lockdep_assert_held(&local->mtx); | 2285 | lockdep_assert_held(&local->mtx); |
| 2191 | 2286 | ||
| 2287 | if (local->use_chanctx && !local->ops->remain_on_channel) | ||
| 2288 | return -EOPNOTSUPP; | ||
| 2289 | |||
| 2192 | roc = kzalloc(sizeof(*roc), GFP_KERNEL); | 2290 | roc = kzalloc(sizeof(*roc), GFP_KERNEL); |
| 2193 | if (!roc) | 2291 | if (!roc) |
| 2194 | return -ENOMEM; | 2292 | return -ENOMEM; |
| 2195 | 2293 | ||
| 2196 | roc->chan = channel; | 2294 | roc->chan = channel; |
| 2197 | roc->chan_type = channel_type; | ||
| 2198 | roc->duration = duration; | 2295 | roc->duration = duration; |
| 2199 | roc->req_duration = duration; | 2296 | roc->req_duration = duration; |
| 2200 | roc->frame = txskb; | 2297 | roc->frame = txskb; |
| @@ -2227,7 +2324,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2227 | if (!duration) | 2324 | if (!duration) |
| 2228 | duration = 10; | 2325 | duration = 10; |
| 2229 | 2326 | ||
| 2230 | ret = drv_remain_on_channel(local, channel, channel_type, duration); | 2327 | ret = drv_remain_on_channel(local, sdata, channel, duration); |
| 2231 | if (ret) { | 2328 | if (ret) { |
| 2232 | kfree(roc); | 2329 | kfree(roc); |
| 2233 | return ret; | 2330 | return ret; |
| @@ -2238,7 +2335,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2238 | 2335 | ||
| 2239 | out_check_combine: | 2336 | out_check_combine: |
| 2240 | list_for_each_entry(tmp, &local->roc_list, list) { | 2337 | list_for_each_entry(tmp, &local->roc_list, list) { |
| 2241 | if (tmp->chan != channel || tmp->chan_type != channel_type) | 2338 | if (tmp->chan != channel || tmp->sdata != sdata) |
| 2242 | continue; | 2339 | continue; |
| 2243 | 2340 | ||
| 2244 | /* | 2341 | /* |
| @@ -2332,13 +2429,22 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2332 | list_add_tail(&roc->list, &local->roc_list); | 2429 | list_add_tail(&roc->list, &local->roc_list); |
| 2333 | 2430 | ||
| 2334 | /* | 2431 | /* |
| 2335 | * cookie is either the roc (for normal roc) | 2432 | * cookie is either the roc cookie (for normal roc) |
| 2336 | * or the SKB (for mgmt TX) | 2433 | * or the SKB (for mgmt TX) |
| 2337 | */ | 2434 | */ |
| 2338 | if (txskb) | 2435 | if (!txskb) { |
| 2436 | /* local->mtx protects this */ | ||
| 2437 | local->roc_cookie_counter++; | ||
| 2438 | roc->cookie = local->roc_cookie_counter; | ||
| 2439 | /* wow, you wrapped 64 bits ... more likely a bug */ | ||
| 2440 | if (WARN_ON(roc->cookie == 0)) { | ||
| 2441 | roc->cookie = 1; | ||
| 2442 | local->roc_cookie_counter++; | ||
| 2443 | } | ||
| 2444 | *cookie = roc->cookie; | ||
| 2445 | } else { | ||
| 2339 | *cookie = (unsigned long)txskb; | 2446 | *cookie = (unsigned long)txskb; |
| 2340 | else | 2447 | } |
| 2341 | *cookie = (unsigned long)roc; | ||
| 2342 | 2448 | ||
| 2343 | return 0; | 2449 | return 0; |
| 2344 | } | 2450 | } |
| @@ -2346,7 +2452,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
| 2346 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, | 2452 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
| 2347 | struct wireless_dev *wdev, | 2453 | struct wireless_dev *wdev, |
| 2348 | struct ieee80211_channel *chan, | 2454 | struct ieee80211_channel *chan, |
| 2349 | enum nl80211_channel_type channel_type, | ||
| 2350 | unsigned int duration, | 2455 | unsigned int duration, |
| 2351 | u64 *cookie) | 2456 | u64 *cookie) |
| 2352 | { | 2457 | { |
| @@ -2355,7 +2460,7 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy, | |||
| 2355 | int ret; | 2460 | int ret; |
| 2356 | 2461 | ||
| 2357 | mutex_lock(&local->mtx); | 2462 | mutex_lock(&local->mtx); |
| 2358 | ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, | 2463 | ret = ieee80211_start_roc_work(local, sdata, chan, |
| 2359 | duration, cookie, NULL); | 2464 | duration, cookie, NULL); |
| 2360 | mutex_unlock(&local->mtx); | 2465 | mutex_unlock(&local->mtx); |
| 2361 | 2466 | ||
| @@ -2373,7 +2478,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
| 2373 | struct ieee80211_roc_work *dep, *tmp2; | 2478 | struct ieee80211_roc_work *dep, *tmp2; |
| 2374 | 2479 | ||
| 2375 | list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { | 2480 | list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { |
| 2376 | if (!mgmt_tx && (unsigned long)dep != cookie) | 2481 | if (!mgmt_tx && dep->cookie != cookie) |
| 2377 | continue; | 2482 | continue; |
| 2378 | else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) | 2483 | else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) |
| 2379 | continue; | 2484 | continue; |
| @@ -2385,7 +2490,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
| 2385 | return 0; | 2490 | return 0; |
| 2386 | } | 2491 | } |
| 2387 | 2492 | ||
| 2388 | if (!mgmt_tx && (unsigned long)roc != cookie) | 2493 | if (!mgmt_tx && roc->cookie != cookie) |
| 2389 | continue; | 2494 | continue; |
| 2390 | else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) | 2495 | else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) |
| 2391 | continue; | 2496 | continue; |
| @@ -2448,10 +2553,8 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | |||
| 2448 | 2553 | ||
| 2449 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | 2554 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 2450 | struct ieee80211_channel *chan, bool offchan, | 2555 | struct ieee80211_channel *chan, bool offchan, |
| 2451 | enum nl80211_channel_type channel_type, | 2556 | unsigned int wait, const u8 *buf, size_t len, |
| 2452 | bool channel_type_valid, unsigned int wait, | 2557 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) |
| 2453 | const u8 *buf, size_t len, bool no_cck, | ||
| 2454 | bool dont_wait_for_ack, u64 *cookie) | ||
| 2455 | { | 2558 | { |
| 2456 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 2559 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
| 2457 | struct ieee80211_local *local = sdata->local; | 2560 | struct ieee80211_local *local = sdata->local; |
| @@ -2515,10 +2618,16 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 2515 | 2618 | ||
| 2516 | /* Check if the operating channel is the requested channel */ | 2619 | /* Check if the operating channel is the requested channel */ |
| 2517 | if (!need_offchan) { | 2620 | if (!need_offchan) { |
| 2518 | need_offchan = chan != local->oper_channel; | 2621 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 2519 | if (channel_type_valid && | 2622 | |
| 2520 | channel_type != local->_oper_channel_type) | 2623 | rcu_read_lock(); |
| 2624 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 2625 | |||
| 2626 | if (chanctx_conf) | ||
| 2627 | need_offchan = chan != chanctx_conf->def.chan; | ||
| 2628 | else | ||
| 2521 | need_offchan = true; | 2629 | need_offchan = true; |
| 2630 | rcu_read_unlock(); | ||
| 2522 | } | 2631 | } |
| 2523 | 2632 | ||
| 2524 | if (need_offchan && !offchan) { | 2633 | if (need_offchan && !offchan) { |
| @@ -2552,7 +2661,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
| 2552 | local->hw.offchannel_tx_hw_queue; | 2661 | local->hw.offchannel_tx_hw_queue; |
| 2553 | 2662 | ||
| 2554 | /* This will handle all kinds of coalescing and immediate TX */ | 2663 | /* This will handle all kinds of coalescing and immediate TX */ |
| 2555 | ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, | 2664 | ret = ieee80211_start_roc_work(local, sdata, chan, |
| 2556 | wait, cookie, skb); | 2665 | wait, cookie, skb); |
| 2557 | if (ret) | 2666 | if (ret) |
| 2558 | kfree_skb(skb); | 2667 | kfree_skb(skb); |
| @@ -2670,7 +2779,7 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) | |||
| 2670 | u16 capab; | 2779 | u16 capab; |
| 2671 | 2780 | ||
| 2672 | capab = 0; | 2781 | capab = 0; |
| 2673 | if (local->oper_channel->band != IEEE80211_BAND_2GHZ) | 2782 | if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ) |
| 2674 | return capab; | 2783 | return capab; |
| 2675 | 2784 | ||
| 2676 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | 2785 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) |
| @@ -2702,7 +2811,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
| 2702 | u16 status_code, struct sk_buff *skb) | 2811 | u16 status_code, struct sk_buff *skb) |
| 2703 | { | 2812 | { |
| 2704 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2813 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 2705 | struct ieee80211_local *local = sdata->local; | 2814 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
| 2706 | struct ieee80211_tdls_data *tf; | 2815 | struct ieee80211_tdls_data *tf; |
| 2707 | 2816 | ||
| 2708 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); | 2817 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); |
| @@ -2722,10 +2831,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
| 2722 | tf->u.setup_req.capability = | 2831 | tf->u.setup_req.capability = |
| 2723 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2832 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
| 2724 | 2833 | ||
| 2725 | ieee80211_add_srates_ie(sdata, skb, false, | 2834 | ieee80211_add_srates_ie(sdata, skb, false, band); |
| 2726 | local->oper_channel->band); | 2835 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); |
| 2727 | ieee80211_add_ext_srates_ie(sdata, skb, false, | ||
| 2728 | local->oper_channel->band); | ||
| 2729 | ieee80211_tdls_add_ext_capab(skb); | 2836 | ieee80211_tdls_add_ext_capab(skb); |
| 2730 | break; | 2837 | break; |
| 2731 | case WLAN_TDLS_SETUP_RESPONSE: | 2838 | case WLAN_TDLS_SETUP_RESPONSE: |
| @@ -2738,10 +2845,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
| 2738 | tf->u.setup_resp.capability = | 2845 | tf->u.setup_resp.capability = |
| 2739 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2846 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
| 2740 | 2847 | ||
| 2741 | ieee80211_add_srates_ie(sdata, skb, false, | 2848 | ieee80211_add_srates_ie(sdata, skb, false, band); |
| 2742 | local->oper_channel->band); | 2849 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); |
| 2743 | ieee80211_add_ext_srates_ie(sdata, skb, false, | ||
| 2744 | local->oper_channel->band); | ||
| 2745 | ieee80211_tdls_add_ext_capab(skb); | 2850 | ieee80211_tdls_add_ext_capab(skb); |
| 2746 | break; | 2851 | break; |
| 2747 | case WLAN_TDLS_SETUP_CONFIRM: | 2852 | case WLAN_TDLS_SETUP_CONFIRM: |
| @@ -2779,7 +2884,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
| 2779 | u16 status_code, struct sk_buff *skb) | 2884 | u16 status_code, struct sk_buff *skb) |
| 2780 | { | 2885 | { |
| 2781 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2886 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 2782 | struct ieee80211_local *local = sdata->local; | 2887 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
| 2783 | struct ieee80211_mgmt *mgmt; | 2888 | struct ieee80211_mgmt *mgmt; |
| 2784 | 2889 | ||
| 2785 | mgmt = (void *)skb_put(skb, 24); | 2890 | mgmt = (void *)skb_put(skb, 24); |
| @@ -2802,10 +2907,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
| 2802 | mgmt->u.action.u.tdls_discover_resp.capability = | 2907 | mgmt->u.action.u.tdls_discover_resp.capability = |
| 2803 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2908 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
| 2804 | 2909 | ||
| 2805 | ieee80211_add_srates_ie(sdata, skb, false, | 2910 | ieee80211_add_srates_ie(sdata, skb, false, band); |
| 2806 | local->oper_channel->band); | 2911 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); |
| 2807 | ieee80211_add_ext_srates_ie(sdata, skb, false, | ||
| 2808 | local->oper_channel->band); | ||
| 2809 | ieee80211_tdls_add_ext_capab(skb); | 2912 | ieee80211_tdls_add_ext_capab(skb); |
| 2810 | break; | 2913 | break; |
| 2811 | default: | 2914 | default: |
| @@ -2822,7 +2925,6 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
| 2822 | { | 2925 | { |
| 2823 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2926 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 2824 | struct ieee80211_local *local = sdata->local; | 2927 | struct ieee80211_local *local = sdata->local; |
| 2825 | struct ieee80211_tx_info *info; | ||
| 2826 | struct sk_buff *skb = NULL; | 2928 | struct sk_buff *skb = NULL; |
| 2827 | bool send_direct; | 2929 | bool send_direct; |
| 2828 | int ret; | 2930 | int ret; |
| @@ -2848,7 +2950,6 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
| 2848 | if (!skb) | 2950 | if (!skb) |
| 2849 | return -ENOMEM; | 2951 | return -ENOMEM; |
| 2850 | 2952 | ||
| 2851 | info = IEEE80211_SKB_CB(skb); | ||
| 2852 | skb_reserve(skb, local->hw.extra_tx_headroom); | 2953 | skb_reserve(skb, local->hw.extra_tx_headroom); |
| 2853 | 2954 | ||
| 2854 | switch (action_code) { | 2955 | switch (action_code) { |
| @@ -2985,12 +3086,19 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
| 2985 | bool qos; | 3086 | bool qos; |
| 2986 | struct ieee80211_tx_info *info; | 3087 | struct ieee80211_tx_info *info; |
| 2987 | struct sta_info *sta; | 3088 | struct sta_info *sta; |
| 3089 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 3090 | enum ieee80211_band band; | ||
| 2988 | 3091 | ||
| 2989 | rcu_read_lock(); | 3092 | rcu_read_lock(); |
| 3093 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 3094 | if (WARN_ON(!chanctx_conf)) { | ||
| 3095 | rcu_read_unlock(); | ||
| 3096 | return -EINVAL; | ||
| 3097 | } | ||
| 3098 | band = chanctx_conf->def.chan->band; | ||
| 2990 | sta = sta_info_get(sdata, peer); | 3099 | sta = sta_info_get(sdata, peer); |
| 2991 | if (sta) { | 3100 | if (sta) { |
| 2992 | qos = test_sta_flag(sta, WLAN_STA_WME); | 3101 | qos = test_sta_flag(sta, WLAN_STA_WME); |
| 2993 | rcu_read_unlock(); | ||
| 2994 | } else { | 3102 | } else { |
| 2995 | rcu_read_unlock(); | 3103 | rcu_read_unlock(); |
| 2996 | return -ENOLINK; | 3104 | return -ENOLINK; |
| @@ -3008,8 +3116,10 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
| 3008 | } | 3116 | } |
| 3009 | 3117 | ||
| 3010 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + size); | 3118 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + size); |
| 3011 | if (!skb) | 3119 | if (!skb) { |
| 3120 | rcu_read_unlock(); | ||
| 3012 | return -ENOMEM; | 3121 | return -ENOMEM; |
| 3122 | } | ||
| 3013 | 3123 | ||
| 3014 | skb->dev = dev; | 3124 | skb->dev = dev; |
| 3015 | 3125 | ||
| @@ -3034,21 +3144,31 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
| 3034 | nullfunc->qos_ctrl = cpu_to_le16(7); | 3144 | nullfunc->qos_ctrl = cpu_to_le16(7); |
| 3035 | 3145 | ||
| 3036 | local_bh_disable(); | 3146 | local_bh_disable(); |
| 3037 | ieee80211_xmit(sdata, skb); | 3147 | ieee80211_xmit(sdata, skb, band); |
| 3038 | local_bh_enable(); | 3148 | local_bh_enable(); |
| 3149 | rcu_read_unlock(); | ||
| 3039 | 3150 | ||
| 3040 | *cookie = (unsigned long) skb; | 3151 | *cookie = (unsigned long) skb; |
| 3041 | return 0; | 3152 | return 0; |
| 3042 | } | 3153 | } |
| 3043 | 3154 | ||
| 3044 | static struct ieee80211_channel * | 3155 | static int ieee80211_cfg_get_channel(struct wiphy *wiphy, |
| 3045 | ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | 3156 | struct wireless_dev *wdev, |
| 3046 | enum nl80211_channel_type *type) | 3157 | struct cfg80211_chan_def *chandef) |
| 3047 | { | 3158 | { |
| 3048 | struct ieee80211_local *local = wiphy_priv(wiphy); | 3159 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
| 3160 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 3161 | int ret = -ENODATA; | ||
| 3162 | |||
| 3163 | rcu_read_lock(); | ||
| 3164 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 3165 | if (chanctx_conf) { | ||
| 3166 | *chandef = chanctx_conf->def; | ||
| 3167 | ret = 0; | ||
| 3168 | } | ||
| 3169 | rcu_read_unlock(); | ||
| 3049 | 3170 | ||
| 3050 | *type = local->_oper_channel_type; | 3171 | return ret; |
| 3051 | return local->oper_channel; | ||
| 3052 | } | 3172 | } |
| 3053 | 3173 | ||
| 3054 | #ifdef CONFIG_PM | 3174 | #ifdef CONFIG_PM |
| @@ -3103,6 +3223,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
| 3103 | .disassoc = ieee80211_disassoc, | 3223 | .disassoc = ieee80211_disassoc, |
| 3104 | .join_ibss = ieee80211_join_ibss, | 3224 | .join_ibss = ieee80211_join_ibss, |
| 3105 | .leave_ibss = ieee80211_leave_ibss, | 3225 | .leave_ibss = ieee80211_leave_ibss, |
| 3226 | .set_mcast_rate = ieee80211_set_mcast_rate, | ||
| 3106 | .set_wiphy_params = ieee80211_set_wiphy_params, | 3227 | .set_wiphy_params = ieee80211_set_wiphy_params, |
| 3107 | .set_tx_power = ieee80211_set_tx_power, | 3228 | .set_tx_power = ieee80211_set_tx_power, |
| 3108 | .get_tx_power = ieee80211_get_tx_power, | 3229 | .get_tx_power = ieee80211_get_tx_power, |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 0bfc914ddd15..53f03120db55 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
| @@ -3,168 +3,347 @@ | |||
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | #include <linux/nl80211.h> | 5 | #include <linux/nl80211.h> |
| 6 | #include <linux/export.h> | ||
| 6 | #include <net/cfg80211.h> | 7 | #include <net/cfg80211.h> |
| 7 | #include "ieee80211_i.h" | 8 | #include "ieee80211_i.h" |
| 9 | #include "driver-ops.h" | ||
| 8 | 10 | ||
| 9 | static enum ieee80211_chan_mode | 11 | static void ieee80211_change_chandef(struct ieee80211_local *local, |
| 10 | __ieee80211_get_channel_mode(struct ieee80211_local *local, | 12 | struct ieee80211_chanctx *ctx, |
| 11 | struct ieee80211_sub_if_data *ignore) | 13 | const struct cfg80211_chan_def *chandef) |
| 12 | { | 14 | { |
| 15 | if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) | ||
| 16 | return; | ||
| 17 | |||
| 18 | WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef)); | ||
| 19 | |||
| 20 | ctx->conf.def = *chandef; | ||
| 21 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); | ||
| 22 | |||
| 23 | if (!local->use_chanctx) { | ||
| 24 | local->_oper_channel_type = cfg80211_get_chandef_type(chandef); | ||
| 25 | ieee80211_hw_config(local, 0); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | static struct ieee80211_chanctx * | ||
| 30 | ieee80211_find_chanctx(struct ieee80211_local *local, | ||
| 31 | const struct cfg80211_chan_def *chandef, | ||
| 32 | enum ieee80211_chanctx_mode mode) | ||
| 33 | { | ||
| 34 | struct ieee80211_chanctx *ctx; | ||
| 35 | |||
| 36 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 37 | |||
| 38 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) | ||
| 39 | return NULL; | ||
| 40 | |||
| 41 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
| 42 | const struct cfg80211_chan_def *compat; | ||
| 43 | |||
| 44 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | ||
| 45 | continue; | ||
| 46 | |||
| 47 | compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef); | ||
| 48 | if (!compat) | ||
| 49 | continue; | ||
| 50 | |||
| 51 | ieee80211_change_chandef(local, ctx, compat); | ||
| 52 | |||
| 53 | return ctx; | ||
| 54 | } | ||
| 55 | |||
| 56 | return NULL; | ||
| 57 | } | ||
| 58 | |||
| 59 | static struct ieee80211_chanctx * | ||
| 60 | ieee80211_new_chanctx(struct ieee80211_local *local, | ||
| 61 | const struct cfg80211_chan_def *chandef, | ||
| 62 | enum ieee80211_chanctx_mode mode) | ||
| 63 | { | ||
| 64 | struct ieee80211_chanctx *ctx; | ||
| 65 | int err; | ||
| 66 | |||
| 67 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 68 | |||
| 69 | ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); | ||
| 70 | if (!ctx) | ||
| 71 | return ERR_PTR(-ENOMEM); | ||
| 72 | |||
| 73 | ctx->conf.def = *chandef; | ||
| 74 | ctx->conf.rx_chains_static = 1; | ||
| 75 | ctx->conf.rx_chains_dynamic = 1; | ||
| 76 | ctx->mode = mode; | ||
| 77 | |||
| 78 | if (!local->use_chanctx) { | ||
| 79 | local->_oper_channel_type = | ||
| 80 | cfg80211_get_chandef_type(chandef); | ||
| 81 | local->_oper_channel = chandef->chan; | ||
| 82 | ieee80211_hw_config(local, 0); | ||
| 83 | } else { | ||
| 84 | err = drv_add_chanctx(local, ctx); | ||
| 85 | if (err) { | ||
| 86 | kfree(ctx); | ||
| 87 | return ERR_PTR(err); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | list_add_rcu(&ctx->list, &local->chanctx_list); | ||
| 92 | |||
| 93 | return ctx; | ||
| 94 | } | ||
| 95 | |||
| 96 | static void ieee80211_free_chanctx(struct ieee80211_local *local, | ||
| 97 | struct ieee80211_chanctx *ctx) | ||
| 98 | { | ||
| 99 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 100 | |||
| 101 | WARN_ON_ONCE(ctx->refcount != 0); | ||
| 102 | |||
| 103 | if (!local->use_chanctx) { | ||
| 104 | local->_oper_channel_type = NL80211_CHAN_NO_HT; | ||
| 105 | ieee80211_hw_config(local, 0); | ||
| 106 | } else { | ||
| 107 | drv_remove_chanctx(local, ctx); | ||
| 108 | } | ||
| 109 | |||
| 110 | list_del_rcu(&ctx->list); | ||
| 111 | kfree_rcu(ctx, rcu_head); | ||
| 112 | } | ||
| 113 | |||
| 114 | static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | ||
| 115 | struct ieee80211_chanctx *ctx) | ||
| 116 | { | ||
| 117 | struct ieee80211_local *local = sdata->local; | ||
| 118 | int ret; | ||
| 119 | |||
| 120 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 121 | |||
| 122 | ret = drv_assign_vif_chanctx(local, sdata, ctx); | ||
| 123 | if (ret) | ||
| 124 | return ret; | ||
| 125 | |||
| 126 | rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); | ||
| 127 | ctx->refcount++; | ||
| 128 | |||
| 129 | ieee80211_recalc_txpower(sdata); | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, | ||
| 135 | struct ieee80211_chanctx *ctx) | ||
| 136 | { | ||
| 137 | struct ieee80211_chanctx_conf *conf = &ctx->conf; | ||
| 13 | struct ieee80211_sub_if_data *sdata; | 138 | struct ieee80211_sub_if_data *sdata; |
| 139 | const struct cfg80211_chan_def *compat = NULL; | ||
| 14 | 140 | ||
| 15 | lockdep_assert_held(&local->iflist_mtx); | 141 | lockdep_assert_held(&local->chanctx_mtx); |
| 16 | 142 | ||
| 17 | list_for_each_entry(sdata, &local->interfaces, list) { | 143 | rcu_read_lock(); |
| 18 | if (sdata == ignore) | 144 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 145 | |||
| 146 | if (!ieee80211_sdata_running(sdata)) | ||
| 147 | continue; | ||
| 148 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) | ||
| 19 | continue; | 149 | continue; |
| 20 | 150 | ||
| 151 | if (!compat) | ||
| 152 | compat = &sdata->vif.bss_conf.chandef; | ||
| 153 | |||
| 154 | compat = cfg80211_chandef_compatible( | ||
| 155 | &sdata->vif.bss_conf.chandef, compat); | ||
| 156 | if (!compat) | ||
| 157 | break; | ||
| 158 | } | ||
| 159 | rcu_read_unlock(); | ||
| 160 | |||
| 161 | if (WARN_ON_ONCE(!compat)) | ||
| 162 | return; | ||
| 163 | |||
| 164 | ieee80211_change_chandef(local, ctx, compat); | ||
| 165 | } | ||
| 166 | |||
| 167 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | ||
| 168 | struct ieee80211_chanctx *ctx) | ||
| 169 | { | ||
| 170 | struct ieee80211_local *local = sdata->local; | ||
| 171 | |||
| 172 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 173 | |||
| 174 | ctx->refcount--; | ||
| 175 | rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); | ||
| 176 | |||
| 177 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
| 178 | |||
| 179 | if (ctx->refcount > 0) { | ||
| 180 | ieee80211_recalc_chanctx_chantype(sdata->local, ctx); | ||
| 181 | ieee80211_recalc_smps_chanctx(local, ctx); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | ||
| 186 | { | ||
| 187 | struct ieee80211_local *local = sdata->local; | ||
| 188 | struct ieee80211_chanctx_conf *conf; | ||
| 189 | struct ieee80211_chanctx *ctx; | ||
| 190 | |||
| 191 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 192 | |||
| 193 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 194 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 195 | if (!conf) | ||
| 196 | return; | ||
| 197 | |||
| 198 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
| 199 | |||
| 200 | ieee80211_unassign_vif_chanctx(sdata, ctx); | ||
| 201 | if (ctx->refcount == 0) | ||
| 202 | ieee80211_free_chanctx(local, ctx); | ||
| 203 | } | ||
| 204 | |||
| 205 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | ||
| 206 | struct ieee80211_chanctx *chanctx) | ||
| 207 | { | ||
| 208 | struct ieee80211_sub_if_data *sdata; | ||
| 209 | u8 rx_chains_static, rx_chains_dynamic; | ||
| 210 | |||
| 211 | lockdep_assert_held(&local->chanctx_mtx); | ||
| 212 | |||
| 213 | rx_chains_static = 1; | ||
| 214 | rx_chains_dynamic = 1; | ||
| 215 | |||
| 216 | rcu_read_lock(); | ||
| 217 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 218 | u8 needed_static, needed_dynamic; | ||
| 219 | |||
| 21 | if (!ieee80211_sdata_running(sdata)) | 220 | if (!ieee80211_sdata_running(sdata)) |
| 22 | continue; | 221 | continue; |
| 23 | 222 | ||
| 223 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != | ||
| 224 | &chanctx->conf) | ||
| 225 | continue; | ||
| 226 | |||
| 24 | switch (sdata->vif.type) { | 227 | switch (sdata->vif.type) { |
| 25 | case NL80211_IFTYPE_MONITOR: | 228 | case NL80211_IFTYPE_P2P_DEVICE: |
| 26 | continue; | 229 | continue; |
| 27 | case NL80211_IFTYPE_STATION: | 230 | case NL80211_IFTYPE_STATION: |
| 28 | if (!sdata->u.mgd.associated) | 231 | if (!sdata->u.mgd.associated) |
| 29 | continue; | 232 | continue; |
| 30 | break; | 233 | break; |
| 31 | case NL80211_IFTYPE_ADHOC: | ||
| 32 | if (!sdata->u.ibss.ssid_len) | ||
| 33 | continue; | ||
| 34 | if (!sdata->u.ibss.fixed_channel) | ||
| 35 | return CHAN_MODE_HOPPING; | ||
| 36 | break; | ||
| 37 | case NL80211_IFTYPE_AP_VLAN: | 234 | case NL80211_IFTYPE_AP_VLAN: |
| 38 | /* will also have _AP interface */ | ||
| 39 | continue; | 235 | continue; |
| 40 | case NL80211_IFTYPE_AP: | 236 | case NL80211_IFTYPE_AP: |
| 41 | if (!sdata->u.ap.beacon) | 237 | case NL80211_IFTYPE_ADHOC: |
| 42 | continue; | 238 | case NL80211_IFTYPE_WDS: |
| 43 | break; | ||
| 44 | case NL80211_IFTYPE_MESH_POINT: | 239 | case NL80211_IFTYPE_MESH_POINT: |
| 45 | if (!sdata->wdev.mesh_id_len) | ||
| 46 | continue; | ||
| 47 | break; | 240 | break; |
| 48 | default: | 241 | default: |
| 242 | WARN_ON_ONCE(1); | ||
| 243 | } | ||
| 244 | |||
| 245 | switch (sdata->smps_mode) { | ||
| 246 | default: | ||
| 247 | WARN_ONCE(1, "Invalid SMPS mode %d\n", | ||
| 248 | sdata->smps_mode); | ||
| 249 | /* fall through */ | ||
| 250 | case IEEE80211_SMPS_OFF: | ||
| 251 | needed_static = sdata->needed_rx_chains; | ||
| 252 | needed_dynamic = sdata->needed_rx_chains; | ||
| 253 | break; | ||
| 254 | case IEEE80211_SMPS_DYNAMIC: | ||
| 255 | needed_static = 1; | ||
| 256 | needed_dynamic = sdata->needed_rx_chains; | ||
| 257 | break; | ||
| 258 | case IEEE80211_SMPS_STATIC: | ||
| 259 | needed_static = 1; | ||
| 260 | needed_dynamic = 1; | ||
| 49 | break; | 261 | break; |
| 50 | } | 262 | } |
| 51 | 263 | ||
| 52 | return CHAN_MODE_FIXED; | 264 | rx_chains_static = max(rx_chains_static, needed_static); |
| 265 | rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); | ||
| 53 | } | 266 | } |
| 267 | rcu_read_unlock(); | ||
| 54 | 268 | ||
| 55 | return CHAN_MODE_UNDEFINED; | 269 | if (!local->use_chanctx) { |
| 56 | } | 270 | if (rx_chains_static > 1) |
| 57 | 271 | local->smps_mode = IEEE80211_SMPS_OFF; | |
| 58 | enum ieee80211_chan_mode | 272 | else if (rx_chains_dynamic > 1) |
| 59 | ieee80211_get_channel_mode(struct ieee80211_local *local, | 273 | local->smps_mode = IEEE80211_SMPS_DYNAMIC; |
| 60 | struct ieee80211_sub_if_data *ignore) | 274 | else |
| 61 | { | 275 | local->smps_mode = IEEE80211_SMPS_STATIC; |
| 62 | enum ieee80211_chan_mode mode; | 276 | ieee80211_hw_config(local, 0); |
| 277 | } | ||
| 63 | 278 | ||
| 64 | mutex_lock(&local->iflist_mtx); | 279 | if (rx_chains_static == chanctx->conf.rx_chains_static && |
| 65 | mode = __ieee80211_get_channel_mode(local, ignore); | 280 | rx_chains_dynamic == chanctx->conf.rx_chains_dynamic) |
| 66 | mutex_unlock(&local->iflist_mtx); | 281 | return; |
| 67 | 282 | ||
| 68 | return mode; | 283 | chanctx->conf.rx_chains_static = rx_chains_static; |
| 284 | chanctx->conf.rx_chains_dynamic = rx_chains_dynamic; | ||
| 285 | drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS); | ||
| 69 | } | 286 | } |
| 70 | 287 | ||
| 71 | static enum nl80211_channel_type | 288 | int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, |
| 72 | ieee80211_get_superchan(struct ieee80211_local *local, | 289 | const struct cfg80211_chan_def *chandef, |
| 73 | struct ieee80211_sub_if_data *sdata) | 290 | enum ieee80211_chanctx_mode mode) |
| 74 | { | 291 | { |
| 75 | enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; | 292 | struct ieee80211_local *local = sdata->local; |
| 76 | struct ieee80211_sub_if_data *tmp; | 293 | struct ieee80211_chanctx *ctx; |
| 294 | int ret; | ||
| 77 | 295 | ||
| 78 | mutex_lock(&local->iflist_mtx); | 296 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); |
| 79 | list_for_each_entry(tmp, &local->interfaces, list) { | ||
| 80 | if (tmp == sdata) | ||
| 81 | continue; | ||
| 82 | |||
| 83 | if (!ieee80211_sdata_running(tmp)) | ||
| 84 | continue; | ||
| 85 | 297 | ||
| 86 | switch (tmp->vif.bss_conf.channel_type) { | 298 | mutex_lock(&local->chanctx_mtx); |
| 87 | case NL80211_CHAN_NO_HT: | 299 | __ieee80211_vif_release_channel(sdata); |
| 88 | case NL80211_CHAN_HT20: | ||
| 89 | if (superchan > tmp->vif.bss_conf.channel_type) | ||
| 90 | break; | ||
| 91 | 300 | ||
| 92 | superchan = tmp->vif.bss_conf.channel_type; | 301 | ctx = ieee80211_find_chanctx(local, chandef, mode); |
| 93 | break; | 302 | if (!ctx) |
| 94 | case NL80211_CHAN_HT40PLUS: | 303 | ctx = ieee80211_new_chanctx(local, chandef, mode); |
| 95 | WARN_ON(superchan == NL80211_CHAN_HT40MINUS); | 304 | if (IS_ERR(ctx)) { |
| 96 | superchan = NL80211_CHAN_HT40PLUS; | 305 | ret = PTR_ERR(ctx); |
| 97 | break; | 306 | goto out; |
| 98 | case NL80211_CHAN_HT40MINUS: | ||
| 99 | WARN_ON(superchan == NL80211_CHAN_HT40PLUS); | ||
| 100 | superchan = NL80211_CHAN_HT40MINUS; | ||
| 101 | break; | ||
| 102 | } | ||
| 103 | } | 307 | } |
| 104 | mutex_unlock(&local->iflist_mtx); | ||
| 105 | 308 | ||
| 106 | return superchan; | 309 | sdata->vif.bss_conf.chandef = *chandef; |
| 107 | } | ||
| 108 | 310 | ||
| 109 | static bool | 311 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); |
| 110 | ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, | 312 | if (ret) { |
| 111 | enum nl80211_channel_type chantype2, | 313 | /* if assign fails refcount stays the same */ |
| 112 | enum nl80211_channel_type *compat) | 314 | if (ctx->refcount == 0) |
| 113 | { | 315 | ieee80211_free_chanctx(local, ctx); |
| 114 | /* | 316 | goto out; |
| 115 | * start out with chantype1 being the result, | ||
| 116 | * overwriting later if needed | ||
| 117 | */ | ||
| 118 | if (compat) | ||
| 119 | *compat = chantype1; | ||
| 120 | |||
| 121 | switch (chantype1) { | ||
| 122 | case NL80211_CHAN_NO_HT: | ||
| 123 | if (compat) | ||
| 124 | *compat = chantype2; | ||
| 125 | break; | ||
| 126 | case NL80211_CHAN_HT20: | ||
| 127 | /* | ||
| 128 | * allow any change that doesn't go to no-HT | ||
| 129 | * (if it already is no-HT no change is needed) | ||
| 130 | */ | ||
| 131 | if (chantype2 == NL80211_CHAN_NO_HT) | ||
| 132 | break; | ||
| 133 | if (compat) | ||
| 134 | *compat = chantype2; | ||
| 135 | break; | ||
| 136 | case NL80211_CHAN_HT40PLUS: | ||
| 137 | case NL80211_CHAN_HT40MINUS: | ||
| 138 | /* allow smaller bandwidth and same */ | ||
| 139 | if (chantype2 == NL80211_CHAN_NO_HT) | ||
| 140 | break; | ||
| 141 | if (chantype2 == NL80211_CHAN_HT20) | ||
| 142 | break; | ||
| 143 | if (chantype2 == chantype1) | ||
| 144 | break; | ||
| 145 | return false; | ||
| 146 | } | 317 | } |
| 147 | 318 | ||
| 148 | return true; | 319 | ieee80211_recalc_smps_chanctx(local, ctx); |
| 320 | out: | ||
| 321 | mutex_unlock(&local->chanctx_mtx); | ||
| 322 | return ret; | ||
| 149 | } | 323 | } |
| 150 | 324 | ||
| 151 | bool ieee80211_set_channel_type(struct ieee80211_local *local, | 325 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) |
| 152 | struct ieee80211_sub_if_data *sdata, | ||
| 153 | enum nl80211_channel_type chantype) | ||
| 154 | { | 326 | { |
| 155 | enum nl80211_channel_type superchan; | 327 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); |
| 156 | enum nl80211_channel_type compatchan; | ||
| 157 | |||
| 158 | superchan = ieee80211_get_superchan(local, sdata); | ||
| 159 | if (!ieee80211_channel_types_are_compatible(superchan, chantype, | ||
| 160 | &compatchan)) | ||
| 161 | return false; | ||
| 162 | 328 | ||
| 163 | local->_oper_channel_type = compatchan; | 329 | mutex_lock(&sdata->local->chanctx_mtx); |
| 164 | 330 | __ieee80211_vif_release_channel(sdata); | |
| 165 | if (sdata) | 331 | mutex_unlock(&sdata->local->chanctx_mtx); |
| 166 | sdata->vif.bss_conf.channel_type = chantype; | 332 | } |
| 167 | 333 | ||
| 168 | return true; | 334 | void ieee80211_iter_chan_contexts_atomic( |
| 335 | struct ieee80211_hw *hw, | ||
| 336 | void (*iter)(struct ieee80211_hw *hw, | ||
| 337 | struct ieee80211_chanctx_conf *chanctx_conf, | ||
| 338 | void *data), | ||
| 339 | void *iter_data) | ||
| 340 | { | ||
| 341 | struct ieee80211_local *local = hw_to_local(hw); | ||
| 342 | struct ieee80211_chanctx *ctx; | ||
| 169 | 343 | ||
| 344 | rcu_read_lock(); | ||
| 345 | list_for_each_entry_rcu(ctx, &local->chanctx_list, list) | ||
| 346 | iter(hw, &ctx->conf, iter_data); | ||
| 347 | rcu_read_unlock(); | ||
| 170 | } | 348 | } |
| 349 | EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic); | ||
diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index 9be4e6d71d00..214ed4ecd739 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h | |||
| @@ -2,9 +2,9 @@ | |||
| 2 | #define __MAC80211_DEBUGFS_H | 2 | #define __MAC80211_DEBUGFS_H |
| 3 | 3 | ||
| 4 | #ifdef CONFIG_MAC80211_DEBUGFS | 4 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 5 | extern void debugfs_hw_add(struct ieee80211_local *local); | 5 | void debugfs_hw_add(struct ieee80211_local *local); |
| 6 | extern int mac80211_format_buffer(char __user *userbuf, size_t count, | 6 | int __printf(4, 5) mac80211_format_buffer(char __user *userbuf, size_t count, |
| 7 | loff_t *ppos, char *fmt, ...); | 7 | loff_t *ppos, char *fmt, ...); |
| 8 | #else | 8 | #else |
| 9 | static inline void debugfs_hw_add(struct ieee80211_local *local) | 9 | static inline void debugfs_hw_add(struct ieee80211_local *local) |
| 10 | { | 10 | { |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 090d08ff22c4..c3a3082b72e5 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
| @@ -116,7 +116,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
| 116 | size_t count, loff_t *ppos) | 116 | size_t count, loff_t *ppos) |
| 117 | { | 117 | { |
| 118 | struct ieee80211_key *key = file->private_data; | 118 | struct ieee80211_key *key = file->private_data; |
| 119 | char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf; | 119 | char buf[14*IEEE80211_NUM_TIDS+1], *p = buf; |
| 120 | int i, len; | 120 | int i, len; |
| 121 | const u8 *rpn; | 121 | const u8 *rpn; |
| 122 | 122 | ||
| @@ -126,7 +126,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
| 126 | len = scnprintf(buf, sizeof(buf), "\n"); | 126 | len = scnprintf(buf, sizeof(buf), "\n"); |
| 127 | break; | 127 | break; |
| 128 | case WLAN_CIPHER_SUITE_TKIP: | 128 | case WLAN_CIPHER_SUITE_TKIP: |
| 129 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 129 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 130 | p += scnprintf(p, sizeof(buf)+buf-p, | 130 | p += scnprintf(p, sizeof(buf)+buf-p, |
| 131 | "%08x %04x\n", | 131 | "%08x %04x\n", |
| 132 | key->u.tkip.rx[i].iv32, | 132 | key->u.tkip.rx[i].iv32, |
| @@ -134,7 +134,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, | |||
| 134 | len = p - buf; | 134 | len = p - buf; |
| 135 | break; | 135 | break; |
| 136 | case WLAN_CIPHER_SUITE_CCMP: | 136 | case WLAN_CIPHER_SUITE_CCMP: |
| 137 | for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) { | 137 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { |
| 138 | rpn = key->u.ccmp.rx_pn[i]; | 138 | rpn = key->u.ccmp.rx_pn[i]; |
| 139 | p += scnprintf(p, sizeof(buf)+buf-p, | 139 | p += scnprintf(p, sizeof(buf)+buf-p, |
| 140 | "%02x%02x%02x%02x%02x%02x\n", | 140 | "%02x%02x%02x%02x%02x%02x\n", |
| @@ -199,6 +199,22 @@ static ssize_t key_icverrors_read(struct file *file, char __user *userbuf, | |||
| 199 | } | 199 | } |
| 200 | KEY_OPS(icverrors); | 200 | KEY_OPS(icverrors); |
| 201 | 201 | ||
| 202 | static ssize_t key_mic_failures_read(struct file *file, char __user *userbuf, | ||
| 203 | size_t count, loff_t *ppos) | ||
| 204 | { | ||
| 205 | struct ieee80211_key *key = file->private_data; | ||
| 206 | char buf[20]; | ||
| 207 | int len; | ||
| 208 | |||
| 209 | if (key->conf.cipher != WLAN_CIPHER_SUITE_TKIP) | ||
| 210 | return -EINVAL; | ||
| 211 | |||
| 212 | len = scnprintf(buf, sizeof(buf), "%u\n", key->u.tkip.mic_failures); | ||
| 213 | |||
| 214 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
| 215 | } | ||
| 216 | KEY_OPS(mic_failures); | ||
| 217 | |||
| 202 | static ssize_t key_key_read(struct file *file, char __user *userbuf, | 218 | static ssize_t key_key_read(struct file *file, char __user *userbuf, |
| 203 | size_t count, loff_t *ppos) | 219 | size_t count, loff_t *ppos) |
| 204 | { | 220 | { |
| @@ -260,6 +276,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) | |||
| 260 | DEBUGFS_ADD(rx_spec); | 276 | DEBUGFS_ADD(rx_spec); |
| 261 | DEBUGFS_ADD(replays); | 277 | DEBUGFS_ADD(replays); |
| 262 | DEBUGFS_ADD(icverrors); | 278 | DEBUGFS_ADD(icverrors); |
| 279 | DEBUGFS_ADD(mic_failures); | ||
| 263 | DEBUGFS_ADD(key); | 280 | DEBUGFS_ADD(key); |
| 264 | DEBUGFS_ADD(ifindex); | 281 | DEBUGFS_ADD(ifindex); |
| 265 | }; | 282 | }; |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 6d5aec9418ee..cbde5cc49a40 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
| 12 | #include <linux/if.h> | 12 | #include <linux/if.h> |
| 13 | #include <linux/if_ether.h> | ||
| 13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
| 14 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
| 15 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
| @@ -167,7 +168,29 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz, | |||
| 167 | 168 | ||
| 168 | IEEE80211_IF_FILE(flags, flags, HEX); | 169 | IEEE80211_IF_FILE(flags, flags, HEX); |
| 169 | IEEE80211_IF_FILE(state, state, LHEX); | 170 | IEEE80211_IF_FILE(state, state, LHEX); |
| 170 | IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); | 171 | IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); |
| 172 | IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC); | ||
| 173 | IEEE80211_IF_FILE(user_power_level, user_power_level, DEC); | ||
| 174 | |||
| 175 | static ssize_t | ||
| 176 | ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata, | ||
| 177 | char *buf, int buflen) | ||
| 178 | { | ||
| 179 | int len; | ||
| 180 | |||
| 181 | len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n", | ||
| 182 | sdata->vif.hw_queue[IEEE80211_AC_VO], | ||
| 183 | sdata->vif.hw_queue[IEEE80211_AC_VI], | ||
| 184 | sdata->vif.hw_queue[IEEE80211_AC_BE], | ||
| 185 | sdata->vif.hw_queue[IEEE80211_AC_BK]); | ||
| 186 | |||
| 187 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
| 188 | len += scnprintf(buf + len, buflen - len, "cab queue: %d\n", | ||
| 189 | sdata->vif.cab_queue); | ||
| 190 | |||
| 191 | return len; | ||
| 192 | } | ||
| 193 | __IEEE80211_IF_FILE(hw_queues, NULL); | ||
| 171 | 194 | ||
| 172 | /* STA attributes */ | 195 | /* STA attributes */ |
| 173 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 196 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
| @@ -217,7 +240,7 @@ static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata, | |||
| 217 | 240 | ||
| 218 | return snprintf(buf, buflen, "request: %s\nused: %s\n", | 241 | return snprintf(buf, buflen, "request: %s\nused: %s\n", |
| 219 | smps_modes[sdata->u.mgd.req_smps], | 242 | smps_modes[sdata->u.mgd.req_smps], |
| 220 | smps_modes[sdata->u.mgd.ap_smps]); | 243 | smps_modes[sdata->smps_mode]); |
| 221 | } | 244 | } |
| 222 | 245 | ||
| 223 | static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, | 246 | static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, |
| @@ -245,27 +268,6 @@ static ssize_t ieee80211_if_fmt_tkip_mic_test( | |||
| 245 | return -EOPNOTSUPP; | 268 | return -EOPNOTSUPP; |
| 246 | } | 269 | } |
| 247 | 270 | ||
| 248 | static int hwaddr_aton(const char *txt, u8 *addr) | ||
| 249 | { | ||
| 250 | int i; | ||
| 251 | |||
| 252 | for (i = 0; i < ETH_ALEN; i++) { | ||
| 253 | int a, b; | ||
| 254 | |||
| 255 | a = hex_to_bin(*txt++); | ||
| 256 | if (a < 0) | ||
| 257 | return -1; | ||
| 258 | b = hex_to_bin(*txt++); | ||
| 259 | if (b < 0) | ||
| 260 | return -1; | ||
| 261 | *addr++ = (a << 4) | b; | ||
| 262 | if (i < 5 && *txt++ != ':') | ||
| 263 | return -1; | ||
| 264 | } | ||
| 265 | |||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | static ssize_t ieee80211_if_parse_tkip_mic_test( | 271 | static ssize_t ieee80211_if_parse_tkip_mic_test( |
| 270 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) | 272 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) |
| 271 | { | 273 | { |
| @@ -275,13 +277,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( | |||
| 275 | struct ieee80211_hdr *hdr; | 277 | struct ieee80211_hdr *hdr; |
| 276 | __le16 fc; | 278 | __le16 fc; |
| 277 | 279 | ||
| 278 | /* | 280 | if (!mac_pton(buf, addr)) |
| 279 | * Assume colon-delimited MAC address with possible white space | ||
| 280 | * following. | ||
| 281 | */ | ||
| 282 | if (buflen < 3 * ETH_ALEN - 1) | ||
| 283 | return -EINVAL; | ||
| 284 | if (hwaddr_aton(buf, addr) < 0) | ||
| 285 | return -EINVAL; | 281 | return -EINVAL; |
| 286 | 282 | ||
| 287 | if (!ieee80211_sdata_running(sdata)) | 283 | if (!ieee80211_sdata_running(sdata)) |
| @@ -307,13 +303,16 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( | |||
| 307 | case NL80211_IFTYPE_STATION: | 303 | case NL80211_IFTYPE_STATION: |
| 308 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 304 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
| 309 | /* BSSID SA DA */ | 305 | /* BSSID SA DA */ |
| 310 | if (sdata->vif.bss_conf.bssid == NULL) { | 306 | mutex_lock(&sdata->u.mgd.mtx); |
| 307 | if (!sdata->u.mgd.associated) { | ||
| 308 | mutex_unlock(&sdata->u.mgd.mtx); | ||
| 311 | dev_kfree_skb(skb); | 309 | dev_kfree_skb(skb); |
| 312 | return -ENOTCONN; | 310 | return -ENOTCONN; |
| 313 | } | 311 | } |
| 314 | memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN); | 312 | memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN); |
| 315 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); | 313 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); |
| 316 | memcpy(hdr->addr3, addr, ETH_ALEN); | 314 | memcpy(hdr->addr3, addr, ETH_ALEN); |
| 315 | mutex_unlock(&sdata->u.mgd.mtx); | ||
| 317 | break; | 316 | break; |
| 318 | default: | 317 | default: |
| 319 | dev_kfree_skb(skb); | 318 | dev_kfree_skb(skb); |
| @@ -395,14 +394,14 @@ __IEEE80211_IF_FILE_W(uapsd_max_sp_len); | |||
| 395 | 394 | ||
| 396 | /* AP attributes */ | 395 | /* AP attributes */ |
| 397 | IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); | 396 | IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); |
| 398 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | 397 | IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC); |
| 399 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); | 398 | IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC); |
| 400 | 399 | ||
| 401 | static ssize_t ieee80211_if_fmt_num_buffered_multicast( | 400 | static ssize_t ieee80211_if_fmt_num_buffered_multicast( |
| 402 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | 401 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) |
| 403 | { | 402 | { |
| 404 | return scnprintf(buf, buflen, "%u\n", | 403 | return scnprintf(buf, buflen, "%u\n", |
| 405 | skb_queue_len(&sdata->u.ap.ps_bc_buf)); | 404 | skb_queue_len(&sdata->u.ap.ps.bc_buf)); |
| 406 | } | 405 | } |
| 407 | __IEEE80211_IF_FILE(num_buffered_multicast, NULL); | 406 | __IEEE80211_IF_FILE(num_buffered_multicast, NULL); |
| 408 | 407 | ||
| @@ -443,7 +442,7 @@ static ssize_t ieee80211_if_parse_tsf( | |||
| 443 | } | 442 | } |
| 444 | ret = kstrtoull(buf, 10, &tsf); | 443 | ret = kstrtoull(buf, 10, &tsf); |
| 445 | if (ret < 0) | 444 | if (ret < 0) |
| 446 | return -EINVAL; | 445 | return ret; |
| 447 | if (tsf_is_delta) | 446 | if (tsf_is_delta) |
| 448 | tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; | 447 | tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; |
| 449 | if (local->ops->set_tsf) { | 448 | if (local->ops->set_tsf) { |
| @@ -471,7 +470,7 @@ IEEE80211_IF_FILE(dropped_frames_congestion, | |||
| 471 | u.mesh.mshstats.dropped_frames_congestion, DEC); | 470 | u.mesh.mshstats.dropped_frames_congestion, DEC); |
| 472 | IEEE80211_IF_FILE(dropped_frames_no_route, | 471 | IEEE80211_IF_FILE(dropped_frames_no_route, |
| 473 | u.mesh.mshstats.dropped_frames_no_route, DEC); | 472 | u.mesh.mshstats.dropped_frames_no_route, DEC); |
| 474 | IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC); | 473 | IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC); |
| 475 | 474 | ||
| 476 | /* Mesh parameters */ | 475 | /* Mesh parameters */ |
| 477 | IEEE80211_IF_FILE(dot11MeshMaxRetries, | 476 | IEEE80211_IF_FILE(dot11MeshMaxRetries, |
| @@ -531,6 +530,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata) | |||
| 531 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 530 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
| 532 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | 531 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); |
| 533 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | 532 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); |
| 533 | DEBUGFS_ADD(hw_queues); | ||
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 536 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
| @@ -631,7 +631,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
| 631 | 631 | ||
| 632 | DEBUGFS_ADD(flags); | 632 | DEBUGFS_ADD(flags); |
| 633 | DEBUGFS_ADD(state); | 633 | DEBUGFS_ADD(state); |
| 634 | DEBUGFS_ADD(channel_type); | 634 | DEBUGFS_ADD(txpower); |
| 635 | DEBUGFS_ADD(user_power_level); | ||
| 636 | DEBUGFS_ADD(ap_power_level); | ||
| 635 | 637 | ||
| 636 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 638 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) |
| 637 | add_common_files(sdata); | 639 | add_common_files(sdata); |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 5ccec2c1e9f6..6fb1168b9f16 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "debugfs.h" | 14 | #include "debugfs.h" |
| 15 | #include "debugfs_sta.h" | 15 | #include "debugfs_sta.h" |
| 16 | #include "sta_info.h" | 16 | #include "sta_info.h" |
| 17 | #include "driver-ops.h" | ||
| 17 | 18 | ||
| 18 | /* sta attributtes */ | 19 | /* sta attributtes */ |
| 19 | 20 | ||
| @@ -52,6 +53,7 @@ static const struct file_operations sta_ ##name## _ops = { \ | |||
| 52 | STA_FILE(aid, sta.aid, D); | 53 | STA_FILE(aid, sta.aid, D); |
| 53 | STA_FILE(dev, sdata->name, S); | 54 | STA_FILE(dev, sdata->name, S); |
| 54 | STA_FILE(last_signal, last_signal, D); | 55 | STA_FILE(last_signal, last_signal, D); |
| 56 | STA_FILE(last_ack_signal, last_ack_signal, D); | ||
| 55 | 57 | ||
| 56 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | 58 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, |
| 57 | size_t count, loff_t *ppos) | 59 | size_t count, loff_t *ppos) |
| @@ -131,10 +133,10 @@ STA_OPS(connected_time); | |||
| 131 | static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, | 133 | static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf, |
| 132 | size_t count, loff_t *ppos) | 134 | size_t count, loff_t *ppos) |
| 133 | { | 135 | { |
| 134 | char buf[15*NUM_RX_DATA_QUEUES], *p = buf; | 136 | char buf[15*IEEE80211_NUM_TIDS], *p = buf; |
| 135 | int i; | 137 | int i; |
| 136 | struct sta_info *sta = file->private_data; | 138 | struct sta_info *sta = file->private_data; |
| 137 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 139 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 138 | p += scnprintf(p, sizeof(buf)+buf-p, "%x ", | 140 | p += scnprintf(p, sizeof(buf)+buf-p, "%x ", |
| 139 | le16_to_cpu(sta->last_seq_ctrl[i])); | 141 | le16_to_cpu(sta->last_seq_ctrl[i])); |
| 140 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | 142 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); |
| @@ -145,7 +147,7 @@ STA_OPS(last_seq_ctrl); | |||
| 145 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | 147 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, |
| 146 | size_t count, loff_t *ppos) | 148 | size_t count, loff_t *ppos) |
| 147 | { | 149 | { |
| 148 | char buf[71 + STA_TID_NUM * 40], *p = buf; | 150 | char buf[71 + IEEE80211_NUM_TIDS * 40], *p = buf; |
| 149 | int i; | 151 | int i; |
| 150 | struct sta_info *sta = file->private_data; | 152 | struct sta_info *sta = file->private_data; |
| 151 | struct tid_ampdu_rx *tid_rx; | 153 | struct tid_ampdu_rx *tid_rx; |
| @@ -158,7 +160,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | |||
| 158 | p += scnprintf(p, sizeof(buf) + buf - p, | 160 | p += scnprintf(p, sizeof(buf) + buf - p, |
| 159 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); | 161 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); |
| 160 | 162 | ||
| 161 | for (i = 0; i < STA_TID_NUM; i++) { | 163 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 162 | tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); | 164 | tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); |
| 163 | tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); | 165 | tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); |
| 164 | 166 | ||
| @@ -218,9 +220,11 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu | |||
| 218 | } else | 220 | } else |
| 219 | return -EINVAL; | 221 | return -EINVAL; |
| 220 | 222 | ||
| 221 | tid = simple_strtoul(buf, NULL, 0); | 223 | ret = kstrtoul(buf, 0, &tid); |
| 224 | if (ret) | ||
| 225 | return ret; | ||
| 222 | 226 | ||
| 223 | if (tid >= STA_TID_NUM) | 227 | if (tid >= IEEE80211_NUM_TIDS) |
| 224 | return -EINVAL; | 228 | return -EINVAL; |
| 225 | 229 | ||
| 226 | if (tx) { | 230 | if (tx) { |
| @@ -320,6 +324,38 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, | |||
| 320 | } | 324 | } |
| 321 | STA_OPS(ht_capa); | 325 | STA_OPS(ht_capa); |
| 322 | 326 | ||
| 327 | static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf, | ||
| 328 | size_t count, loff_t *ppos) | ||
| 329 | { | ||
| 330 | struct sta_info *sta = file->private_data; | ||
| 331 | struct rate_info rinfo; | ||
| 332 | u16 rate; | ||
| 333 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo); | ||
| 334 | rate = cfg80211_calculate_bitrate(&rinfo); | ||
| 335 | |||
| 336 | return mac80211_format_buffer(userbuf, count, ppos, | ||
| 337 | "%d.%d MBit/s\n", | ||
| 338 | rate/10, rate%10); | ||
| 339 | } | ||
| 340 | STA_OPS(current_tx_rate); | ||
| 341 | |||
| 342 | static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf, | ||
| 343 | size_t count, loff_t *ppos) | ||
| 344 | { | ||
| 345 | struct sta_info *sta = file->private_data; | ||
| 346 | struct rate_info rinfo; | ||
| 347 | u16 rate; | ||
| 348 | |||
| 349 | sta_set_rate_info_rx(sta, &rinfo); | ||
| 350 | |||
| 351 | rate = cfg80211_calculate_bitrate(&rinfo); | ||
| 352 | |||
| 353 | return mac80211_format_buffer(userbuf, count, ppos, | ||
| 354 | "%d.%d MBit/s\n", | ||
| 355 | rate/10, rate%10); | ||
| 356 | } | ||
| 357 | STA_OPS(last_rx_rate); | ||
| 358 | |||
| 323 | #define DEBUGFS_ADD(name) \ | 359 | #define DEBUGFS_ADD(name) \ |
| 324 | debugfs_create_file(#name, 0400, \ | 360 | debugfs_create_file(#name, 0400, \ |
| 325 | sta->debugfs.dir, sta, &sta_ ##name## _ops); | 361 | sta->debugfs.dir, sta, &sta_ ##name## _ops); |
| @@ -334,6 +370,8 @@ STA_OPS(ht_capa); | |||
| 334 | 370 | ||
| 335 | void ieee80211_sta_debugfs_add(struct sta_info *sta) | 371 | void ieee80211_sta_debugfs_add(struct sta_info *sta) |
| 336 | { | 372 | { |
| 373 | struct ieee80211_local *local = sta->local; | ||
| 374 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 337 | struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; | 375 | struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; |
| 338 | u8 mac[3*ETH_ALEN]; | 376 | u8 mac[3*ETH_ALEN]; |
| 339 | 377 | ||
| @@ -366,6 +404,9 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
| 366 | DEBUGFS_ADD(dev); | 404 | DEBUGFS_ADD(dev); |
| 367 | DEBUGFS_ADD(last_signal); | 405 | DEBUGFS_ADD(last_signal); |
| 368 | DEBUGFS_ADD(ht_capa); | 406 | DEBUGFS_ADD(ht_capa); |
| 407 | DEBUGFS_ADD(last_ack_signal); | ||
| 408 | DEBUGFS_ADD(current_tx_rate); | ||
| 409 | DEBUGFS_ADD(last_rx_rate); | ||
| 369 | 410 | ||
| 370 | DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); | 411 | DEBUGFS_ADD_COUNTER(rx_packets, rx_packets); |
| 371 | DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); | 412 | DEBUGFS_ADD_COUNTER(tx_packets, tx_packets); |
| @@ -379,10 +420,16 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
| 379 | DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); | 420 | DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed); |
| 380 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); | 421 | DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count); |
| 381 | DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); | 422 | DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count); |
| 423 | |||
| 424 | drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); | ||
| 382 | } | 425 | } |
| 383 | 426 | ||
| 384 | void ieee80211_sta_debugfs_remove(struct sta_info *sta) | 427 | void ieee80211_sta_debugfs_remove(struct sta_info *sta) |
| 385 | { | 428 | { |
| 429 | struct ieee80211_local *local = sta->local; | ||
| 430 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 431 | |||
| 432 | drv_sta_remove_debugfs(local, sdata, &sta->sta, sta->debugfs.dir); | ||
| 386 | debugfs_remove_recursive(sta->debugfs.dir); | 433 | debugfs_remove_recursive(sta->debugfs.dir); |
| 387 | sta->debugfs.dir = NULL; | 434 | sta->debugfs.dir = NULL; |
| 388 | } | 435 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index da9003b20004..698dc7e6f309 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -490,6 +490,38 @@ static inline void drv_sta_remove(struct ieee80211_local *local, | |||
| 490 | trace_drv_return_void(local); | 490 | trace_drv_return_void(local); |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
| 494 | static inline void drv_sta_add_debugfs(struct ieee80211_local *local, | ||
| 495 | struct ieee80211_sub_if_data *sdata, | ||
| 496 | struct ieee80211_sta *sta, | ||
| 497 | struct dentry *dir) | ||
| 498 | { | ||
| 499 | might_sleep(); | ||
| 500 | |||
| 501 | sdata = get_bss_sdata(sdata); | ||
| 502 | check_sdata_in_driver(sdata); | ||
| 503 | |||
| 504 | if (local->ops->sta_add_debugfs) | ||
| 505 | local->ops->sta_add_debugfs(&local->hw, &sdata->vif, | ||
| 506 | sta, dir); | ||
| 507 | } | ||
| 508 | |||
| 509 | static inline void drv_sta_remove_debugfs(struct ieee80211_local *local, | ||
| 510 | struct ieee80211_sub_if_data *sdata, | ||
| 511 | struct ieee80211_sta *sta, | ||
| 512 | struct dentry *dir) | ||
| 513 | { | ||
| 514 | might_sleep(); | ||
| 515 | |||
| 516 | sdata = get_bss_sdata(sdata); | ||
| 517 | check_sdata_in_driver(sdata); | ||
| 518 | |||
| 519 | if (local->ops->sta_remove_debugfs) | ||
| 520 | local->ops->sta_remove_debugfs(&local->hw, &sdata->vif, | ||
| 521 | sta, dir); | ||
| 522 | } | ||
| 523 | #endif | ||
| 524 | |||
| 493 | static inline __must_check | 525 | static inline __must_check |
| 494 | int drv_sta_state(struct ieee80211_local *local, | 526 | int drv_sta_state(struct ieee80211_local *local, |
| 495 | struct ieee80211_sub_if_data *sdata, | 527 | struct ieee80211_sub_if_data *sdata, |
| @@ -602,7 +634,7 @@ static inline void drv_reset_tsf(struct ieee80211_local *local, | |||
| 602 | 634 | ||
| 603 | static inline int drv_tx_last_beacon(struct ieee80211_local *local) | 635 | static inline int drv_tx_last_beacon(struct ieee80211_local *local) |
| 604 | { | 636 | { |
| 605 | int ret = 0; /* default unsuported op for less congestion */ | 637 | int ret = 0; /* default unsupported op for less congestion */ |
| 606 | 638 | ||
| 607 | might_sleep(); | 639 | might_sleep(); |
| 608 | 640 | ||
| @@ -704,17 +736,17 @@ static inline int drv_get_antenna(struct ieee80211_local *local, | |||
| 704 | } | 736 | } |
| 705 | 737 | ||
| 706 | static inline int drv_remain_on_channel(struct ieee80211_local *local, | 738 | static inline int drv_remain_on_channel(struct ieee80211_local *local, |
| 739 | struct ieee80211_sub_if_data *sdata, | ||
| 707 | struct ieee80211_channel *chan, | 740 | struct ieee80211_channel *chan, |
| 708 | enum nl80211_channel_type chantype, | ||
| 709 | unsigned int duration) | 741 | unsigned int duration) |
| 710 | { | 742 | { |
| 711 | int ret; | 743 | int ret; |
| 712 | 744 | ||
| 713 | might_sleep(); | 745 | might_sleep(); |
| 714 | 746 | ||
| 715 | trace_drv_remain_on_channel(local, chan, chantype, duration); | 747 | trace_drv_remain_on_channel(local, sdata, chan, duration); |
| 716 | ret = local->ops->remain_on_channel(&local->hw, chan, chantype, | 748 | ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, |
| 717 | duration); | 749 | chan, duration); |
| 718 | trace_drv_return_int(local, ret); | 750 | trace_drv_return_int(local, ret); |
| 719 | 751 | ||
| 720 | return ret; | 752 | return ret; |
| @@ -871,4 +903,104 @@ static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, | |||
| 871 | local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); | 903 | local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); |
| 872 | trace_drv_return_void(local); | 904 | trace_drv_return_void(local); |
| 873 | } | 905 | } |
| 906 | |||
| 907 | static inline int drv_add_chanctx(struct ieee80211_local *local, | ||
| 908 | struct ieee80211_chanctx *ctx) | ||
| 909 | { | ||
| 910 | int ret = -EOPNOTSUPP; | ||
| 911 | |||
| 912 | trace_drv_add_chanctx(local, ctx); | ||
| 913 | if (local->ops->add_chanctx) | ||
| 914 | ret = local->ops->add_chanctx(&local->hw, &ctx->conf); | ||
| 915 | trace_drv_return_int(local, ret); | ||
| 916 | |||
| 917 | return ret; | ||
| 918 | } | ||
| 919 | |||
| 920 | static inline void drv_remove_chanctx(struct ieee80211_local *local, | ||
| 921 | struct ieee80211_chanctx *ctx) | ||
| 922 | { | ||
| 923 | trace_drv_remove_chanctx(local, ctx); | ||
| 924 | if (local->ops->remove_chanctx) | ||
| 925 | local->ops->remove_chanctx(&local->hw, &ctx->conf); | ||
| 926 | trace_drv_return_void(local); | ||
| 927 | } | ||
| 928 | |||
| 929 | static inline void drv_change_chanctx(struct ieee80211_local *local, | ||
| 930 | struct ieee80211_chanctx *ctx, | ||
| 931 | u32 changed) | ||
| 932 | { | ||
| 933 | trace_drv_change_chanctx(local, ctx, changed); | ||
| 934 | if (local->ops->change_chanctx) | ||
| 935 | local->ops->change_chanctx(&local->hw, &ctx->conf, changed); | ||
| 936 | trace_drv_return_void(local); | ||
| 937 | } | ||
| 938 | |||
| 939 | static inline int drv_assign_vif_chanctx(struct ieee80211_local *local, | ||
| 940 | struct ieee80211_sub_if_data *sdata, | ||
| 941 | struct ieee80211_chanctx *ctx) | ||
| 942 | { | ||
| 943 | int ret = 0; | ||
| 944 | |||
| 945 | check_sdata_in_driver(sdata); | ||
| 946 | |||
| 947 | trace_drv_assign_vif_chanctx(local, sdata, ctx); | ||
| 948 | if (local->ops->assign_vif_chanctx) | ||
| 949 | ret = local->ops->assign_vif_chanctx(&local->hw, | ||
| 950 | &sdata->vif, | ||
| 951 | &ctx->conf); | ||
| 952 | trace_drv_return_int(local, ret); | ||
| 953 | |||
| 954 | return ret; | ||
| 955 | } | ||
| 956 | |||
| 957 | static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, | ||
| 958 | struct ieee80211_sub_if_data *sdata, | ||
| 959 | struct ieee80211_chanctx *ctx) | ||
| 960 | { | ||
| 961 | check_sdata_in_driver(sdata); | ||
| 962 | |||
| 963 | trace_drv_unassign_vif_chanctx(local, sdata, ctx); | ||
| 964 | if (local->ops->unassign_vif_chanctx) | ||
| 965 | local->ops->unassign_vif_chanctx(&local->hw, | ||
| 966 | &sdata->vif, | ||
| 967 | &ctx->conf); | ||
| 968 | trace_drv_return_void(local); | ||
| 969 | } | ||
| 970 | |||
| 971 | static inline int drv_start_ap(struct ieee80211_local *local, | ||
| 972 | struct ieee80211_sub_if_data *sdata) | ||
| 973 | { | ||
| 974 | int ret = 0; | ||
| 975 | |||
| 976 | check_sdata_in_driver(sdata); | ||
| 977 | |||
| 978 | trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); | ||
| 979 | if (local->ops->start_ap) | ||
| 980 | ret = local->ops->start_ap(&local->hw, &sdata->vif); | ||
| 981 | trace_drv_return_int(local, ret); | ||
| 982 | return ret; | ||
| 983 | } | ||
| 984 | |||
| 985 | static inline void drv_stop_ap(struct ieee80211_local *local, | ||
| 986 | struct ieee80211_sub_if_data *sdata) | ||
| 987 | { | ||
| 988 | check_sdata_in_driver(sdata); | ||
| 989 | |||
| 990 | trace_drv_stop_ap(local, sdata); | ||
| 991 | if (local->ops->stop_ap) | ||
| 992 | local->ops->stop_ap(&local->hw, &sdata->vif); | ||
| 993 | trace_drv_return_void(local); | ||
| 994 | } | ||
| 995 | |||
| 996 | static inline void drv_restart_complete(struct ieee80211_local *local) | ||
| 997 | { | ||
| 998 | might_sleep(); | ||
| 999 | |||
| 1000 | trace_drv_restart_complete(local); | ||
| 1001 | if (local->ops->restart_complete) | ||
| 1002 | local->ops->restart_complete(&local->hw); | ||
| 1003 | trace_drv_return_void(local); | ||
| 1004 | } | ||
| 1005 | |||
| 874 | #endif /* __MAC80211_DRIVER_OPS */ | 1006 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 4b4538d63925..a71d891794a4 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
| @@ -185,7 +185,7 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx) | |||
| 185 | 185 | ||
| 186 | cancel_work_sync(&sta->ampdu_mlme.work); | 186 | cancel_work_sync(&sta->ampdu_mlme.work); |
| 187 | 187 | ||
| 188 | for (i = 0; i < STA_TID_NUM; i++) { | 188 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 189 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx); | 189 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx); |
| 190 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, | 190 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, |
| 191 | WLAN_REASON_QSTA_LEAVE_QBSS, tx); | 191 | WLAN_REASON_QSTA_LEAVE_QBSS, tx); |
| @@ -209,7 +209,7 @@ void ieee80211_ba_session_work(struct work_struct *work) | |||
| 209 | return; | 209 | return; |
| 210 | 210 | ||
| 211 | mutex_lock(&sta->ampdu_mlme.mtx); | 211 | mutex_lock(&sta->ampdu_mlme.mtx); |
| 212 | for (tid = 0; tid < STA_TID_NUM; tid++) { | 212 | for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { |
| 213 | if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) | 213 | if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired)) |
| 214 | ___ieee80211_stop_rx_ba_session( | 214 | ___ieee80211_stop_rx_ba_session( |
| 215 | sta, tid, WLAN_BACK_RECIPIENT, | 215 | sta, tid, WLAN_BACK_RECIPIENT, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c21e33d1abd0..8881fc77fb13 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | #include "rate.h" | 26 | #include "rate.h" |
| 27 | 27 | ||
| 28 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | 28 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) |
| 29 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) | ||
| 30 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | 29 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) |
| 31 | 30 | ||
| 32 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | 31 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) |
| @@ -39,7 +38,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 39 | const u8 *bssid, const int beacon_int, | 38 | const u8 *bssid, const int beacon_int, |
| 40 | struct ieee80211_channel *chan, | 39 | struct ieee80211_channel *chan, |
| 41 | const u32 basic_rates, | 40 | const u32 basic_rates, |
| 42 | const u16 capability, u64 tsf) | 41 | const u16 capability, u64 tsf, |
| 42 | bool creator) | ||
| 43 | { | 43 | { |
| 44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 45 | struct ieee80211_local *local = sdata->local; | 45 | struct ieee80211_local *local = sdata->local; |
| @@ -51,7 +51,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 51 | struct cfg80211_bss *bss; | 51 | struct cfg80211_bss *bss; |
| 52 | u32 bss_change; | 52 | u32 bss_change; |
| 53 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 53 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
| 54 | enum nl80211_channel_type channel_type; | 54 | struct cfg80211_chan_def chandef; |
| 55 | 55 | ||
| 56 | lockdep_assert_held(&ifibss->mtx); | 56 | lockdep_assert_held(&ifibss->mtx); |
| 57 | 57 | ||
| @@ -72,25 +72,29 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 72 | /* if merging, indicate to driver that we leave the old IBSS */ | 72 | /* if merging, indicate to driver that we leave the old IBSS */ |
| 73 | if (sdata->vif.bss_conf.ibss_joined) { | 73 | if (sdata->vif.bss_conf.ibss_joined) { |
| 74 | sdata->vif.bss_conf.ibss_joined = false; | 74 | sdata->vif.bss_conf.ibss_joined = false; |
| 75 | sdata->vif.bss_conf.ibss_creator = false; | ||
| 75 | netif_carrier_off(sdata->dev); | 76 | netif_carrier_off(sdata->dev); |
| 76 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS); | 77 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS); |
| 77 | } | 78 | } |
| 78 | 79 | ||
| 79 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
| 80 | |||
| 81 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; | 80 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; |
| 82 | 81 | ||
| 83 | local->oper_channel = chan; | 82 | cfg80211_chandef_create(&chandef, chan, ifibss->channel_type); |
| 84 | channel_type = ifibss->channel_type; | 83 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { |
| 85 | if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type)) | 84 | chandef.width = NL80211_CHAN_WIDTH_20; |
| 86 | channel_type = NL80211_CHAN_HT20; | 85 | chandef.center_freq1 = chan->center_freq; |
| 87 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) { | 86 | } |
| 88 | /* can only fail due to HT40+/- mismatch */ | 87 | |
| 89 | channel_type = NL80211_CHAN_HT20; | 88 | ieee80211_vif_release_channel(sdata); |
| 90 | WARN_ON(!ieee80211_set_channel_type(local, sdata, | 89 | if (ieee80211_vif_use_channel(sdata, &chandef, |
| 91 | NL80211_CHAN_HT20)); | 90 | ifibss->fixed_channel ? |
| 91 | IEEE80211_CHANCTX_SHARED : | ||
| 92 | IEEE80211_CHANCTX_EXCLUSIVE)) { | ||
| 93 | sdata_info(sdata, "Failed to join IBSS, no channel context\n"); | ||
| 94 | return; | ||
| 92 | } | 95 | } |
| 93 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 96 | |
| 97 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
| 94 | 98 | ||
| 95 | sband = local->hw.wiphy->bands[chan->band]; | 99 | sband = local->hw.wiphy->bands[chan->band]; |
| 96 | 100 | ||
| @@ -156,7 +160,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 156 | ifibss->ie, ifibss->ie_len); | 160 | ifibss->ie, ifibss->ie_len); |
| 157 | 161 | ||
| 158 | /* add HT capability and information IEs */ | 162 | /* add HT capability and information IEs */ |
| 159 | if (channel_type && sband->ht_cap.ht_supported) { | 163 | if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT && |
| 164 | sband->ht_cap.ht_supported) { | ||
| 160 | pos = skb_put(skb, 4 + | 165 | pos = skb_put(skb, 4 + |
| 161 | sizeof(struct ieee80211_ht_cap) + | 166 | sizeof(struct ieee80211_ht_cap) + |
| 162 | sizeof(struct ieee80211_ht_operation)); | 167 | sizeof(struct ieee80211_ht_operation)); |
| @@ -168,7 +173,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 168 | * keep them at 0 | 173 | * keep them at 0 |
| 169 | */ | 174 | */ |
| 170 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, | 175 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, |
| 171 | chan, channel_type, 0); | 176 | &chandef, 0); |
| 172 | } | 177 | } |
| 173 | 178 | ||
| 174 | if (local->hw.queues >= IEEE80211_NUM_ACS) { | 179 | if (local->hw.queues >= IEEE80211_NUM_ACS) { |
| @@ -196,7 +201,22 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 196 | bss_change |= BSS_CHANGED_BASIC_RATES; | 201 | bss_change |= BSS_CHANGED_BASIC_RATES; |
| 197 | bss_change |= BSS_CHANGED_HT; | 202 | bss_change |= BSS_CHANGED_HT; |
| 198 | bss_change |= BSS_CHANGED_IBSS; | 203 | bss_change |= BSS_CHANGED_IBSS; |
| 204 | |||
| 205 | /* | ||
| 206 | * In 5 GHz/802.11a, we can always use short slot time. | ||
| 207 | * (IEEE 802.11-2012 18.3.8.7) | ||
| 208 | * | ||
| 209 | * In 2.4GHz, we must always use long slots in IBSS for compatibility | ||
| 210 | * reasons. | ||
| 211 | * (IEEE 802.11-2012 19.4.5) | ||
| 212 | * | ||
| 213 | * HT follows these specifications (IEEE 802.11-2012 20.3.18) | ||
| 214 | */ | ||
| 215 | sdata->vif.bss_conf.use_short_slot = chan->band == IEEE80211_BAND_5GHZ; | ||
| 216 | bss_change |= BSS_CHANGED_ERP_SLOT; | ||
| 217 | |||
| 199 | sdata->vif.bss_conf.ibss_joined = true; | 218 | sdata->vif.bss_conf.ibss_joined = true; |
| 219 | sdata->vif.bss_conf.ibss_creator = creator; | ||
| 200 | ieee80211_bss_info_change_notify(sdata, bss_change); | 220 | ieee80211_bss_info_change_notify(sdata, bss_change); |
| 201 | 221 | ||
| 202 | ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); | 222 | ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); |
| @@ -249,7 +269,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 249 | cbss->channel, | 269 | cbss->channel, |
| 250 | basic_rates, | 270 | basic_rates, |
| 251 | cbss->capability, | 271 | cbss->capability, |
| 252 | cbss->tsf); | 272 | cbss->tsf, |
| 273 | false); | ||
| 253 | } | 274 | } |
| 254 | 275 | ||
| 255 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | 276 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, |
| @@ -279,7 +300,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, | |||
| 279 | ibss_dbg(sdata, | 300 | ibss_dbg(sdata, |
| 280 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", | 301 | "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", |
| 281 | sdata->vif.addr, addr, sdata->u.ibss.bssid); | 302 | sdata->vif.addr, addr, sdata->u.ibss.bssid); |
| 282 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, | 303 | ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0, |
| 283 | addr, sdata->u.ibss.bssid, NULL, 0, 0); | 304 | addr, sdata->u.ibss.bssid, NULL, 0, 0); |
| 284 | } | 305 | } |
| 285 | return sta; | 306 | return sta; |
| @@ -294,7 +315,8 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
| 294 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 315 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 295 | struct ieee80211_local *local = sdata->local; | 316 | struct ieee80211_local *local = sdata->local; |
| 296 | struct sta_info *sta; | 317 | struct sta_info *sta; |
| 297 | int band = local->oper_channel->band; | 318 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 319 | int band; | ||
| 298 | 320 | ||
| 299 | /* | 321 | /* |
| 300 | * XXX: Consider removing the least recently used entry and | 322 | * XXX: Consider removing the least recently used entry and |
| @@ -317,6 +339,13 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
| 317 | return NULL; | 339 | return NULL; |
| 318 | } | 340 | } |
| 319 | 341 | ||
| 342 | rcu_read_lock(); | ||
| 343 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 344 | if (WARN_ON_ONCE(!chanctx_conf)) | ||
| 345 | return NULL; | ||
| 346 | band = chanctx_conf->def.chan->band; | ||
| 347 | rcu_read_unlock(); | ||
| 348 | |||
| 320 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); | 349 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); |
| 321 | if (!sta) { | 350 | if (!sta) { |
| 322 | rcu_read_lock(); | 351 | rcu_read_lock(); |
| @@ -362,11 +391,13 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 362 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 391 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
| 363 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 392 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
| 364 | 393 | ||
| 365 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | ||
| 366 | return; | ||
| 367 | ibss_dbg(sdata, | 394 | ibss_dbg(sdata, |
| 368 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", | 395 | "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", |
| 369 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); | 396 | mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); |
| 397 | |||
| 398 | if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) | ||
| 399 | return; | ||
| 400 | |||
| 370 | sta_info_destroy_addr(sdata, mgmt->sa); | 401 | sta_info_destroy_addr(sdata, mgmt->sa); |
| 371 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); | 402 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); |
| 372 | rcu_read_unlock(); | 403 | rcu_read_unlock(); |
| @@ -389,7 +420,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
| 389 | * However, try to reply to authentication attempts if someone | 420 | * However, try to reply to authentication attempts if someone |
| 390 | * has actually implemented this. | 421 | * has actually implemented this. |
| 391 | */ | 422 | */ |
| 392 | ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, | 423 | ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0, |
| 393 | mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0); | 424 | mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0); |
| 394 | } | 425 | } |
| 395 | 426 | ||
| @@ -461,9 +492,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 461 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { | 492 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { |
| 462 | /* we both use HT */ | 493 | /* we both use HT */ |
| 463 | struct ieee80211_sta_ht_cap sta_ht_cap_new; | 494 | struct ieee80211_sta_ht_cap sta_ht_cap_new; |
| 464 | enum nl80211_channel_type channel_type = | 495 | struct cfg80211_chan_def chandef; |
| 465 | ieee80211_ht_oper_to_channel_type( | 496 | |
| 466 | elems->ht_operation); | 497 | ieee80211_ht_oper_to_chandef(channel, |
| 498 | elems->ht_operation, | ||
| 499 | &chandef); | ||
| 467 | 500 | ||
| 468 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 501 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 469 | elems->ht_cap_elem, | 502 | elems->ht_cap_elem, |
| @@ -473,9 +506,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 473 | * fall back to HT20 if we don't use or use | 506 | * fall back to HT20 if we don't use or use |
| 474 | * the other extension channel | 507 | * the other extension channel |
| 475 | */ | 508 | */ |
| 476 | if (!(channel_type == NL80211_CHAN_HT40MINUS || | 509 | if (chandef.width != NL80211_CHAN_WIDTH_40 || |
| 477 | channel_type == NL80211_CHAN_HT40PLUS) || | 510 | cfg80211_get_chandef_type(&chandef) != |
| 478 | channel_type != sdata->u.ibss.channel_type) | 511 | sdata->u.ibss.channel_type) |
| 479 | sta_ht_cap_new.cap &= | 512 | sta_ht_cap_new.cap &= |
| 480 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 513 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
| 481 | 514 | ||
| @@ -517,7 +550,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 517 | goto put_bss; | 550 | goto put_bss; |
| 518 | 551 | ||
| 519 | /* different channel */ | 552 | /* different channel */ |
| 520 | if (cbss->channel != local->oper_channel) | 553 | if (sdata->u.ibss.fixed_channel && |
| 554 | sdata->u.ibss.channel != cbss->channel) | ||
| 521 | goto put_bss; | 555 | goto put_bss; |
| 522 | 556 | ||
| 523 | /* different SSID */ | 557 | /* different SSID */ |
| @@ -530,30 +564,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 530 | if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) | 564 | if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid)) |
| 531 | goto put_bss; | 565 | goto put_bss; |
| 532 | 566 | ||
| 533 | if (rx_status->flag & RX_FLAG_MACTIME_MPDU) { | 567 | if (ieee80211_have_rx_timestamp(rx_status)) { |
| 534 | /* | 568 | /* time when timestamp field was received */ |
| 535 | * For correct IBSS merging we need mactime; since mactime is | 569 | rx_timestamp = |
| 536 | * defined as the time the first data symbol of the frame hits | 570 | ieee80211_calculate_rx_timestamp(local, rx_status, |
| 537 | * the PHY, and the timestamp of the beacon is defined as "the | 571 | len + FCS_LEN, 24); |
| 538 | * time that the data symbol containing the first bit of the | ||
| 539 | * timestamp is transmitted to the PHY plus the transmitting | ||
| 540 | * STA's delays through its local PHY from the MAC-PHY | ||
| 541 | * interface to its interface with the WM" (802.11 11.1.2) | ||
| 542 | * - equals the time this bit arrives at the receiver - we have | ||
| 543 | * to take into account the offset between the two. | ||
| 544 | * | ||
| 545 | * E.g. at 1 MBit that means mactime is 192 usec earlier | ||
| 546 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | ||
| 547 | */ | ||
| 548 | int rate; | ||
| 549 | |||
| 550 | if (rx_status->flag & RX_FLAG_HT) | ||
| 551 | rate = 65; /* TODO: HT rates */ | ||
| 552 | else | ||
| 553 | rate = local->hw.wiphy->bands[band]-> | ||
| 554 | bitrates[rx_status->rate_idx].bitrate; | ||
| 555 | |||
| 556 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
| 557 | } else { | 572 | } else { |
| 558 | /* | 573 | /* |
| 559 | * second best option: get current TSF | 574 | * second best option: get current TSF |
| @@ -592,7 +607,8 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
| 592 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 607 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
| 593 | struct ieee80211_local *local = sdata->local; | 608 | struct ieee80211_local *local = sdata->local; |
| 594 | struct sta_info *sta; | 609 | struct sta_info *sta; |
| 595 | int band = local->oper_channel->band; | 610 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 611 | int band; | ||
| 596 | 612 | ||
| 597 | /* | 613 | /* |
| 598 | * XXX: Consider removing the least recently used entry and | 614 | * XXX: Consider removing the least recently used entry and |
| @@ -610,6 +626,15 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
| 610 | if (!ether_addr_equal(bssid, sdata->u.ibss.bssid)) | 626 | if (!ether_addr_equal(bssid, sdata->u.ibss.bssid)) |
| 611 | return; | 627 | return; |
| 612 | 628 | ||
| 629 | rcu_read_lock(); | ||
| 630 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 631 | if (WARN_ON_ONCE(!chanctx_conf)) { | ||
| 632 | rcu_read_unlock(); | ||
| 633 | return; | ||
| 634 | } | ||
| 635 | band = chanctx_conf->def.chan->band; | ||
| 636 | rcu_read_unlock(); | ||
| 637 | |||
| 613 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 638 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); |
| 614 | if (!sta) | 639 | if (!sta) |
| 615 | return; | 640 | return; |
| @@ -715,7 +740,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 715 | 740 | ||
| 716 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, | 741 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, |
| 717 | ifibss->channel, ifibss->basic_rates, | 742 | ifibss->channel, ifibss->basic_rates, |
| 718 | capability, 0); | 743 | capability, 0, true); |
| 719 | } | 744 | } |
| 720 | 745 | ||
| 721 | /* | 746 | /* |
| @@ -784,18 +809,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
| 784 | int interval = IEEE80211_SCAN_INTERVAL; | 809 | int interval = IEEE80211_SCAN_INTERVAL; |
| 785 | 810 | ||
| 786 | if (time_after(jiffies, ifibss->ibss_join_req + | 811 | if (time_after(jiffies, ifibss->ibss_join_req + |
| 787 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | 812 | IEEE80211_IBSS_JOIN_TIMEOUT)) |
| 788 | if (!(local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) { | 813 | ieee80211_sta_create_ibss(sdata); |
| 789 | ieee80211_sta_create_ibss(sdata); | ||
| 790 | return; | ||
| 791 | } | ||
| 792 | sdata_info(sdata, "IBSS not allowed on %d MHz\n", | ||
| 793 | local->oper_channel->center_freq); | ||
| 794 | |||
| 795 | /* No IBSS found - decrease scan interval and continue | ||
| 796 | * scanning. */ | ||
| 797 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | ||
| 798 | } | ||
| 799 | 814 | ||
| 800 | mod_timer(&ifibss->timer, | 815 | mod_timer(&ifibss->timer, |
| 801 | round_jiffies(jiffies + interval)); | 816 | round_jiffies(jiffies + interval)); |
| @@ -1082,21 +1097,11 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
| 1082 | 1097 | ||
| 1083 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; | 1098 | sdata->vif.bss_conf.beacon_int = params->beacon_interval; |
| 1084 | 1099 | ||
| 1085 | sdata->u.ibss.channel = params->channel; | 1100 | sdata->u.ibss.channel = params->chandef.chan; |
| 1086 | sdata->u.ibss.channel_type = params->channel_type; | 1101 | sdata->u.ibss.channel_type = |
| 1102 | cfg80211_get_chandef_type(¶ms->chandef); | ||
| 1087 | sdata->u.ibss.fixed_channel = params->channel_fixed; | 1103 | sdata->u.ibss.fixed_channel = params->channel_fixed; |
| 1088 | 1104 | ||
| 1089 | /* fix ourselves to that channel now already */ | ||
| 1090 | if (params->channel_fixed) { | ||
| 1091 | sdata->local->oper_channel = params->channel; | ||
| 1092 | if (!ieee80211_set_channel_type(sdata->local, sdata, | ||
| 1093 | params->channel_type)) { | ||
| 1094 | mutex_unlock(&sdata->u.ibss.mtx); | ||
| 1095 | kfree_skb(skb); | ||
| 1096 | return -EINVAL; | ||
| 1097 | } | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | if (params->ie) { | 1105 | if (params->ie) { |
| 1101 | sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len, | 1106 | sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len, |
| 1102 | GFP_KERNEL); | 1107 | GFP_KERNEL); |
| @@ -1134,6 +1139,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
| 1134 | changed |= BSS_CHANGED_HT; | 1139 | changed |= BSS_CHANGED_HT; |
| 1135 | ieee80211_bss_info_change_notify(sdata, changed); | 1140 | ieee80211_bss_info_change_notify(sdata, changed); |
| 1136 | 1141 | ||
| 1142 | sdata->smps_mode = IEEE80211_SMPS_OFF; | ||
| 1143 | sdata->needed_rx_chains = sdata->local->rx_chains; | ||
| 1144 | |||
| 1137 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | 1145 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
| 1138 | 1146 | ||
| 1139 | return 0; | 1147 | return 0; |
| @@ -1197,6 +1205,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
| 1197 | lockdep_is_held(&sdata->u.ibss.mtx)); | 1205 | lockdep_is_held(&sdata->u.ibss.mtx)); |
| 1198 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | 1206 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); |
| 1199 | sdata->vif.bss_conf.ibss_joined = false; | 1207 | sdata->vif.bss_conf.ibss_joined = false; |
| 1208 | sdata->vif.bss_conf.ibss_creator = false; | ||
| 1200 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 1209 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
| 1201 | BSS_CHANGED_IBSS); | 1210 | BSS_CHANGED_IBSS); |
| 1202 | synchronize_rcu(); | 1211 | synchronize_rcu(); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 156e5835e37f..42d0d0267730 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
| @@ -56,6 +56,9 @@ struct ieee80211_local; | |||
| 56 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) | 56 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) |
| 57 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) | 57 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) |
| 58 | 58 | ||
| 59 | /* power level hasn't been configured (or set to automatic) */ | ||
| 60 | #define IEEE80211_UNSET_POWER_LEVEL INT_MIN | ||
| 61 | |||
| 59 | /* | 62 | /* |
| 60 | * Some APs experience problems when working with U-APSD. Decrease the | 63 | * Some APs experience problems when working with U-APSD. Decrease the |
| 61 | * probability of that happening by using legacy mode for all ACs but VO. | 64 | * probability of that happening by using legacy mode for all ACs but VO. |
| @@ -280,23 +283,27 @@ struct probe_resp { | |||
| 280 | u8 data[0]; | 283 | u8 data[0]; |
| 281 | }; | 284 | }; |
| 282 | 285 | ||
| 283 | struct ieee80211_if_ap { | 286 | struct ps_data { |
| 284 | struct beacon_data __rcu *beacon; | ||
| 285 | struct probe_resp __rcu *probe_resp; | ||
| 286 | |||
| 287 | struct list_head vlans; | ||
| 288 | |||
| 289 | /* yes, this looks ugly, but guarantees that we can later use | 287 | /* yes, this looks ugly, but guarantees that we can later use |
| 290 | * bitmap_empty :) | 288 | * bitmap_empty :) |
| 291 | * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ | 289 | * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ |
| 292 | u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; | 290 | u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; |
| 293 | struct sk_buff_head ps_bc_buf; | 291 | struct sk_buff_head bc_buf; |
| 294 | atomic_t num_sta_ps; /* number of stations in PS mode */ | 292 | atomic_t num_sta_ps; /* number of stations in PS mode */ |
| 295 | atomic_t num_mcast_sta; /* number of stations receiving multicast */ | ||
| 296 | int dtim_count; | 293 | int dtim_count; |
| 297 | bool dtim_bc_mc; | 294 | bool dtim_bc_mc; |
| 298 | }; | 295 | }; |
| 299 | 296 | ||
| 297 | struct ieee80211_if_ap { | ||
| 298 | struct beacon_data __rcu *beacon; | ||
| 299 | struct probe_resp __rcu *probe_resp; | ||
| 300 | |||
| 301 | struct list_head vlans; | ||
| 302 | |||
| 303 | struct ps_data ps; | ||
| 304 | atomic_t num_mcast_sta; /* number of stations receiving multicast */ | ||
| 305 | }; | ||
| 306 | |||
| 300 | struct ieee80211_if_wds { | 307 | struct ieee80211_if_wds { |
| 301 | struct sta_info *sta; | 308 | struct sta_info *sta; |
| 302 | u8 remote_addr[ETH_ALEN]; | 309 | u8 remote_addr[ETH_ALEN]; |
| @@ -316,7 +323,6 @@ struct mesh_stats { | |||
| 316 | __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ | 323 | __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ |
| 317 | __u32 dropped_frames_no_route; /* Not transmitted, no route found */ | 324 | __u32 dropped_frames_no_route; /* Not transmitted, no route found */ |
| 318 | __u32 dropped_frames_congestion;/* Not forwarded due to congestion */ | 325 | __u32 dropped_frames_congestion;/* Not forwarded due to congestion */ |
| 319 | atomic_t estab_plinks; | ||
| 320 | }; | 326 | }; |
| 321 | 327 | ||
| 322 | #define PREQ_Q_F_START 0x1 | 328 | #define PREQ_Q_F_START 0x1 |
| @@ -342,7 +348,6 @@ struct ieee80211_roc_work { | |||
| 342 | struct ieee80211_sub_if_data *sdata; | 348 | struct ieee80211_sub_if_data *sdata; |
| 343 | 349 | ||
| 344 | struct ieee80211_channel *chan; | 350 | struct ieee80211_channel *chan; |
| 345 | enum nl80211_channel_type chan_type; | ||
| 346 | 351 | ||
| 347 | bool started, abort, hw_begun, notified; | 352 | bool started, abort, hw_begun, notified; |
| 348 | 353 | ||
| @@ -350,7 +355,7 @@ struct ieee80211_roc_work { | |||
| 350 | 355 | ||
| 351 | u32 duration, req_duration; | 356 | u32 duration, req_duration; |
| 352 | struct sk_buff *frame; | 357 | struct sk_buff *frame; |
| 353 | u64 mgmt_tx_cookie; | 358 | u64 cookie, mgmt_tx_cookie; |
| 354 | }; | 359 | }; |
| 355 | 360 | ||
| 356 | /* flags used in struct ieee80211_if_managed.flags */ | 361 | /* flags used in struct ieee80211_if_managed.flags */ |
| @@ -358,7 +363,7 @@ enum ieee80211_sta_flags { | |||
| 358 | IEEE80211_STA_BEACON_POLL = BIT(0), | 363 | IEEE80211_STA_BEACON_POLL = BIT(0), |
| 359 | IEEE80211_STA_CONNECTION_POLL = BIT(1), | 364 | IEEE80211_STA_CONNECTION_POLL = BIT(1), |
| 360 | IEEE80211_STA_CONTROL_PORT = BIT(2), | 365 | IEEE80211_STA_CONTROL_PORT = BIT(2), |
| 361 | IEEE80211_STA_DISABLE_11N = BIT(4), | 366 | IEEE80211_STA_DISABLE_HT = BIT(4), |
| 362 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | 367 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
| 363 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 368 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
| 364 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | 369 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
| @@ -366,6 +371,8 @@ enum ieee80211_sta_flags { | |||
| 366 | IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), | 371 | IEEE80211_STA_RESET_SIGNAL_AVE = BIT(9), |
| 367 | IEEE80211_STA_DISABLE_40MHZ = BIT(10), | 372 | IEEE80211_STA_DISABLE_40MHZ = BIT(10), |
| 368 | IEEE80211_STA_DISABLE_VHT = BIT(11), | 373 | IEEE80211_STA_DISABLE_VHT = BIT(11), |
| 374 | IEEE80211_STA_DISABLE_80P80MHZ = BIT(12), | ||
| 375 | IEEE80211_STA_DISABLE_160MHZ = BIT(13), | ||
| 369 | }; | 376 | }; |
| 370 | 377 | ||
| 371 | struct ieee80211_mgd_auth_data { | 378 | struct ieee80211_mgd_auth_data { |
| @@ -378,8 +385,9 @@ struct ieee80211_mgd_auth_data { | |||
| 378 | u8 key_len, key_idx; | 385 | u8 key_len, key_idx; |
| 379 | bool done; | 386 | bool done; |
| 380 | 387 | ||
| 381 | size_t ie_len; | 388 | u16 sae_trans, sae_status; |
| 382 | u8 ie[]; | 389 | size_t data_len; |
| 390 | u8 data[]; | ||
| 383 | }; | 391 | }; |
| 384 | 392 | ||
| 385 | struct ieee80211_mgd_assoc_data { | 393 | struct ieee80211_mgd_assoc_data { |
| @@ -433,7 +441,6 @@ struct ieee80211_if_managed { | |||
| 433 | bool powersave; /* powersave requested for this iface */ | 441 | bool powersave; /* powersave requested for this iface */ |
| 434 | bool broken_ap; /* AP is broken -- turn off powersave */ | 442 | bool broken_ap; /* AP is broken -- turn off powersave */ |
| 435 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ | 443 | enum ieee80211_smps_mode req_smps, /* requested smps mode */ |
| 436 | ap_smps, /* smps mode AP thinks we're in */ | ||
| 437 | driver_smps_mode; /* smps mode request */ | 444 | driver_smps_mode; /* smps mode request */ |
| 438 | 445 | ||
| 439 | struct work_struct request_smps_work; | 446 | struct work_struct request_smps_work; |
| @@ -467,6 +474,8 @@ struct ieee80211_if_managed { | |||
| 467 | 474 | ||
| 468 | u8 use_4addr; | 475 | u8 use_4addr; |
| 469 | 476 | ||
| 477 | u8 p2p_noa_index; | ||
| 478 | |||
| 470 | /* Signal strength from the last Beacon frame in the current BSS. */ | 479 | /* Signal strength from the last Beacon frame in the current BSS. */ |
| 471 | int last_beacon_signal; | 480 | int last_beacon_signal; |
| 472 | 481 | ||
| @@ -599,6 +608,7 @@ struct ieee80211_if_mesh { | |||
| 599 | int preq_queue_len; | 608 | int preq_queue_len; |
| 600 | struct mesh_stats mshstats; | 609 | struct mesh_stats mshstats; |
| 601 | struct mesh_config mshcfg; | 610 | struct mesh_config mshcfg; |
| 611 | atomic_t estab_plinks; | ||
| 602 | u32 mesh_seqnum; | 612 | u32 mesh_seqnum; |
| 603 | bool accepting_plinks; | 613 | bool accepting_plinks; |
| 604 | int num_gates; | 614 | int num_gates; |
| @@ -610,7 +620,7 @@ struct ieee80211_if_mesh { | |||
| 610 | IEEE80211_MESH_SEC_SECURED = 0x2, | 620 | IEEE80211_MESH_SEC_SECURED = 0x2, |
| 611 | } security; | 621 | } security; |
| 612 | /* Extensible Synchronization Framework */ | 622 | /* Extensible Synchronization Framework */ |
| 613 | struct ieee80211_mesh_sync_ops *sync_ops; | 623 | const struct ieee80211_mesh_sync_ops *sync_ops; |
| 614 | s64 sync_offset_clockdrift_max; | 624 | s64 sync_offset_clockdrift_max; |
| 615 | spinlock_t sync_offset_lock; | 625 | spinlock_t sync_offset_lock; |
| 616 | bool adjusting_tbtt; | 626 | bool adjusting_tbtt; |
| @@ -658,6 +668,30 @@ enum ieee80211_sdata_state_bits { | |||
| 658 | SDATA_STATE_OFFCHANNEL, | 668 | SDATA_STATE_OFFCHANNEL, |
| 659 | }; | 669 | }; |
| 660 | 670 | ||
| 671 | /** | ||
| 672 | * enum ieee80211_chanctx_mode - channel context configuration mode | ||
| 673 | * | ||
| 674 | * @IEEE80211_CHANCTX_SHARED: channel context may be used by | ||
| 675 | * multiple interfaces | ||
| 676 | * @IEEE80211_CHANCTX_EXCLUSIVE: channel context can be used | ||
| 677 | * only by a single interface. This can be used for example for | ||
| 678 | * non-fixed channel IBSS. | ||
| 679 | */ | ||
| 680 | enum ieee80211_chanctx_mode { | ||
| 681 | IEEE80211_CHANCTX_SHARED, | ||
| 682 | IEEE80211_CHANCTX_EXCLUSIVE | ||
| 683 | }; | ||
| 684 | |||
| 685 | struct ieee80211_chanctx { | ||
| 686 | struct list_head list; | ||
| 687 | struct rcu_head rcu_head; | ||
| 688 | |||
| 689 | enum ieee80211_chanctx_mode mode; | ||
| 690 | int refcount; | ||
| 691 | |||
| 692 | struct ieee80211_chanctx_conf conf; | ||
| 693 | }; | ||
| 694 | |||
| 661 | struct ieee80211_sub_if_data { | 695 | struct ieee80211_sub_if_data { |
| 662 | struct list_head list; | 696 | struct list_head list; |
| 663 | 697 | ||
| @@ -704,11 +738,20 @@ struct ieee80211_sub_if_data { | |||
| 704 | 738 | ||
| 705 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; | 739 | struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; |
| 706 | 740 | ||
| 741 | /* used to reconfigure hardware SM PS */ | ||
| 742 | struct work_struct recalc_smps; | ||
| 743 | |||
| 707 | struct work_struct work; | 744 | struct work_struct work; |
| 708 | struct sk_buff_head skb_queue; | 745 | struct sk_buff_head skb_queue; |
| 709 | 746 | ||
| 710 | bool arp_filter_state; | 747 | bool arp_filter_state; |
| 711 | 748 | ||
| 749 | u8 needed_rx_chains; | ||
| 750 | enum ieee80211_smps_mode smps_mode; | ||
| 751 | |||
| 752 | int user_power_level; /* in dBm */ | ||
| 753 | int ap_power_level; /* in dBm */ | ||
| 754 | |||
| 712 | /* | 755 | /* |
| 713 | * AP this belongs to: self in AP mode and | 756 | * AP this belongs to: self in AP mode and |
| 714 | * corresponding AP in VLAN mode, NULL for | 757 | * corresponding AP in VLAN mode, NULL for |
| @@ -749,6 +792,21 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) | |||
| 749 | return container_of(p, struct ieee80211_sub_if_data, vif); | 792 | return container_of(p, struct ieee80211_sub_if_data, vif); |
| 750 | } | 793 | } |
| 751 | 794 | ||
| 795 | static inline enum ieee80211_band | ||
| 796 | ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata) | ||
| 797 | { | ||
| 798 | enum ieee80211_band band = IEEE80211_BAND_2GHZ; | ||
| 799 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 800 | |||
| 801 | rcu_read_lock(); | ||
| 802 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 803 | if (!WARN_ON(!chanctx_conf)) | ||
| 804 | band = chanctx_conf->def.chan->band; | ||
| 805 | rcu_read_unlock(); | ||
| 806 | |||
| 807 | return band; | ||
| 808 | } | ||
| 809 | |||
| 752 | enum sdata_queue_type { | 810 | enum sdata_queue_type { |
| 753 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, | 811 | IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, |
| 754 | IEEE80211_SDATA_QUEUE_AGG_START = 1, | 812 | IEEE80211_SDATA_QUEUE_AGG_START = 1, |
| @@ -821,6 +879,7 @@ enum { | |||
| 821 | * @SCAN_SUSPEND: Suspend the scan and go back to operating channel to | 879 | * @SCAN_SUSPEND: Suspend the scan and go back to operating channel to |
| 822 | * send out data | 880 | * send out data |
| 823 | * @SCAN_RESUME: Resume the scan and scan the next channel | 881 | * @SCAN_RESUME: Resume the scan and scan the next channel |
| 882 | * @SCAN_ABORT: Abort the scan and go back to operating channel | ||
| 824 | */ | 883 | */ |
| 825 | enum mac80211_scan_state { | 884 | enum mac80211_scan_state { |
| 826 | SCAN_DECISION, | 885 | SCAN_DECISION, |
| @@ -828,6 +887,7 @@ enum mac80211_scan_state { | |||
| 828 | SCAN_SEND_PROBE, | 887 | SCAN_SEND_PROBE, |
| 829 | SCAN_SUSPEND, | 888 | SCAN_SUSPEND, |
| 830 | SCAN_RESUME, | 889 | SCAN_RESUME, |
| 890 | SCAN_ABORT, | ||
| 831 | }; | 891 | }; |
| 832 | 892 | ||
| 833 | struct ieee80211_local { | 893 | struct ieee80211_local { |
| @@ -858,15 +918,14 @@ struct ieee80211_local { | |||
| 858 | 918 | ||
| 859 | bool wiphy_ciphers_allocated; | 919 | bool wiphy_ciphers_allocated; |
| 860 | 920 | ||
| 921 | bool use_chanctx; | ||
| 922 | |||
| 861 | /* protects the aggregated multicast list and filter calls */ | 923 | /* protects the aggregated multicast list and filter calls */ |
| 862 | spinlock_t filter_lock; | 924 | spinlock_t filter_lock; |
| 863 | 925 | ||
| 864 | /* used for uploading changed mc list */ | 926 | /* used for uploading changed mc list */ |
| 865 | struct work_struct reconfig_filter; | 927 | struct work_struct reconfig_filter; |
| 866 | 928 | ||
| 867 | /* used to reconfigure hardware SM PS */ | ||
| 868 | struct work_struct recalc_smps; | ||
| 869 | |||
| 870 | /* aggregated multicast list */ | 929 | /* aggregated multicast list */ |
| 871 | struct netdev_hw_addr_list mc_list; | 930 | struct netdev_hw_addr_list mc_list; |
| 872 | 931 | ||
| @@ -903,6 +962,9 @@ struct ieee80211_local { | |||
| 903 | /* wowlan is enabled -- don't reconfig on resume */ | 962 | /* wowlan is enabled -- don't reconfig on resume */ |
| 904 | bool wowlan; | 963 | bool wowlan; |
| 905 | 964 | ||
| 965 | /* number of RX chains the hardware has */ | ||
| 966 | u8 rx_chains; | ||
| 967 | |||
| 906 | int tx_headroom; /* required headroom for hardware/radiotap */ | 968 | int tx_headroom; /* required headroom for hardware/radiotap */ |
| 907 | 969 | ||
| 908 | /* Tasklet and skb queue to process calls from IRQ mode. All frames | 970 | /* Tasklet and skb queue to process calls from IRQ mode. All frames |
| @@ -972,6 +1034,7 @@ struct ieee80211_local { | |||
| 972 | enum ieee80211_band hw_scan_band; | 1034 | enum ieee80211_band hw_scan_band; |
| 973 | int scan_channel_idx; | 1035 | int scan_channel_idx; |
| 974 | int scan_ies_len; | 1036 | int scan_ies_len; |
| 1037 | int hw_scan_ies_bufsize; | ||
| 975 | 1038 | ||
| 976 | struct work_struct sched_scan_stopped_work; | 1039 | struct work_struct sched_scan_stopped_work; |
| 977 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; | 1040 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; |
| @@ -980,12 +1043,17 @@ struct ieee80211_local { | |||
| 980 | enum mac80211_scan_state next_scan_state; | 1043 | enum mac80211_scan_state next_scan_state; |
| 981 | struct delayed_work scan_work; | 1044 | struct delayed_work scan_work; |
| 982 | struct ieee80211_sub_if_data __rcu *scan_sdata; | 1045 | struct ieee80211_sub_if_data __rcu *scan_sdata; |
| 1046 | struct ieee80211_channel *csa_channel; | ||
| 1047 | /* For backward compatibility only -- do not use */ | ||
| 1048 | struct ieee80211_channel *_oper_channel; | ||
| 983 | enum nl80211_channel_type _oper_channel_type; | 1049 | enum nl80211_channel_type _oper_channel_type; |
| 984 | struct ieee80211_channel *oper_channel, *csa_channel; | ||
| 985 | 1050 | ||
| 986 | /* Temporary remain-on-channel for off-channel operations */ | 1051 | /* Temporary remain-on-channel for off-channel operations */ |
| 987 | struct ieee80211_channel *tmp_channel; | 1052 | struct ieee80211_channel *tmp_channel; |
| 988 | enum nl80211_channel_type tmp_channel_type; | 1053 | |
| 1054 | /* channel contexts */ | ||
| 1055 | struct list_head chanctx_list; | ||
| 1056 | struct mutex chanctx_mtx; | ||
| 989 | 1057 | ||
| 990 | /* SNMP counters */ | 1058 | /* SNMP counters */ |
| 991 | /* dot11CountersTable */ | 1059 | /* dot11CountersTable */ |
| @@ -1058,8 +1126,7 @@ struct ieee80211_local { | |||
| 1058 | int dynamic_ps_user_timeout; | 1126 | int dynamic_ps_user_timeout; |
| 1059 | bool disable_dynamic_ps; | 1127 | bool disable_dynamic_ps; |
| 1060 | 1128 | ||
| 1061 | int user_power_level; /* in dBm */ | 1129 | int user_power_level; /* in dBm, for all interfaces */ |
| 1062 | int ap_power_level; /* in dBm */ | ||
| 1063 | 1130 | ||
| 1064 | enum ieee80211_smps_mode smps_mode; | 1131 | enum ieee80211_smps_mode smps_mode; |
| 1065 | 1132 | ||
| @@ -1078,6 +1145,7 @@ struct ieee80211_local { | |||
| 1078 | struct list_head roc_list; | 1145 | struct list_head roc_list; |
| 1079 | struct work_struct hw_roc_start, hw_roc_done; | 1146 | struct work_struct hw_roc_start, hw_roc_done; |
| 1080 | unsigned long hw_roc_start_time; | 1147 | unsigned long hw_roc_start_time; |
| 1148 | u64 roc_cookie_counter; | ||
| 1081 | 1149 | ||
| 1082 | struct idr ack_status_frames; | 1150 | struct idr ack_status_frames; |
| 1083 | spinlock_t ack_status_lock; | 1151 | spinlock_t ack_status_lock; |
| @@ -1091,6 +1159,7 @@ struct ieee80211_local { | |||
| 1091 | 1159 | ||
| 1092 | /* virtual monitor interface */ | 1160 | /* virtual monitor interface */ |
| 1093 | struct ieee80211_sub_if_data __rcu *monitor_sdata; | 1161 | struct ieee80211_sub_if_data __rcu *monitor_sdata; |
| 1162 | struct cfg80211_chan_def monitor_chandef; | ||
| 1094 | }; | 1163 | }; |
| 1095 | 1164 | ||
| 1096 | static inline struct ieee80211_sub_if_data * | 1165 | static inline struct ieee80211_sub_if_data * |
| @@ -1133,6 +1202,8 @@ struct ieee802_11_elems { | |||
| 1133 | u8 *wmm_param; | 1202 | u8 *wmm_param; |
| 1134 | struct ieee80211_ht_cap *ht_cap_elem; | 1203 | struct ieee80211_ht_cap *ht_cap_elem; |
| 1135 | struct ieee80211_ht_operation *ht_operation; | 1204 | struct ieee80211_ht_operation *ht_operation; |
| 1205 | struct ieee80211_vht_cap *vht_cap_elem; | ||
| 1206 | struct ieee80211_vht_operation *vht_operation; | ||
| 1136 | struct ieee80211_meshconf_ie *mesh_config; | 1207 | struct ieee80211_meshconf_ie *mesh_config; |
| 1137 | u8 *mesh_id; | 1208 | u8 *mesh_id; |
| 1138 | u8 *peering; | 1209 | u8 *peering; |
| @@ -1188,7 +1259,18 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) | |||
| 1188 | is_broadcast_ether_addr(raddr); | 1259 | is_broadcast_ether_addr(raddr); |
| 1189 | } | 1260 | } |
| 1190 | 1261 | ||
| 1262 | static inline bool | ||
| 1263 | ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status) | ||
| 1264 | { | ||
| 1265 | WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START && | ||
| 1266 | status->flag & RX_FLAG_MACTIME_END); | ||
| 1267 | return status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END); | ||
| 1268 | } | ||
| 1191 | 1269 | ||
| 1270 | u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | ||
| 1271 | struct ieee80211_rx_status *status, | ||
| 1272 | unsigned int mpdu_len, | ||
| 1273 | unsigned int mpdu_offset); | ||
| 1192 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); | 1274 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); |
| 1193 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); | 1275 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); |
| 1194 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 1276 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
| @@ -1302,6 +1384,9 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | |||
| 1302 | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); | 1384 | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); |
| 1303 | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); | 1385 | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); |
| 1304 | 1386 | ||
| 1387 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | ||
| 1388 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | ||
| 1389 | |||
| 1305 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1390 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) |
| 1306 | { | 1391 | { |
| 1307 | return test_bit(SDATA_STATE_RUNNING, &sdata->state); | 1392 | return test_bit(SDATA_STATE_RUNNING, &sdata->state); |
| @@ -1361,6 +1446,13 @@ void ieee80211_ba_session_work(struct work_struct *work); | |||
| 1361 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid); | 1446 | void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid); |
| 1362 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid); | 1447 | void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid); |
| 1363 | 1448 | ||
| 1449 | u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs); | ||
| 1450 | |||
| 1451 | /* VHT */ | ||
| 1452 | void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | ||
| 1453 | struct ieee80211_supported_band *sband, | ||
| 1454 | struct ieee80211_vht_cap *vht_cap_ie, | ||
| 1455 | struct ieee80211_sta_vht_cap *vht_cap); | ||
| 1364 | /* Spectrum management */ | 1456 | /* Spectrum management */ |
| 1365 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1457 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
| 1366 | struct ieee80211_mgmt *mgmt, | 1458 | struct ieee80211_mgmt *mgmt, |
| @@ -1395,11 +1487,42 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke | |||
| 1395 | gfp_t gfp); | 1487 | gfp_t gfp); |
| 1396 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | 1488 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, |
| 1397 | bool bss_notify); | 1489 | bool bss_notify); |
| 1398 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 1490 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
| 1491 | enum ieee80211_band band); | ||
| 1492 | |||
| 1493 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | ||
| 1494 | struct sk_buff *skb, int tid, | ||
| 1495 | enum ieee80211_band band); | ||
| 1399 | 1496 | ||
| 1400 | void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, | 1497 | static inline void |
| 1401 | struct sk_buff *skb, int tid); | 1498 | ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
| 1402 | static void inline ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, | 1499 | struct sk_buff *skb, int tid, |
| 1500 | enum ieee80211_band band) | ||
| 1501 | { | ||
| 1502 | rcu_read_lock(); | ||
| 1503 | __ieee80211_tx_skb_tid_band(sdata, skb, tid, band); | ||
| 1504 | rcu_read_unlock(); | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, | ||
| 1508 | struct sk_buff *skb, int tid) | ||
| 1509 | { | ||
| 1510 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 1511 | |||
| 1512 | rcu_read_lock(); | ||
| 1513 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 1514 | if (WARN_ON(!chanctx_conf)) { | ||
| 1515 | rcu_read_unlock(); | ||
| 1516 | kfree_skb(skb); | ||
| 1517 | return; | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | __ieee80211_tx_skb_tid_band(sdata, skb, tid, | ||
| 1521 | chanctx_conf->def.chan->band); | ||
| 1522 | rcu_read_unlock(); | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, | ||
| 1403 | struct sk_buff *skb) | 1526 | struct sk_buff *skb) |
| 1404 | { | 1527 | { |
| 1405 | /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ | 1528 | /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */ |
| @@ -1446,14 +1569,14 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
| 1446 | } | 1569 | } |
| 1447 | 1570 | ||
| 1448 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1571 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
| 1449 | u16 transaction, u16 auth_alg, | 1572 | u16 transaction, u16 auth_alg, u16 status, |
| 1450 | u8 *extra, size_t extra_len, const u8 *bssid, | 1573 | u8 *extra, size_t extra_len, const u8 *bssid, |
| 1451 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx); | 1574 | const u8 *da, const u8 *key, u8 key_len, u8 key_idx); |
| 1452 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 1575 | void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
| 1453 | const u8 *bssid, u16 stype, u16 reason, | 1576 | const u8 *bssid, u16 stype, u16 reason, |
| 1454 | bool send_frame, u8 *frame_buf); | 1577 | bool send_frame, u8 *frame_buf); |
| 1455 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1578 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
| 1456 | const u8 *ie, size_t ie_len, | 1579 | size_t buffer_len, const u8 *ie, size_t ie_len, |
| 1457 | enum ieee80211_band band, u32 rate_mask, | 1580 | enum ieee80211_band band, u32 rate_mask, |
| 1458 | u8 channel); | 1581 | u8 channel); |
| 1459 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1582 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
| @@ -1466,7 +1589,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
| 1466 | const u8 *ssid, size_t ssid_len, | 1589 | const u8 *ssid, size_t ssid_len, |
| 1467 | const u8 *ie, size_t ie_len, | 1590 | const u8 *ie, size_t ie_len, |
| 1468 | u32 ratemask, bool directed, bool no_cck, | 1591 | u32 ratemask, bool directed, bool no_cck, |
| 1469 | struct ieee80211_channel *channel); | 1592 | struct ieee80211_channel *channel, bool scan); |
| 1470 | 1593 | ||
| 1471 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 1594 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, |
| 1472 | const size_t supp_rates_len, | 1595 | const size_t supp_rates_len, |
| @@ -1476,7 +1599,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
| 1476 | enum ieee80211_band band, u32 *basic_rates); | 1599 | enum ieee80211_band band, u32 *basic_rates); |
| 1477 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | 1600 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, |
| 1478 | enum ieee80211_smps_mode smps_mode); | 1601 | enum ieee80211_smps_mode smps_mode); |
| 1479 | void ieee80211_recalc_smps(struct ieee80211_local *local); | 1602 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); |
| 1480 | 1603 | ||
| 1481 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1604 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, |
| 1482 | const u8 *ids, int n_ids, size_t offset); | 1605 | const u8 *ids, int n_ids, size_t offset); |
| @@ -1484,8 +1607,7 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | |||
| 1484 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1607 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
| 1485 | u16 cap); | 1608 | u16 cap); |
| 1486 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1609 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
| 1487 | struct ieee80211_channel *channel, | 1610 | const struct cfg80211_chan_def *chandef, |
| 1488 | enum nl80211_channel_type channel_type, | ||
| 1489 | u16 prot_mode); | 1611 | u16 prot_mode); |
| 1490 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | 1612 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, |
| 1491 | u32 cap); | 1613 | u32 cap); |
| @@ -1497,20 +1619,18 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | |||
| 1497 | enum ieee80211_band band); | 1619 | enum ieee80211_band band); |
| 1498 | 1620 | ||
| 1499 | /* channel management */ | 1621 | /* channel management */ |
| 1500 | enum ieee80211_chan_mode { | 1622 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
| 1501 | CHAN_MODE_UNDEFINED, | 1623 | struct ieee80211_ht_operation *ht_oper, |
| 1502 | CHAN_MODE_HOPPING, | 1624 | struct cfg80211_chan_def *chandef); |
| 1503 | CHAN_MODE_FIXED, | 1625 | |
| 1504 | }; | 1626 | int __must_check |
| 1505 | 1627 | ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |
| 1506 | enum ieee80211_chan_mode | 1628 | const struct cfg80211_chan_def *chandef, |
| 1507 | ieee80211_get_channel_mode(struct ieee80211_local *local, | 1629 | enum ieee80211_chanctx_mode mode); |
| 1508 | struct ieee80211_sub_if_data *ignore); | 1630 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata); |
| 1509 | bool ieee80211_set_channel_type(struct ieee80211_local *local, | 1631 | |
| 1510 | struct ieee80211_sub_if_data *sdata, | 1632 | void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, |
| 1511 | enum nl80211_channel_type chantype); | 1633 | struct ieee80211_chanctx *chanctx); |
| 1512 | enum nl80211_channel_type | ||
| 1513 | ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper); | ||
| 1514 | 1634 | ||
| 1515 | #ifdef CONFIG_MAC80211_NOINLINE | 1635 | #ifdef CONFIG_MAC80211_NOINLINE |
| 1516 | #define debug_noinline noinline | 1636 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7de7717ad67d..09a80b55cf5a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -42,6 +42,41 @@ | |||
| 42 | * by either the RTNL, the iflist_mtx or RCU. | 42 | * by either the RTNL, the iflist_mtx or RCU. |
| 43 | */ | 43 | */ |
| 44 | 44 | ||
| 45 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | ||
| 46 | { | ||
| 47 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 48 | int power; | ||
| 49 | |||
| 50 | rcu_read_lock(); | ||
| 51 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 52 | if (!chanctx_conf) { | ||
| 53 | rcu_read_unlock(); | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | power = chanctx_conf->def.chan->max_power; | ||
| 58 | rcu_read_unlock(); | ||
| 59 | |||
| 60 | if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) | ||
| 61 | power = min(power, sdata->user_power_level); | ||
| 62 | |||
| 63 | if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL) | ||
| 64 | power = min(power, sdata->ap_power_level); | ||
| 65 | |||
| 66 | if (power != sdata->vif.bss_conf.txpower) { | ||
| 67 | sdata->vif.bss_conf.txpower = power; | ||
| 68 | ieee80211_hw_config(sdata->local, 0); | ||
| 69 | return true; | ||
| 70 | } | ||
| 71 | |||
| 72 | return false; | ||
| 73 | } | ||
| 74 | |||
| 75 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | ||
| 76 | { | ||
| 77 | if (__ieee80211_recalc_txpower(sdata)) | ||
| 78 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); | ||
| 79 | } | ||
| 45 | 80 | ||
| 46 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | 81 | static u32 ieee80211_idle_off(struct ieee80211_local *local, |
| 47 | const char *reason) | 82 | const char *reason) |
| @@ -188,6 +223,47 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | |||
| 188 | return 0; | 223 | return 0; |
| 189 | } | 224 | } |
| 190 | 225 | ||
| 226 | static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) | ||
| 227 | { | ||
| 228 | struct ieee80211_sub_if_data *sdata; | ||
| 229 | u64 new, mask, tmp; | ||
| 230 | u8 *m; | ||
| 231 | int ret = 0; | ||
| 232 | |||
| 233 | if (is_zero_ether_addr(local->hw.wiphy->addr_mask)) | ||
| 234 | return 0; | ||
| 235 | |||
| 236 | m = addr; | ||
| 237 | new = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
| 238 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
| 239 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
| 240 | |||
| 241 | m = local->hw.wiphy->addr_mask; | ||
| 242 | mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
| 243 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
| 244 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
| 245 | |||
| 246 | |||
| 247 | mutex_lock(&local->iflist_mtx); | ||
| 248 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 249 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) | ||
| 250 | continue; | ||
| 251 | |||
| 252 | m = sdata->vif.addr; | ||
| 253 | tmp = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
| 254 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
| 255 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
| 256 | |||
| 257 | if ((new & ~mask) != (tmp & ~mask)) { | ||
| 258 | ret = -EINVAL; | ||
| 259 | break; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | mutex_unlock(&local->iflist_mtx); | ||
| 263 | |||
| 264 | return ret; | ||
| 265 | } | ||
| 266 | |||
| 191 | static int ieee80211_change_mac(struct net_device *dev, void *addr) | 267 | static int ieee80211_change_mac(struct net_device *dev, void *addr) |
| 192 | { | 268 | { |
| 193 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 269 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| @@ -197,6 +273,10 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) | |||
| 197 | if (ieee80211_sdata_running(sdata)) | 273 | if (ieee80211_sdata_running(sdata)) |
| 198 | return -EBUSY; | 274 | return -EBUSY; |
| 199 | 275 | ||
| 276 | ret = ieee80211_verify_mac(sdata->local, sa->sa_data); | ||
| 277 | if (ret) | ||
| 278 | return ret; | ||
| 279 | |||
| 200 | ret = eth_mac_addr(dev, sa); | 280 | ret = eth_mac_addr(dev, sa); |
| 201 | 281 | ||
| 202 | if (ret == 0) | 282 | if (ret == 0) |
| @@ -380,6 +460,14 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
| 380 | goto out_unlock; | 460 | goto out_unlock; |
| 381 | } | 461 | } |
| 382 | 462 | ||
| 463 | ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef, | ||
| 464 | IEEE80211_CHANCTX_EXCLUSIVE); | ||
| 465 | if (ret) { | ||
| 466 | drv_remove_interface(local, sdata); | ||
| 467 | kfree(sdata); | ||
| 468 | goto out_unlock; | ||
| 469 | } | ||
| 470 | |||
| 383 | rcu_assign_pointer(local->monitor_sdata, sdata); | 471 | rcu_assign_pointer(local->monitor_sdata, sdata); |
| 384 | out_unlock: | 472 | out_unlock: |
| 385 | mutex_unlock(&local->iflist_mtx); | 473 | mutex_unlock(&local->iflist_mtx); |
| @@ -403,6 +491,8 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | |||
| 403 | rcu_assign_pointer(local->monitor_sdata, NULL); | 491 | rcu_assign_pointer(local->monitor_sdata, NULL); |
| 404 | synchronize_net(); | 492 | synchronize_net(); |
| 405 | 493 | ||
| 494 | ieee80211_vif_release_channel(sdata); | ||
| 495 | |||
| 406 | drv_remove_interface(local, sdata); | 496 | drv_remove_interface(local, sdata); |
| 407 | 497 | ||
| 408 | kfree(sdata); | 498 | kfree(sdata); |
| @@ -665,7 +755,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 665 | struct sk_buff *skb, *tmp; | 755 | struct sk_buff *skb, *tmp; |
| 666 | u32 hw_reconf_flags = 0; | 756 | u32 hw_reconf_flags = 0; |
| 667 | int i; | 757 | int i; |
| 668 | enum nl80211_channel_type orig_ct; | ||
| 669 | 758 | ||
| 670 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 759 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); |
| 671 | 760 | ||
| @@ -729,34 +818,17 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 729 | del_timer_sync(&local->dynamic_ps_timer); | 818 | del_timer_sync(&local->dynamic_ps_timer); |
| 730 | cancel_work_sync(&local->dynamic_ps_enable_work); | 819 | cancel_work_sync(&local->dynamic_ps_enable_work); |
| 731 | 820 | ||
| 821 | cancel_work_sync(&sdata->recalc_smps); | ||
| 822 | |||
| 732 | /* APs need special treatment */ | 823 | /* APs need special treatment */ |
| 733 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 824 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
| 734 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 825 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
| 735 | struct beacon_data *old_beacon = | ||
| 736 | rtnl_dereference(sdata->u.ap.beacon); | ||
| 737 | struct probe_resp *old_probe_resp = | ||
| 738 | rtnl_dereference(sdata->u.ap.probe_resp); | ||
| 739 | |||
| 740 | /* sdata_running will return false, so this will disable */ | ||
| 741 | ieee80211_bss_info_change_notify(sdata, | ||
| 742 | BSS_CHANGED_BEACON_ENABLED); | ||
| 743 | |||
| 744 | /* remove beacon and probe response */ | ||
| 745 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | ||
| 746 | RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | ||
| 747 | synchronize_rcu(); | ||
| 748 | kfree(old_beacon); | ||
| 749 | kfree(old_probe_resp); | ||
| 750 | 826 | ||
| 751 | /* down all dependent devices, that is VLANs */ | 827 | /* down all dependent devices, that is VLANs */ |
| 752 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 828 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
| 753 | u.vlan.list) | 829 | u.vlan.list) |
| 754 | dev_close(vlan->dev); | 830 | dev_close(vlan->dev); |
| 755 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 831 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
| 756 | |||
| 757 | /* free all potentially still buffered bcast frames */ | ||
| 758 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps_bc_buf); | ||
| 759 | skb_queue_purge(&sdata->u.ap.ps_bc_buf); | ||
| 760 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 832 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
| 761 | ieee80211_mgd_stop(sdata); | 833 | ieee80211_mgd_stop(sdata); |
| 762 | } | 834 | } |
| @@ -790,7 +862,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 790 | rcu_assign_pointer(local->p2p_sdata, NULL); | 862 | rcu_assign_pointer(local->p2p_sdata, NULL); |
| 791 | /* fall through */ | 863 | /* fall through */ |
| 792 | default: | 864 | default: |
| 793 | flush_work(&sdata->work); | 865 | cancel_work_sync(&sdata->work); |
| 794 | /* | 866 | /* |
| 795 | * When we get here, the interface is marked down. | 867 | * When we get here, the interface is marked down. |
| 796 | * Call rcu_barrier() to wait both for the RX path | 868 | * Call rcu_barrier() to wait both for the RX path |
| @@ -837,14 +909,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
| 837 | hw_reconf_flags = 0; | 909 | hw_reconf_flags = 0; |
| 838 | } | 910 | } |
| 839 | 911 | ||
| 840 | /* Re-calculate channel-type, in case there are multiple vifs | ||
| 841 | * on different channel types. | ||
| 842 | */ | ||
| 843 | orig_ct = local->_oper_channel_type; | ||
| 844 | ieee80211_set_channel_type(local, NULL, NL80211_CHAN_NO_HT); | ||
| 845 | |||
| 846 | /* do after stop to avoid reconfiguring when we stop anyway */ | 912 | /* do after stop to avoid reconfiguring when we stop anyway */ |
| 847 | if (hw_reconf_flags || (orig_ct != local->_oper_channel_type)) | 913 | if (hw_reconf_flags) |
| 848 | ieee80211_hw_config(local, hw_reconf_flags); | 914 | ieee80211_hw_config(local, hw_reconf_flags); |
| 849 | 915 | ||
| 850 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 916 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
| @@ -1121,6 +1187,13 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
| 1121 | } | 1187 | } |
| 1122 | } | 1188 | } |
| 1123 | 1189 | ||
| 1190 | static void ieee80211_recalc_smps_work(struct work_struct *work) | ||
| 1191 | { | ||
| 1192 | struct ieee80211_sub_if_data *sdata = | ||
| 1193 | container_of(work, struct ieee80211_sub_if_data, recalc_smps); | ||
| 1194 | |||
| 1195 | ieee80211_recalc_smps(sdata); | ||
| 1196 | } | ||
| 1124 | 1197 | ||
| 1125 | /* | 1198 | /* |
| 1126 | * Helper function to initialise an interface to a specific type. | 1199 | * Helper function to initialise an interface to a specific type. |
| @@ -1149,6 +1222,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
| 1149 | 1222 | ||
| 1150 | skb_queue_head_init(&sdata->skb_queue); | 1223 | skb_queue_head_init(&sdata->skb_queue); |
| 1151 | INIT_WORK(&sdata->work, ieee80211_iface_work); | 1224 | INIT_WORK(&sdata->work, ieee80211_iface_work); |
| 1225 | INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); | ||
| 1152 | 1226 | ||
| 1153 | switch (type) { | 1227 | switch (type) { |
| 1154 | case NL80211_IFTYPE_P2P_GO: | 1228 | case NL80211_IFTYPE_P2P_GO: |
| @@ -1157,7 +1231,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
| 1157 | sdata->vif.p2p = true; | 1231 | sdata->vif.p2p = true; |
| 1158 | /* fall through */ | 1232 | /* fall through */ |
| 1159 | case NL80211_IFTYPE_AP: | 1233 | case NL80211_IFTYPE_AP: |
| 1160 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); | 1234 | skb_queue_head_init(&sdata->u.ap.ps.bc_buf); |
| 1161 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 1235 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
| 1162 | break; | 1236 | break; |
| 1163 | case NL80211_IFTYPE_P2P_CLIENT: | 1237 | case NL80211_IFTYPE_P2P_CLIENT: |
| @@ -1282,11 +1356,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
| 1282 | if (type == ieee80211_vif_type_p2p(&sdata->vif)) | 1356 | if (type == ieee80211_vif_type_p2p(&sdata->vif)) |
| 1283 | return 0; | 1357 | return 0; |
| 1284 | 1358 | ||
| 1285 | /* Setting ad-hoc mode on non-IBSS channel is not supported. */ | ||
| 1286 | if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS && | ||
| 1287 | type == NL80211_IFTYPE_ADHOC) | ||
| 1288 | return -EOPNOTSUPP; | ||
| 1289 | |||
| 1290 | if (ieee80211_sdata_running(sdata)) { | 1359 | if (ieee80211_sdata_running(sdata)) { |
| 1291 | ret = ieee80211_runtime_change_iftype(sdata, type); | 1360 | ret = ieee80211_runtime_change_iftype(sdata, type); |
| 1292 | if (ret) | 1361 | if (ret) |
| @@ -1298,9 +1367,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
| 1298 | } | 1367 | } |
| 1299 | 1368 | ||
| 1300 | /* reset some values that shouldn't be kept across type changes */ | 1369 | /* reset some values that shouldn't be kept across type changes */ |
| 1301 | sdata->vif.bss_conf.basic_rates = | ||
| 1302 | ieee80211_mandatory_rates(sdata->local, | ||
| 1303 | sdata->local->oper_channel->band); | ||
| 1304 | sdata->drop_unencrypted = 0; | 1370 | sdata->drop_unencrypted = 0; |
| 1305 | if (type == NL80211_IFTYPE_STATION) | 1371 | if (type == NL80211_IFTYPE_STATION) |
| 1306 | sdata->u.mgd.use_4addr = false; | 1372 | sdata->u.mgd.use_4addr = false; |
| @@ -1523,6 +1589,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 1523 | 1589 | ||
| 1524 | ieee80211_set_default_queues(sdata); | 1590 | ieee80211_set_default_queues(sdata); |
| 1525 | 1591 | ||
| 1592 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | ||
| 1593 | sdata->user_power_level = local->user_power_level; | ||
| 1594 | |||
| 1526 | /* setup type-dependent data */ | 1595 | /* setup type-dependent data */ |
| 1527 | ieee80211_setup_sdata(sdata, type); | 1596 | ieee80211_setup_sdata(sdata, type); |
| 1528 | 1597 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d27e61aaa71b..619c5d697999 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
| @@ -339,7 +339,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 339 | key->conf.iv_len = TKIP_IV_LEN; | 339 | key->conf.iv_len = TKIP_IV_LEN; |
| 340 | key->conf.icv_len = TKIP_ICV_LEN; | 340 | key->conf.icv_len = TKIP_ICV_LEN; |
| 341 | if (seq) { | 341 | if (seq) { |
| 342 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { | 342 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 343 | key->u.tkip.rx[i].iv32 = | 343 | key->u.tkip.rx[i].iv32 = |
| 344 | get_unaligned_le32(&seq[2]); | 344 | get_unaligned_le32(&seq[2]); |
| 345 | key->u.tkip.rx[i].iv16 = | 345 | key->u.tkip.rx[i].iv16 = |
| @@ -352,7 +352,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 352 | key->conf.iv_len = CCMP_HDR_LEN; | 352 | key->conf.iv_len = CCMP_HDR_LEN; |
| 353 | key->conf.icv_len = CCMP_MIC_LEN; | 353 | key->conf.icv_len = CCMP_MIC_LEN; |
| 354 | if (seq) { | 354 | if (seq) { |
| 355 | for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) | 355 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) |
| 356 | for (j = 0; j < CCMP_PN_LEN; j++) | 356 | for (j = 0; j < CCMP_PN_LEN; j++) |
| 357 | key->u.ccmp.rx_pn[i][j] = | 357 | key->u.ccmp.rx_pn[i][j] = |
| 358 | seq[CCMP_PN_LEN - j - 1]; | 358 | seq[CCMP_PN_LEN - j - 1]; |
| @@ -372,8 +372,9 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
| 372 | key->conf.iv_len = 0; | 372 | key->conf.iv_len = 0; |
| 373 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | 373 | key->conf.icv_len = sizeof(struct ieee80211_mmie); |
| 374 | if (seq) | 374 | if (seq) |
| 375 | for (j = 0; j < 6; j++) | 375 | for (j = 0; j < CMAC_PN_LEN; j++) |
| 376 | key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; | 376 | key->u.aes_cmac.rx_pn[j] = |
| 377 | seq[CMAC_PN_LEN - j - 1]; | ||
| 377 | /* | 378 | /* |
| 378 | * Initialize AES key state here as an optimization so that | 379 | * Initialize AES key state here as an optimization so that |
| 379 | * it does not need to be initialized for every packet. | 380 | * it does not need to be initialized for every packet. |
| @@ -654,16 +655,16 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
| 654 | 655 | ||
| 655 | switch (key->conf.cipher) { | 656 | switch (key->conf.cipher) { |
| 656 | case WLAN_CIPHER_SUITE_TKIP: | 657 | case WLAN_CIPHER_SUITE_TKIP: |
| 657 | if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES)) | 658 | if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS)) |
| 658 | return; | 659 | return; |
| 659 | seq->tkip.iv32 = key->u.tkip.rx[tid].iv32; | 660 | seq->tkip.iv32 = key->u.tkip.rx[tid].iv32; |
| 660 | seq->tkip.iv16 = key->u.tkip.rx[tid].iv16; | 661 | seq->tkip.iv16 = key->u.tkip.rx[tid].iv16; |
| 661 | break; | 662 | break; |
| 662 | case WLAN_CIPHER_SUITE_CCMP: | 663 | case WLAN_CIPHER_SUITE_CCMP: |
| 663 | if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES)) | 664 | if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS)) |
| 664 | return; | 665 | return; |
| 665 | if (tid < 0) | 666 | if (tid < 0) |
| 666 | pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES]; | 667 | pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS]; |
| 667 | else | 668 | else |
| 668 | pn = key->u.ccmp.rx_pn[tid]; | 669 | pn = key->u.ccmp.rx_pn[tid]; |
| 669 | memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); | 670 | memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 7d4e31f037d7..382dc44ed330 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
| @@ -30,8 +30,6 @@ | |||
| 30 | #define TKIP_ICV_LEN 4 | 30 | #define TKIP_ICV_LEN 4 |
| 31 | #define CMAC_PN_LEN 6 | 31 | #define CMAC_PN_LEN 6 |
| 32 | 32 | ||
| 33 | #define NUM_RX_DATA_QUEUES 16 | ||
| 34 | |||
| 35 | struct ieee80211_local; | 33 | struct ieee80211_local; |
| 36 | struct ieee80211_sub_if_data; | 34 | struct ieee80211_sub_if_data; |
| 37 | struct sta_info; | 35 | struct sta_info; |
| @@ -82,17 +80,20 @@ struct ieee80211_key { | |||
| 82 | struct tkip_ctx tx; | 80 | struct tkip_ctx tx; |
| 83 | 81 | ||
| 84 | /* last received RSC */ | 82 | /* last received RSC */ |
| 85 | struct tkip_ctx rx[NUM_RX_DATA_QUEUES]; | 83 | struct tkip_ctx rx[IEEE80211_NUM_TIDS]; |
| 84 | |||
| 85 | /* number of mic failures */ | ||
| 86 | u32 mic_failures; | ||
| 86 | } tkip; | 87 | } tkip; |
| 87 | struct { | 88 | struct { |
| 88 | atomic64_t tx_pn; | 89 | atomic64_t tx_pn; |
| 89 | /* | 90 | /* |
| 90 | * Last received packet number. The first | 91 | * Last received packet number. The first |
| 91 | * NUM_RX_DATA_QUEUES counters are used with Data | 92 | * IEEE80211_NUM_TIDS counters are used with Data |
| 92 | * frames and the last counter is used with Robust | 93 | * frames and the last counter is used with Robust |
| 93 | * Management frames. | 94 | * Management frames. |
| 94 | */ | 95 | */ |
| 95 | u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN]; | 96 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][CCMP_PN_LEN]; |
| 96 | struct crypto_cipher *tfm; | 97 | struct crypto_cipher *tfm; |
| 97 | u32 replays; /* dot11RSNAStatsCCMPReplays */ | 98 | u32 replays; /* dot11RSNAStatsCCMPReplays */ |
| 98 | } ccmp; | 99 | } ccmp; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f57f597972f8..1b087fff93e7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -93,15 +93,15 @@ static void ieee80211_reconfig_filter(struct work_struct *work) | |||
| 93 | ieee80211_configure_filter(local); | 93 | ieee80211_configure_filter(local); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | 96 | static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) |
| 97 | { | 97 | { |
| 98 | struct ieee80211_sub_if_data *sdata; | ||
| 98 | struct ieee80211_channel *chan; | 99 | struct ieee80211_channel *chan; |
| 99 | int ret = 0; | 100 | u32 changed = 0; |
| 100 | int power; | 101 | int power; |
| 101 | enum nl80211_channel_type channel_type; | 102 | enum nl80211_channel_type channel_type; |
| 102 | u32 offchannel_flag; | 103 | u32 offchannel_flag; |
| 103 | 104 | bool scanning = false; | |
| 104 | might_sleep(); | ||
| 105 | 105 | ||
| 106 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; | 106 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; |
| 107 | if (local->scan_channel) { | 107 | if (local->scan_channel) { |
| @@ -109,19 +109,19 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
| 109 | /* If scanning on oper channel, use whatever channel-type | 109 | /* If scanning on oper channel, use whatever channel-type |
| 110 | * is currently in use. | 110 | * is currently in use. |
| 111 | */ | 111 | */ |
| 112 | if (chan == local->oper_channel) | 112 | if (chan == local->_oper_channel) |
| 113 | channel_type = local->_oper_channel_type; | 113 | channel_type = local->_oper_channel_type; |
| 114 | else | 114 | else |
| 115 | channel_type = NL80211_CHAN_NO_HT; | 115 | channel_type = NL80211_CHAN_NO_HT; |
| 116 | } else if (local->tmp_channel) { | 116 | } else if (local->tmp_channel) { |
| 117 | chan = local->tmp_channel; | 117 | chan = local->tmp_channel; |
| 118 | channel_type = local->tmp_channel_type; | 118 | channel_type = NL80211_CHAN_NO_HT; |
| 119 | } else { | 119 | } else { |
| 120 | chan = local->oper_channel; | 120 | chan = local->_oper_channel; |
| 121 | channel_type = local->_oper_channel_type; | 121 | channel_type = local->_oper_channel_type; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | if (chan != local->oper_channel || | 124 | if (chan != local->_oper_channel || |
| 125 | channel_type != local->_oper_channel_type) | 125 | channel_type != local->_oper_channel_type) |
| 126 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | 126 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; |
| 127 | else | 127 | else |
| @@ -148,22 +148,39 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
| 148 | changed |= IEEE80211_CONF_CHANGE_SMPS; | 148 | changed |= IEEE80211_CONF_CHANGE_SMPS; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | if (test_bit(SCAN_SW_SCANNING, &local->scanning) || | 151 | scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) || |
| 152 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || | 152 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || |
| 153 | test_bit(SCAN_HW_SCANNING, &local->scanning) || | 153 | test_bit(SCAN_HW_SCANNING, &local->scanning); |
| 154 | !local->ap_power_level) | 154 | power = chan->max_power; |
| 155 | power = chan->max_power; | ||
| 156 | else | ||
| 157 | power = min(chan->max_power, local->ap_power_level); | ||
| 158 | 155 | ||
| 159 | if (local->user_power_level >= 0) | 156 | rcu_read_lock(); |
| 160 | power = min(power, local->user_power_level); | 157 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 158 | if (!rcu_access_pointer(sdata->vif.chanctx_conf)) | ||
| 159 | continue; | ||
| 160 | power = min(power, sdata->vif.bss_conf.txpower); | ||
| 161 | } | ||
| 162 | rcu_read_unlock(); | ||
| 161 | 163 | ||
| 162 | if (local->hw.conf.power_level != power) { | 164 | if (local->hw.conf.power_level != power) { |
| 163 | changed |= IEEE80211_CONF_CHANGE_POWER; | 165 | changed |= IEEE80211_CONF_CHANGE_POWER; |
| 164 | local->hw.conf.power_level = power; | 166 | local->hw.conf.power_level = power; |
| 165 | } | 167 | } |
| 166 | 168 | ||
| 169 | return changed; | ||
| 170 | } | ||
| 171 | |||
| 172 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | ||
| 173 | { | ||
| 174 | int ret = 0; | ||
| 175 | |||
| 176 | might_sleep(); | ||
| 177 | |||
| 178 | if (!local->use_chanctx) | ||
| 179 | changed |= ieee80211_hw_conf_chan(local); | ||
| 180 | else | ||
| 181 | changed &= ~(IEEE80211_CONF_CHANGE_CHANNEL | | ||
| 182 | IEEE80211_CONF_CHANGE_POWER); | ||
| 183 | |||
| 167 | if (changed && local->open_count) { | 184 | if (changed && local->open_count) { |
| 168 | ret = drv_config(local, changed); | 185 | ret = drv_config(local, changed); |
| 169 | /* | 186 | /* |
| @@ -359,14 +376,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
| 359 | } | 376 | } |
| 360 | EXPORT_SYMBOL(ieee80211_restart_hw); | 377 | EXPORT_SYMBOL(ieee80211_restart_hw); |
| 361 | 378 | ||
| 362 | static void ieee80211_recalc_smps_work(struct work_struct *work) | ||
| 363 | { | ||
| 364 | struct ieee80211_local *local = | ||
| 365 | container_of(work, struct ieee80211_local, recalc_smps); | ||
| 366 | |||
| 367 | ieee80211_recalc_smps(local); | ||
| 368 | } | ||
| 369 | |||
| 370 | #ifdef CONFIG_INET | 379 | #ifdef CONFIG_INET |
| 371 | static int ieee80211_ifa_changed(struct notifier_block *nb, | 380 | static int ieee80211_ifa_changed(struct notifier_block *nb, |
| 372 | unsigned long data, void *arg) | 381 | unsigned long data, void *arg) |
| @@ -465,7 +474,8 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | |||
| 465 | .tx = 0xffff, | 474 | .tx = 0xffff, |
| 466 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | 475 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | |
| 467 | BIT(IEEE80211_STYPE_AUTH >> 4) | | 476 | BIT(IEEE80211_STYPE_AUTH >> 4) | |
| 468 | BIT(IEEE80211_STYPE_DEAUTH >> 4), | 477 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | |
| 478 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4), | ||
| 469 | }, | 479 | }, |
| 470 | [NL80211_IFTYPE_STATION] = { | 480 | [NL80211_IFTYPE_STATION] = { |
| 471 | .tx = 0xffff, | 481 | .tx = 0xffff, |
| @@ -540,6 +550,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 540 | struct ieee80211_local *local; | 550 | struct ieee80211_local *local; |
| 541 | int priv_size, i; | 551 | int priv_size, i; |
| 542 | struct wiphy *wiphy; | 552 | struct wiphy *wiphy; |
| 553 | bool use_chanctx; | ||
| 543 | 554 | ||
| 544 | if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || | 555 | if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config || |
| 545 | !ops->add_interface || !ops->remove_interface || | 556 | !ops->add_interface || !ops->remove_interface || |
| @@ -549,6 +560,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 549 | if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) | 560 | if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove))) |
| 550 | return NULL; | 561 | return NULL; |
| 551 | 562 | ||
| 563 | /* check all or no channel context operations exist */ | ||
| 564 | i = !!ops->add_chanctx + !!ops->remove_chanctx + | ||
| 565 | !!ops->change_chanctx + !!ops->assign_vif_chanctx + | ||
| 566 | !!ops->unassign_vif_chanctx; | ||
| 567 | if (WARN_ON(i != 0 && i != 5)) | ||
| 568 | return NULL; | ||
| 569 | use_chanctx = i == 5; | ||
| 570 | |||
| 552 | /* Ensure 32-byte alignment of our private data and hw private data. | 571 | /* Ensure 32-byte alignment of our private data and hw private data. |
| 553 | * We use the wiphy priv data for both our ieee80211_local and for | 572 | * We use the wiphy priv data for both our ieee80211_local and for |
| 554 | * the driver's private data | 573 | * the driver's private data |
| @@ -584,8 +603,15 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 584 | if (ops->remain_on_channel) | 603 | if (ops->remain_on_channel) |
| 585 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 604 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
| 586 | 605 | ||
| 587 | wiphy->features = NL80211_FEATURE_SK_TX_STATUS | | 606 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | |
| 588 | NL80211_FEATURE_HT_IBSS; | 607 | NL80211_FEATURE_SAE | |
| 608 | NL80211_FEATURE_HT_IBSS | | ||
| 609 | NL80211_FEATURE_VIF_TXPOWER; | ||
| 610 | |||
| 611 | if (!ops->hw_scan) | ||
| 612 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | | ||
| 613 | NL80211_FEATURE_AP_SCAN; | ||
| 614 | |||
| 589 | 615 | ||
| 590 | if (!ops->set_key) | 616 | if (!ops->set_key) |
| 591 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 617 | wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
| @@ -599,6 +625,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 599 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); | 625 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); |
| 600 | 626 | ||
| 601 | local->ops = ops; | 627 | local->ops = ops; |
| 628 | local->use_chanctx = use_chanctx; | ||
| 602 | 629 | ||
| 603 | /* set up some defaults */ | 630 | /* set up some defaults */ |
| 604 | local->hw.queues = 1; | 631 | local->hw.queues = 1; |
| @@ -612,7 +639,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 612 | local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | | 639 | local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | |
| 613 | IEEE80211_RADIOTAP_MCS_HAVE_GI | | 640 | IEEE80211_RADIOTAP_MCS_HAVE_GI | |
| 614 | IEEE80211_RADIOTAP_MCS_HAVE_BW; | 641 | IEEE80211_RADIOTAP_MCS_HAVE_BW; |
| 615 | local->user_power_level = -1; | 642 | local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | |
| 643 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; | ||
| 644 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; | ||
| 616 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 645 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
| 617 | 646 | ||
| 618 | INIT_LIST_HEAD(&local->interfaces); | 647 | INIT_LIST_HEAD(&local->interfaces); |
| @@ -626,6 +655,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 626 | spin_lock_init(&local->filter_lock); | 655 | spin_lock_init(&local->filter_lock); |
| 627 | spin_lock_init(&local->queue_stop_reason_lock); | 656 | spin_lock_init(&local->queue_stop_reason_lock); |
| 628 | 657 | ||
| 658 | INIT_LIST_HEAD(&local->chanctx_list); | ||
| 659 | mutex_init(&local->chanctx_mtx); | ||
| 660 | |||
| 629 | /* | 661 | /* |
| 630 | * The rx_skb_queue is only accessed from tasklets, | 662 | * The rx_skb_queue is only accessed from tasklets, |
| 631 | * but other SKB queues are used from within IRQ | 663 | * but other SKB queues are used from within IRQ |
| @@ -641,7 +673,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 641 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 673 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
| 642 | 674 | ||
| 643 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | 675 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); |
| 644 | INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); | ||
| 645 | local->smps_mode = IEEE80211_SMPS_OFF; | 676 | local->smps_mode = IEEE80211_SMPS_OFF; |
| 646 | 677 | ||
| 647 | INIT_WORK(&local->dynamic_ps_enable_work, | 678 | INIT_WORK(&local->dynamic_ps_enable_work, |
| @@ -719,6 +750,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 719 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) | 750 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) |
| 720 | return -EINVAL; | 751 | return -EINVAL; |
| 721 | 752 | ||
| 753 | if (!local->use_chanctx) { | ||
| 754 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | ||
| 755 | const struct ieee80211_iface_combination *comb; | ||
| 756 | |||
| 757 | comb = &local->hw.wiphy->iface_combinations[i]; | ||
| 758 | |||
| 759 | if (comb->num_different_channels > 1) | ||
| 760 | return -EINVAL; | ||
| 761 | } | ||
| 762 | } else { | ||
| 763 | /* | ||
| 764 | * WDS is currently prohibited when channel contexts are used | ||
| 765 | * because there's no clear definition of which channel WDS | ||
| 766 | * type interfaces use | ||
| 767 | */ | ||
| 768 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) | ||
| 769 | return -EINVAL; | ||
| 770 | } | ||
| 771 | |||
| 722 | /* Only HW csum features are currently compatible with mac80211 */ | 772 | /* Only HW csum features are currently compatible with mac80211 */ |
| 723 | feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | | 773 | feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | |
| 724 | NETIF_F_HW_CSUM; | 774 | NETIF_F_HW_CSUM; |
| @@ -728,6 +778,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 728 | if (hw->max_report_rates == 0) | 778 | if (hw->max_report_rates == 0) |
| 729 | hw->max_report_rates = hw->max_rates; | 779 | hw->max_report_rates = hw->max_rates; |
| 730 | 780 | ||
| 781 | local->rx_chains = 1; | ||
| 782 | |||
| 731 | /* | 783 | /* |
| 732 | * generic code guarantees at least one band, | 784 | * generic code guarantees at least one band, |
| 733 | * set this very early because much code assumes | 785 | * set this very early because much code assumes |
| @@ -743,18 +795,28 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 743 | sband = local->hw.wiphy->bands[band]; | 795 | sband = local->hw.wiphy->bands[band]; |
| 744 | if (!sband) | 796 | if (!sband) |
| 745 | continue; | 797 | continue; |
| 746 | if (!local->oper_channel) { | 798 | if (!local->use_chanctx && !local->_oper_channel) { |
| 747 | /* init channel we're on */ | 799 | /* init channel we're on */ |
| 748 | local->hw.conf.channel = | 800 | local->hw.conf.channel = |
| 749 | local->oper_channel = &sband->channels[0]; | 801 | local->_oper_channel = &sband->channels[0]; |
| 750 | local->hw.conf.channel_type = NL80211_CHAN_NO_HT; | 802 | local->hw.conf.channel_type = NL80211_CHAN_NO_HT; |
| 751 | } | 803 | } |
| 804 | cfg80211_chandef_create(&local->monitor_chandef, | ||
| 805 | &sband->channels[0], | ||
| 806 | NL80211_CHAN_NO_HT); | ||
| 752 | channels += sband->n_channels; | 807 | channels += sband->n_channels; |
| 753 | 808 | ||
| 754 | if (max_bitrates < sband->n_bitrates) | 809 | if (max_bitrates < sband->n_bitrates) |
| 755 | max_bitrates = sband->n_bitrates; | 810 | max_bitrates = sband->n_bitrates; |
| 756 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | 811 | supp_ht = supp_ht || sband->ht_cap.ht_supported; |
| 757 | supp_vht = supp_vht || sband->vht_cap.vht_supported; | 812 | supp_vht = supp_vht || sband->vht_cap.vht_supported; |
| 813 | |||
| 814 | if (sband->ht_cap.ht_supported) | ||
| 815 | local->rx_chains = | ||
| 816 | max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs), | ||
| 817 | local->rx_chains); | ||
| 818 | |||
| 819 | /* TODO: consider VHT for RX chains, hopefully it's the same */ | ||
| 758 | } | 820 | } |
| 759 | 821 | ||
| 760 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + | 822 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + |
| @@ -778,19 +840,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 778 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 840 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
| 779 | hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); | 841 | hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR); |
| 780 | 842 | ||
| 781 | /* | 843 | /* mac80211 doesn't support more than one IBSS interface right now */ |
| 782 | * mac80211 doesn't support more than 1 channel, and also not more | ||
| 783 | * than one IBSS interface | ||
| 784 | */ | ||
| 785 | for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { | 844 | for (i = 0; i < hw->wiphy->n_iface_combinations; i++) { |
| 786 | const struct ieee80211_iface_combination *c; | 845 | const struct ieee80211_iface_combination *c; |
| 787 | int j; | 846 | int j; |
| 788 | 847 | ||
| 789 | c = &hw->wiphy->iface_combinations[i]; | 848 | c = &hw->wiphy->iface_combinations[i]; |
| 790 | 849 | ||
| 791 | if (c->num_different_channels > 1) | ||
| 792 | return -EINVAL; | ||
| 793 | |||
| 794 | for (j = 0; j < c->n_limits; j++) | 850 | for (j = 0; j < c->n_limits; j++) |
| 795 | if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && | 851 | if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) && |
| 796 | c->limits[j].max > 1) | 852 | c->limits[j].max > 1) |
| @@ -830,9 +886,21 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 830 | if (supp_ht) | 886 | if (supp_ht) |
| 831 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); | 887 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); |
| 832 | 888 | ||
| 833 | if (supp_vht) | 889 | if (supp_vht) { |
| 834 | local->scan_ies_len += | 890 | local->scan_ies_len += |
| 835 | 2 + sizeof(struct ieee80211_vht_capabilities); | 891 | 2 + sizeof(struct ieee80211_vht_cap); |
| 892 | |||
| 893 | /* | ||
| 894 | * (for now at least), drivers wanting to use VHT must | ||
| 895 | * support channel contexts, as they contain all the | ||
| 896 | * necessary VHT information and the global hw config | ||
| 897 | * doesn't (yet) | ||
| 898 | */ | ||
| 899 | if (WARN_ON(!local->use_chanctx)) { | ||
| 900 | result = -EINVAL; | ||
| 901 | goto fail_wiphy_register; | ||
| 902 | } | ||
| 903 | } | ||
| 836 | 904 | ||
| 837 | if (!local->ops->hw_scan) { | 905 | if (!local->ops->hw_scan) { |
| 838 | /* For hw_scan, driver needs to set these up. */ | 906 | /* For hw_scan, driver needs to set these up. */ |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index ff0296c7bab8..1bf03f9ff3ba 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -76,7 +76,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
| 76 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 76 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 77 | struct ieee80211_local *local = sdata->local; | 77 | struct ieee80211_local *local = sdata->local; |
| 78 | u32 basic_rates = 0; | 78 | u32 basic_rates = 0; |
| 79 | enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT; | 79 | struct cfg80211_chan_def sta_chan_def; |
| 80 | 80 | ||
| 81 | /* | 81 | /* |
| 82 | * As support for each feature is added, check for matching | 82 | * As support for each feature is added, check for matching |
| @@ -97,23 +97,17 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
| 97 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) | 97 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) |
| 98 | goto mismatch; | 98 | goto mismatch; |
| 99 | 99 | ||
| 100 | ieee80211_sta_get_rates(local, ie, local->oper_channel->band, | 100 | ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata), |
| 101 | &basic_rates); | 101 | &basic_rates); |
| 102 | 102 | ||
| 103 | if (sdata->vif.bss_conf.basic_rates != basic_rates) | 103 | if (sdata->vif.bss_conf.basic_rates != basic_rates) |
| 104 | goto mismatch; | 104 | goto mismatch; |
| 105 | 105 | ||
| 106 | if (ie->ht_operation) | 106 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
| 107 | sta_channel_type = | 107 | ie->ht_operation, &sta_chan_def); |
| 108 | ieee80211_ht_oper_to_channel_type(ie->ht_operation); | 108 | |
| 109 | 109 | if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, | |
| 110 | /* Disallow HT40+/- mismatch */ | 110 | &sta_chan_def)) |
| 111 | if (ie->ht_operation && | ||
| 112 | (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS || | ||
| 113 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) && | ||
| 114 | (sta_channel_type == NL80211_CHAN_HT40MINUS || | ||
| 115 | sta_channel_type == NL80211_CHAN_HT40PLUS) && | ||
| 116 | sdata->vif.bss_conf.channel_type != sta_channel_type) | ||
| 117 | goto mismatch; | 111 | goto mismatch; |
| 118 | 112 | ||
| 119 | return true; | 113 | return true; |
| @@ -129,7 +123,7 @@ mismatch: | |||
| 129 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) | 123 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
| 130 | { | 124 | { |
| 131 | return (ie->mesh_config->meshconf_cap & | 125 | return (ie->mesh_config->meshconf_cap & |
| 132 | MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; | 126 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; |
| 133 | } | 127 | } |
| 134 | 128 | ||
| 135 | /** | 129 | /** |
| @@ -264,16 +258,16 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
| 264 | /* Authentication Protocol identifier */ | 258 | /* Authentication Protocol identifier */ |
| 265 | *pos++ = ifmsh->mesh_auth_id; | 259 | *pos++ = ifmsh->mesh_auth_id; |
| 266 | /* Mesh Formation Info - number of neighbors */ | 260 | /* Mesh Formation Info - number of neighbors */ |
| 267 | neighbors = atomic_read(&ifmsh->mshstats.estab_plinks); | 261 | neighbors = atomic_read(&ifmsh->estab_plinks); |
| 268 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ | 262 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ |
| 269 | neighbors = (neighbors > 15) ? 15 : neighbors; | 263 | neighbors = (neighbors > 15) ? 15 : neighbors; |
| 270 | *pos++ = neighbors << 1; | 264 | *pos++ = neighbors << 1; |
| 271 | /* Mesh capability */ | 265 | /* Mesh capability */ |
| 272 | *pos = MESHCONF_CAPAB_FORWARDING; | 266 | *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; |
| 273 | *pos |= ifmsh->accepting_plinks ? | 267 | *pos |= ifmsh->accepting_plinks ? |
| 274 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 268 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
| 275 | *pos++ |= ifmsh->adjusting_tbtt ? | 269 | *pos++ |= ifmsh->adjusting_tbtt ? |
| 276 | MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; | 270 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; |
| 277 | *pos++ = 0x00; | 271 | *pos++ = 0x00; |
| 278 | 272 | ||
| 279 | return 0; | 273 | return 0; |
| @@ -355,12 +349,22 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, | |||
| 355 | { | 349 | { |
| 356 | struct ieee80211_local *local = sdata->local; | 350 | struct ieee80211_local *local = sdata->local; |
| 357 | struct ieee80211_supported_band *sband; | 351 | struct ieee80211_supported_band *sband; |
| 358 | struct ieee80211_channel *chan = local->oper_channel; | 352 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 353 | struct ieee80211_channel *chan; | ||
| 359 | u8 *pos; | 354 | u8 *pos; |
| 360 | 355 | ||
| 361 | if (skb_tailroom(skb) < 3) | 356 | if (skb_tailroom(skb) < 3) |
| 362 | return -ENOMEM; | 357 | return -ENOMEM; |
| 363 | 358 | ||
| 359 | rcu_read_lock(); | ||
| 360 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 361 | if (WARN_ON(!chanctx_conf)) { | ||
| 362 | rcu_read_unlock(); | ||
| 363 | return -EINVAL; | ||
| 364 | } | ||
| 365 | chan = chanctx_conf->def.chan; | ||
| 366 | rcu_read_unlock(); | ||
| 367 | |||
| 364 | sband = local->hw.wiphy->bands[chan->band]; | 368 | sband = local->hw.wiphy->bands[chan->band]; |
| 365 | if (sband->band == IEEE80211_BAND_2GHZ) { | 369 | if (sband->band == IEEE80211_BAND_2GHZ) { |
| 366 | pos = skb_put(skb, 2 + 1); | 370 | pos = skb_put(skb, 2 + 1); |
| @@ -376,12 +380,13 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, | |||
| 376 | struct ieee80211_sub_if_data *sdata) | 380 | struct ieee80211_sub_if_data *sdata) |
| 377 | { | 381 | { |
| 378 | struct ieee80211_local *local = sdata->local; | 382 | struct ieee80211_local *local = sdata->local; |
| 383 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
| 379 | struct ieee80211_supported_band *sband; | 384 | struct ieee80211_supported_band *sband; |
| 380 | u8 *pos; | 385 | u8 *pos; |
| 381 | 386 | ||
| 382 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 387 | sband = local->hw.wiphy->bands[band]; |
| 383 | if (!sband->ht_cap.ht_supported || | 388 | if (!sband->ht_cap.ht_supported || |
| 384 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) | 389 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 385 | return 0; | 390 | return 0; |
| 386 | 391 | ||
| 387 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) | 392 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) |
| @@ -397,14 +402,26 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, | |||
| 397 | struct ieee80211_sub_if_data *sdata) | 402 | struct ieee80211_sub_if_data *sdata) |
| 398 | { | 403 | { |
| 399 | struct ieee80211_local *local = sdata->local; | 404 | struct ieee80211_local *local = sdata->local; |
| 400 | struct ieee80211_channel *channel = local->oper_channel; | 405 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 406 | struct ieee80211_channel *channel; | ||
| 401 | enum nl80211_channel_type channel_type = | 407 | enum nl80211_channel_type channel_type = |
| 402 | sdata->vif.bss_conf.channel_type; | 408 | cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef); |
| 403 | struct ieee80211_supported_band *sband = | 409 | struct ieee80211_supported_band *sband; |
| 404 | local->hw.wiphy->bands[channel->band]; | 410 | struct ieee80211_sta_ht_cap *ht_cap; |
| 405 | struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; | ||
| 406 | u8 *pos; | 411 | u8 *pos; |
| 407 | 412 | ||
| 413 | rcu_read_lock(); | ||
| 414 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 415 | if (WARN_ON(!chanctx_conf)) { | ||
| 416 | rcu_read_unlock(); | ||
| 417 | return -EINVAL; | ||
| 418 | } | ||
| 419 | channel = chanctx_conf->def.chan; | ||
| 420 | rcu_read_unlock(); | ||
| 421 | |||
| 422 | sband = local->hw.wiphy->bands[channel->band]; | ||
| 423 | ht_cap = &sband->ht_cap; | ||
| 424 | |||
| 408 | if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) | 425 | if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) |
| 409 | return 0; | 426 | return 0; |
| 410 | 427 | ||
| @@ -412,7 +429,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, | |||
| 412 | return -ENOMEM; | 429 | return -ENOMEM; |
| 413 | 430 | ||
| 414 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); | 431 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); |
| 415 | ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type, | 432 | ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef, |
| 416 | sdata->vif.bss_conf.ht_operation_mode); | 433 | sdata->vif.bss_conf.ht_operation_mode); |
| 417 | 434 | ||
| 418 | return 0; | 435 | return 0; |
| @@ -610,7 +627,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
| 610 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | 627 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; |
| 611 | sdata->vif.bss_conf.basic_rates = | 628 | sdata->vif.bss_conf.basic_rates = |
| 612 | ieee80211_mandatory_rates(sdata->local, | 629 | ieee80211_mandatory_rates(sdata->local, |
| 613 | sdata->local->oper_channel->band); | 630 | ieee80211_get_sdata_band(sdata)); |
| 614 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 631 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
| 615 | BSS_CHANGED_BEACON_ENABLED | | 632 | BSS_CHANGED_BEACON_ENABLED | |
| 616 | BSS_CHANGED_HT | | 633 | BSS_CHANGED_HT | |
| @@ -680,8 +697,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 680 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 697 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
| 681 | &elems); | 698 | &elems); |
| 682 | 699 | ||
| 683 | /* ignore beacons from secure mesh peers if our security is off */ | 700 | /* ignore non-mesh or secure / unsecure mismatch */ |
| 684 | if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) | 701 | if ((!elems.mesh_id || !elems.mesh_config) || |
| 702 | (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || | ||
| 703 | (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) | ||
| 685 | return; | 704 | return; |
| 686 | 705 | ||
| 687 | if (elems.ds_params && elems.ds_params_len == 1) | 706 | if (elems.ds_params && elems.ds_params_len == 1) |
| @@ -694,8 +713,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 694 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 713 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
| 695 | return; | 714 | return; |
| 696 | 715 | ||
| 697 | if (elems.mesh_id && elems.mesh_config && | 716 | if (mesh_matches_local(sdata, &elems)) |
| 698 | mesh_matches_local(sdata, &elems)) | ||
| 699 | mesh_neighbour_update(sdata, mgmt->sa, &elems); | 717 | mesh_neighbour_update(sdata, mgmt->sa, &elems); |
| 700 | 718 | ||
| 701 | if (ifmsh->sync_ops) | 719 | if (ifmsh->sync_ops) |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 25d0f17dec71..7c9215fb2ac8 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
| @@ -19,20 +19,6 @@ | |||
| 19 | /* Data structures */ | 19 | /* Data structures */ |
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | * enum mesh_config_capab_flags - mesh config IE capability flags | ||
| 23 | * | ||
| 24 | * @MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish | ||
| 25 | * additional mesh peerings with other mesh STAs | ||
| 26 | * @MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs | ||
| 27 | * @MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure is ongoing | ||
| 28 | */ | ||
| 29 | enum mesh_config_capab_flags { | ||
| 30 | MESHCONF_CAPAB_ACCEPT_PLINKS = BIT(0), | ||
| 31 | MESHCONF_CAPAB_FORWARDING = BIT(3), | ||
| 32 | MESHCONF_CAPAB_TBTT_ADJUSTING = BIT(5), | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * enum mesh_path_flags - mac80211 mesh path flags | 22 | * enum mesh_path_flags - mac80211 mesh path flags |
| 37 | * | 23 | * |
| 38 | * | 24 | * |
| @@ -256,7 +242,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | |||
| 256 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 242 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
| 257 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 243 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
| 258 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); | 244 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); |
| 259 | struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); | 245 | const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); |
| 260 | 246 | ||
| 261 | /* Mesh paths */ | 247 | /* Mesh paths */ |
| 262 | int mesh_nexthop_lookup(struct sk_buff *skb, | 248 | int mesh_nexthop_lookup(struct sk_buff *skb, |
| @@ -324,7 +310,7 @@ extern int mesh_allocated; | |||
| 324 | static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) | 310 | static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) |
| 325 | { | 311 | { |
| 326 | return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks - | 312 | return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks - |
| 327 | atomic_read(&sdata->u.mesh.mshstats.estab_plinks); | 313 | atomic_read(&sdata->u.mesh.estab_plinks); |
| 328 | } | 314 | } |
| 329 | 315 | ||
| 330 | static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) | 316 | static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 3ab34d816897..4b274e9c91a5 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
| @@ -19,12 +19,6 @@ | |||
| 19 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | 19 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ |
| 20 | jiffies + HZ * t / 1000)) | 20 | jiffies + HZ * t / 1000)) |
| 21 | 21 | ||
| 22 | #define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries) | ||
| 23 | #define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout) | ||
| 24 | #define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout) | ||
| 25 | #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout) | ||
| 26 | #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks) | ||
| 27 | |||
| 28 | /* We only need a valid sta if user configured a minimum rssi_threshold. */ | 22 | /* We only need a valid sta if user configured a minimum rssi_threshold. */ |
| 29 | #define rssi_threshold_check(sta, sdata) \ | 23 | #define rssi_threshold_check(sta, sdata) \ |
| 30 | (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ | 24 | (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\ |
| @@ -50,14 +44,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 50 | static inline | 44 | static inline |
| 51 | u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | 45 | u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) |
| 52 | { | 46 | { |
| 53 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); | 47 | atomic_inc(&sdata->u.mesh.estab_plinks); |
| 54 | return mesh_accept_plinks_update(sdata); | 48 | return mesh_accept_plinks_update(sdata); |
| 55 | } | 49 | } |
| 56 | 50 | ||
| 57 | static inline | 51 | static inline |
| 58 | u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | 52 | u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) |
| 59 | { | 53 | { |
| 60 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); | 54 | atomic_dec(&sdata->u.mesh.estab_plinks); |
| 61 | return mesh_accept_plinks_update(sdata); | 55 | return mesh_accept_plinks_update(sdata); |
| 62 | } | 56 | } |
| 63 | 57 | ||
| @@ -117,7 +111,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) | |||
| 117 | u16 ht_opmode; | 111 | u16 ht_opmode; |
| 118 | bool non_ht_sta = false, ht20_sta = false; | 112 | bool non_ht_sta = false, ht20_sta = false; |
| 119 | 113 | ||
| 120 | if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) | 114 | if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 121 | return 0; | 115 | return 0; |
| 122 | 116 | ||
| 123 | rcu_read_lock(); | 117 | rcu_read_lock(); |
| @@ -126,14 +120,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) | |||
| 126 | sta->plink_state != NL80211_PLINK_ESTAB) | 120 | sta->plink_state != NL80211_PLINK_ESTAB) |
| 127 | continue; | 121 | continue; |
| 128 | 122 | ||
| 129 | switch (sta->ch_type) { | 123 | switch (sta->ch_width) { |
| 130 | case NL80211_CHAN_NO_HT: | 124 | case NL80211_CHAN_WIDTH_20_NOHT: |
| 131 | mpl_dbg(sdata, | 125 | mpl_dbg(sdata, |
| 132 | "mesh_plink %pM: nonHT sta (%pM) is present\n", | 126 | "mesh_plink %pM: nonHT sta (%pM) is present\n", |
| 133 | sdata->vif.addr, sta->sta.addr); | 127 | sdata->vif.addr, sta->sta.addr); |
| 134 | non_ht_sta = true; | 128 | non_ht_sta = true; |
| 135 | goto out; | 129 | goto out; |
| 136 | case NL80211_CHAN_HT20: | 130 | case NL80211_CHAN_WIDTH_20: |
| 137 | mpl_dbg(sdata, | 131 | mpl_dbg(sdata, |
| 138 | "mesh_plink %pM: HT20 sta (%pM) is present\n", | 132 | "mesh_plink %pM: HT20 sta (%pM) is present\n", |
| 139 | sdata->vif.addr, sta->sta.addr); | 133 | sdata->vif.addr, sta->sta.addr); |
| @@ -148,7 +142,7 @@ out: | |||
| 148 | if (non_ht_sta) | 142 | if (non_ht_sta) |
| 149 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; | 143 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; |
| 150 | else if (ht20_sta && | 144 | else if (ht20_sta && |
| 151 | sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20) | 145 | sdata->vif.bss_conf.chandef.width > NL80211_CHAN_WIDTH_20) |
| 152 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; | 146 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; |
| 153 | else | 147 | else |
| 154 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; | 148 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; |
| @@ -252,6 +246,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 252 | mgmt->u.action.u.self_prot.action_code = action; | 246 | mgmt->u.action.u.self_prot.action_code = action; |
| 253 | 247 | ||
| 254 | if (action != WLAN_SP_MESH_PEERING_CLOSE) { | 248 | if (action != WLAN_SP_MESH_PEERING_CLOSE) { |
| 249 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
| 250 | |||
| 255 | /* capability info */ | 251 | /* capability info */ |
| 256 | pos = skb_put(skb, 2); | 252 | pos = skb_put(skb, 2); |
| 257 | memset(pos, 0, 2); | 253 | memset(pos, 0, 2); |
| @@ -260,10 +256,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 260 | pos = skb_put(skb, 2); | 256 | pos = skb_put(skb, 2); |
| 261 | memcpy(pos + 2, &plid, 2); | 257 | memcpy(pos + 2, &plid, 2); |
| 262 | } | 258 | } |
| 263 | if (ieee80211_add_srates_ie(sdata, skb, true, | 259 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || |
| 264 | local->oper_channel->band) || | 260 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || |
| 265 | ieee80211_add_ext_srates_ie(sdata, skb, true, | ||
| 266 | local->oper_channel->band) || | ||
| 267 | mesh_add_rsn_ie(skb, sdata) || | 261 | mesh_add_rsn_ie(skb, sdata) || |
| 268 | mesh_add_meshid_ie(skb, sdata) || | 262 | mesh_add_meshid_ie(skb, sdata) || |
| 269 | mesh_add_meshconf_ie(skb, sdata)) | 263 | mesh_add_meshconf_ie(skb, sdata)) |
| @@ -343,7 +337,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | |||
| 343 | struct ieee802_11_elems *elems) | 337 | struct ieee802_11_elems *elems) |
| 344 | { | 338 | { |
| 345 | struct ieee80211_local *local = sdata->local; | 339 | struct ieee80211_local *local = sdata->local; |
| 346 | enum ieee80211_band band = local->oper_channel->band; | 340 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
| 347 | struct ieee80211_supported_band *sband; | 341 | struct ieee80211_supported_band *sband; |
| 348 | u32 rates, basic_rates = 0; | 342 | u32 rates, basic_rates = 0; |
| 349 | struct sta_info *sta; | 343 | struct sta_info *sta; |
| @@ -378,7 +372,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | |||
| 378 | 372 | ||
| 379 | sta->sta.supp_rates[band] = rates; | 373 | sta->sta.supp_rates[band] = rates; |
| 380 | if (elems->ht_cap_elem && | 374 | if (elems->ht_cap_elem && |
| 381 | sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT) | 375 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) |
| 382 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 376 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 383 | elems->ht_cap_elem, | 377 | elems->ht_cap_elem, |
| 384 | &sta->sta.ht_cap); | 378 | &sta->sta.ht_cap); |
| @@ -386,15 +380,19 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | |||
| 386 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); | 380 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); |
| 387 | 381 | ||
| 388 | if (elems->ht_operation) { | 382 | if (elems->ht_operation) { |
| 383 | struct cfg80211_chan_def chandef; | ||
| 384 | |||
| 389 | if (!(elems->ht_operation->ht_param & | 385 | if (!(elems->ht_operation->ht_param & |
| 390 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | 386 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) |
| 391 | sta->sta.ht_cap.cap &= | 387 | sta->sta.ht_cap.cap &= |
| 392 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 388 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
| 393 | sta->ch_type = | 389 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
| 394 | ieee80211_ht_oper_to_channel_type(elems->ht_operation); | 390 | elems->ht_operation, &chandef); |
| 391 | sta->ch_width = chandef.width; | ||
| 395 | } | 392 | } |
| 396 | 393 | ||
| 397 | rate_control_rate_init(sta); | 394 | if (insert) |
| 395 | rate_control_rate_init(sta); | ||
| 398 | spin_unlock_bh(&sta->lock); | 396 | spin_unlock_bh(&sta->lock); |
| 399 | 397 | ||
| 400 | if (insert && sta_info_insert(sta)) | 398 | if (insert && sta_info_insert(sta)) |
| @@ -430,6 +428,7 @@ static void mesh_plink_timer(unsigned long data) | |||
| 430 | struct sta_info *sta; | 428 | struct sta_info *sta; |
| 431 | __le16 llid, plid, reason; | 429 | __le16 llid, plid, reason; |
| 432 | struct ieee80211_sub_if_data *sdata; | 430 | struct ieee80211_sub_if_data *sdata; |
| 431 | struct mesh_config *mshcfg; | ||
| 433 | 432 | ||
| 434 | /* | 433 | /* |
| 435 | * This STA is valid because sta_info_destroy() will | 434 | * This STA is valid because sta_info_destroy() will |
| @@ -456,12 +455,13 @@ static void mesh_plink_timer(unsigned long data) | |||
| 456 | llid = sta->llid; | 455 | llid = sta->llid; |
| 457 | plid = sta->plid; | 456 | plid = sta->plid; |
| 458 | sdata = sta->sdata; | 457 | sdata = sta->sdata; |
| 458 | mshcfg = &sdata->u.mesh.mshcfg; | ||
| 459 | 459 | ||
| 460 | switch (sta->plink_state) { | 460 | switch (sta->plink_state) { |
| 461 | case NL80211_PLINK_OPN_RCVD: | 461 | case NL80211_PLINK_OPN_RCVD: |
| 462 | case NL80211_PLINK_OPN_SNT: | 462 | case NL80211_PLINK_OPN_SNT: |
| 463 | /* retry timer */ | 463 | /* retry timer */ |
| 464 | if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { | 464 | if (sta->plink_retries < mshcfg->dot11MeshMaxRetries) { |
| 465 | u32 rand; | 465 | u32 rand; |
| 466 | mpl_dbg(sta->sdata, | 466 | mpl_dbg(sta->sdata, |
| 467 | "Mesh plink for %pM (retry, timeout): %d %d\n", | 467 | "Mesh plink for %pM (retry, timeout): %d %d\n", |
| @@ -484,7 +484,7 @@ static void mesh_plink_timer(unsigned long data) | |||
| 484 | if (!reason) | 484 | if (!reason) |
| 485 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); | 485 | reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT); |
| 486 | sta->plink_state = NL80211_PLINK_HOLDING; | 486 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 487 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 487 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
| 488 | spin_unlock_bh(&sta->lock); | 488 | spin_unlock_bh(&sta->lock); |
| 489 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 489 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, |
| 490 | sta->sta.addr, llid, plid, reason); | 490 | sta->sta.addr, llid, plid, reason); |
| @@ -543,7 +543,7 @@ int mesh_plink_open(struct sta_info *sta) | |||
| 543 | return -EBUSY; | 543 | return -EBUSY; |
| 544 | } | 544 | } |
| 545 | sta->plink_state = NL80211_PLINK_OPN_SNT; | 545 | sta->plink_state = NL80211_PLINK_OPN_SNT; |
| 546 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | 546 | mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); |
| 547 | spin_unlock_bh(&sta->lock); | 547 | spin_unlock_bh(&sta->lock); |
| 548 | mpl_dbg(sdata, | 548 | mpl_dbg(sdata, |
| 549 | "Mesh plink: starting establishment with %pM\n", | 549 | "Mesh plink: starting establishment with %pM\n", |
| @@ -570,6 +570,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
| 570 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, | 570 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, |
| 571 | size_t len, struct ieee80211_rx_status *rx_status) | 571 | size_t len, struct ieee80211_rx_status *rx_status) |
| 572 | { | 572 | { |
| 573 | struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; | ||
| 573 | struct ieee802_11_elems elems; | 574 | struct ieee802_11_elems elems; |
| 574 | struct sta_info *sta; | 575 | struct sta_info *sta; |
| 575 | enum plink_event event; | 576 | enum plink_event event; |
| @@ -777,7 +778,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 777 | sta->plid = plid; | 778 | sta->plid = plid; |
| 778 | get_random_bytes(&llid, 2); | 779 | get_random_bytes(&llid, 2); |
| 779 | sta->llid = llid; | 780 | sta->llid = llid; |
| 780 | mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); | 781 | mesh_plink_timer_set(sta, |
| 782 | mshcfg->dot11MeshRetryTimeout); | ||
| 781 | spin_unlock_bh(&sta->lock); | 783 | spin_unlock_bh(&sta->lock); |
| 782 | mesh_plink_frame_tx(sdata, | 784 | mesh_plink_frame_tx(sdata, |
| 783 | WLAN_SP_MESH_PEERING_OPEN, | 785 | WLAN_SP_MESH_PEERING_OPEN, |
| @@ -803,7 +805,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 803 | sta->reason = reason; | 805 | sta->reason = reason; |
| 804 | sta->plink_state = NL80211_PLINK_HOLDING; | 806 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 805 | if (!mod_plink_timer(sta, | 807 | if (!mod_plink_timer(sta, |
| 806 | dot11MeshHoldingTimeout(sdata))) | 808 | mshcfg->dot11MeshHoldingTimeout)) |
| 807 | sta->ignore_plink_timer = true; | 809 | sta->ignore_plink_timer = true; |
| 808 | 810 | ||
| 809 | llid = sta->llid; | 811 | llid = sta->llid; |
| @@ -825,7 +827,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 825 | case CNF_ACPT: | 827 | case CNF_ACPT: |
| 826 | sta->plink_state = NL80211_PLINK_CNF_RCVD; | 828 | sta->plink_state = NL80211_PLINK_CNF_RCVD; |
| 827 | if (!mod_plink_timer(sta, | 829 | if (!mod_plink_timer(sta, |
| 828 | dot11MeshConfirmTimeout(sdata))) | 830 | mshcfg->dot11MeshConfirmTimeout)) |
| 829 | sta->ignore_plink_timer = true; | 831 | sta->ignore_plink_timer = true; |
| 830 | 832 | ||
| 831 | spin_unlock_bh(&sta->lock); | 833 | spin_unlock_bh(&sta->lock); |
| @@ -847,7 +849,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 847 | sta->reason = reason; | 849 | sta->reason = reason; |
| 848 | sta->plink_state = NL80211_PLINK_HOLDING; | 850 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 849 | if (!mod_plink_timer(sta, | 851 | if (!mod_plink_timer(sta, |
| 850 | dot11MeshHoldingTimeout(sdata))) | 852 | mshcfg->dot11MeshHoldingTimeout)) |
| 851 | sta->ignore_plink_timer = true; | 853 | sta->ignore_plink_timer = true; |
| 852 | 854 | ||
| 853 | llid = sta->llid; | 855 | llid = sta->llid; |
| @@ -888,7 +890,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 888 | sta->reason = reason; | 890 | sta->reason = reason; |
| 889 | sta->plink_state = NL80211_PLINK_HOLDING; | 891 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 890 | if (!mod_plink_timer(sta, | 892 | if (!mod_plink_timer(sta, |
| 891 | dot11MeshHoldingTimeout(sdata))) | 893 | mshcfg->dot11MeshHoldingTimeout)) |
| 892 | sta->ignore_plink_timer = true; | 894 | sta->ignore_plink_timer = true; |
| 893 | 895 | ||
| 894 | llid = sta->llid; | 896 | llid = sta->llid; |
| @@ -923,7 +925,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 923 | changed |= __mesh_plink_deactivate(sta); | 925 | changed |= __mesh_plink_deactivate(sta); |
| 924 | sta->plink_state = NL80211_PLINK_HOLDING; | 926 | sta->plink_state = NL80211_PLINK_HOLDING; |
| 925 | llid = sta->llid; | 927 | llid = sta->llid; |
| 926 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 928 | mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
| 927 | spin_unlock_bh(&sta->lock); | 929 | spin_unlock_bh(&sta->lock); |
| 928 | changed |= mesh_set_ht_prot_mode(sdata); | 930 | changed |= mesh_set_ht_prot_mode(sdata); |
| 929 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 931 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, |
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index a16b7b4b1e02..aa8d1e437385 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c | |||
| @@ -43,7 +43,7 @@ struct sync_method { | |||
| 43 | static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) | 43 | static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) |
| 44 | { | 44 | { |
| 45 | return (ie->mesh_config->meshconf_cap & | 45 | return (ie->mesh_config->meshconf_cap & |
| 46 | MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; | 46 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | 49 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) |
| @@ -116,43 +116,13 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 116 | goto no_sync; | 116 | goto no_sync; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) { | 119 | if (ieee80211_have_rx_timestamp(rx_status)) |
| 120 | /* | 120 | /* time when timestamp field was received */ |
| 121 | * The mactime is defined as the time the first data symbol | 121 | t_r = ieee80211_calculate_rx_timestamp(local, rx_status, |
| 122 | * of the frame hits the PHY, and the timestamp of the beacon | 122 | 24 + 12 + |
| 123 | * is defined as "the time that the data symbol containing the | 123 | elems->total_len + |
| 124 | * first bit of the timestamp is transmitted to the PHY plus | 124 | FCS_LEN, |
| 125 | * the transmitting STA's delays through its local PHY from the | 125 | 24); |
| 126 | * MAC-PHY interface to its interface with the WM" (802.11 | ||
| 127 | * 11.1.2) | ||
| 128 | * | ||
| 129 | * T_r, in 13.13.2.2.2, is just defined as "the frame reception | ||
| 130 | * time" but we unless we interpret that time to be the same | ||
| 131 | * time of the beacon timestamp, the offset calculation will be | ||
| 132 | * off. Below we adjust t_r to be "the time at which the first | ||
| 133 | * symbol of the timestamp element in the beacon is received". | ||
| 134 | * This correction depends on the rate. | ||
| 135 | * | ||
| 136 | * Based on similar code in ibss.c | ||
| 137 | */ | ||
| 138 | int rate; | ||
| 139 | |||
| 140 | if (rx_status->flag & RX_FLAG_HT) { | ||
| 141 | /* TODO: | ||
| 142 | * In principle there could be HT-beacons (Dual Beacon | ||
| 143 | * HT Operation options), but for now ignore them and | ||
| 144 | * just use the primary (i.e. non-HT) beacons for | ||
| 145 | * synchronization. | ||
| 146 | * */ | ||
| 147 | goto no_sync; | ||
| 148 | } else | ||
| 149 | rate = local->hw.wiphy->bands[rx_status->band]-> | ||
| 150 | bitrates[rx_status->rate_idx].bitrate; | ||
| 151 | |||
| 152 | /* 24 bytes of header * 8 bits/byte * | ||
| 153 | * 10*(100 Kbps)/Mbps / rate (100 Kbps)*/ | ||
| 154 | t_r = rx_status->mactime + (24 * 8 * 10 / rate); | ||
| 155 | } | ||
| 156 | 126 | ||
| 157 | /* Timing offset calculation (see 13.13.2.2.2) */ | 127 | /* Timing offset calculation (see 13.13.2.2.2) */ |
| 158 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); | 128 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); |
| @@ -225,58 +195,20 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | |||
| 225 | ifmsh->sync_offset_clockdrift_max); | 195 | ifmsh->sync_offset_clockdrift_max); |
| 226 | set_bit(MESH_WORK_DRIFT_ADJUST, | 196 | set_bit(MESH_WORK_DRIFT_ADJUST, |
| 227 | &ifmsh->wrkq_flags); | 197 | &ifmsh->wrkq_flags); |
| 198 | |||
| 199 | ifmsh->adjusting_tbtt = true; | ||
| 228 | } else { | 200 | } else { |
| 229 | msync_dbg(sdata, | 201 | msync_dbg(sdata, |
| 230 | "TBTT : max clockdrift=%lld; too small to adjust\n", | 202 | "TBTT : max clockdrift=%lld; too small to adjust\n", |
| 231 | (long long)ifmsh->sync_offset_clockdrift_max); | 203 | (long long)ifmsh->sync_offset_clockdrift_max); |
| 232 | ifmsh->sync_offset_clockdrift_max = 0; | 204 | ifmsh->sync_offset_clockdrift_max = 0; |
| 205 | |||
| 206 | ifmsh->adjusting_tbtt = false; | ||
| 233 | } | 207 | } |
| 234 | spin_unlock_bh(&ifmsh->sync_offset_lock); | 208 | spin_unlock_bh(&ifmsh->sync_offset_lock); |
| 235 | } | 209 | } |
| 236 | 210 | ||
| 237 | static const u8 *mesh_get_vendor_oui(struct ieee80211_sub_if_data *sdata) | 211 | static const struct sync_method sync_methods[] = { |
| 238 | { | ||
| 239 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
| 240 | u8 offset; | ||
| 241 | |||
| 242 | if (!ifmsh->ie || !ifmsh->ie_len) | ||
| 243 | return NULL; | ||
| 244 | |||
| 245 | offset = ieee80211_ie_split_vendor(ifmsh->ie, | ||
| 246 | ifmsh->ie_len, 0); | ||
| 247 | |||
| 248 | if (!offset) | ||
| 249 | return NULL; | ||
| 250 | |||
| 251 | return ifmsh->ie + offset + 2; | ||
| 252 | } | ||
| 253 | |||
| 254 | static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | ||
| 255 | u16 stype, | ||
| 256 | struct ieee80211_mgmt *mgmt, | ||
| 257 | struct ieee802_11_elems *elems, | ||
| 258 | struct ieee80211_rx_status *rx_status) | ||
| 259 | { | ||
| 260 | const u8 *oui; | ||
| 261 | |||
| 262 | WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); | ||
| 263 | msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n"); | ||
| 264 | oui = mesh_get_vendor_oui(sdata); | ||
| 265 | /* here you would implement the vendor offset tracking for this oui */ | ||
| 266 | } | ||
| 267 | |||
| 268 | static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | ||
| 269 | { | ||
| 270 | const u8 *oui; | ||
| 271 | |||
| 272 | WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); | ||
| 273 | msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n"); | ||
| 274 | oui = mesh_get_vendor_oui(sdata); | ||
| 275 | /* here you would implement the vendor tsf adjustment for this oui */ | ||
| 276 | } | ||
| 277 | |||
| 278 | /* global variable */ | ||
| 279 | static struct sync_method sync_methods[] = { | ||
| 280 | { | 212 | { |
| 281 | .method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, | 213 | .method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, |
| 282 | .ops = { | 214 | .ops = { |
| @@ -284,18 +216,11 @@ static struct sync_method sync_methods[] = { | |||
| 284 | .adjust_tbtt = &mesh_sync_offset_adjust_tbtt, | 216 | .adjust_tbtt = &mesh_sync_offset_adjust_tbtt, |
| 285 | } | 217 | } |
| 286 | }, | 218 | }, |
| 287 | { | ||
| 288 | .method = IEEE80211_SYNC_METHOD_VENDOR, | ||
| 289 | .ops = { | ||
| 290 | .rx_bcn_presp = &mesh_sync_vendor_rx_bcn_presp, | ||
| 291 | .adjust_tbtt = &mesh_sync_vendor_adjust_tbtt, | ||
| 292 | } | ||
| 293 | }, | ||
| 294 | }; | 219 | }; |
| 295 | 220 | ||
| 296 | struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method) | 221 | const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method) |
| 297 | { | 222 | { |
| 298 | struct ieee80211_mesh_sync_ops *ops = NULL; | 223 | const struct ieee80211_mesh_sync_ops *ops = NULL; |
| 299 | u8 i; | 224 | u8 i; |
| 300 | 225 | ||
| 301 | for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) { | 226 | for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) { |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1b7eed252fe9..7753a9ca98a6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -178,20 +178,32 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, | |||
| 178 | { | 178 | { |
| 179 | struct ieee80211_local *local = sdata->local; | 179 | struct ieee80211_local *local = sdata->local; |
| 180 | struct ieee80211_supported_band *sband; | 180 | struct ieee80211_supported_band *sband; |
| 181 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 182 | struct ieee80211_channel *chan; | ||
| 181 | struct sta_info *sta; | 183 | struct sta_info *sta; |
| 182 | u32 changed = 0; | 184 | u32 changed = 0; |
| 183 | u16 ht_opmode; | 185 | u16 ht_opmode; |
| 184 | bool disable_40 = false; | 186 | bool disable_40 = false; |
| 185 | 187 | ||
| 186 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 188 | rcu_read_lock(); |
| 189 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 190 | if (WARN_ON(!chanctx_conf)) { | ||
| 191 | rcu_read_unlock(); | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | chan = chanctx_conf->def.chan; | ||
| 195 | rcu_read_unlock(); | ||
| 196 | sband = local->hw.wiphy->bands[chan->band]; | ||
| 187 | 197 | ||
| 188 | switch (sdata->vif.bss_conf.channel_type) { | 198 | switch (sdata->vif.bss_conf.chandef.width) { |
| 189 | case NL80211_CHAN_HT40PLUS: | 199 | case NL80211_CHAN_WIDTH_40: |
| 190 | if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40PLUS) | 200 | if (sdata->vif.bss_conf.chandef.chan->center_freq > |
| 201 | sdata->vif.bss_conf.chandef.center_freq1 && | ||
| 202 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
| 191 | disable_40 = true; | 203 | disable_40 = true; |
| 192 | break; | 204 | if (sdata->vif.bss_conf.chandef.chan->center_freq < |
| 193 | case NL80211_CHAN_HT40MINUS: | 205 | sdata->vif.bss_conf.chandef.center_freq1 && |
| 194 | if (local->oper_channel->flags & IEEE80211_CHAN_NO_HT40MINUS) | 206 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) |
| 195 | disable_40 = true; | 207 | disable_40 = true; |
| 196 | break; | 208 | break; |
| 197 | default: | 209 | default: |
| @@ -342,8 +354,18 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
| 342 | /* determine capability flags */ | 354 | /* determine capability flags */ |
| 343 | cap = vht_cap.cap; | 355 | cap = vht_cap.cap; |
| 344 | 356 | ||
| 357 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) { | ||
| 358 | cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; | ||
| 359 | cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | ||
| 360 | } | ||
| 361 | |||
| 362 | if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) { | ||
| 363 | cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; | ||
| 364 | cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | ||
| 365 | } | ||
| 366 | |||
| 345 | /* reserve and fill IE */ | 367 | /* reserve and fill IE */ |
| 346 | pos = skb_put(skb, sizeof(struct ieee80211_vht_capabilities) + 2); | 368 | pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); |
| 347 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); | 369 | ieee80211_ie_build_vht_cap(pos, &vht_cap, cap); |
| 348 | } | 370 | } |
| 349 | 371 | ||
| @@ -359,11 +381,21 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 359 | int i, count, rates_len, supp_rates_len; | 381 | int i, count, rates_len, supp_rates_len; |
| 360 | u16 capab; | 382 | u16 capab; |
| 361 | struct ieee80211_supported_band *sband; | 383 | struct ieee80211_supported_band *sband; |
| 384 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 385 | struct ieee80211_channel *chan; | ||
| 362 | u32 rates = 0; | 386 | u32 rates = 0; |
| 363 | 387 | ||
| 364 | lockdep_assert_held(&ifmgd->mtx); | 388 | lockdep_assert_held(&ifmgd->mtx); |
| 365 | 389 | ||
| 366 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 390 | rcu_read_lock(); |
| 391 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 392 | if (WARN_ON(!chanctx_conf)) { | ||
| 393 | rcu_read_unlock(); | ||
| 394 | return; | ||
| 395 | } | ||
| 396 | chan = chanctx_conf->def.chan; | ||
| 397 | rcu_read_unlock(); | ||
| 398 | sband = local->hw.wiphy->bands[chan->band]; | ||
| 367 | 399 | ||
| 368 | if (assoc_data->supp_rates_len) { | 400 | if (assoc_data->supp_rates_len) { |
| 369 | /* | 401 | /* |
| @@ -392,7 +424,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 392 | 4 + /* power capability */ | 424 | 4 + /* power capability */ |
| 393 | 2 + 2 * sband->n_channels + /* supported channels */ | 425 | 2 + 2 * sband->n_channels + /* supported channels */ |
| 394 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | 426 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ |
| 395 | 2 + sizeof(struct ieee80211_vht_capabilities) + /* VHT */ | 427 | 2 + sizeof(struct ieee80211_vht_cap) + /* VHT */ |
| 396 | assoc_data->ie_len + /* extra IEs */ | 428 | assoc_data->ie_len + /* extra IEs */ |
| 397 | 9, /* WMM */ | 429 | 9, /* WMM */ |
| 398 | GFP_KERNEL); | 430 | GFP_KERNEL); |
| @@ -485,7 +517,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 485 | *pos++ = WLAN_EID_PWR_CAPABILITY; | 517 | *pos++ = WLAN_EID_PWR_CAPABILITY; |
| 486 | *pos++ = 2; | 518 | *pos++ = 2; |
| 487 | *pos++ = 0; /* min tx power */ | 519 | *pos++ = 0; /* min tx power */ |
| 488 | *pos++ = local->oper_channel->max_power; /* max tx power */ | 520 | *pos++ = chan->max_power; /* max tx power */ |
| 489 | 521 | ||
| 490 | /* 2. supported channels */ | 522 | /* 2. supported channels */ |
| 491 | /* TODO: get this in reg domain format */ | 523 | /* TODO: get this in reg domain format */ |
| @@ -521,9 +553,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
| 521 | offset = noffset; | 553 | offset = noffset; |
| 522 | } | 554 | } |
| 523 | 555 | ||
| 524 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 556 | if (WARN_ON_ONCE((ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
| 557 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))) | ||
| 558 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
| 559 | |||
| 560 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | ||
| 525 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, | 561 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param, |
| 526 | sband, local->oper_channel, ifmgd->ap_smps); | 562 | sband, chan, sdata->smps_mode); |
| 527 | 563 | ||
| 528 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | 564 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
| 529 | ieee80211_add_vht_ie(sdata, skb, sband); | 565 | ieee80211_add_vht_ie(sdata, skb, sband); |
| @@ -657,18 +693,18 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 657 | if (!ifmgd->associated) | 693 | if (!ifmgd->associated) |
| 658 | goto out; | 694 | goto out; |
| 659 | 695 | ||
| 660 | sdata->local->oper_channel = sdata->local->csa_channel; | 696 | sdata->local->_oper_channel = sdata->local->csa_channel; |
| 661 | if (!sdata->local->ops->channel_switch) { | 697 | if (!sdata->local->ops->channel_switch) { |
| 662 | /* call "hw_config" only if doing sw channel switch */ | 698 | /* call "hw_config" only if doing sw channel switch */ |
| 663 | ieee80211_hw_config(sdata->local, | 699 | ieee80211_hw_config(sdata->local, |
| 664 | IEEE80211_CONF_CHANGE_CHANNEL); | 700 | IEEE80211_CONF_CHANGE_CHANNEL); |
| 665 | } else { | 701 | } else { |
| 666 | /* update the device channel directly */ | 702 | /* update the device channel directly */ |
| 667 | sdata->local->hw.conf.channel = sdata->local->oper_channel; | 703 | sdata->local->hw.conf.channel = sdata->local->_oper_channel; |
| 668 | } | 704 | } |
| 669 | 705 | ||
| 670 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 706 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
| 671 | ifmgd->associated->channel = sdata->local->oper_channel; | 707 | ifmgd->associated->channel = sdata->local->_oper_channel; |
| 672 | 708 | ||
| 673 | /* XXX: wait for a beacon first? */ | 709 | /* XXX: wait for a beacon first? */ |
| 674 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 710 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
| @@ -680,11 +716,8 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
| 680 | 716 | ||
| 681 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | 717 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) |
| 682 | { | 718 | { |
| 683 | struct ieee80211_sub_if_data *sdata; | 719 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
| 684 | struct ieee80211_if_managed *ifmgd; | 720 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 685 | |||
| 686 | sdata = vif_to_sdata(vif); | ||
| 687 | ifmgd = &sdata->u.mgd; | ||
| 688 | 721 | ||
| 689 | trace_api_chswitch_done(sdata, success); | 722 | trace_api_chswitch_done(sdata, success); |
| 690 | if (!success) { | 723 | if (!success) { |
| @@ -723,6 +756,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 723 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 756 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 724 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num, | 757 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num, |
| 725 | cbss->channel->band); | 758 | cbss->channel->band); |
| 759 | struct ieee80211_chanctx *chanctx; | ||
| 726 | 760 | ||
| 727 | ASSERT_MGD_MTX(ifmgd); | 761 | ASSERT_MGD_MTX(ifmgd); |
| 728 | 762 | ||
| @@ -748,10 +782,35 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 748 | return; | 782 | return; |
| 749 | } | 783 | } |
| 750 | 784 | ||
| 751 | sdata->local->csa_channel = new_ch; | ||
| 752 | |||
| 753 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 785 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
| 754 | 786 | ||
| 787 | if (sdata->local->use_chanctx) { | ||
| 788 | sdata_info(sdata, | ||
| 789 | "not handling channel switch with channel contexts\n"); | ||
| 790 | ieee80211_queue_work(&sdata->local->hw, | ||
| 791 | &ifmgd->csa_connection_drop_work); | ||
| 792 | return; | ||
| 793 | } | ||
| 794 | |||
| 795 | mutex_lock(&sdata->local->chanctx_mtx); | ||
| 796 | if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) { | ||
| 797 | mutex_unlock(&sdata->local->chanctx_mtx); | ||
| 798 | return; | ||
| 799 | } | ||
| 800 | chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf), | ||
| 801 | struct ieee80211_chanctx, conf); | ||
| 802 | if (chanctx->refcount > 1) { | ||
| 803 | sdata_info(sdata, | ||
| 804 | "channel switch with multiple interfaces on the same channel, disconnecting\n"); | ||
| 805 | ieee80211_queue_work(&sdata->local->hw, | ||
| 806 | &ifmgd->csa_connection_drop_work); | ||
| 807 | mutex_unlock(&sdata->local->chanctx_mtx); | ||
| 808 | return; | ||
| 809 | } | ||
| 810 | mutex_unlock(&sdata->local->chanctx_mtx); | ||
| 811 | |||
| 812 | sdata->local->csa_channel = new_ch; | ||
| 813 | |||
| 755 | if (sw_elem->mode) | 814 | if (sw_elem->mode) |
| 756 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | 815 | ieee80211_stop_queues_by_reason(&sdata->local->hw, |
| 757 | IEEE80211_QUEUE_STOP_REASON_CSA); | 816 | IEEE80211_QUEUE_STOP_REASON_CSA); |
| @@ -778,10 +837,10 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
| 778 | cbss->beacon_interval)); | 837 | cbss->beacon_interval)); |
| 779 | } | 838 | } |
| 780 | 839 | ||
| 781 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | 840 | static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, |
| 782 | struct ieee80211_channel *channel, | 841 | struct ieee80211_channel *channel, |
| 783 | const u8 *country_ie, u8 country_ie_len, | 842 | const u8 *country_ie, u8 country_ie_len, |
| 784 | const u8 *pwr_constr_elem) | 843 | const u8 *pwr_constr_elem) |
| 785 | { | 844 | { |
| 786 | struct ieee80211_country_ie_triplet *triplet; | 845 | struct ieee80211_country_ie_triplet *triplet; |
| 787 | int chan = ieee80211_frequency_to_channel(channel->center_freq); | 846 | int chan = ieee80211_frequency_to_channel(channel->center_freq); |
| @@ -790,7 +849,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
| 790 | 849 | ||
| 791 | /* Invalid IE */ | 850 | /* Invalid IE */ |
| 792 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 851 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
| 793 | return; | 852 | return 0; |
| 794 | 853 | ||
| 795 | triplet = (void *)(country_ie + 3); | 854 | triplet = (void *)(country_ie + 3); |
| 796 | country_ie_len -= 3; | 855 | country_ie_len -= 3; |
| @@ -831,19 +890,21 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
| 831 | } | 890 | } |
| 832 | 891 | ||
| 833 | if (!have_chan_pwr) | 892 | if (!have_chan_pwr) |
| 834 | return; | 893 | return 0; |
| 835 | 894 | ||
| 836 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); | 895 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); |
| 837 | 896 | ||
| 838 | if (sdata->local->ap_power_level == new_ap_level) | 897 | if (sdata->ap_power_level == new_ap_level) |
| 839 | return; | 898 | return 0; |
| 840 | 899 | ||
| 841 | sdata_info(sdata, | 900 | sdata_info(sdata, |
| 842 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", | 901 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", |
| 843 | new_ap_level, chan_pwr, *pwr_constr_elem, | 902 | new_ap_level, chan_pwr, *pwr_constr_elem, |
| 844 | sdata->u.mgd.bssid); | 903 | sdata->u.mgd.bssid); |
| 845 | sdata->local->ap_power_level = new_ap_level; | 904 | sdata->ap_power_level = new_ap_level; |
| 846 | ieee80211_hw_config(sdata->local, 0); | 905 | if (__ieee80211_recalc_txpower(sdata)) |
| 906 | return BSS_CHANGED_TXPOWER; | ||
| 907 | return 0; | ||
| 847 | } | 908 | } |
| 848 | 909 | ||
| 849 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | 910 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) |
| @@ -1280,7 +1341,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
| 1280 | } | 1341 | } |
| 1281 | 1342 | ||
| 1282 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | 1343 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); |
| 1283 | if (sdata->local->oper_channel->band == IEEE80211_BAND_5GHZ) | 1344 | if (ieee80211_get_sdata_band(sdata) == IEEE80211_BAND_5GHZ) |
| 1284 | use_short_slot = true; | 1345 | use_short_slot = true; |
| 1285 | 1346 | ||
| 1286 | if (use_protection != bss_conf->use_cts_prot) { | 1347 | if (use_protection != bss_conf->use_cts_prot) { |
| @@ -1321,6 +1382,29 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
| 1321 | 1382 | ||
| 1322 | sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; | 1383 | sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; |
| 1323 | 1384 | ||
| 1385 | if (sdata->vif.p2p) { | ||
| 1386 | const struct cfg80211_bss_ies *ies; | ||
| 1387 | |||
| 1388 | rcu_read_lock(); | ||
| 1389 | ies = rcu_dereference(cbss->ies); | ||
| 1390 | if (ies) { | ||
| 1391 | u8 noa[2]; | ||
| 1392 | int ret; | ||
| 1393 | |||
| 1394 | ret = cfg80211_get_p2p_attr( | ||
| 1395 | ies->data, ies->len, | ||
| 1396 | IEEE80211_P2P_ATTR_ABSENCE_NOTICE, | ||
| 1397 | noa, sizeof(noa)); | ||
| 1398 | if (ret >= 2) { | ||
| 1399 | bss_conf->p2p_oppps = noa[1] & 0x80; | ||
| 1400 | bss_conf->p2p_ctwindow = noa[1] & 0x7f; | ||
| 1401 | bss_info_changed |= BSS_CHANGED_P2P_PS; | ||
| 1402 | sdata->u.mgd.p2p_noa_index = noa[0]; | ||
| 1403 | } | ||
| 1404 | } | ||
| 1405 | rcu_read_unlock(); | ||
| 1406 | } | ||
| 1407 | |||
| 1324 | /* just to be sure */ | 1408 | /* just to be sure */ |
| 1325 | ieee80211_stop_poll(sdata); | 1409 | ieee80211_stop_poll(sdata); |
| 1326 | 1410 | ||
| @@ -1350,7 +1434,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
| 1350 | ieee80211_recalc_ps(local, -1); | 1434 | ieee80211_recalc_ps(local, -1); |
| 1351 | mutex_unlock(&local->iflist_mtx); | 1435 | mutex_unlock(&local->iflist_mtx); |
| 1352 | 1436 | ||
| 1353 | ieee80211_recalc_smps(local); | 1437 | ieee80211_recalc_smps(sdata); |
| 1354 | ieee80211_recalc_ps_vif(sdata); | 1438 | ieee80211_recalc_ps_vif(sdata); |
| 1355 | 1439 | ||
| 1356 | netif_tx_start_all_queues(sdata->dev); | 1440 | netif_tx_start_all_queues(sdata->dev); |
| @@ -1443,11 +1527,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1443 | changed |= BSS_CHANGED_ASSOC; | 1527 | changed |= BSS_CHANGED_ASSOC; |
| 1444 | sdata->vif.bss_conf.assoc = false; | 1528 | sdata->vif.bss_conf.assoc = false; |
| 1445 | 1529 | ||
| 1530 | sdata->vif.bss_conf.p2p_ctwindow = 0; | ||
| 1531 | sdata->vif.bss_conf.p2p_oppps = false; | ||
| 1532 | |||
| 1446 | /* on the next assoc, re-program HT parameters */ | 1533 | /* on the next assoc, re-program HT parameters */ |
| 1447 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1534 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
| 1448 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1535 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
| 1449 | 1536 | ||
| 1450 | local->ap_power_level = 0; | 1537 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
| 1451 | 1538 | ||
| 1452 | del_timer_sync(&local->dynamic_ps_timer); | 1539 | del_timer_sync(&local->dynamic_ps_timer); |
| 1453 | cancel_work_sync(&local->dynamic_ps_enable_work); | 1540 | cancel_work_sync(&local->dynamic_ps_enable_work); |
| @@ -1465,10 +1552,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1465 | changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; | 1552 | changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; |
| 1466 | ieee80211_bss_info_change_notify(sdata, changed); | 1553 | ieee80211_bss_info_change_notify(sdata, changed); |
| 1467 | 1554 | ||
| 1468 | /* channel(_type) changes are handled by ieee80211_hw_config */ | ||
| 1469 | WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT)); | ||
| 1470 | ieee80211_hw_config(local, 0); | ||
| 1471 | |||
| 1472 | /* disassociated - set to defaults now */ | 1555 | /* disassociated - set to defaults now */ |
| 1473 | ieee80211_set_wmm_default(sdata, false); | 1556 | ieee80211_set_wmm_default(sdata, false); |
| 1474 | 1557 | ||
| @@ -1478,6 +1561,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1478 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | 1561 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
| 1479 | 1562 | ||
| 1480 | sdata->u.mgd.timers_running = 0; | 1563 | sdata->u.mgd.timers_running = 0; |
| 1564 | |||
| 1565 | ifmgd->flags = 0; | ||
| 1566 | ieee80211_vif_release_channel(sdata); | ||
| 1481 | } | 1567 | } |
| 1482 | 1568 | ||
| 1483 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1569 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
| @@ -1581,6 +1667,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
| 1581 | } else { | 1667 | } else { |
| 1582 | int ssid_len; | 1668 | int ssid_len; |
| 1583 | 1669 | ||
| 1670 | rcu_read_lock(); | ||
| 1584 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1671 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
| 1585 | if (WARN_ON_ONCE(ssid == NULL)) | 1672 | if (WARN_ON_ONCE(ssid == NULL)) |
| 1586 | ssid_len = 0; | 1673 | ssid_len = 0; |
| @@ -1589,7 +1676,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
| 1589 | 1676 | ||
| 1590 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | 1677 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, |
| 1591 | 0, (u32) -1, true, false, | 1678 | 0, (u32) -1, true, false, |
| 1592 | ifmgd->associated->channel); | 1679 | ifmgd->associated->channel, false); |
| 1680 | rcu_read_unlock(); | ||
| 1593 | } | 1681 | } |
| 1594 | 1682 | ||
| 1595 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 1683 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
| @@ -1685,6 +1773,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
| 1685 | else | 1773 | else |
| 1686 | return NULL; | 1774 | return NULL; |
| 1687 | 1775 | ||
| 1776 | rcu_read_lock(); | ||
| 1688 | ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); | 1777 | ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); |
| 1689 | if (WARN_ON_ONCE(ssid == NULL)) | 1778 | if (WARN_ON_ONCE(ssid == NULL)) |
| 1690 | ssid_len = 0; | 1779 | ssid_len = 0; |
| @@ -1692,10 +1781,10 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
| 1692 | ssid_len = ssid[1]; | 1781 | ssid_len = ssid[1]; |
| 1693 | 1782 | ||
| 1694 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, | 1783 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, |
| 1695 | (u32) -1, | 1784 | (u32) -1, cbss->channel, |
| 1696 | sdata->local->oper_channel, | ||
| 1697 | ssid + 2, ssid_len, | 1785 | ssid + 2, ssid_len, |
| 1698 | NULL, 0, true); | 1786 | NULL, 0, true); |
| 1787 | rcu_read_unlock(); | ||
| 1699 | 1788 | ||
| 1700 | return skb; | 1789 | return skb; |
| 1701 | } | 1790 | } |
| @@ -1804,6 +1893,8 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | |||
| 1804 | 1893 | ||
| 1805 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 1894 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
| 1806 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 1895 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
| 1896 | sdata->u.mgd.flags = 0; | ||
| 1897 | ieee80211_vif_release_channel(sdata); | ||
| 1807 | } | 1898 | } |
| 1808 | 1899 | ||
| 1809 | cfg80211_put_bss(auth_data->bss); | 1900 | cfg80211_put_bss(auth_data->bss); |
| @@ -1824,7 +1915,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
| 1824 | return; | 1915 | return; |
| 1825 | auth_data->expected_transaction = 4; | 1916 | auth_data->expected_transaction = 4; |
| 1826 | drv_mgd_prepare_tx(sdata->local, sdata); | 1917 | drv_mgd_prepare_tx(sdata->local, sdata); |
| 1827 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, | 1918 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0, |
| 1828 | elems.challenge - 2, elems.challenge_len + 2, | 1919 | elems.challenge - 2, elems.challenge_len + 2, |
| 1829 | auth_data->bss->bssid, auth_data->bss->bssid, | 1920 | auth_data->bss->bssid, auth_data->bss->bssid, |
| 1830 | auth_data->key, auth_data->key_len, | 1921 | auth_data->key, auth_data->key_len, |
| @@ -1858,8 +1949,13 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
| 1858 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | 1949 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
| 1859 | 1950 | ||
| 1860 | if (auth_alg != ifmgd->auth_data->algorithm || | 1951 | if (auth_alg != ifmgd->auth_data->algorithm || |
| 1861 | auth_transaction != ifmgd->auth_data->expected_transaction) | 1952 | auth_transaction != ifmgd->auth_data->expected_transaction) { |
| 1953 | sdata_info(sdata, "%pM unexpected authentication state: alg %d (expected %d) transact %d (expected %d)\n", | ||
| 1954 | mgmt->sa, auth_alg, ifmgd->auth_data->algorithm, | ||
| 1955 | auth_transaction, | ||
| 1956 | ifmgd->auth_data->expected_transaction); | ||
| 1862 | return RX_MGMT_NONE; | 1957 | return RX_MGMT_NONE; |
| 1958 | } | ||
| 1863 | 1959 | ||
| 1864 | if (status_code != WLAN_STATUS_SUCCESS) { | 1960 | if (status_code != WLAN_STATUS_SUCCESS) { |
| 1865 | sdata_info(sdata, "%pM denied authentication (status %d)\n", | 1961 | sdata_info(sdata, "%pM denied authentication (status %d)\n", |
| @@ -1872,6 +1968,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
| 1872 | case WLAN_AUTH_OPEN: | 1968 | case WLAN_AUTH_OPEN: |
| 1873 | case WLAN_AUTH_LEAP: | 1969 | case WLAN_AUTH_LEAP: |
| 1874 | case WLAN_AUTH_FT: | 1970 | case WLAN_AUTH_FT: |
| 1971 | case WLAN_AUTH_SAE: | ||
| 1875 | break; | 1972 | break; |
| 1876 | case WLAN_AUTH_SHARED_KEY: | 1973 | case WLAN_AUTH_SHARED_KEY: |
| 1877 | if (ifmgd->auth_data->expected_transaction != 4) { | 1974 | if (ifmgd->auth_data->expected_transaction != 4) { |
| @@ -1891,6 +1988,15 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
| 1891 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; | 1988 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; |
| 1892 | run_again(ifmgd, ifmgd->auth_data->timeout); | 1989 | run_again(ifmgd, ifmgd->auth_data->timeout); |
| 1893 | 1990 | ||
| 1991 | if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && | ||
| 1992 | ifmgd->auth_data->expected_transaction != 2) { | ||
| 1993 | /* | ||
| 1994 | * Report auth frame to user space for processing since another | ||
| 1995 | * round of Authentication frames is still needed. | ||
| 1996 | */ | ||
| 1997 | return RX_MGMT_CFG80211_RX_AUTH; | ||
| 1998 | } | ||
| 1999 | |||
| 1894 | /* move station state to auth */ | 2000 | /* move station state to auth */ |
| 1895 | mutex_lock(&sdata->local->sta_mtx); | 2001 | mutex_lock(&sdata->local->sta_mtx); |
| 1896 | sta = sta_info_get(sdata, bssid); | 2002 | sta = sta_info_get(sdata, bssid); |
| @@ -2030,6 +2136,8 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, | |||
| 2030 | 2136 | ||
| 2031 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | 2137 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); |
| 2032 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 2138 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
| 2139 | sdata->u.mgd.flags = 0; | ||
| 2140 | ieee80211_vif_release_channel(sdata); | ||
| 2033 | } | 2141 | } |
| 2034 | 2142 | ||
| 2035 | kfree(assoc_data); | 2143 | kfree(assoc_data); |
| @@ -2091,15 +2199,20 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
| 2091 | return false; | 2199 | return false; |
| 2092 | } | 2200 | } |
| 2093 | 2201 | ||
| 2094 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 2202 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; |
| 2095 | 2203 | ||
| 2096 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 2204 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
| 2097 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 2205 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
| 2098 | elems.ht_cap_elem, &sta->sta.ht_cap); | 2206 | elems.ht_cap_elem, &sta->sta.ht_cap); |
| 2099 | 2207 | ||
| 2100 | sta->supports_40mhz = | 2208 | sta->supports_40mhz = |
| 2101 | sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 2209 | sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
| 2102 | 2210 | ||
| 2211 | if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | ||
| 2212 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | ||
| 2213 | elems.vht_cap_elem, | ||
| 2214 | &sta->sta.vht_cap); | ||
| 2215 | |||
| 2103 | rate_control_rate_init(sta); | 2216 | rate_control_rate_init(sta); |
| 2104 | 2217 | ||
| 2105 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) | 2218 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) |
| @@ -2140,7 +2253,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
| 2140 | changed |= BSS_CHANGED_QOS; | 2253 | changed |= BSS_CHANGED_QOS; |
| 2141 | 2254 | ||
| 2142 | if (elems.ht_operation && elems.wmm_param && | 2255 | if (elems.ht_operation && elems.wmm_param && |
| 2143 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 2256 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
| 2144 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | 2257 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, |
| 2145 | cbss->bssid, false); | 2258 | cbss->bssid, false); |
| 2146 | 2259 | ||
| @@ -2247,9 +2360,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
| 2247 | 2360 | ||
| 2248 | return RX_MGMT_CFG80211_RX_ASSOC; | 2361 | return RX_MGMT_CFG80211_RX_ASSOC; |
| 2249 | } | 2362 | } |
| 2363 | |||
| 2250 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 2364 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
| 2251 | struct ieee80211_mgmt *mgmt, | 2365 | struct ieee80211_mgmt *mgmt, size_t len, |
| 2252 | size_t len, | ||
| 2253 | struct ieee80211_rx_status *rx_status, | 2366 | struct ieee80211_rx_status *rx_status, |
| 2254 | struct ieee802_11_elems *elems, | 2367 | struct ieee802_11_elems *elems, |
| 2255 | bool beacon) | 2368 | bool beacon) |
| @@ -2369,8 +2482,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2369 | size_t baselen; | 2482 | size_t baselen; |
| 2370 | struct ieee802_11_elems elems; | 2483 | struct ieee802_11_elems elems; |
| 2371 | struct ieee80211_local *local = sdata->local; | 2484 | struct ieee80211_local *local = sdata->local; |
| 2485 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 2486 | struct ieee80211_channel *chan; | ||
| 2372 | u32 changed = 0; | 2487 | u32 changed = 0; |
| 2373 | bool erp_valid, directed_tim = false; | 2488 | bool erp_valid; |
| 2374 | u8 erp_value = 0; | 2489 | u8 erp_value = 0; |
| 2375 | u32 ncrc; | 2490 | u32 ncrc; |
| 2376 | u8 *bssid; | 2491 | u8 *bssid; |
| @@ -2382,8 +2497,19 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2382 | if (baselen > len) | 2497 | if (baselen > len) |
| 2383 | return; | 2498 | return; |
| 2384 | 2499 | ||
| 2385 | if (rx_status->freq != local->oper_channel->center_freq) | 2500 | rcu_read_lock(); |
| 2501 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 2502 | if (!chanctx_conf) { | ||
| 2503 | rcu_read_unlock(); | ||
| 2504 | return; | ||
| 2505 | } | ||
| 2506 | |||
| 2507 | if (rx_status->freq != chanctx_conf->def.chan->center_freq) { | ||
| 2508 | rcu_read_unlock(); | ||
| 2386 | return; | 2509 | return; |
| 2510 | } | ||
| 2511 | chan = chanctx_conf->def.chan; | ||
| 2512 | rcu_read_unlock(); | ||
| 2387 | 2513 | ||
| 2388 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && | 2514 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && |
| 2389 | ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { | 2515 | ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { |
| @@ -2490,11 +2616,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2490 | len - baselen, &elems, | 2616 | len - baselen, &elems, |
| 2491 | care_about_ies, ncrc); | 2617 | care_about_ies, ncrc); |
| 2492 | 2618 | ||
| 2493 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | ||
| 2494 | directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, | ||
| 2495 | ifmgd->aid); | ||
| 2496 | |||
| 2497 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { | 2619 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { |
| 2620 | bool directed_tim = ieee80211_check_tim(elems.tim, | ||
| 2621 | elems.tim_len, | ||
| 2622 | ifmgd->aid); | ||
| 2498 | if (directed_tim) { | 2623 | if (directed_tim) { |
| 2499 | if (local->hw.conf.dynamic_ps_timeout > 0) { | 2624 | if (local->hw.conf.dynamic_ps_timeout > 0) { |
| 2500 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | 2625 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { |
| @@ -2519,6 +2644,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2519 | } | 2644 | } |
| 2520 | } | 2645 | } |
| 2521 | 2646 | ||
| 2647 | if (sdata->vif.p2p) { | ||
| 2648 | u8 noa[2]; | ||
| 2649 | int ret; | ||
| 2650 | |||
| 2651 | ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable, | ||
| 2652 | len - baselen, | ||
| 2653 | IEEE80211_P2P_ATTR_ABSENCE_NOTICE, | ||
| 2654 | noa, sizeof(noa)); | ||
| 2655 | if (ret >= 2 && sdata->u.mgd.p2p_noa_index != noa[0]) { | ||
| 2656 | bss_conf->p2p_oppps = noa[1] & 0x80; | ||
| 2657 | bss_conf->p2p_ctwindow = noa[1] & 0x7f; | ||
| 2658 | changed |= BSS_CHANGED_P2P_PS; | ||
| 2659 | sdata->u.mgd.p2p_noa_index = noa[0]; | ||
| 2660 | /* | ||
| 2661 | * make sure we update all information, the CRC | ||
| 2662 | * mechanism doesn't look at P2P attributes. | ||
| 2663 | */ | ||
| 2664 | ifmgd->beacon_crc_valid = false; | ||
| 2665 | } | ||
| 2666 | } | ||
| 2667 | |||
| 2522 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 2668 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
| 2523 | return; | 2669 | return; |
| 2524 | ifmgd->beacon_crc = ncrc; | 2670 | ifmgd->beacon_crc = ncrc; |
| @@ -2543,22 +2689,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 2543 | 2689 | ||
| 2544 | 2690 | ||
| 2545 | if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && | 2691 | if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param && |
| 2546 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { | 2692 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
| 2547 | struct ieee80211_supported_band *sband; | ||
| 2548 | |||
| 2549 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||
| 2550 | |||
| 2551 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, | 2693 | changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation, |
| 2552 | bssid, true); | 2694 | bssid, true); |
| 2553 | } | ||
| 2554 | 2695 | ||
| 2555 | if (elems.country_elem && elems.pwr_constr_elem && | 2696 | if (elems.country_elem && elems.pwr_constr_elem && |
| 2556 | mgmt->u.probe_resp.capab_info & | 2697 | mgmt->u.probe_resp.capab_info & |
| 2557 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) | 2698 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) |
| 2558 | ieee80211_handle_pwr_constr(sdata, local->oper_channel, | 2699 | changed |= ieee80211_handle_pwr_constr(sdata, chan, |
| 2559 | elems.country_elem, | 2700 | elems.country_elem, |
| 2560 | elems.country_elem_len, | 2701 | elems.country_elem_len, |
| 2561 | elems.pwr_constr_elem); | 2702 | elems.pwr_constr_elem); |
| 2562 | 2703 | ||
| 2563 | ieee80211_bss_info_change_notify(sdata, changed); | 2704 | ieee80211_bss_info_change_notify(sdata, changed); |
| 2564 | } | 2705 | } |
| @@ -2703,13 +2844,23 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
| 2703 | drv_mgd_prepare_tx(local, sdata); | 2844 | drv_mgd_prepare_tx(local, sdata); |
| 2704 | 2845 | ||
| 2705 | if (auth_data->bss->proberesp_ies) { | 2846 | if (auth_data->bss->proberesp_ies) { |
| 2847 | u16 trans = 1; | ||
| 2848 | u16 status = 0; | ||
| 2849 | |||
| 2706 | sdata_info(sdata, "send auth to %pM (try %d/%d)\n", | 2850 | sdata_info(sdata, "send auth to %pM (try %d/%d)\n", |
| 2707 | auth_data->bss->bssid, auth_data->tries, | 2851 | auth_data->bss->bssid, auth_data->tries, |
| 2708 | IEEE80211_AUTH_MAX_TRIES); | 2852 | IEEE80211_AUTH_MAX_TRIES); |
| 2709 | 2853 | ||
| 2710 | auth_data->expected_transaction = 2; | 2854 | auth_data->expected_transaction = 2; |
| 2711 | ieee80211_send_auth(sdata, 1, auth_data->algorithm, | 2855 | |
| 2712 | auth_data->ie, auth_data->ie_len, | 2856 | if (auth_data->algorithm == WLAN_AUTH_SAE) { |
| 2857 | trans = auth_data->sae_trans; | ||
| 2858 | status = auth_data->sae_status; | ||
| 2859 | auth_data->expected_transaction = trans; | ||
| 2860 | } | ||
| 2861 | |||
| 2862 | ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, | ||
| 2863 | auth_data->data, auth_data->data_len, | ||
| 2713 | auth_data->bss->bssid, | 2864 | auth_data->bss->bssid, |
| 2714 | auth_data->bss->bssid, NULL, 0, 0); | 2865 | auth_data->bss->bssid, NULL, 0, 0); |
| 2715 | } else { | 2866 | } else { |
| @@ -2719,16 +2870,20 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
| 2719 | auth_data->bss->bssid, auth_data->tries, | 2870 | auth_data->bss->bssid, auth_data->tries, |
| 2720 | IEEE80211_AUTH_MAX_TRIES); | 2871 | IEEE80211_AUTH_MAX_TRIES); |
| 2721 | 2872 | ||
| 2873 | rcu_read_lock(); | ||
| 2722 | ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); | 2874 | ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); |
| 2723 | if (!ssidie) | 2875 | if (!ssidie) { |
| 2876 | rcu_read_unlock(); | ||
| 2724 | return -EINVAL; | 2877 | return -EINVAL; |
| 2878 | } | ||
| 2725 | /* | 2879 | /* |
| 2726 | * Direct probe is sent to broadcast address as some APs | 2880 | * Direct probe is sent to broadcast address as some APs |
| 2727 | * will not answer to direct packet in unassociated state. | 2881 | * will not answer to direct packet in unassociated state. |
| 2728 | */ | 2882 | */ |
| 2729 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | 2883 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], |
| 2730 | NULL, 0, (u32) -1, true, false, | 2884 | NULL, 0, (u32) -1, true, false, |
| 2731 | auth_data->bss->channel); | 2885 | auth_data->bss->channel, false); |
| 2886 | rcu_read_unlock(); | ||
| 2732 | } | 2887 | } |
| 2733 | 2888 | ||
| 2734 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 2889 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
| @@ -3058,90 +3213,313 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
| 3058 | return 0; | 3213 | return 0; |
| 3059 | } | 3214 | } |
| 3060 | 3215 | ||
| 3216 | static u32 chandef_downgrade(struct cfg80211_chan_def *c) | ||
| 3217 | { | ||
| 3218 | u32 ret; | ||
| 3219 | int tmp; | ||
| 3220 | |||
| 3221 | switch (c->width) { | ||
| 3222 | case NL80211_CHAN_WIDTH_20: | ||
| 3223 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 3224 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 3225 | break; | ||
| 3226 | case NL80211_CHAN_WIDTH_40: | ||
| 3227 | c->width = NL80211_CHAN_WIDTH_20; | ||
| 3228 | c->center_freq1 = c->chan->center_freq; | ||
| 3229 | ret = IEEE80211_STA_DISABLE_40MHZ | | ||
| 3230 | IEEE80211_STA_DISABLE_VHT; | ||
| 3231 | break; | ||
| 3232 | case NL80211_CHAN_WIDTH_80: | ||
| 3233 | tmp = (30 + c->chan->center_freq - c->center_freq1)/20; | ||
| 3234 | /* n_P40 */ | ||
| 3235 | tmp /= 2; | ||
| 3236 | /* freq_P40 */ | ||
| 3237 | c->center_freq1 = c->center_freq1 - 20 + 40 * tmp; | ||
| 3238 | c->width = NL80211_CHAN_WIDTH_40; | ||
| 3239 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3240 | break; | ||
| 3241 | case NL80211_CHAN_WIDTH_80P80: | ||
| 3242 | c->center_freq2 = 0; | ||
| 3243 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 3244 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 3245 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 3246 | break; | ||
| 3247 | case NL80211_CHAN_WIDTH_160: | ||
| 3248 | /* n_P20 */ | ||
| 3249 | tmp = (70 + c->chan->center_freq - c->center_freq1)/20; | ||
| 3250 | /* n_P80 */ | ||
| 3251 | tmp /= 4; | ||
| 3252 | c->center_freq1 = c->center_freq1 - 40 + 80 * tmp; | ||
| 3253 | c->width = NL80211_CHAN_WIDTH_80; | ||
| 3254 | ret = IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 3255 | IEEE80211_STA_DISABLE_160MHZ; | ||
| 3256 | break; | ||
| 3257 | default: | ||
| 3258 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
| 3259 | WARN_ON_ONCE(1); | ||
| 3260 | c->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 3261 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 3262 | break; | ||
| 3263 | } | ||
| 3264 | |||
| 3265 | WARN_ON_ONCE(!cfg80211_chandef_valid(c)); | ||
| 3266 | |||
| 3267 | return ret; | ||
| 3268 | } | ||
| 3269 | |||
| 3270 | static u32 | ||
| 3271 | ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | ||
| 3272 | struct ieee80211_supported_band *sband, | ||
| 3273 | struct ieee80211_channel *channel, | ||
| 3274 | const struct ieee80211_ht_operation *ht_oper, | ||
| 3275 | const struct ieee80211_vht_operation *vht_oper, | ||
| 3276 | struct cfg80211_chan_def *chandef) | ||
| 3277 | { | ||
| 3278 | struct cfg80211_chan_def vht_chandef; | ||
| 3279 | u32 ht_cfreq, ret; | ||
| 3280 | |||
| 3281 | chandef->chan = channel; | ||
| 3282 | chandef->width = NL80211_CHAN_WIDTH_20_NOHT; | ||
| 3283 | chandef->center_freq1 = channel->center_freq; | ||
| 3284 | chandef->center_freq2 = 0; | ||
| 3285 | |||
| 3286 | if (!ht_oper || !sband->ht_cap.ht_supported) { | ||
| 3287 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 3288 | goto out; | ||
| 3289 | } | ||
| 3290 | |||
| 3291 | chandef->width = NL80211_CHAN_WIDTH_20; | ||
| 3292 | |||
| 3293 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | ||
| 3294 | channel->band); | ||
| 3295 | /* check that channel matches the right operating channel */ | ||
| 3296 | if (channel->center_freq != ht_cfreq) { | ||
| 3297 | /* | ||
| 3298 | * It's possible that some APs are confused here; | ||
| 3299 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
| 3300 | * the actual channel in association responses, but | ||
| 3301 | * since we look at probe response/beacon data here | ||
| 3302 | * it should be OK. | ||
| 3303 | */ | ||
| 3304 | sdata_info(sdata, | ||
| 3305 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | ||
| 3306 | channel->center_freq, ht_cfreq, | ||
| 3307 | ht_oper->primary_chan, channel->band); | ||
| 3308 | ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; | ||
| 3309 | goto out; | ||
| 3310 | } | ||
| 3311 | |||
| 3312 | /* check 40 MHz support, if we have it */ | ||
| 3313 | if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | ||
| 3314 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
| 3315 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
| 3316 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
| 3317 | chandef->center_freq1 += 10; | ||
| 3318 | break; | ||
| 3319 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 3320 | chandef->width = NL80211_CHAN_WIDTH_40; | ||
| 3321 | chandef->center_freq1 -= 10; | ||
| 3322 | break; | ||
| 3323 | } | ||
| 3324 | } else { | ||
| 3325 | /* 40 MHz (and 80 MHz) must be supported for VHT */ | ||
| 3326 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3327 | goto out; | ||
| 3328 | } | ||
| 3329 | |||
| 3330 | if (!vht_oper || !sband->vht_cap.vht_supported) { | ||
| 3331 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3332 | goto out; | ||
| 3333 | } | ||
| 3334 | |||
| 3335 | vht_chandef.chan = channel; | ||
| 3336 | vht_chandef.center_freq1 = | ||
| 3337 | ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx, | ||
| 3338 | channel->band); | ||
| 3339 | vht_chandef.center_freq2 = 0; | ||
| 3340 | |||
| 3341 | if (vht_oper->center_freq_seg2_idx) | ||
| 3342 | vht_chandef.center_freq2 = | ||
| 3343 | ieee80211_channel_to_frequency( | ||
| 3344 | vht_oper->center_freq_seg2_idx, | ||
| 3345 | channel->band); | ||
| 3346 | |||
| 3347 | switch (vht_oper->chan_width) { | ||
| 3348 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | ||
| 3349 | vht_chandef.width = chandef->width; | ||
| 3350 | break; | ||
| 3351 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | ||
| 3352 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | ||
| 3353 | break; | ||
| 3354 | case IEEE80211_VHT_CHANWIDTH_160MHZ: | ||
| 3355 | vht_chandef.width = NL80211_CHAN_WIDTH_160; | ||
| 3356 | break; | ||
| 3357 | case IEEE80211_VHT_CHANWIDTH_80P80MHZ: | ||
| 3358 | vht_chandef.width = NL80211_CHAN_WIDTH_80P80; | ||
| 3359 | break; | ||
| 3360 | default: | ||
| 3361 | sdata_info(sdata, | ||
| 3362 | "AP VHT operation IE has invalid channel width (%d), disable VHT\n", | ||
| 3363 | vht_oper->chan_width); | ||
| 3364 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3365 | goto out; | ||
| 3366 | } | ||
| 3367 | |||
| 3368 | if (!cfg80211_chandef_valid(&vht_chandef)) { | ||
| 3369 | sdata_info(sdata, | ||
| 3370 | "AP VHT information is invalid, disable VHT\n"); | ||
| 3371 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3372 | goto out; | ||
| 3373 | } | ||
| 3374 | |||
| 3375 | if (cfg80211_chandef_identical(chandef, &vht_chandef)) { | ||
| 3376 | ret = 0; | ||
| 3377 | goto out; | ||
| 3378 | } | ||
| 3379 | |||
| 3380 | if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) { | ||
| 3381 | sdata_info(sdata, | ||
| 3382 | "AP VHT information doesn't match HT, disable VHT\n"); | ||
| 3383 | ret = IEEE80211_STA_DISABLE_VHT; | ||
| 3384 | goto out; | ||
| 3385 | } | ||
| 3386 | |||
| 3387 | *chandef = vht_chandef; | ||
| 3388 | |||
| 3389 | ret = 0; | ||
| 3390 | |||
| 3391 | while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef, | ||
| 3392 | IEEE80211_CHAN_DISABLED)) { | ||
| 3393 | if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) { | ||
| 3394 | ret = IEEE80211_STA_DISABLE_HT | | ||
| 3395 | IEEE80211_STA_DISABLE_VHT; | ||
| 3396 | goto out; | ||
| 3397 | } | ||
| 3398 | |||
| 3399 | ret = chandef_downgrade(chandef); | ||
| 3400 | } | ||
| 3401 | |||
| 3402 | if (chandef->width != vht_chandef.width) | ||
| 3403 | sdata_info(sdata, | ||
| 3404 | "local regulatory prevented using AP HT/VHT configuration, downgraded\n"); | ||
| 3405 | |||
| 3406 | out: | ||
| 3407 | WARN_ON_ONCE(!cfg80211_chandef_valid(chandef)); | ||
| 3408 | return ret; | ||
| 3409 | } | ||
| 3410 | |||
| 3411 | static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata, | ||
| 3412 | struct cfg80211_bss *cbss) | ||
| 3413 | { | ||
| 3414 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
| 3415 | const u8 *ht_cap_ie, *vht_cap_ie; | ||
| 3416 | const struct ieee80211_ht_cap *ht_cap; | ||
| 3417 | const struct ieee80211_vht_cap *vht_cap; | ||
| 3418 | u8 chains = 1; | ||
| 3419 | |||
| 3420 | if (ifmgd->flags & IEEE80211_STA_DISABLE_HT) | ||
| 3421 | return chains; | ||
| 3422 | |||
| 3423 | ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY); | ||
| 3424 | if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap)) { | ||
| 3425 | ht_cap = (void *)(ht_cap_ie + 2); | ||
| 3426 | chains = ieee80211_mcs_to_chains(&ht_cap->mcs); | ||
| 3427 | /* | ||
| 3428 | * TODO: use "Tx Maximum Number Spatial Streams Supported" and | ||
| 3429 | * "Tx Unequal Modulation Supported" fields. | ||
| 3430 | */ | ||
| 3431 | } | ||
| 3432 | |||
| 3433 | if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT) | ||
| 3434 | return chains; | ||
| 3435 | |||
| 3436 | vht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY); | ||
| 3437 | if (vht_cap_ie && vht_cap_ie[1] >= sizeof(*vht_cap)) { | ||
| 3438 | u8 nss; | ||
| 3439 | u16 tx_mcs_map; | ||
| 3440 | |||
| 3441 | vht_cap = (void *)(vht_cap_ie + 2); | ||
| 3442 | tx_mcs_map = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map); | ||
| 3443 | for (nss = 8; nss > 0; nss--) { | ||
| 3444 | if (((tx_mcs_map >> (2 * (nss - 1))) & 3) != | ||
| 3445 | IEEE80211_VHT_MCS_NOT_SUPPORTED) | ||
| 3446 | break; | ||
| 3447 | } | ||
| 3448 | /* TODO: use "Tx Highest Supported Long GI Data Rate" field? */ | ||
| 3449 | chains = max(chains, nss); | ||
| 3450 | } | ||
| 3451 | |||
| 3452 | return chains; | ||
| 3453 | } | ||
| 3454 | |||
| 3061 | static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, | 3455 | static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, |
| 3062 | struct cfg80211_bss *cbss) | 3456 | struct cfg80211_bss *cbss) |
| 3063 | { | 3457 | { |
| 3064 | struct ieee80211_local *local = sdata->local; | 3458 | struct ieee80211_local *local = sdata->local; |
| 3065 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3459 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 3066 | int ht_cfreq; | ||
| 3067 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
| 3068 | const u8 *ht_oper_ie; | ||
| 3069 | const struct ieee80211_ht_operation *ht_oper = NULL; | 3460 | const struct ieee80211_ht_operation *ht_oper = NULL; |
| 3461 | const struct ieee80211_vht_operation *vht_oper = NULL; | ||
| 3070 | struct ieee80211_supported_band *sband; | 3462 | struct ieee80211_supported_band *sband; |
| 3463 | struct cfg80211_chan_def chandef; | ||
| 3464 | int ret; | ||
| 3071 | 3465 | ||
| 3072 | sband = local->hw.wiphy->bands[cbss->channel->band]; | 3466 | sband = local->hw.wiphy->bands[cbss->channel->band]; |
| 3073 | 3467 | ||
| 3074 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_40MHZ; | 3468 | ifmgd->flags &= ~(IEEE80211_STA_DISABLE_40MHZ | |
| 3469 | IEEE80211_STA_DISABLE_80P80MHZ | | ||
| 3470 | IEEE80211_STA_DISABLE_160MHZ); | ||
| 3471 | |||
| 3472 | rcu_read_lock(); | ||
| 3473 | |||
| 3474 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | ||
| 3475 | sband->ht_cap.ht_supported) { | ||
| 3476 | const u8 *ht_oper_ie; | ||
| 3075 | 3477 | ||
| 3076 | if (sband->ht_cap.ht_supported) { | 3478 | ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); |
| 3077 | ht_oper_ie = cfg80211_find_ie(WLAN_EID_HT_OPERATION, | ||
| 3078 | cbss->information_elements, | ||
| 3079 | cbss->len_information_elements); | ||
| 3080 | if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) | 3479 | if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) |
| 3081 | ht_oper = (void *)(ht_oper_ie + 2); | 3480 | ht_oper = (void *)(ht_oper_ie + 2); |
| 3082 | } | 3481 | } |
| 3083 | 3482 | ||
| 3084 | if (ht_oper) { | 3483 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
| 3085 | ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, | 3484 | sband->vht_cap.vht_supported) { |
| 3086 | cbss->channel->band); | 3485 | const u8 *vht_oper_ie; |
| 3087 | /* check that channel matches the right operating channel */ | 3486 | |
| 3088 | if (cbss->channel->center_freq != ht_cfreq) { | 3487 | vht_oper_ie = ieee80211_bss_get_ie(cbss, |
| 3089 | /* | 3488 | WLAN_EID_VHT_OPERATION); |
| 3090 | * It's possible that some APs are confused here; | 3489 | if (vht_oper_ie && vht_oper_ie[1] >= sizeof(*vht_oper)) |
| 3091 | * Netgear WNDR3700 sometimes reports 4 higher than | 3490 | vht_oper = (void *)(vht_oper_ie + 2); |
| 3092 | * the actual channel in association responses, but | 3491 | if (vht_oper && !ht_oper) { |
| 3093 | * since we look at probe response/beacon data here | 3492 | vht_oper = NULL; |
| 3094 | * it should be OK. | ||
| 3095 | */ | ||
| 3096 | sdata_info(sdata, | 3493 | sdata_info(sdata, |
| 3097 | "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", | 3494 | "AP advertised VHT without HT, disabling both\n"); |
| 3098 | cbss->channel->center_freq, | 3495 | sdata->flags |= IEEE80211_STA_DISABLE_HT; |
| 3099 | ht_cfreq, ht_oper->primary_chan, | 3496 | sdata->flags |= IEEE80211_STA_DISABLE_VHT; |
| 3100 | cbss->channel->band); | ||
| 3101 | ht_oper = NULL; | ||
| 3102 | } else { | ||
| 3103 | channel_type = NL80211_CHAN_HT20; | ||
| 3104 | } | 3497 | } |
| 3105 | } | 3498 | } |
| 3106 | 3499 | ||
| 3107 | if (ht_oper && sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | 3500 | ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, |
| 3108 | /* | 3501 | cbss->channel, |
| 3109 | * cfg80211 already verified that the channel itself can | 3502 | ht_oper, vht_oper, |
| 3110 | * be used, but it didn't check that we can do the right | 3503 | &chandef); |
| 3111 | * HT type, so do that here as well. If HT40 isn't allowed | ||
| 3112 | * on this channel, disable 40 MHz operation. | ||
| 3113 | */ | ||
| 3114 | 3504 | ||
| 3115 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 3505 | sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), |
| 3116 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 3506 | local->rx_chains); |
| 3117 | if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
| 3118 | ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; | ||
| 3119 | else | ||
| 3120 | channel_type = NL80211_CHAN_HT40PLUS; | ||
| 3121 | break; | ||
| 3122 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
| 3123 | if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
| 3124 | ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; | ||
| 3125 | else | ||
| 3126 | channel_type = NL80211_CHAN_HT40MINUS; | ||
| 3127 | break; | ||
| 3128 | } | ||
| 3129 | } | ||
| 3130 | 3507 | ||
| 3131 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) { | 3508 | rcu_read_unlock(); |
| 3132 | /* can only fail due to HT40+/- mismatch */ | ||
| 3133 | channel_type = NL80211_CHAN_HT20; | ||
| 3134 | sdata_info(sdata, | ||
| 3135 | "disabling 40 MHz due to multi-vif mismatch\n"); | ||
| 3136 | ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; | ||
| 3137 | WARN_ON(!ieee80211_set_channel_type(local, sdata, | ||
| 3138 | channel_type)); | ||
| 3139 | } | ||
| 3140 | 3509 | ||
| 3141 | local->oper_channel = cbss->channel; | 3510 | /* will change later if needed */ |
| 3142 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 3511 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 3143 | 3512 | ||
| 3144 | return 0; | 3513 | /* |
| 3514 | * If this fails (possibly due to channel context sharing | ||
| 3515 | * on incompatible channels, e.g. 80+80 and 160 sharing the | ||
| 3516 | * same control channel) try to use a smaller bandwidth. | ||
| 3517 | */ | ||
| 3518 | ret = ieee80211_vif_use_channel(sdata, &chandef, | ||
| 3519 | IEEE80211_CHANCTX_SHARED); | ||
| 3520 | while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) | ||
| 3521 | ifmgd->flags |= chandef_downgrade(&chandef); | ||
| 3522 | return ret; | ||
| 3145 | } | 3523 | } |
| 3146 | 3524 | ||
| 3147 | static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | 3525 | static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, |
| @@ -3211,7 +3589,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
| 3211 | sdata->vif.bss_conf.basic_rates = basic_rates; | 3589 | sdata->vif.bss_conf.basic_rates = basic_rates; |
| 3212 | 3590 | ||
| 3213 | /* cf. IEEE 802.11 9.2.12 */ | 3591 | /* cf. IEEE 802.11 9.2.12 */ |
| 3214 | if (local->oper_channel->band == IEEE80211_BAND_2GHZ && | 3592 | if (cbss->channel->band == IEEE80211_BAND_2GHZ && |
| 3215 | have_higher_than_11mbit) | 3593 | have_higher_than_11mbit) |
| 3216 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 3594 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
| 3217 | else | 3595 | else |
| @@ -3273,19 +3651,33 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
| 3273 | case NL80211_AUTHTYPE_NETWORK_EAP: | 3651 | case NL80211_AUTHTYPE_NETWORK_EAP: |
| 3274 | auth_alg = WLAN_AUTH_LEAP; | 3652 | auth_alg = WLAN_AUTH_LEAP; |
| 3275 | break; | 3653 | break; |
| 3654 | case NL80211_AUTHTYPE_SAE: | ||
| 3655 | auth_alg = WLAN_AUTH_SAE; | ||
| 3656 | break; | ||
| 3276 | default: | 3657 | default: |
| 3277 | return -EOPNOTSUPP; | 3658 | return -EOPNOTSUPP; |
| 3278 | } | 3659 | } |
| 3279 | 3660 | ||
| 3280 | auth_data = kzalloc(sizeof(*auth_data) + req->ie_len, GFP_KERNEL); | 3661 | auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len + |
| 3662 | req->ie_len, GFP_KERNEL); | ||
| 3281 | if (!auth_data) | 3663 | if (!auth_data) |
| 3282 | return -ENOMEM; | 3664 | return -ENOMEM; |
| 3283 | 3665 | ||
| 3284 | auth_data->bss = req->bss; | 3666 | auth_data->bss = req->bss; |
| 3285 | 3667 | ||
| 3668 | if (req->sae_data_len >= 4) { | ||
| 3669 | __le16 *pos = (__le16 *) req->sae_data; | ||
| 3670 | auth_data->sae_trans = le16_to_cpu(pos[0]); | ||
| 3671 | auth_data->sae_status = le16_to_cpu(pos[1]); | ||
| 3672 | memcpy(auth_data->data, req->sae_data + 4, | ||
| 3673 | req->sae_data_len - 4); | ||
| 3674 | auth_data->data_len += req->sae_data_len - 4; | ||
| 3675 | } | ||
| 3676 | |||
| 3286 | if (req->ie && req->ie_len) { | 3677 | if (req->ie && req->ie_len) { |
| 3287 | memcpy(auth_data->ie, req->ie, req->ie_len); | 3678 | memcpy(&auth_data->data[auth_data->data_len], |
| 3288 | auth_data->ie_len = req->ie_len; | 3679 | req->ie, req->ie_len); |
| 3680 | auth_data->data_len += req->ie_len; | ||
| 3289 | } | 3681 | } |
| 3290 | 3682 | ||
| 3291 | if (req->key && req->key_len) { | 3683 | if (req->key && req->key_len) { |
| @@ -3355,14 +3747,21 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3355 | const u8 *ssidie, *ht_ie; | 3747 | const u8 *ssidie, *ht_ie; |
| 3356 | int i, err; | 3748 | int i, err; |
| 3357 | 3749 | ||
| 3358 | ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | ||
| 3359 | if (!ssidie) | ||
| 3360 | return -EINVAL; | ||
| 3361 | |||
| 3362 | assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); | 3750 | assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); |
| 3363 | if (!assoc_data) | 3751 | if (!assoc_data) |
| 3364 | return -ENOMEM; | 3752 | return -ENOMEM; |
| 3365 | 3753 | ||
| 3754 | rcu_read_lock(); | ||
| 3755 | ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | ||
| 3756 | if (!ssidie) { | ||
| 3757 | rcu_read_unlock(); | ||
| 3758 | kfree(assoc_data); | ||
| 3759 | return -EINVAL; | ||
| 3760 | } | ||
| 3761 | memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]); | ||
| 3762 | assoc_data->ssid_len = ssidie[1]; | ||
| 3763 | rcu_read_unlock(); | ||
| 3764 | |||
| 3366 | mutex_lock(&ifmgd->mtx); | 3765 | mutex_lock(&ifmgd->mtx); |
| 3367 | 3766 | ||
| 3368 | if (ifmgd->associated) | 3767 | if (ifmgd->associated) |
| @@ -3388,13 +3787,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3388 | 3787 | ||
| 3389 | /* prepare assoc data */ | 3788 | /* prepare assoc data */ |
| 3390 | 3789 | ||
| 3391 | /* | ||
| 3392 | * keep only the 40 MHz disable bit set as it might have | ||
| 3393 | * been set during authentication already, all other bits | ||
| 3394 | * should be reset for a new connection | ||
| 3395 | */ | ||
| 3396 | ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ; | ||
| 3397 | |||
| 3398 | ifmgd->beacon_crc_valid = false; | 3790 | ifmgd->beacon_crc_valid = false; |
| 3399 | 3791 | ||
| 3400 | /* | 3792 | /* |
| @@ -3408,7 +3800,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3408 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | 3800 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || |
| 3409 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || | 3801 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || |
| 3410 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { | 3802 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) { |
| 3411 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3803 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3412 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 3804 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
| 3413 | netdev_info(sdata->dev, | 3805 | netdev_info(sdata->dev, |
| 3414 | "disabling HT/VHT due to WEP/TKIP use\n"); | 3806 | "disabling HT/VHT due to WEP/TKIP use\n"); |
| @@ -3416,7 +3808,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3416 | } | 3808 | } |
| 3417 | 3809 | ||
| 3418 | if (req->flags & ASSOC_REQ_DISABLE_HT) { | 3810 | if (req->flags & ASSOC_REQ_DISABLE_HT) { |
| 3419 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3811 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3420 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 3812 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
| 3421 | } | 3813 | } |
| 3422 | 3814 | ||
| @@ -3424,7 +3816,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3424 | sband = local->hw.wiphy->bands[req->bss->channel->band]; | 3816 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
| 3425 | if (!sband->ht_cap.ht_supported || | 3817 | if (!sband->ht_cap.ht_supported || |
| 3426 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | 3818 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { |
| 3427 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3819 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3428 | if (!bss->wmm_used) | 3820 | if (!bss->wmm_used) |
| 3429 | netdev_info(sdata->dev, | 3821 | netdev_info(sdata->dev, |
| 3430 | "disabling HT as WMM/QoS is not supported by the AP\n"); | 3822 | "disabling HT as WMM/QoS is not supported by the AP\n"); |
| @@ -3452,11 +3844,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3452 | 3844 | ||
| 3453 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { | 3845 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { |
| 3454 | if (ifmgd->powersave) | 3846 | if (ifmgd->powersave) |
| 3455 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; | 3847 | sdata->smps_mode = IEEE80211_SMPS_DYNAMIC; |
| 3456 | else | 3848 | else |
| 3457 | ifmgd->ap_smps = IEEE80211_SMPS_OFF; | 3849 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 3458 | } else | 3850 | } else |
| 3459 | ifmgd->ap_smps = ifmgd->req_smps; | 3851 | sdata->smps_mode = ifmgd->req_smps; |
| 3460 | 3852 | ||
| 3461 | assoc_data->capability = req->bss->capability; | 3853 | assoc_data->capability = req->bss->capability; |
| 3462 | assoc_data->wmm = bss->wmm_used && | 3854 | assoc_data->wmm = bss->wmm_used && |
| @@ -3464,12 +3856,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3464 | assoc_data->supp_rates = bss->supp_rates; | 3856 | assoc_data->supp_rates = bss->supp_rates; |
| 3465 | assoc_data->supp_rates_len = bss->supp_rates_len; | 3857 | assoc_data->supp_rates_len = bss->supp_rates_len; |
| 3466 | 3858 | ||
| 3859 | rcu_read_lock(); | ||
| 3467 | ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); | 3860 | ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); |
| 3468 | if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation)) | 3861 | if (ht_ie && ht_ie[1] >= sizeof(struct ieee80211_ht_operation)) |
| 3469 | assoc_data->ap_ht_param = | 3862 | assoc_data->ap_ht_param = |
| 3470 | ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; | 3863 | ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param; |
| 3471 | else | 3864 | else |
| 3472 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3865 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
| 3866 | rcu_read_unlock(); | ||
| 3473 | 3867 | ||
| 3474 | if (bss->wmm_used && bss->uapsd_supported && | 3868 | if (bss->wmm_used && bss->uapsd_supported && |
| 3475 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | 3869 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { |
| @@ -3480,9 +3874,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
| 3480 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; | 3874 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; |
| 3481 | } | 3875 | } |
| 3482 | 3876 | ||
| 3483 | memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]); | ||
| 3484 | assoc_data->ssid_len = ssidie[1]; | ||
| 3485 | |||
| 3486 | if (req->prev_bssid) | 3877 | if (req->prev_bssid) |
| 3487 | memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN); | 3878 | memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN); |
| 3488 | 3879 | ||
| @@ -3560,40 +3951,44 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
| 3560 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3951 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
| 3561 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 3952 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
| 3562 | bool tx = !req->local_state_change; | 3953 | bool tx = !req->local_state_change; |
| 3954 | bool sent_frame = false; | ||
| 3563 | 3955 | ||
| 3564 | mutex_lock(&ifmgd->mtx); | 3956 | mutex_lock(&ifmgd->mtx); |
| 3565 | 3957 | ||
| 3566 | if (ifmgd->auth_data) { | ||
| 3567 | ieee80211_destroy_auth_data(sdata, false); | ||
| 3568 | mutex_unlock(&ifmgd->mtx); | ||
| 3569 | return 0; | ||
| 3570 | } | ||
| 3571 | |||
| 3572 | sdata_info(sdata, | 3958 | sdata_info(sdata, |
| 3573 | "deauthenticating from %pM by local choice (reason=%d)\n", | 3959 | "deauthenticating from %pM by local choice (reason=%d)\n", |
| 3574 | req->bssid, req->reason_code); | 3960 | req->bssid, req->reason_code); |
| 3575 | 3961 | ||
| 3576 | if (ifmgd->associated && | 3962 | if (ifmgd->auth_data) { |
| 3577 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | ||
| 3578 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||
| 3579 | req->reason_code, tx, frame_buf); | ||
| 3580 | } else { | ||
| 3581 | drv_mgd_prepare_tx(sdata->local, sdata); | 3963 | drv_mgd_prepare_tx(sdata->local, sdata); |
| 3582 | ieee80211_send_deauth_disassoc(sdata, req->bssid, | 3964 | ieee80211_send_deauth_disassoc(sdata, req->bssid, |
| 3583 | IEEE80211_STYPE_DEAUTH, | 3965 | IEEE80211_STYPE_DEAUTH, |
| 3584 | req->reason_code, tx, | 3966 | req->reason_code, tx, |
| 3585 | frame_buf); | 3967 | frame_buf); |
| 3968 | ieee80211_destroy_auth_data(sdata, false); | ||
| 3969 | mutex_unlock(&ifmgd->mtx); | ||
| 3970 | |||
| 3971 | sent_frame = tx; | ||
| 3972 | goto out; | ||
| 3586 | } | 3973 | } |
| 3587 | 3974 | ||
| 3975 | if (ifmgd->associated && | ||
| 3976 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | ||
| 3977 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||
| 3978 | req->reason_code, tx, frame_buf); | ||
| 3979 | sent_frame = tx; | ||
| 3980 | } | ||
| 3588 | mutex_unlock(&ifmgd->mtx); | 3981 | mutex_unlock(&ifmgd->mtx); |
| 3589 | 3982 | ||
| 3590 | __cfg80211_send_deauth(sdata->dev, frame_buf, | 3983 | out: |
| 3591 | IEEE80211_DEAUTH_FRAME_LEN); | ||
| 3592 | |||
| 3593 | mutex_lock(&sdata->local->mtx); | 3984 | mutex_lock(&sdata->local->mtx); |
| 3594 | ieee80211_recalc_idle(sdata->local); | 3985 | ieee80211_recalc_idle(sdata->local); |
| 3595 | mutex_unlock(&sdata->local->mtx); | 3986 | mutex_unlock(&sdata->local->mtx); |
| 3596 | 3987 | ||
| 3988 | if (sent_frame) | ||
| 3989 | __cfg80211_send_deauth(sdata->dev, frame_buf, | ||
| 3990 | IEEE80211_DEAUTH_FRAME_LEN); | ||
| 3991 | |||
| 3597 | return 0; | 3992 | return 0; |
| 3598 | } | 3993 | } |
| 3599 | 3994 | ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 2c84185dfdb0..a5379aea7d09 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
| @@ -107,6 +107,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, | |||
| 107 | { | 107 | { |
| 108 | struct ieee80211_sub_if_data *sdata; | 108 | struct ieee80211_sub_if_data *sdata; |
| 109 | 109 | ||
| 110 | if (WARN_ON(local->use_chanctx)) | ||
| 111 | return; | ||
| 112 | |||
| 110 | /* | 113 | /* |
| 111 | * notify the AP about us leaving the channel and stop all | 114 | * notify the AP about us leaving the channel and stop all |
| 112 | * STA interfaces. | 115 | * STA interfaces. |
| @@ -145,6 +148,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
| 145 | { | 148 | { |
| 146 | struct ieee80211_sub_if_data *sdata; | 149 | struct ieee80211_sub_if_data *sdata; |
| 147 | 150 | ||
| 151 | if (WARN_ON(local->use_chanctx)) | ||
| 152 | return; | ||
| 153 | |||
| 148 | mutex_lock(&local->iflist_mtx); | 154 | mutex_lock(&local->iflist_mtx); |
| 149 | list_for_each_entry(sdata, &local->interfaces, list) { | 155 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 150 | if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | 156 | if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) |
| @@ -193,13 +199,14 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) | |||
| 193 | 199 | ||
| 194 | if (roc->mgmt_tx_cookie) { | 200 | if (roc->mgmt_tx_cookie) { |
| 195 | if (!WARN_ON(!roc->frame)) { | 201 | if (!WARN_ON(!roc->frame)) { |
| 196 | ieee80211_tx_skb(roc->sdata, roc->frame); | 202 | ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7, |
| 203 | roc->chan->band); | ||
| 197 | roc->frame = NULL; | 204 | roc->frame = NULL; |
| 198 | } | 205 | } |
| 199 | } else { | 206 | } else { |
| 200 | cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, | 207 | cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie, |
| 201 | roc->chan, roc->chan_type, | 208 | roc->chan, roc->req_duration, |
| 202 | roc->req_duration, GFP_KERNEL); | 209 | GFP_KERNEL); |
| 203 | } | 210 | } |
| 204 | 211 | ||
| 205 | roc->notified = true; | 212 | roc->notified = true; |
| @@ -276,8 +283,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) | |||
| 276 | if (!duration) | 283 | if (!duration) |
| 277 | duration = 10; | 284 | duration = 10; |
| 278 | 285 | ||
| 279 | ret = drv_remain_on_channel(local, roc->chan, | 286 | ret = drv_remain_on_channel(local, roc->sdata, roc->chan, |
| 280 | roc->chan_type, | ||
| 281 | duration); | 287 | duration); |
| 282 | 288 | ||
| 283 | roc->started = true; | 289 | roc->started = true; |
| @@ -313,8 +319,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) | |||
| 313 | 319 | ||
| 314 | if (!roc->mgmt_tx_cookie) | 320 | if (!roc->mgmt_tx_cookie) |
| 315 | cfg80211_remain_on_channel_expired(&roc->sdata->wdev, | 321 | cfg80211_remain_on_channel_expired(&roc->sdata->wdev, |
| 316 | (unsigned long)roc, | 322 | roc->cookie, roc->chan, |
| 317 | roc->chan, roc->chan_type, | ||
| 318 | GFP_KERNEL); | 323 | GFP_KERNEL); |
| 319 | 324 | ||
| 320 | list_for_each_entry_safe(dep, tmp, &roc->dependents, list) | 325 | list_for_each_entry_safe(dep, tmp, &roc->dependents, list) |
| @@ -353,7 +358,6 @@ void ieee80211_sw_roc_work(struct work_struct *work) | |||
| 353 | ieee80211_recalc_idle(local); | 358 | ieee80211_recalc_idle(local); |
| 354 | 359 | ||
| 355 | local->tmp_channel = roc->chan; | 360 | local->tmp_channel = roc->chan; |
| 356 | local->tmp_channel_type = roc->chan_type; | ||
| 357 | ieee80211_hw_config(local, 0); | 361 | ieee80211_hw_config(local, 0); |
| 358 | 362 | ||
| 359 | /* tell userspace or send frame */ | 363 | /* tell userspace or send frame */ |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 5c572e7a1a71..79a48f37d409 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
| @@ -33,6 +33,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 33 | struct ieee80211_local *local = hw_to_local(hw); | 33 | struct ieee80211_local *local = hw_to_local(hw); |
| 34 | struct ieee80211_sub_if_data *sdata; | 34 | struct ieee80211_sub_if_data *sdata; |
| 35 | struct sta_info *sta; | 35 | struct sta_info *sta; |
| 36 | struct ieee80211_chanctx *ctx; | ||
| 36 | 37 | ||
| 37 | if (!local->open_count) | 38 | if (!local->open_count) |
| 38 | goto suspend; | 39 | goto suspend; |
| @@ -135,12 +136,55 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 135 | ieee80211_bss_info_change_notify(sdata, | 136 | ieee80211_bss_info_change_notify(sdata, |
| 136 | BSS_CHANGED_BEACON_ENABLED); | 137 | BSS_CHANGED_BEACON_ENABLED); |
| 137 | 138 | ||
| 139 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
| 140 | rcu_access_pointer(sdata->u.ap.beacon)) | ||
| 141 | drv_stop_ap(local, sdata); | ||
| 142 | |||
| 143 | if (local->use_chanctx) { | ||
| 144 | struct ieee80211_chanctx_conf *conf; | ||
| 145 | |||
| 146 | mutex_lock(&local->chanctx_mtx); | ||
| 147 | conf = rcu_dereference_protected( | ||
| 148 | sdata->vif.chanctx_conf, | ||
| 149 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 150 | if (conf) { | ||
| 151 | ctx = container_of(conf, | ||
| 152 | struct ieee80211_chanctx, | ||
| 153 | conf); | ||
| 154 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
| 155 | } | ||
| 156 | |||
| 157 | mutex_unlock(&local->chanctx_mtx); | ||
| 158 | } | ||
| 138 | drv_remove_interface(local, sdata); | 159 | drv_remove_interface(local, sdata); |
| 139 | } | 160 | } |
| 140 | 161 | ||
| 141 | sdata = rtnl_dereference(local->monitor_sdata); | 162 | sdata = rtnl_dereference(local->monitor_sdata); |
| 142 | if (sdata) | 163 | if (sdata) { |
| 164 | if (local->use_chanctx) { | ||
| 165 | struct ieee80211_chanctx_conf *conf; | ||
| 166 | |||
| 167 | mutex_lock(&local->chanctx_mtx); | ||
| 168 | conf = rcu_dereference_protected( | ||
| 169 | sdata->vif.chanctx_conf, | ||
| 170 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 171 | if (conf) { | ||
| 172 | ctx = container_of(conf, | ||
| 173 | struct ieee80211_chanctx, | ||
| 174 | conf); | ||
| 175 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
| 176 | } | ||
| 177 | |||
| 178 | mutex_unlock(&local->chanctx_mtx); | ||
| 179 | } | ||
| 180 | |||
| 143 | drv_remove_interface(local, sdata); | 181 | drv_remove_interface(local, sdata); |
| 182 | } | ||
| 183 | |||
| 184 | mutex_lock(&local->chanctx_mtx); | ||
| 185 | list_for_each_entry(ctx, &local->chanctx_list, list) | ||
| 186 | drv_remove_chanctx(local, ctx); | ||
| 187 | mutex_unlock(&local->chanctx_mtx); | ||
| 144 | 188 | ||
| 145 | /* stop hardware - this must stop RX */ | 189 | /* stop hardware - this must stop RX */ |
| 146 | if (local->open_count) | 190 | if (local->open_count) |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 3313c117b322..dd88381c53b7 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
| @@ -391,7 +391,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
| 391 | return; | 391 | return; |
| 392 | 392 | ||
| 393 | /* if HT BSS, and we handle a data frame, also try HT rates */ | 393 | /* if HT BSS, and we handle a data frame, also try HT rates */ |
| 394 | if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT) | 394 | if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 395 | return; | 395 | return; |
| 396 | 396 | ||
| 397 | fc = hdr->frame_control; | 397 | fc = hdr->frame_control; |
| @@ -408,8 +408,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
| 408 | 408 | ||
| 409 | alt_rate.flags |= IEEE80211_TX_RC_MCS; | 409 | alt_rate.flags |= IEEE80211_TX_RC_MCS; |
| 410 | 410 | ||
| 411 | if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) || | 411 | if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_40) |
| 412 | (txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS)) | ||
| 413 | alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 412 | alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
| 414 | 413 | ||
| 415 | if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) { | 414 | if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) { |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 10de668eb9f6..301386dabf88 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
| @@ -52,11 +52,21 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
| 52 | struct ieee80211_sta *ista = &sta->sta; | 52 | struct ieee80211_sta *ista = &sta->sta; |
| 53 | void *priv_sta = sta->rate_ctrl_priv; | 53 | void *priv_sta = sta->rate_ctrl_priv; |
| 54 | struct ieee80211_supported_band *sband; | 54 | struct ieee80211_supported_band *sband; |
| 55 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 55 | 56 | ||
| 56 | if (!ref) | 57 | if (!ref) |
| 57 | return; | 58 | return; |
| 58 | 59 | ||
| 59 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 60 | rcu_read_lock(); |
| 61 | |||
| 62 | chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); | ||
| 63 | if (WARN_ON(!chanctx_conf)) { | ||
| 64 | rcu_read_unlock(); | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | |||
| 68 | sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; | ||
| 69 | rcu_read_unlock(); | ||
| 60 | 70 | ||
| 61 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 71 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); |
| 62 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); | 72 | set_sta_flag(sta, WLAN_STA_RATE_CONTROL); |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 79633ae06fd6..8c5acdc06226 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
| @@ -154,6 +154,7 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 154 | struct ieee80211_sta *sta, void *priv_sta, | 154 | struct ieee80211_sta *sta, void *priv_sta, |
| 155 | struct sk_buff *skb) | 155 | struct sk_buff *skb) |
| 156 | { | 156 | { |
| 157 | struct minstrel_priv *mp = priv; | ||
| 157 | struct minstrel_sta_info *mi = priv_sta; | 158 | struct minstrel_sta_info *mi = priv_sta; |
| 158 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 159 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 159 | struct ieee80211_tx_rate *ar = info->status.rates; | 160 | struct ieee80211_tx_rate *ar = info->status.rates; |
| @@ -181,6 +182,10 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 181 | 182 | ||
| 182 | if (mi->sample_deferred > 0) | 183 | if (mi->sample_deferred > 0) |
| 183 | mi->sample_deferred--; | 184 | mi->sample_deferred--; |
| 185 | |||
| 186 | if (time_after(jiffies, mi->stats_update + | ||
| 187 | (mp->update_interval * HZ) / 1000)) | ||
| 188 | minstrel_update_stats(mp, mi); | ||
| 184 | } | 189 | } |
| 185 | 190 | ||
| 186 | 191 | ||
| @@ -235,10 +240,6 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
| 235 | 240 | ||
| 236 | mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot; | 241 | mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot; |
| 237 | 242 | ||
| 238 | if (time_after(jiffies, mi->stats_update + (mp->update_interval * | ||
| 239 | HZ) / 1000)) | ||
| 240 | minstrel_update_stats(mp, mi); | ||
| 241 | |||
| 242 | ndx = mi->max_tp_rate; | 243 | ndx = mi->max_tp_rate; |
| 243 | 244 | ||
| 244 | if (mrr) | 245 | if (mrr) |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index fb1d4aa65e8c..9f9c453bc45d 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
| @@ -389,9 +389,9 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 389 | struct ieee80211_tx_rate *ar = info->status.rates; | 389 | struct ieee80211_tx_rate *ar = info->status.rates; |
| 390 | struct minstrel_rate_stats *rate, *rate2; | 390 | struct minstrel_rate_stats *rate, *rate2; |
| 391 | struct minstrel_priv *mp = priv; | 391 | struct minstrel_priv *mp = priv; |
| 392 | bool last = false; | 392 | bool last; |
| 393 | int group; | 393 | int group; |
| 394 | int i = 0; | 394 | int i; |
| 395 | 395 | ||
| 396 | if (!msp->is_ht) | 396 | if (!msp->is_ht) |
| 397 | return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb); | 397 | return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb); |
| @@ -419,13 +419,11 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 419 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) | 419 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) |
| 420 | mi->sample_packets += info->status.ampdu_len; | 420 | mi->sample_packets += info->status.ampdu_len; |
| 421 | 421 | ||
| 422 | last = !minstrel_ht_txstat_valid(&ar[0]); | ||
| 422 | for (i = 0; !last; i++) { | 423 | for (i = 0; !last; i++) { |
| 423 | last = (i == IEEE80211_TX_MAX_RATES - 1) || | 424 | last = (i == IEEE80211_TX_MAX_RATES - 1) || |
| 424 | !minstrel_ht_txstat_valid(&ar[i + 1]); | 425 | !minstrel_ht_txstat_valid(&ar[i + 1]); |
| 425 | 426 | ||
| 426 | if (!minstrel_ht_txstat_valid(&ar[i])) | ||
| 427 | break; | ||
| 428 | |||
| 429 | group = minstrel_ht_get_group_idx(&ar[i]); | 427 | group = minstrel_ht_get_group_idx(&ar[i]); |
| 430 | rate = &mi->groups[group].rates[ar[i].idx % 8]; | 428 | rate = &mi->groups[group].rates[ar[i].idx % 8]; |
| 431 | 429 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 00ade7feb2e3..580704eba8b8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -40,6 +40,8 @@ | |||
| 40 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | 40 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, |
| 41 | struct sk_buff *skb) | 41 | struct sk_buff *skb) |
| 42 | { | 42 | { |
| 43 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | ||
| 44 | |||
| 43 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 45 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
| 44 | if (likely(skb->len > FCS_LEN)) | 46 | if (likely(skb->len > FCS_LEN)) |
| 45 | __pskb_trim(skb, skb->len - FCS_LEN); | 47 | __pskb_trim(skb, skb->len - FCS_LEN); |
| @@ -47,24 +49,29 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
| 47 | /* driver bug */ | 49 | /* driver bug */ |
| 48 | WARN_ON(1); | 50 | WARN_ON(1); |
| 49 | dev_kfree_skb(skb); | 51 | dev_kfree_skb(skb); |
| 50 | skb = NULL; | 52 | return NULL; |
| 51 | } | 53 | } |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 56 | if (status->vendor_radiotap_len) | ||
| 57 | __pskb_pull(skb, status->vendor_radiotap_len); | ||
| 58 | |||
| 54 | return skb; | 59 | return skb; |
| 55 | } | 60 | } |
| 56 | 61 | ||
| 57 | static inline int should_drop_frame(struct sk_buff *skb, | 62 | static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) |
| 58 | int present_fcs_len) | ||
| 59 | { | 63 | { |
| 60 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 64 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
| 61 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 65 | struct ieee80211_hdr *hdr; |
| 66 | |||
| 67 | hdr = (void *)(skb->data + status->vendor_radiotap_len); | ||
| 62 | 68 | ||
| 63 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | 69 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
| 64 | RX_FLAG_FAILED_PLCP_CRC | | 70 | RX_FLAG_FAILED_PLCP_CRC | |
| 65 | RX_FLAG_AMPDU_IS_ZEROLEN)) | 71 | RX_FLAG_AMPDU_IS_ZEROLEN)) |
| 66 | return 1; | 72 | return 1; |
| 67 | if (unlikely(skb->len < 16 + present_fcs_len)) | 73 | if (unlikely(skb->len < 16 + present_fcs_len + |
| 74 | status->vendor_radiotap_len)) | ||
| 68 | return 1; | 75 | return 1; |
| 69 | if (ieee80211_is_ctl(hdr->frame_control) && | 76 | if (ieee80211_is_ctl(hdr->frame_control) && |
| 70 | !ieee80211_is_pspoll(hdr->frame_control) && | 77 | !ieee80211_is_pspoll(hdr->frame_control) && |
| @@ -74,32 +81,53 @@ static inline int should_drop_frame(struct sk_buff *skb, | |||
| 74 | } | 81 | } |
| 75 | 82 | ||
| 76 | static int | 83 | static int |
| 77 | ieee80211_rx_radiotap_len(struct ieee80211_local *local, | 84 | ieee80211_rx_radiotap_space(struct ieee80211_local *local, |
| 78 | struct ieee80211_rx_status *status) | 85 | struct ieee80211_rx_status *status) |
| 79 | { | 86 | { |
| 80 | int len; | 87 | int len; |
| 81 | 88 | ||
| 82 | /* always present fields */ | 89 | /* always present fields */ |
| 83 | len = sizeof(struct ieee80211_radiotap_header) + 9; | 90 | len = sizeof(struct ieee80211_radiotap_header) + 9; |
| 84 | 91 | ||
| 85 | if (status->flag & RX_FLAG_MACTIME_MPDU) | 92 | /* allocate extra bitmap */ |
| 93 | if (status->vendor_radiotap_len) | ||
| 94 | len += 4; | ||
| 95 | |||
| 96 | if (ieee80211_have_rx_timestamp(status)) { | ||
| 97 | len = ALIGN(len, 8); | ||
| 86 | len += 8; | 98 | len += 8; |
| 99 | } | ||
| 87 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | 100 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
| 88 | len += 1; | 101 | len += 1; |
| 89 | 102 | ||
| 90 | if (len & 1) /* padding for RX_FLAGS if necessary */ | 103 | /* padding for RX_FLAGS if necessary */ |
| 91 | len++; | 104 | len = ALIGN(len, 2); |
| 92 | 105 | ||
| 93 | if (status->flag & RX_FLAG_HT) /* HT info */ | 106 | if (status->flag & RX_FLAG_HT) /* HT info */ |
| 94 | len += 3; | 107 | len += 3; |
| 95 | 108 | ||
| 96 | if (status->flag & RX_FLAG_AMPDU_DETAILS) { | 109 | if (status->flag & RX_FLAG_AMPDU_DETAILS) { |
| 97 | /* padding */ | 110 | len = ALIGN(len, 4); |
| 98 | while (len & 3) | ||
| 99 | len++; | ||
| 100 | len += 8; | 111 | len += 8; |
| 101 | } | 112 | } |
| 102 | 113 | ||
| 114 | if (status->flag & RX_FLAG_VHT) { | ||
| 115 | len = ALIGN(len, 2); | ||
| 116 | len += 12; | ||
| 117 | } | ||
| 118 | |||
| 119 | if (status->vendor_radiotap_len) { | ||
| 120 | if (WARN_ON_ONCE(status->vendor_radiotap_align == 0)) | ||
| 121 | status->vendor_radiotap_align = 1; | ||
| 122 | /* align standard part of vendor namespace */ | ||
| 123 | len = ALIGN(len, 2); | ||
| 124 | /* allocate standard part of vendor namespace */ | ||
| 125 | len += 6; | ||
| 126 | /* align vendor-defined part */ | ||
| 127 | len = ALIGN(len, status->vendor_radiotap_align); | ||
| 128 | /* vendor-defined part is already in skb */ | ||
| 129 | } | ||
| 130 | |||
| 103 | return len; | 131 | return len; |
| 104 | } | 132 | } |
| 105 | 133 | ||
| @@ -118,6 +146,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 118 | struct ieee80211_radiotap_header *rthdr; | 146 | struct ieee80211_radiotap_header *rthdr; |
| 119 | unsigned char *pos; | 147 | unsigned char *pos; |
| 120 | u16 rx_flags = 0; | 148 | u16 rx_flags = 0; |
| 149 | int mpdulen; | ||
| 150 | |||
| 151 | mpdulen = skb->len; | ||
| 152 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) | ||
| 153 | mpdulen += FCS_LEN; | ||
| 121 | 154 | ||
| 122 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); | 155 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); |
| 123 | memset(rthdr, 0, rtap_len); | 156 | memset(rthdr, 0, rtap_len); |
| @@ -128,17 +161,30 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 128 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | 161 | (1 << IEEE80211_RADIOTAP_CHANNEL) | |
| 129 | (1 << IEEE80211_RADIOTAP_ANTENNA) | | 162 | (1 << IEEE80211_RADIOTAP_ANTENNA) | |
| 130 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | 163 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); |
| 131 | rthdr->it_len = cpu_to_le16(rtap_len); | 164 | rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len); |
| 132 | 165 | ||
| 133 | pos = (unsigned char *)(rthdr+1); | 166 | pos = (unsigned char *)(rthdr + 1); |
| 167 | |||
| 168 | if (status->vendor_radiotap_len) { | ||
| 169 | rthdr->it_present |= | ||
| 170 | cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) | | ||
| 171 | cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT)); | ||
| 172 | put_unaligned_le32(status->vendor_radiotap_bitmap, pos); | ||
| 173 | pos += 4; | ||
| 174 | } | ||
| 134 | 175 | ||
| 135 | /* the order of the following fields is important */ | 176 | /* the order of the following fields is important */ |
| 136 | 177 | ||
| 137 | /* IEEE80211_RADIOTAP_TSFT */ | 178 | /* IEEE80211_RADIOTAP_TSFT */ |
| 138 | if (status->flag & RX_FLAG_MACTIME_MPDU) { | 179 | if (ieee80211_have_rx_timestamp(status)) { |
| 139 | put_unaligned_le64(status->mactime, pos); | 180 | /* padding */ |
| 140 | rthdr->it_present |= | 181 | while ((pos - (u8 *)rthdr) & 7) |
| 141 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | 182 | *pos++ = 0; |
| 183 | put_unaligned_le64( | ||
| 184 | ieee80211_calculate_rx_timestamp(local, status, | ||
| 185 | mpdulen, 0), | ||
| 186 | pos); | ||
| 187 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | ||
| 142 | pos += 8; | 188 | pos += 8; |
| 143 | } | 189 | } |
| 144 | 190 | ||
| @@ -152,7 +198,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 152 | pos++; | 198 | pos++; |
| 153 | 199 | ||
| 154 | /* IEEE80211_RADIOTAP_RATE */ | 200 | /* IEEE80211_RADIOTAP_RATE */ |
| 155 | if (!rate || status->flag & RX_FLAG_HT) { | 201 | if (!rate || status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) { |
| 156 | /* | 202 | /* |
| 157 | * Without rate information don't add it. If we have, | 203 | * Without rate information don't add it. If we have, |
| 158 | * MCS information is a separate field in radiotap, | 204 | * MCS information is a separate field in radiotap, |
| @@ -172,7 +218,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 172 | if (status->band == IEEE80211_BAND_5GHZ) | 218 | if (status->band == IEEE80211_BAND_5GHZ) |
| 173 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, | 219 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, |
| 174 | pos); | 220 | pos); |
| 175 | else if (status->flag & RX_FLAG_HT) | 221 | else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) |
| 176 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, | 222 | put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, |
| 177 | pos); | 223 | pos); |
| 178 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) | 224 | else if (rate && rate->flags & IEEE80211_RATE_ERP_G) |
| @@ -205,7 +251,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 205 | /* IEEE80211_RADIOTAP_RX_FLAGS */ | 251 | /* IEEE80211_RADIOTAP_RX_FLAGS */ |
| 206 | /* ensure 2 byte alignment for the 2 byte field as required */ | 252 | /* ensure 2 byte alignment for the 2 byte field as required */ |
| 207 | if ((pos - (u8 *)rthdr) & 1) | 253 | if ((pos - (u8 *)rthdr) & 1) |
| 208 | pos++; | 254 | *pos++ = 0; |
| 209 | if (status->flag & RX_FLAG_FAILED_PLCP_CRC) | 255 | if (status->flag & RX_FLAG_FAILED_PLCP_CRC) |
| 210 | rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; | 256 | rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP; |
| 211 | put_unaligned_le16(rx_flags, pos); | 257 | put_unaligned_le16(rx_flags, pos); |
| @@ -255,6 +301,56 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 255 | *pos++ = 0; | 301 | *pos++ = 0; |
| 256 | *pos++ = 0; | 302 | *pos++ = 0; |
| 257 | } | 303 | } |
| 304 | |||
| 305 | if (status->flag & RX_FLAG_VHT) { | ||
| 306 | u16 known = local->hw.radiotap_vht_details; | ||
| 307 | |||
| 308 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); | ||
| 309 | /* known field - how to handle 80+80? */ | ||
| 310 | if (status->flag & RX_FLAG_80P80MHZ) | ||
| 311 | known &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; | ||
| 312 | put_unaligned_le16(known, pos); | ||
| 313 | pos += 2; | ||
| 314 | /* flags */ | ||
| 315 | if (status->flag & RX_FLAG_SHORT_GI) | ||
| 316 | *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; | ||
| 317 | pos++; | ||
| 318 | /* bandwidth */ | ||
| 319 | if (status->flag & RX_FLAG_80MHZ) | ||
| 320 | *pos++ = 4; | ||
| 321 | else if (status->flag & RX_FLAG_80P80MHZ) | ||
| 322 | *pos++ = 0; /* marked not known above */ | ||
| 323 | else if (status->flag & RX_FLAG_160MHZ) | ||
| 324 | *pos++ = 11; | ||
| 325 | else if (status->flag & RX_FLAG_40MHZ) | ||
| 326 | *pos++ = 1; | ||
| 327 | else /* 20 MHz */ | ||
| 328 | *pos++ = 0; | ||
| 329 | /* MCS/NSS */ | ||
| 330 | *pos = (status->rate_idx << 4) | status->vht_nss; | ||
| 331 | pos += 4; | ||
| 332 | /* coding field */ | ||
| 333 | pos++; | ||
| 334 | /* group ID */ | ||
| 335 | pos++; | ||
| 336 | /* partial_aid */ | ||
| 337 | pos += 2; | ||
| 338 | } | ||
| 339 | |||
| 340 | if (status->vendor_radiotap_len) { | ||
| 341 | /* ensure 2 byte alignment for the vendor field as required */ | ||
| 342 | if ((pos - (u8 *)rthdr) & 1) | ||
| 343 | *pos++ = 0; | ||
| 344 | *pos++ = status->vendor_radiotap_oui[0]; | ||
| 345 | *pos++ = status->vendor_radiotap_oui[1]; | ||
| 346 | *pos++ = status->vendor_radiotap_oui[2]; | ||
| 347 | *pos++ = status->vendor_radiotap_subns; | ||
| 348 | put_unaligned_le16(status->vendor_radiotap_len, pos); | ||
| 349 | pos += 2; | ||
| 350 | /* align the actual payload as requested */ | ||
| 351 | while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1)) | ||
| 352 | *pos++ = 0; | ||
| 353 | } | ||
| 258 | } | 354 | } |
| 259 | 355 | ||
| 260 | /* | 356 | /* |
| @@ -282,14 +378,11 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
| 282 | * the SKB because it has a bad FCS/PLCP checksum. | 378 | * the SKB because it has a bad FCS/PLCP checksum. |
| 283 | */ | 379 | */ |
| 284 | 380 | ||
| 285 | /* room for the radiotap header based on driver features */ | ||
| 286 | needed_headroom = ieee80211_rx_radiotap_len(local, status); | ||
| 287 | |||
| 288 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 381 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
| 289 | present_fcs_len = FCS_LEN; | 382 | present_fcs_len = FCS_LEN; |
| 290 | 383 | ||
| 291 | /* make sure hdr->frame_control is on the linear part */ | 384 | /* ensure hdr->frame_control and vendor radiotap data are in skb head */ |
| 292 | if (!pskb_may_pull(origskb, 2)) { | 385 | if (!pskb_may_pull(origskb, 2 + status->vendor_radiotap_len)) { |
| 293 | dev_kfree_skb(origskb); | 386 | dev_kfree_skb(origskb); |
| 294 | return NULL; | 387 | return NULL; |
| 295 | } | 388 | } |
| @@ -303,6 +396,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
| 303 | return remove_monitor_info(local, origskb); | 396 | return remove_monitor_info(local, origskb); |
| 304 | } | 397 | } |
| 305 | 398 | ||
| 399 | /* room for the radiotap header based on driver features */ | ||
| 400 | needed_headroom = ieee80211_rx_radiotap_space(local, status); | ||
| 401 | |||
| 306 | if (should_drop_frame(origskb, present_fcs_len)) { | 402 | if (should_drop_frame(origskb, present_fcs_len)) { |
| 307 | /* only need to expand headroom if necessary */ | 403 | /* only need to expand headroom if necessary */ |
| 308 | skb = origskb; | 404 | skb = origskb; |
| @@ -374,7 +470,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
| 374 | return origskb; | 470 | return origskb; |
| 375 | } | 471 | } |
| 376 | 472 | ||
| 377 | |||
| 378 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | 473 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) |
| 379 | { | 474 | { |
| 380 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 475 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| @@ -403,10 +498,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | |||
| 403 | * | 498 | * |
| 404 | * We also use that counter for non-QoS STAs. | 499 | * We also use that counter for non-QoS STAs. |
| 405 | */ | 500 | */ |
| 406 | seqno_idx = NUM_RX_DATA_QUEUES; | 501 | seqno_idx = IEEE80211_NUM_TIDS; |
| 407 | security_idx = 0; | 502 | security_idx = 0; |
| 408 | if (ieee80211_is_mgmt(hdr->frame_control)) | 503 | if (ieee80211_is_mgmt(hdr->frame_control)) |
| 409 | security_idx = NUM_RX_DATA_QUEUES; | 504 | security_idx = IEEE80211_NUM_TIDS; |
| 410 | tid = 0; | 505 | tid = 0; |
| 411 | } | 506 | } |
| 412 | 507 | ||
| @@ -481,8 +576,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
| 481 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; | 576 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; |
| 482 | struct ieee80211_mmie *mmie; | 577 | struct ieee80211_mmie *mmie; |
| 483 | 578 | ||
| 484 | if (skb->len < 24 + sizeof(*mmie) || | 579 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) |
| 485 | !is_multicast_ether_addr(hdr->da)) | ||
| 486 | return -1; | 580 | return -1; |
| 487 | 581 | ||
| 488 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) | 582 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) |
| @@ -497,9 +591,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
| 497 | return le16_to_cpu(mmie->key_id); | 591 | return le16_to_cpu(mmie->key_id); |
| 498 | } | 592 | } |
| 499 | 593 | ||
| 500 | 594 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |
| 501 | static ieee80211_rx_result | ||
| 502 | ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | ||
| 503 | { | 595 | { |
| 504 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 596 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| 505 | char *dev_addr = rx->sdata->vif.addr; | 597 | char *dev_addr = rx->sdata->vif.addr; |
| @@ -507,7 +599,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
| 507 | if (ieee80211_is_data(hdr->frame_control)) { | 599 | if (ieee80211_is_data(hdr->frame_control)) { |
| 508 | if (is_multicast_ether_addr(hdr->addr1)) { | 600 | if (is_multicast_ether_addr(hdr->addr1)) { |
| 509 | if (ieee80211_has_tods(hdr->frame_control) || | 601 | if (ieee80211_has_tods(hdr->frame_control) || |
| 510 | !ieee80211_has_fromds(hdr->frame_control)) | 602 | !ieee80211_has_fromds(hdr->frame_control)) |
| 511 | return RX_DROP_MONITOR; | 603 | return RX_DROP_MONITOR; |
| 512 | if (ether_addr_equal(hdr->addr3, dev_addr)) | 604 | if (ether_addr_equal(hdr->addr3, dev_addr)) |
| 513 | return RX_DROP_MONITOR; | 605 | return RX_DROP_MONITOR; |
| @@ -539,7 +631,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
| 539 | mgmt = (struct ieee80211_mgmt *)hdr; | 631 | mgmt = (struct ieee80211_mgmt *)hdr; |
| 540 | category = mgmt->u.action.category; | 632 | category = mgmt->u.action.category; |
| 541 | if (category != WLAN_CATEGORY_MESH_ACTION && | 633 | if (category != WLAN_CATEGORY_MESH_ACTION && |
| 542 | category != WLAN_CATEGORY_SELF_PROTECTED) | 634 | category != WLAN_CATEGORY_SELF_PROTECTED) |
| 543 | return RX_DROP_MONITOR; | 635 | return RX_DROP_MONITOR; |
| 544 | return RX_CONTINUE; | 636 | return RX_CONTINUE; |
| 545 | } | 637 | } |
| @@ -551,7 +643,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
| 551 | return RX_CONTINUE; | 643 | return RX_CONTINUE; |
| 552 | 644 | ||
| 553 | return RX_DROP_MONITOR; | 645 | return RX_DROP_MONITOR; |
| 554 | |||
| 555 | } | 646 | } |
| 556 | 647 | ||
| 557 | return RX_CONTINUE; | 648 | return RX_CONTINUE; |
| @@ -575,7 +666,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) | |||
| 575 | return (sq1 - sq2) & SEQ_MASK; | 666 | return (sq1 - sq2) & SEQ_MASK; |
| 576 | } | 667 | } |
| 577 | 668 | ||
| 578 | |||
| 579 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | 669 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, |
| 580 | struct tid_ampdu_rx *tid_agg_rx, | 670 | struct tid_ampdu_rx *tid_agg_rx, |
| 581 | int index) | 671 | int index) |
| @@ -1148,12 +1238,19 @@ ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx) | |||
| 1148 | return RX_CONTINUE; | 1238 | return RX_CONTINUE; |
| 1149 | } | 1239 | } |
| 1150 | 1240 | ||
| 1151 | static void ap_sta_ps_start(struct sta_info *sta) | 1241 | static void sta_ps_start(struct sta_info *sta) |
| 1152 | { | 1242 | { |
| 1153 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1243 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 1154 | struct ieee80211_local *local = sdata->local; | 1244 | struct ieee80211_local *local = sdata->local; |
| 1245 | struct ps_data *ps; | ||
| 1246 | |||
| 1247 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 1248 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 1249 | ps = &sdata->bss->ps; | ||
| 1250 | else | ||
| 1251 | return; | ||
| 1155 | 1252 | ||
| 1156 | atomic_inc(&sdata->bss->num_sta_ps); | 1253 | atomic_inc(&ps->num_sta_ps); |
| 1157 | set_sta_flag(sta, WLAN_STA_PS_STA); | 1254 | set_sta_flag(sta, WLAN_STA_PS_STA); |
| 1158 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) | 1255 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
| 1159 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); | 1256 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); |
| @@ -1161,7 +1258,7 @@ static void ap_sta_ps_start(struct sta_info *sta) | |||
| 1161 | sta->sta.addr, sta->sta.aid); | 1258 | sta->sta.addr, sta->sta.aid); |
| 1162 | } | 1259 | } |
| 1163 | 1260 | ||
| 1164 | static void ap_sta_ps_end(struct sta_info *sta) | 1261 | static void sta_ps_end(struct sta_info *sta) |
| 1165 | { | 1262 | { |
| 1166 | ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n", | 1263 | ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n", |
| 1167 | sta->sta.addr, sta->sta.aid); | 1264 | sta->sta.addr, sta->sta.aid); |
| @@ -1188,9 +1285,9 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start) | |||
| 1188 | return -EINVAL; | 1285 | return -EINVAL; |
| 1189 | 1286 | ||
| 1190 | if (start) | 1287 | if (start) |
| 1191 | ap_sta_ps_start(sta_inf); | 1288 | sta_ps_start(sta_inf); |
| 1192 | else | 1289 | else |
| 1193 | ap_sta_ps_end(sta_inf); | 1290 | sta_ps_end(sta_inf); |
| 1194 | 1291 | ||
| 1195 | return 0; | 1292 | return 0; |
| 1196 | } | 1293 | } |
| @@ -1284,17 +1381,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
| 1284 | 1381 | ||
| 1285 | /* | 1382 | /* |
| 1286 | * Update last_rx only for IBSS packets which are for the current | 1383 | * Update last_rx only for IBSS packets which are for the current |
| 1287 | * BSSID to avoid keeping the current IBSS network alive in cases | 1384 | * BSSID and for station already AUTHORIZED to avoid keeping the |
| 1288 | * where other STAs start using different BSSID. | 1385 | * current IBSS network alive in cases where other STAs start |
| 1386 | * using different BSSID. This will also give the station another | ||
| 1387 | * chance to restart the authentication/authorization in case | ||
| 1388 | * something went wrong the first time. | ||
| 1289 | */ | 1389 | */ |
| 1290 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1390 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
| 1291 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | 1391 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, |
| 1292 | NL80211_IFTYPE_ADHOC); | 1392 | NL80211_IFTYPE_ADHOC); |
| 1293 | if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid)) { | 1393 | if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) && |
| 1394 | test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { | ||
| 1294 | sta->last_rx = jiffies; | 1395 | sta->last_rx = jiffies; |
| 1295 | if (ieee80211_is_data(hdr->frame_control)) { | 1396 | if (ieee80211_is_data(hdr->frame_control)) { |
| 1296 | sta->last_rx_rate_idx = status->rate_idx; | 1397 | sta->last_rx_rate_idx = status->rate_idx; |
| 1297 | sta->last_rx_rate_flag = status->flag; | 1398 | sta->last_rx_rate_flag = status->flag; |
| 1399 | sta->last_rx_rate_vht_nss = status->vht_nss; | ||
| 1298 | } | 1400 | } |
| 1299 | } | 1401 | } |
| 1300 | } else if (!is_multicast_ether_addr(hdr->addr1)) { | 1402 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
| @@ -1306,6 +1408,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
| 1306 | if (ieee80211_is_data(hdr->frame_control)) { | 1408 | if (ieee80211_is_data(hdr->frame_control)) { |
| 1307 | sta->last_rx_rate_idx = status->rate_idx; | 1409 | sta->last_rx_rate_idx = status->rate_idx; |
| 1308 | sta->last_rx_rate_flag = status->flag; | 1410 | sta->last_rx_rate_flag = status->flag; |
| 1411 | sta->last_rx_rate_vht_nss = status->vht_nss; | ||
| 1309 | } | 1412 | } |
| 1310 | } | 1413 | } |
| 1311 | 1414 | ||
| @@ -1342,10 +1445,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
| 1342 | */ | 1445 | */ |
| 1343 | if (ieee80211_is_data(hdr->frame_control) && | 1446 | if (ieee80211_is_data(hdr->frame_control) && |
| 1344 | !ieee80211_has_pm(hdr->frame_control)) | 1447 | !ieee80211_has_pm(hdr->frame_control)) |
| 1345 | ap_sta_ps_end(sta); | 1448 | sta_ps_end(sta); |
| 1346 | } else { | 1449 | } else { |
| 1347 | if (ieee80211_has_pm(hdr->frame_control)) | 1450 | if (ieee80211_has_pm(hdr->frame_control)) |
| 1348 | ap_sta_ps_start(sta); | 1451 | sta_ps_start(sta); |
| 1349 | } | 1452 | } |
| 1350 | } | 1453 | } |
| 1351 | 1454 | ||
| @@ -1391,9 +1494,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, | |||
| 1391 | struct sk_buff **skb) | 1494 | struct sk_buff **skb) |
| 1392 | { | 1495 | { |
| 1393 | struct ieee80211_fragment_entry *entry; | 1496 | struct ieee80211_fragment_entry *entry; |
| 1394 | int idx; | ||
| 1395 | 1497 | ||
| 1396 | idx = sdata->fragment_next; | ||
| 1397 | entry = &sdata->fragments[sdata->fragment_next++]; | 1498 | entry = &sdata->fragments[sdata->fragment_next++]; |
| 1398 | if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) | 1499 | if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) |
| 1399 | sdata->fragment_next = 0; | 1500 | sdata->fragment_next = 0; |
| @@ -1580,18 +1681,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
| 1580 | return RX_CONTINUE; | 1681 | return RX_CONTINUE; |
| 1581 | } | 1682 | } |
| 1582 | 1683 | ||
| 1583 | static int | 1684 | static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) |
| 1584 | ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) | ||
| 1585 | { | 1685 | { |
| 1586 | if (unlikely(!rx->sta || | 1686 | if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) |
| 1587 | !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) | ||
| 1588 | return -EACCES; | 1687 | return -EACCES; |
| 1589 | 1688 | ||
| 1590 | return 0; | 1689 | return 0; |
| 1591 | } | 1690 | } |
| 1592 | 1691 | ||
| 1593 | static int | 1692 | static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) |
| 1594 | ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | ||
| 1595 | { | 1693 | { |
| 1596 | struct sk_buff *skb = rx->skb; | 1694 | struct sk_buff *skb = rx->skb; |
| 1597 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 1695 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
| @@ -1613,8 +1711,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | |||
| 1613 | return 0; | 1711 | return 0; |
| 1614 | } | 1712 | } |
| 1615 | 1713 | ||
| 1616 | static int | 1714 | static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) |
| 1617 | ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | ||
| 1618 | { | 1715 | { |
| 1619 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1716 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
| 1620 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 1717 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
| @@ -1998,7 +2095,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
| 1998 | } else { | 2095 | } else { |
| 1999 | /* unable to resolve next hop */ | 2096 | /* unable to resolve next hop */ |
| 2000 | mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, | 2097 | mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, |
| 2001 | 0, reason, fwd_hdr->addr2, sdata); | 2098 | 0, reason, fwd_hdr->addr2, sdata); |
| 2002 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); | 2099 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); |
| 2003 | kfree_skb(fwd_skb); | 2100 | kfree_skb(fwd_skb); |
| 2004 | return RX_DROP_MONITOR; | 2101 | return RX_DROP_MONITOR; |
| @@ -2207,7 +2304,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) | |||
| 2207 | 2304 | ||
| 2208 | cfg80211_report_obss_beacon(rx->local->hw.wiphy, | 2305 | cfg80211_report_obss_beacon(rx->local->hw.wiphy, |
| 2209 | rx->skb->data, rx->skb->len, | 2306 | rx->skb->data, rx->skb->len, |
| 2210 | status->freq, sig, GFP_ATOMIC); | 2307 | status->freq, sig); |
| 2211 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; | 2308 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; |
| 2212 | } | 2309 | } |
| 2213 | 2310 | ||
| @@ -2236,7 +2333,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2236 | if (len < IEEE80211_MIN_ACTION_SIZE) | 2333 | if (len < IEEE80211_MIN_ACTION_SIZE) |
| 2237 | return RX_DROP_UNUSABLE; | 2334 | return RX_DROP_UNUSABLE; |
| 2238 | 2335 | ||
| 2239 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) | 2336 | if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && |
| 2337 | mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED) | ||
| 2240 | return RX_DROP_UNUSABLE; | 2338 | return RX_DROP_UNUSABLE; |
| 2241 | 2339 | ||
| 2242 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | 2340 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
| @@ -2407,7 +2505,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 2407 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2505 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
| 2408 | break; | 2506 | break; |
| 2409 | if (mesh_action_is_path_sel(mgmt) && | 2507 | if (mesh_action_is_path_sel(mgmt) && |
| 2410 | (!mesh_path_sel_is_hwmp(sdata))) | 2508 | !mesh_path_sel_is_hwmp(sdata)) |
| 2411 | break; | 2509 | break; |
| 2412 | goto queue; | 2510 | goto queue; |
| 2413 | } | 2511 | } |
| @@ -2463,7 +2561,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) | |||
| 2463 | return RX_QUEUED; | 2561 | return RX_QUEUED; |
| 2464 | } | 2562 | } |
| 2465 | 2563 | ||
| 2466 | |||
| 2467 | return RX_CONTINUE; | 2564 | return RX_CONTINUE; |
| 2468 | } | 2565 | } |
| 2469 | 2566 | ||
| @@ -2593,7 +2690,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
| 2593 | goto out_free_skb; | 2690 | goto out_free_skb; |
| 2594 | 2691 | ||
| 2595 | /* room for the radiotap header based on driver features */ | 2692 | /* room for the radiotap header based on driver features */ |
| 2596 | needed_headroom = ieee80211_rx_radiotap_len(local, status); | 2693 | needed_headroom = ieee80211_rx_radiotap_space(local, status); |
| 2597 | 2694 | ||
| 2598 | if (skb_headroom(skb) < needed_headroom && | 2695 | if (skb_headroom(skb) < needed_headroom && |
| 2599 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) | 2696 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) |
| @@ -2656,7 +2753,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, | |||
| 2656 | status = IEEE80211_SKB_RXCB((rx->skb)); | 2753 | status = IEEE80211_SKB_RXCB((rx->skb)); |
| 2657 | 2754 | ||
| 2658 | sband = rx->local->hw.wiphy->bands[status->band]; | 2755 | sband = rx->local->hw.wiphy->bands[status->band]; |
| 2659 | if (!(status->flag & RX_FLAG_HT)) | 2756 | if (!(status->flag & RX_FLAG_HT) && |
| 2757 | !(status->flag & RX_FLAG_VHT)) | ||
| 2660 | rate = &sband->bitrates[status->rate_idx]; | 2758 | rate = &sband->bitrates[status->rate_idx]; |
| 2661 | 2759 | ||
| 2662 | ieee80211_rx_cooked_monitor(rx, rate); | 2760 | ieee80211_rx_cooked_monitor(rx, rate); |
| @@ -2823,8 +2921,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
| 2823 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 2921 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
| 2824 | } else if (!rx->sta) { | 2922 | } else if (!rx->sta) { |
| 2825 | int rate_idx; | 2923 | int rate_idx; |
| 2826 | if (status->flag & RX_FLAG_HT) | 2924 | if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) |
| 2827 | rate_idx = 0; /* TODO: HT rates */ | 2925 | rate_idx = 0; /* TODO: HT/VHT rates */ |
| 2828 | else | 2926 | else |
| 2829 | rate_idx = status->rate_idx; | 2927 | rate_idx = status->rate_idx; |
| 2830 | ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, | 2928 | ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, |
| @@ -3048,8 +3146,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 3048 | 3146 | ||
| 3049 | WARN_ON_ONCE(softirq_count() == 0); | 3147 | WARN_ON_ONCE(softirq_count() == 0); |
| 3050 | 3148 | ||
| 3051 | if (WARN_ON(status->band < 0 || | 3149 | if (WARN_ON(status->band >= IEEE80211_NUM_BANDS)) |
| 3052 | status->band >= IEEE80211_NUM_BANDS)) | ||
| 3053 | goto drop; | 3150 | goto drop; |
| 3054 | 3151 | ||
| 3055 | sband = local->hw.wiphy->bands[status->band]; | 3152 | sband = local->hw.wiphy->bands[status->band]; |
| @@ -3094,17 +3191,22 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 3094 | * hardware error. The driver should catch hardware | 3191 | * hardware error. The driver should catch hardware |
| 3095 | * errors. | 3192 | * errors. |
| 3096 | */ | 3193 | */ |
| 3097 | if (WARN((status->rate_idx < 0 || | 3194 | if (WARN(status->rate_idx > 76, |
| 3098 | status->rate_idx > 76), | ||
| 3099 | "Rate marked as an HT rate but passed " | 3195 | "Rate marked as an HT rate but passed " |
| 3100 | "status->rate_idx is not " | 3196 | "status->rate_idx is not " |
| 3101 | "an MCS index [0-76]: %d (0x%02x)\n", | 3197 | "an MCS index [0-76]: %d (0x%02x)\n", |
| 3102 | status->rate_idx, | 3198 | status->rate_idx, |
| 3103 | status->rate_idx)) | 3199 | status->rate_idx)) |
| 3104 | goto drop; | 3200 | goto drop; |
| 3201 | } else if (status->flag & RX_FLAG_VHT) { | ||
| 3202 | if (WARN_ONCE(status->rate_idx > 9 || | ||
| 3203 | !status->vht_nss || | ||
| 3204 | status->vht_nss > 8, | ||
| 3205 | "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n", | ||
| 3206 | status->rate_idx, status->vht_nss)) | ||
| 3207 | goto drop; | ||
| 3105 | } else { | 3208 | } else { |
| 3106 | if (WARN_ON(status->rate_idx < 0 || | 3209 | if (WARN_ON(status->rate_idx >= sband->n_bitrates)) |
| 3107 | status->rate_idx >= sband->n_bitrates)) | ||
| 3108 | goto drop; | 3210 | goto drop; |
| 3109 | rate = &sband->bitrates[status->rate_idx]; | 3211 | rate = &sband->bitrates[status->rate_idx]; |
| 3110 | } | 3212 | } |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 43e60b5a7546..8ed83dcc149f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
| @@ -118,7 +118,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
| 118 | struct ieee80211_tim_ie *tim_ie = elems->tim; | 118 | struct ieee80211_tim_ie *tim_ie = elems->tim; |
| 119 | bss->dtim_period = tim_ie->dtim_period; | 119 | bss->dtim_period = tim_ie->dtim_period; |
| 120 | if (!elems->parse_error) | 120 | if (!elems->parse_error) |
| 121 | bss->valid_data |= IEEE80211_BSS_VALID_DTIM; | 121 | bss->valid_data |= IEEE80211_BSS_VALID_DTIM; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | /* If the beacon had no TIM IE, or it was invalid, use 1 */ | 124 | /* If the beacon had no TIM IE, or it was invalid, use 1 */ |
| @@ -174,7 +174,6 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
| 174 | u8 *elements; | 174 | u8 *elements; |
| 175 | struct ieee80211_channel *channel; | 175 | struct ieee80211_channel *channel; |
| 176 | size_t baselen; | 176 | size_t baselen; |
| 177 | int freq; | ||
| 178 | bool beacon; | 177 | bool beacon; |
| 179 | struct ieee802_11_elems elems; | 178 | struct ieee802_11_elems elems; |
| 180 | 179 | ||
| @@ -209,13 +208,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
| 209 | 208 | ||
| 210 | ieee802_11_parse_elems(elements, skb->len - baselen, &elems); | 209 | ieee802_11_parse_elems(elements, skb->len - baselen, &elems); |
| 211 | 210 | ||
| 212 | if (elems.ds_params && elems.ds_params_len == 1) | 211 | channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); |
| 213 | freq = ieee80211_channel_to_frequency(elems.ds_params[0], | ||
| 214 | rx_status->band); | ||
| 215 | else | ||
| 216 | freq = rx_status->freq; | ||
| 217 | |||
| 218 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
| 219 | 212 | ||
| 220 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 213 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
| 221 | return; | 214 | return; |
| @@ -254,6 +247,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
| 254 | local->hw_scan_req->n_channels = n_chans; | 247 | local->hw_scan_req->n_channels = n_chans; |
| 255 | 248 | ||
| 256 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, | 249 | ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, |
| 250 | local->hw_scan_ies_bufsize, | ||
| 257 | req->ie, req->ie_len, band, | 251 | req->ie, req->ie_len, band, |
| 258 | req->rates[band], 0); | 252 | req->rates[band], 0); |
| 259 | local->hw_scan_req->ie_len = ielen; | 253 | local->hw_scan_req->ie_len = ielen; |
| @@ -336,6 +330,10 @@ EXPORT_SYMBOL(ieee80211_scan_completed); | |||
| 336 | 330 | ||
| 337 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) | 331 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) |
| 338 | { | 332 | { |
| 333 | /* Software scan is not supported in multi-channel cases */ | ||
| 334 | if (local->use_chanctx) | ||
| 335 | return -EOPNOTSUPP; | ||
| 336 | |||
| 339 | /* | 337 | /* |
| 340 | * Hardware/driver doesn't support hw_scan, so use software | 338 | * Hardware/driver doesn't support hw_scan, so use software |
| 341 | * scanning instead. First send a nullfunc frame with power save | 339 | * scanning instead. First send a nullfunc frame with power save |
| @@ -417,7 +415,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
| 417 | local->scan_req->ie, local->scan_req->ie_len, | 415 | local->scan_req->ie, local->scan_req->ie_len, |
| 418 | local->scan_req->rates[band], false, | 416 | local->scan_req->rates[band], false, |
| 419 | local->scan_req->no_cck, | 417 | local->scan_req->no_cck, |
| 420 | local->hw.conf.channel); | 418 | local->hw.conf.channel, true); |
| 421 | 419 | ||
| 422 | /* | 420 | /* |
| 423 | * After sending probe requests, wait for probe responses | 421 | * After sending probe requests, wait for probe responses |
| @@ -448,11 +446,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 448 | if (local->ops->hw_scan) { | 446 | if (local->ops->hw_scan) { |
| 449 | u8 *ies; | 447 | u8 *ies; |
| 450 | 448 | ||
| 449 | local->hw_scan_ies_bufsize = 2 + IEEE80211_MAX_SSID_LEN + | ||
| 450 | local->scan_ies_len + | ||
| 451 | req->ie_len; | ||
| 451 | local->hw_scan_req = kmalloc( | 452 | local->hw_scan_req = kmalloc( |
| 452 | sizeof(*local->hw_scan_req) + | 453 | sizeof(*local->hw_scan_req) + |
| 453 | req->n_channels * sizeof(req->channels[0]) + | 454 | req->n_channels * sizeof(req->channels[0]) + |
| 454 | 2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + | 455 | local->hw_scan_ies_bufsize, GFP_KERNEL); |
| 455 | req->ie_len, GFP_KERNEL); | ||
| 456 | if (!local->hw_scan_req) | 456 | if (!local->hw_scan_req) |
| 457 | return -ENOMEM; | 457 | return -ENOMEM; |
| 458 | 458 | ||
| @@ -462,6 +462,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 462 | sizeof(*local->hw_scan_req) + | 462 | sizeof(*local->hw_scan_req) + |
| 463 | req->n_channels * sizeof(req->channels[0]); | 463 | req->n_channels * sizeof(req->channels[0]); |
| 464 | local->hw_scan_req->ie = ies; | 464 | local->hw_scan_req->ie = ies; |
| 465 | local->hw_scan_req->flags = req->flags; | ||
| 465 | 466 | ||
| 466 | local->hw_scan_band = 0; | 467 | local->hw_scan_band = 0; |
| 467 | 468 | ||
| @@ -480,7 +481,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
| 480 | if (local->ops->hw_scan) { | 481 | if (local->ops->hw_scan) { |
| 481 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 482 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
| 482 | } else if ((req->n_channels == 1) && | 483 | } else if ((req->n_channels == 1) && |
| 483 | (req->channels[0] == local->oper_channel)) { | 484 | (req->channels[0] == local->_oper_channel)) { |
| 484 | /* | 485 | /* |
| 485 | * If we are scanning only on the operating channel | 486 | * If we are scanning only on the operating channel |
| 486 | * then we do not need to stop normal activities | 487 | * then we do not need to stop normal activities |
| @@ -562,6 +563,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
| 562 | unsigned long min_beacon_int = 0; | 563 | unsigned long min_beacon_int = 0; |
| 563 | struct ieee80211_sub_if_data *sdata; | 564 | struct ieee80211_sub_if_data *sdata; |
| 564 | struct ieee80211_channel *next_chan; | 565 | struct ieee80211_channel *next_chan; |
| 566 | enum mac80211_scan_state next_scan_state; | ||
| 565 | 567 | ||
| 566 | /* | 568 | /* |
| 567 | * check if at least one STA interface is associated, | 569 | * check if at least one STA interface is associated, |
| @@ -620,10 +622,18 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
| 620 | usecs_to_jiffies(min_beacon_int * 1024) * | 622 | usecs_to_jiffies(min_beacon_int * 1024) * |
| 621 | local->hw.conf.listen_interval); | 623 | local->hw.conf.listen_interval); |
| 622 | 624 | ||
| 623 | if (associated && (!tx_empty || bad_latency || listen_int_exceeded)) | 625 | if (associated && !tx_empty) { |
| 624 | local->next_scan_state = SCAN_SUSPEND; | 626 | if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) |
| 625 | else | 627 | next_scan_state = SCAN_ABORT; |
| 626 | local->next_scan_state = SCAN_SET_CHANNEL; | 628 | else |
| 629 | next_scan_state = SCAN_SUSPEND; | ||
| 630 | } else if (associated && (bad_latency || listen_int_exceeded)) { | ||
| 631 | next_scan_state = SCAN_SUSPEND; | ||
| 632 | } else { | ||
| 633 | next_scan_state = SCAN_SET_CHANNEL; | ||
| 634 | } | ||
| 635 | |||
| 636 | local->next_scan_state = next_scan_state; | ||
| 627 | 637 | ||
| 628 | *next_delay = 0; | 638 | *next_delay = 0; |
| 629 | } | 639 | } |
| @@ -794,6 +804,9 @@ void ieee80211_scan_work(struct work_struct *work) | |||
| 794 | case SCAN_RESUME: | 804 | case SCAN_RESUME: |
| 795 | ieee80211_scan_state_resume(local, &next_delay); | 805 | ieee80211_scan_state_resume(local, &next_delay); |
| 796 | break; | 806 | break; |
| 807 | case SCAN_ABORT: | ||
| 808 | aborted = true; | ||
| 809 | goto out_complete; | ||
| 797 | } | 810 | } |
| 798 | } while (next_delay == 0); | 811 | } while (next_delay == 0); |
| 799 | 812 | ||
| @@ -918,7 +931,10 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
| 918 | { | 931 | { |
| 919 | struct ieee80211_local *local = sdata->local; | 932 | struct ieee80211_local *local = sdata->local; |
| 920 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; | 933 | struct ieee80211_sched_scan_ies sched_scan_ies = {}; |
| 921 | int ret, i; | 934 | int ret, i, iebufsz; |
| 935 | |||
| 936 | iebufsz = 2 + IEEE80211_MAX_SSID_LEN + | ||
| 937 | local->scan_ies_len + req->ie_len; | ||
| 922 | 938 | ||
| 923 | mutex_lock(&local->mtx); | 939 | mutex_lock(&local->mtx); |
| 924 | 940 | ||
| @@ -936,10 +952,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
| 936 | if (!local->hw.wiphy->bands[i]) | 952 | if (!local->hw.wiphy->bands[i]) |
| 937 | continue; | 953 | continue; |
| 938 | 954 | ||
| 939 | sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + | 955 | sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL); |
| 940 | local->scan_ies_len + | ||
| 941 | req->ie_len, | ||
| 942 | GFP_KERNEL); | ||
| 943 | if (!sched_scan_ies.ie[i]) { | 956 | if (!sched_scan_ies.ie[i]) { |
| 944 | ret = -ENOMEM; | 957 | ret = -ENOMEM; |
| 945 | goto out_free; | 958 | goto out_free; |
| @@ -947,8 +960,8 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
| 947 | 960 | ||
| 948 | sched_scan_ies.len[i] = | 961 | sched_scan_ies.len[i] = |
| 949 | ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], | 962 | ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], |
| 950 | req->ie, req->ie_len, i, | 963 | iebufsz, req->ie, req->ie_len, |
| 951 | (u32) -1, 0); | 964 | i, (u32) -1, 0); |
| 952 | } | 965 | } |
| 953 | 966 | ||
| 954 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 967 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d2eb64e12353..f3e502502fee 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
| @@ -98,6 +98,7 @@ static void free_sta_work(struct work_struct *wk) | |||
| 98 | struct tid_ampdu_tx *tid_tx; | 98 | struct tid_ampdu_tx *tid_tx; |
| 99 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 99 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 100 | struct ieee80211_local *local = sdata->local; | 100 | struct ieee80211_local *local = sdata->local; |
| 101 | struct ps_data *ps; | ||
| 101 | 102 | ||
| 102 | /* | 103 | /* |
| 103 | * At this point, when being called as call_rcu callback, | 104 | * At this point, when being called as call_rcu callback, |
| @@ -107,11 +108,15 @@ static void free_sta_work(struct work_struct *wk) | |||
| 107 | */ | 108 | */ |
| 108 | 109 | ||
| 109 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | 110 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { |
| 110 | BUG_ON(!sdata->bss); | 111 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
| 112 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 113 | ps = &sdata->bss->ps; | ||
| 114 | else | ||
| 115 | return; | ||
| 111 | 116 | ||
| 112 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 117 | clear_sta_flag(sta, WLAN_STA_PS_STA); |
| 113 | 118 | ||
| 114 | atomic_dec(&sdata->bss->num_sta_ps); | 119 | atomic_dec(&ps->num_sta_ps); |
| 115 | sta_info_recalc_tim(sta); | 120 | sta_info_recalc_tim(sta); |
| 116 | } | 121 | } |
| 117 | 122 | ||
| @@ -137,7 +142,7 @@ static void free_sta_work(struct work_struct *wk) | |||
| 137 | * drivers have to handle aggregation stop being requested, followed | 142 | * drivers have to handle aggregation stop being requested, followed |
| 138 | * directly by station destruction. | 143 | * directly by station destruction. |
| 139 | */ | 144 | */ |
| 140 | for (i = 0; i < STA_TID_NUM; i++) { | 145 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 141 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); | 146 | tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]); |
| 142 | if (!tid_tx) | 147 | if (!tid_tx) |
| 143 | continue; | 148 | continue; |
| @@ -325,7 +330,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 325 | return NULL; | 330 | return NULL; |
| 326 | } | 331 | } |
| 327 | 332 | ||
| 328 | for (i = 0; i < STA_TID_NUM; i++) { | 333 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
| 329 | /* | 334 | /* |
| 330 | * timer_to_tid must be initialized with identity mapping | 335 | * timer_to_tid must be initialized with identity mapping |
| 331 | * to enable session_timer's data differentiation. See | 336 | * to enable session_timer's data differentiation. See |
| @@ -338,7 +343,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 338 | skb_queue_head_init(&sta->tx_filtered[i]); | 343 | skb_queue_head_init(&sta->tx_filtered[i]); |
| 339 | } | 344 | } |
| 340 | 345 | ||
| 341 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 346 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
| 342 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); | 347 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); |
| 343 | 348 | ||
| 344 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); | 349 | sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); |
| @@ -502,22 +507,22 @@ int sta_info_insert(struct sta_info *sta) | |||
| 502 | return err; | 507 | return err; |
| 503 | } | 508 | } |
| 504 | 509 | ||
| 505 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 510 | static inline void __bss_tim_set(u8 *tim, u16 id) |
| 506 | { | 511 | { |
| 507 | /* | 512 | /* |
| 508 | * This format has been mandated by the IEEE specifications, | 513 | * This format has been mandated by the IEEE specifications, |
| 509 | * so this line may not be changed to use the __set_bit() format. | 514 | * so this line may not be changed to use the __set_bit() format. |
| 510 | */ | 515 | */ |
| 511 | bss->tim[aid / 8] |= (1 << (aid % 8)); | 516 | tim[id / 8] |= (1 << (id % 8)); |
| 512 | } | 517 | } |
| 513 | 518 | ||
| 514 | static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) | 519 | static inline void __bss_tim_clear(u8 *tim, u16 id) |
| 515 | { | 520 | { |
| 516 | /* | 521 | /* |
| 517 | * This format has been mandated by the IEEE specifications, | 522 | * This format has been mandated by the IEEE specifications, |
| 518 | * so this line may not be changed to use the __clear_bit() format. | 523 | * so this line may not be changed to use the __clear_bit() format. |
| 519 | */ | 524 | */ |
| 520 | bss->tim[aid / 8] &= ~(1 << (aid % 8)); | 525 | tim[id / 8] &= ~(1 << (id % 8)); |
| 521 | } | 526 | } |
| 522 | 527 | ||
| 523 | static unsigned long ieee80211_tids_for_ac(int ac) | 528 | static unsigned long ieee80211_tids_for_ac(int ac) |
| @@ -541,14 +546,23 @@ static unsigned long ieee80211_tids_for_ac(int ac) | |||
| 541 | void sta_info_recalc_tim(struct sta_info *sta) | 546 | void sta_info_recalc_tim(struct sta_info *sta) |
| 542 | { | 547 | { |
| 543 | struct ieee80211_local *local = sta->local; | 548 | struct ieee80211_local *local = sta->local; |
| 544 | struct ieee80211_if_ap *bss = sta->sdata->bss; | 549 | struct ps_data *ps; |
| 545 | unsigned long flags; | 550 | unsigned long flags; |
| 546 | bool indicate_tim = false; | 551 | bool indicate_tim = false; |
| 547 | u8 ignore_for_tim = sta->sta.uapsd_queues; | 552 | u8 ignore_for_tim = sta->sta.uapsd_queues; |
| 548 | int ac; | 553 | int ac; |
| 554 | u16 id; | ||
| 555 | |||
| 556 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 557 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | ||
| 558 | if (WARN_ON_ONCE(!sta->sdata->bss)) | ||
| 559 | return; | ||
| 549 | 560 | ||
| 550 | if (WARN_ON_ONCE(!sta->sdata->bss)) | 561 | ps = &sta->sdata->bss->ps; |
| 562 | id = sta->sta.aid; | ||
| 563 | } else { | ||
| 551 | return; | 564 | return; |
| 565 | } | ||
| 552 | 566 | ||
| 553 | /* No need to do anything if the driver does all */ | 567 | /* No need to do anything if the driver does all */ |
| 554 | if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) | 568 | if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) |
| @@ -587,9 +601,9 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
| 587 | spin_lock_irqsave(&local->tim_lock, flags); | 601 | spin_lock_irqsave(&local->tim_lock, flags); |
| 588 | 602 | ||
| 589 | if (indicate_tim) | 603 | if (indicate_tim) |
| 590 | __bss_tim_set(bss, sta->sta.aid); | 604 | __bss_tim_set(ps->tim, id); |
| 591 | else | 605 | else |
| 592 | __bss_tim_clear(bss, sta->sta.aid); | 606 | __bss_tim_clear(ps->tim, id); |
| 593 | 607 | ||
| 594 | if (local->ops->set_tim) { | 608 | if (local->ops->set_tim) { |
| 595 | local->tim_in_locked_section = true; | 609 | local->tim_in_locked_section = true; |
| @@ -893,8 +907,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
| 893 | continue; | 907 | continue; |
| 894 | 908 | ||
| 895 | if (time_after(jiffies, sta->last_rx + exp_time)) { | 909 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
| 896 | ibss_dbg(sdata, "expiring inactive STA %pM\n", | 910 | sta_dbg(sta->sdata, "expiring inactive STA %pM\n", |
| 897 | sta->sta.addr); | 911 | sta->sta.addr); |
| 898 | WARN_ON(__sta_info_destroy(sta)); | 912 | WARN_ON(__sta_info_destroy(sta)); |
| 899 | } | 913 | } |
| 900 | } | 914 | } |
| @@ -948,10 +962,17 @@ static void clear_sta_ps_flags(void *_sta) | |||
| 948 | { | 962 | { |
| 949 | struct sta_info *sta = _sta; | 963 | struct sta_info *sta = _sta; |
| 950 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 964 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 965 | struct ps_data *ps; | ||
| 966 | |||
| 967 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
| 968 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
| 969 | ps = &sdata->bss->ps; | ||
| 970 | else | ||
| 971 | return; | ||
| 951 | 972 | ||
| 952 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 973 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); |
| 953 | if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA)) | 974 | if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA)) |
| 954 | atomic_dec(&sdata->bss->num_sta_ps); | 975 | atomic_dec(&ps->num_sta_ps); |
| 955 | } | 976 | } |
| 956 | 977 | ||
| 957 | /* powersave support code */ | 978 | /* powersave support code */ |
| @@ -965,7 +986,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
| 965 | 986 | ||
| 966 | clear_sta_flag(sta, WLAN_STA_SP); | 987 | clear_sta_flag(sta, WLAN_STA_SP); |
| 967 | 988 | ||
| 968 | BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1); | 989 | BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); |
| 969 | sta->driver_buffered_tids = 0; | 990 | sta->driver_buffered_tids = 0; |
| 970 | 991 | ||
| 971 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) | 992 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
| @@ -1013,6 +1034,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
| 1013 | __le16 fc; | 1034 | __le16 fc; |
| 1014 | bool qos = test_sta_flag(sta, WLAN_STA_WME); | 1035 | bool qos = test_sta_flag(sta, WLAN_STA_WME); |
| 1015 | struct ieee80211_tx_info *info; | 1036 | struct ieee80211_tx_info *info; |
| 1037 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 1016 | 1038 | ||
| 1017 | if (qos) { | 1039 | if (qos) { |
| 1018 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | | 1040 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | |
| @@ -1062,7 +1084,16 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
| 1062 | 1084 | ||
| 1063 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); | 1085 | drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false); |
| 1064 | 1086 | ||
| 1065 | ieee80211_xmit(sdata, skb); | 1087 | rcu_read_lock(); |
| 1088 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 1089 | if (WARN_ON(!chanctx_conf)) { | ||
| 1090 | rcu_read_unlock(); | ||
| 1091 | kfree_skb(skb); | ||
| 1092 | return; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | ieee80211_xmit(sdata, skb, chanctx_conf->def.chan->band); | ||
| 1096 | rcu_read_unlock(); | ||
| 1066 | } | 1097 | } |
| 1067 | 1098 | ||
| 1068 | static void | 1099 | static void |
| @@ -1343,7 +1374,7 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, | |||
| 1343 | { | 1374 | { |
| 1344 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 1375 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
| 1345 | 1376 | ||
| 1346 | if (WARN_ON(tid >= STA_TID_NUM)) | 1377 | if (WARN_ON(tid >= IEEE80211_NUM_TIDS)) |
| 1347 | return; | 1378 | return; |
| 1348 | 1379 | ||
| 1349 | if (buffered) | 1380 | if (buffered) |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c88f161f8118..1489bca9ea97 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
| @@ -80,7 +80,6 @@ enum ieee80211_sta_info_flags { | |||
| 80 | WLAN_STA_TOFFSET_KNOWN, | 80 | WLAN_STA_TOFFSET_KNOWN, |
| 81 | }; | 81 | }; |
| 82 | 82 | ||
| 83 | #define STA_TID_NUM 16 | ||
| 84 | #define ADDBA_RESP_INTERVAL HZ | 83 | #define ADDBA_RESP_INTERVAL HZ |
| 85 | #define HT_AGG_MAX_RETRIES 15 | 84 | #define HT_AGG_MAX_RETRIES 15 |
| 86 | #define HT_AGG_BURST_RETRIES 3 | 85 | #define HT_AGG_BURST_RETRIES 3 |
| @@ -197,15 +196,15 @@ struct tid_ampdu_rx { | |||
| 197 | struct sta_ampdu_mlme { | 196 | struct sta_ampdu_mlme { |
| 198 | struct mutex mtx; | 197 | struct mutex mtx; |
| 199 | /* rx */ | 198 | /* rx */ |
| 200 | struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM]; | 199 | struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; |
| 201 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)]; | 200 | unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
| 202 | unsigned long tid_rx_stop_requested[BITS_TO_LONGS(STA_TID_NUM)]; | 201 | unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; |
| 203 | /* tx */ | 202 | /* tx */ |
| 204 | struct work_struct work; | 203 | struct work_struct work; |
| 205 | struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; | 204 | struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; |
| 206 | struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; | 205 | struct tid_ampdu_tx *tid_start_tx[IEEE80211_NUM_TIDS]; |
| 207 | unsigned long last_addba_req_time[STA_TID_NUM]; | 206 | unsigned long last_addba_req_time[IEEE80211_NUM_TIDS]; |
| 208 | u8 addba_req_num[STA_TID_NUM]; | 207 | u8 addba_req_num[IEEE80211_NUM_TIDS]; |
| 209 | u8 dialog_token_allocator; | 208 | u8 dialog_token_allocator; |
| 210 | }; | 209 | }; |
| 211 | 210 | ||
| @@ -228,6 +227,7 @@ struct sta_ampdu_mlme { | |||
| 228 | * "the" transmit rate | 227 | * "the" transmit rate |
| 229 | * @last_rx_rate_idx: rx status rate index of the last data packet | 228 | * @last_rx_rate_idx: rx status rate index of the last data packet |
| 230 | * @last_rx_rate_flag: rx status flag of the last data packet | 229 | * @last_rx_rate_flag: rx status flag of the last data packet |
| 230 | * @last_rx_rate_vht_nss: rx status nss of last data packet | ||
| 231 | * @lock: used for locking all fields that require locking, see comments | 231 | * @lock: used for locking all fields that require locking, see comments |
| 232 | * in the header file. | 232 | * in the header file. |
| 233 | * @drv_unblock_wk: used for driver PS unblocking | 233 | * @drv_unblock_wk: used for driver PS unblocking |
| @@ -250,6 +250,7 @@ struct sta_ampdu_mlme { | |||
| 250 | * @rx_dropped: number of dropped MPDUs from this STA | 250 | * @rx_dropped: number of dropped MPDUs from this STA |
| 251 | * @last_signal: signal of last received frame from this STA | 251 | * @last_signal: signal of last received frame from this STA |
| 252 | * @avg_signal: moving average of signal of received frames from this STA | 252 | * @avg_signal: moving average of signal of received frames from this STA |
| 253 | * @last_ack_signal: signal of last received Ack frame from this STA | ||
| 253 | * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) | 254 | * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) |
| 254 | * @tx_filtered_count: number of frames the hardware filtered for this STA | 255 | * @tx_filtered_count: number of frames the hardware filtered for this STA |
| 255 | * @tx_retry_failed: number of frames that failed retry | 256 | * @tx_retry_failed: number of frames that failed retry |
| @@ -273,7 +274,7 @@ struct sta_ampdu_mlme { | |||
| 273 | * @t_offset: timing offset relative to this host | 274 | * @t_offset: timing offset relative to this host |
| 274 | * @t_offset_setpoint: reference timing offset of this sta to be used when | 275 | * @t_offset_setpoint: reference timing offset of this sta to be used when |
| 275 | * calculating clockdrift | 276 | * calculating clockdrift |
| 276 | * @ch_type: peer's channel type | 277 | * @ch_width: peer's channel width |
| 277 | * @debugfs: debug filesystem info | 278 | * @debugfs: debug filesystem info |
| 278 | * @dead: set to true when sta is unlinked | 279 | * @dead: set to true when sta is unlinked |
| 279 | * @uploaded: set to true when sta is uploaded to the driver | 280 | * @uploaded: set to true when sta is uploaded to the driver |
| @@ -329,8 +330,9 @@ struct sta_info { | |||
| 329 | unsigned long rx_dropped; | 330 | unsigned long rx_dropped; |
| 330 | int last_signal; | 331 | int last_signal; |
| 331 | struct ewma avg_signal; | 332 | struct ewma avg_signal; |
| 333 | int last_ack_signal; | ||
| 332 | /* Plus 1 for non-QoS frames */ | 334 | /* Plus 1 for non-QoS frames */ |
| 333 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1]; | 335 | __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; |
| 334 | 336 | ||
| 335 | /* Updated from TX status path only, no locking requirements */ | 337 | /* Updated from TX status path only, no locking requirements */ |
| 336 | unsigned long tx_filtered_count; | 338 | unsigned long tx_filtered_count; |
| @@ -344,14 +346,15 @@ struct sta_info { | |||
| 344 | unsigned long tx_fragments; | 346 | unsigned long tx_fragments; |
| 345 | struct ieee80211_tx_rate last_tx_rate; | 347 | struct ieee80211_tx_rate last_tx_rate; |
| 346 | int last_rx_rate_idx; | 348 | int last_rx_rate_idx; |
| 347 | int last_rx_rate_flag; | 349 | u32 last_rx_rate_flag; |
| 350 | u8 last_rx_rate_vht_nss; | ||
| 348 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; | 351 | u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; |
| 349 | 352 | ||
| 350 | /* | 353 | /* |
| 351 | * Aggregation information, locked with lock. | 354 | * Aggregation information, locked with lock. |
| 352 | */ | 355 | */ |
| 353 | struct sta_ampdu_mlme ampdu_mlme; | 356 | struct sta_ampdu_mlme ampdu_mlme; |
| 354 | u8 timer_to_tid[STA_TID_NUM]; | 357 | u8 timer_to_tid[IEEE80211_NUM_TIDS]; |
| 355 | 358 | ||
| 356 | #ifdef CONFIG_MAC80211_MESH | 359 | #ifdef CONFIG_MAC80211_MESH |
| 357 | /* | 360 | /* |
| @@ -369,7 +372,7 @@ struct sta_info { | |||
| 369 | struct timer_list plink_timer; | 372 | struct timer_list plink_timer; |
| 370 | s64 t_offset; | 373 | s64 t_offset; |
| 371 | s64 t_offset_setpoint; | 374 | s64 t_offset_setpoint; |
| 372 | enum nl80211_channel_type ch_type; | 375 | enum nl80211_chan_width ch_width; |
| 373 | #endif | 376 | #endif |
| 374 | 377 | ||
| 375 | #ifdef CONFIG_MAC80211_DEBUGFS | 378 | #ifdef CONFIG_MAC80211_DEBUGFS |
| @@ -551,6 +554,8 @@ int sta_info_flush(struct ieee80211_local *local, | |||
| 551 | void sta_set_rate_info_tx(struct sta_info *sta, | 554 | void sta_set_rate_info_tx(struct sta_info *sta, |
| 552 | const struct ieee80211_tx_rate *rate, | 555 | const struct ieee80211_tx_rate *rate, |
| 553 | struct rate_info *rinfo); | 556 | struct rate_info *rinfo); |
| 557 | void sta_set_rate_info_rx(struct sta_info *sta, | ||
| 558 | struct rate_info *rinfo); | ||
| 554 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | 559 | void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, |
| 555 | unsigned long exp_time); | 560 | unsigned long exp_time); |
| 556 | 561 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 101eb88a2b78..07d99578a2b1 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
| @@ -189,30 +189,31 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) | |||
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | if (ieee80211_is_action(mgmt->frame_control) && | 191 | if (ieee80211_is_action(mgmt->frame_control) && |
| 192 | sdata->vif.type == NL80211_IFTYPE_STATION && | ||
| 193 | mgmt->u.action.category == WLAN_CATEGORY_HT && | 192 | mgmt->u.action.category == WLAN_CATEGORY_HT && |
| 194 | mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS) { | 193 | mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS && |
| 194 | sdata->vif.type == NL80211_IFTYPE_STATION && | ||
| 195 | ieee80211_sdata_running(sdata)) { | ||
| 195 | /* | 196 | /* |
| 196 | * This update looks racy, but isn't -- if we come | 197 | * This update looks racy, but isn't -- if we come |
| 197 | * here we've definitely got a station that we're | 198 | * here we've definitely got a station that we're |
| 198 | * talking to, and on a managed interface that can | 199 | * talking to, and on a managed interface that can |
| 199 | * only be the AP. And the only other place updating | 200 | * only be the AP. And the only other place updating |
| 200 | * this variable is before we're associated. | 201 | * this variable in managed mode is before association. |
| 201 | */ | 202 | */ |
| 202 | switch (mgmt->u.action.u.ht_smps.smps_control) { | 203 | switch (mgmt->u.action.u.ht_smps.smps_control) { |
| 203 | case WLAN_HT_SMPS_CONTROL_DYNAMIC: | 204 | case WLAN_HT_SMPS_CONTROL_DYNAMIC: |
| 204 | sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_DYNAMIC; | 205 | sdata->smps_mode = IEEE80211_SMPS_DYNAMIC; |
| 205 | break; | 206 | break; |
| 206 | case WLAN_HT_SMPS_CONTROL_STATIC: | 207 | case WLAN_HT_SMPS_CONTROL_STATIC: |
| 207 | sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_STATIC; | 208 | sdata->smps_mode = IEEE80211_SMPS_STATIC; |
| 208 | break; | 209 | break; |
| 209 | case WLAN_HT_SMPS_CONTROL_DISABLED: | 210 | case WLAN_HT_SMPS_CONTROL_DISABLED: |
| 210 | default: /* shouldn't happen since we don't send that */ | 211 | default: /* shouldn't happen since we don't send that */ |
| 211 | sta->sdata->u.mgd.ap_smps = IEEE80211_SMPS_OFF; | 212 | sdata->smps_mode = IEEE80211_SMPS_OFF; |
| 212 | break; | 213 | break; |
| 213 | } | 214 | } |
| 214 | 215 | ||
| 215 | ieee80211_queue_work(&local->hw, &local->recalc_smps); | 216 | ieee80211_queue_work(&local->hw, &sdata->recalc_smps); |
| 216 | } | 217 | } |
| 217 | } | 218 | } |
| 218 | 219 | ||
| @@ -324,6 +325,75 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
| 324 | 325 | ||
| 325 | } | 326 | } |
| 326 | 327 | ||
| 328 | static void ieee80211_report_used_skb(struct ieee80211_local *local, | ||
| 329 | struct sk_buff *skb, bool dropped) | ||
| 330 | { | ||
| 331 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 332 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
| 333 | bool acked = info->flags & IEEE80211_TX_STAT_ACK; | ||
| 334 | |||
| 335 | if (dropped) | ||
| 336 | acked = false; | ||
| 337 | |||
| 338 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | ||
| 339 | struct ieee80211_sub_if_data *sdata = NULL; | ||
| 340 | struct ieee80211_sub_if_data *iter_sdata; | ||
| 341 | u64 cookie = (unsigned long)skb; | ||
| 342 | |||
| 343 | rcu_read_lock(); | ||
| 344 | |||
| 345 | if (skb->dev) { | ||
| 346 | list_for_each_entry_rcu(iter_sdata, &local->interfaces, | ||
| 347 | list) { | ||
| 348 | if (!iter_sdata->dev) | ||
| 349 | continue; | ||
| 350 | |||
| 351 | if (skb->dev == iter_sdata->dev) { | ||
| 352 | sdata = iter_sdata; | ||
| 353 | break; | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } else { | ||
| 357 | sdata = rcu_dereference(local->p2p_sdata); | ||
| 358 | } | ||
| 359 | |||
| 360 | if (!sdata) | ||
| 361 | skb->dev = NULL; | ||
| 362 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
| 363 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
| 364 | cfg80211_probe_status(sdata->dev, hdr->addr1, | ||
| 365 | cookie, acked, GFP_ATOMIC); | ||
| 366 | } else { | ||
| 367 | cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, | ||
| 368 | skb->len, acked, GFP_ATOMIC); | ||
| 369 | } | ||
| 370 | |||
| 371 | rcu_read_unlock(); | ||
| 372 | } | ||
| 373 | |||
| 374 | if (unlikely(info->ack_frame_id)) { | ||
| 375 | struct sk_buff *ack_skb; | ||
| 376 | unsigned long flags; | ||
| 377 | |||
| 378 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
| 379 | ack_skb = idr_find(&local->ack_status_frames, | ||
| 380 | info->ack_frame_id); | ||
| 381 | if (ack_skb) | ||
| 382 | idr_remove(&local->ack_status_frames, | ||
| 383 | info->ack_frame_id); | ||
| 384 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
| 385 | |||
| 386 | if (ack_skb) { | ||
| 387 | if (!dropped) { | ||
| 388 | /* consumes ack_skb */ | ||
| 389 | skb_complete_wifi_ack(ack_skb, acked); | ||
| 390 | } else { | ||
| 391 | dev_kfree_skb_any(ack_skb); | ||
| 392 | } | ||
| 393 | } | ||
| 394 | } | ||
| 395 | } | ||
| 396 | |||
| 327 | /* | 397 | /* |
| 328 | * Use a static threshold for now, best value to be determined | 398 | * Use a static threshold for now, best value to be determined |
| 329 | * by testing ... | 399 | * by testing ... |
| @@ -432,7 +502,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 432 | IEEE80211_BAR_CTRL_TID_INFO_MASK) >> | 502 | IEEE80211_BAR_CTRL_TID_INFO_MASK) >> |
| 433 | IEEE80211_BAR_CTRL_TID_INFO_SHIFT; | 503 | IEEE80211_BAR_CTRL_TID_INFO_SHIFT; |
| 434 | 504 | ||
| 435 | ieee80211_set_bar_pending(sta, tid, ssn); | 505 | if (local->hw.flags & |
| 506 | IEEE80211_HW_TEARDOWN_AGGR_ON_BAR_FAIL) | ||
| 507 | ieee80211_stop_tx_ba_session(&sta->sta, tid); | ||
| 508 | else | ||
| 509 | ieee80211_set_bar_pending(sta, tid, ssn); | ||
| 436 | } | 510 | } |
| 437 | } | 511 | } |
| 438 | 512 | ||
| @@ -469,6 +543,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 469 | sta->lost_packets = 0; | 543 | sta->lost_packets = 0; |
| 470 | } | 544 | } |
| 471 | } | 545 | } |
| 546 | |||
| 547 | if (acked) | ||
| 548 | sta->last_ack_signal = info->status.ack_signal; | ||
| 472 | } | 549 | } |
| 473 | 550 | ||
| 474 | rcu_read_unlock(); | 551 | rcu_read_unlock(); |
| @@ -515,62 +592,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 515 | msecs_to_jiffies(10)); | 592 | msecs_to_jiffies(10)); |
| 516 | } | 593 | } |
| 517 | 594 | ||
| 518 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | 595 | ieee80211_report_used_skb(local, skb, false); |
| 519 | u64 cookie = (unsigned long)skb; | ||
| 520 | bool found = false; | ||
| 521 | |||
| 522 | acked = info->flags & IEEE80211_TX_STAT_ACK; | ||
| 523 | |||
| 524 | rcu_read_lock(); | ||
| 525 | |||
| 526 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
| 527 | if (!sdata->dev) | ||
| 528 | continue; | ||
| 529 | |||
| 530 | if (skb->dev != sdata->dev) | ||
| 531 | continue; | ||
| 532 | |||
| 533 | found = true; | ||
| 534 | break; | ||
| 535 | } | ||
| 536 | |||
| 537 | if (!skb->dev) { | ||
| 538 | sdata = rcu_dereference(local->p2p_sdata); | ||
| 539 | if (sdata) | ||
| 540 | found = true; | ||
| 541 | } | ||
| 542 | |||
| 543 | if (!found) | ||
| 544 | skb->dev = NULL; | ||
| 545 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
| 546 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
| 547 | cfg80211_probe_status(sdata->dev, hdr->addr1, | ||
| 548 | cookie, acked, GFP_ATOMIC); | ||
| 549 | } else { | ||
| 550 | cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, | ||
| 551 | skb->len, acked, GFP_ATOMIC); | ||
| 552 | } | ||
| 553 | |||
| 554 | rcu_read_unlock(); | ||
| 555 | } | ||
| 556 | |||
| 557 | if (unlikely(info->ack_frame_id)) { | ||
| 558 | struct sk_buff *ack_skb; | ||
| 559 | unsigned long flags; | ||
| 560 | |||
| 561 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
| 562 | ack_skb = idr_find(&local->ack_status_frames, | ||
| 563 | info->ack_frame_id); | ||
| 564 | if (ack_skb) | ||
| 565 | idr_remove(&local->ack_status_frames, | ||
| 566 | info->ack_frame_id); | ||
| 567 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
| 568 | |||
| 569 | /* consumes ack_skb */ | ||
| 570 | if (ack_skb) | ||
| 571 | skb_complete_wifi_ack(ack_skb, | ||
| 572 | info->flags & IEEE80211_TX_STAT_ACK); | ||
| 573 | } | ||
| 574 | 596 | ||
| 575 | /* this was a transmitted frame, but now we want to reuse it */ | 597 | /* this was a transmitted frame, but now we want to reuse it */ |
| 576 | skb_orphan(skb); | 598 | skb_orphan(skb); |
| @@ -646,25 +668,8 @@ EXPORT_SYMBOL(ieee80211_report_low_ack); | |||
| 646 | void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) | 668 | void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) |
| 647 | { | 669 | { |
| 648 | struct ieee80211_local *local = hw_to_local(hw); | 670 | struct ieee80211_local *local = hw_to_local(hw); |
| 649 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
| 650 | |||
| 651 | if (unlikely(info->ack_frame_id)) { | ||
| 652 | struct sk_buff *ack_skb; | ||
| 653 | unsigned long flags; | ||
| 654 | |||
| 655 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
| 656 | ack_skb = idr_find(&local->ack_status_frames, | ||
| 657 | info->ack_frame_id); | ||
| 658 | if (ack_skb) | ||
| 659 | idr_remove(&local->ack_status_frames, | ||
| 660 | info->ack_frame_id); | ||
| 661 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
| 662 | |||
| 663 | /* consumes ack_skb */ | ||
| 664 | if (ack_skb) | ||
| 665 | dev_kfree_skb_any(ack_skb); | ||
| 666 | } | ||
| 667 | 671 | ||
| 672 | ieee80211_report_used_skb(local, skb, true); | ||
| 668 | dev_kfree_skb_any(skb); | 673 | dev_kfree_skb_any(skb); |
| 669 | } | 674 | } |
| 670 | EXPORT_SYMBOL(ieee80211_free_txskb); | 675 | EXPORT_SYMBOL(ieee80211_free_txskb); |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 18d9c8a52e9e..a8270b441a6f 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
| @@ -28,6 +28,25 @@ | |||
| 28 | #define VIF_PR_FMT " vif:%s(%d%s)" | 28 | #define VIF_PR_FMT " vif:%s(%d%s)" |
| 29 | #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" | 29 | #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" |
| 30 | 30 | ||
| 31 | #define CHANCTX_ENTRY __field(u32, control_freq) \ | ||
| 32 | __field(u32, chan_width) \ | ||
| 33 | __field(u32, center_freq1) \ | ||
| 34 | __field(u32, center_freq2) \ | ||
| 35 | __field(u8, rx_chains_static) \ | ||
| 36 | __field(u8, rx_chains_dynamic) | ||
| 37 | #define CHANCTX_ASSIGN __entry->control_freq = ctx->conf.def.chan->center_freq;\ | ||
| 38 | __entry->chan_width = ctx->conf.def.width; \ | ||
| 39 | __entry->center_freq1 = ctx->conf.def.center_freq1; \ | ||
| 40 | __entry->center_freq2 = ctx->conf.def.center_freq2; \ | ||
| 41 | __entry->rx_chains_static = ctx->conf.rx_chains_static; \ | ||
| 42 | __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic | ||
| 43 | #define CHANCTX_PR_FMT " control:%d MHz width:%d center: %d/%d MHz chains:%d/%d" | ||
| 44 | #define CHANCTX_PR_ARG __entry->control_freq, __entry->chan_width, \ | ||
| 45 | __entry->center_freq1, __entry->center_freq2, \ | ||
| 46 | __entry->rx_chains_static, __entry->rx_chains_dynamic | ||
| 47 | |||
| 48 | |||
| 49 | |||
| 31 | /* | 50 | /* |
| 32 | * Tracing for driver callbacks. | 51 | * Tracing for driver callbacks. |
| 33 | */ | 52 | */ |
| @@ -301,20 +320,37 @@ TRACE_EVENT(drv_bss_info_changed, | |||
| 301 | TP_STRUCT__entry( | 320 | TP_STRUCT__entry( |
| 302 | LOCAL_ENTRY | 321 | LOCAL_ENTRY |
| 303 | VIF_ENTRY | 322 | VIF_ENTRY |
| 323 | __field(u32, changed) | ||
| 304 | __field(bool, assoc) | 324 | __field(bool, assoc) |
| 325 | __field(bool, ibss_joined) | ||
| 326 | __field(bool, ibss_creator) | ||
| 305 | __field(u16, aid) | 327 | __field(u16, aid) |
| 306 | __field(bool, cts) | 328 | __field(bool, cts) |
| 307 | __field(bool, shortpre) | 329 | __field(bool, shortpre) |
| 308 | __field(bool, shortslot) | 330 | __field(bool, shortslot) |
| 331 | __field(bool, enable_beacon) | ||
| 309 | __field(u8, dtimper) | 332 | __field(u8, dtimper) |
| 310 | __field(u16, bcnint) | 333 | __field(u16, bcnint) |
| 311 | __field(u16, assoc_cap) | 334 | __field(u16, assoc_cap) |
| 312 | __field(u64, sync_tsf) | 335 | __field(u64, sync_tsf) |
| 313 | __field(u32, sync_device_ts) | 336 | __field(u32, sync_device_ts) |
| 314 | __field(u32, basic_rates) | 337 | __field(u32, basic_rates) |
| 315 | __field(u32, changed) | 338 | __array(int, mcast_rate, IEEE80211_NUM_BANDS) |
| 316 | __field(bool, enable_beacon) | ||
| 317 | __field(u16, ht_operation_mode) | 339 | __field(u16, ht_operation_mode) |
| 340 | __field(s32, cqm_rssi_thold); | ||
| 341 | __field(s32, cqm_rssi_hyst); | ||
| 342 | __field(u32, channel_width); | ||
| 343 | __field(u32, channel_cfreq1); | ||
| 344 | __dynamic_array(u32, arp_addr_list, info->arp_addr_cnt); | ||
| 345 | __field(bool, arp_filter_enabled); | ||
| 346 | __field(bool, qos); | ||
| 347 | __field(bool, idle); | ||
| 348 | __field(bool, ps); | ||
| 349 | __dynamic_array(u8, ssid, info->ssid_len); | ||
| 350 | __field(bool, hidden_ssid); | ||
| 351 | __field(int, txpower) | ||
| 352 | __field(u8, p2p_ctwindow) | ||
| 353 | __field(bool, p2p_oppps) | ||
| 318 | ), | 354 | ), |
| 319 | 355 | ||
| 320 | TP_fast_assign( | 356 | TP_fast_assign( |
| @@ -323,17 +359,36 @@ TRACE_EVENT(drv_bss_info_changed, | |||
| 323 | __entry->changed = changed; | 359 | __entry->changed = changed; |
| 324 | __entry->aid = info->aid; | 360 | __entry->aid = info->aid; |
| 325 | __entry->assoc = info->assoc; | 361 | __entry->assoc = info->assoc; |
| 362 | __entry->ibss_joined = info->ibss_joined; | ||
| 363 | __entry->ibss_creator = info->ibss_creator; | ||
| 326 | __entry->shortpre = info->use_short_preamble; | 364 | __entry->shortpre = info->use_short_preamble; |
| 327 | __entry->cts = info->use_cts_prot; | 365 | __entry->cts = info->use_cts_prot; |
| 328 | __entry->shortslot = info->use_short_slot; | 366 | __entry->shortslot = info->use_short_slot; |
| 367 | __entry->enable_beacon = info->enable_beacon; | ||
| 329 | __entry->dtimper = info->dtim_period; | 368 | __entry->dtimper = info->dtim_period; |
| 330 | __entry->bcnint = info->beacon_int; | 369 | __entry->bcnint = info->beacon_int; |
| 331 | __entry->assoc_cap = info->assoc_capability; | 370 | __entry->assoc_cap = info->assoc_capability; |
| 332 | __entry->sync_tsf = info->sync_tsf; | 371 | __entry->sync_tsf = info->sync_tsf; |
| 333 | __entry->sync_device_ts = info->sync_device_ts; | 372 | __entry->sync_device_ts = info->sync_device_ts; |
| 334 | __entry->basic_rates = info->basic_rates; | 373 | __entry->basic_rates = info->basic_rates; |
| 335 | __entry->enable_beacon = info->enable_beacon; | 374 | memcpy(__entry->mcast_rate, info->mcast_rate, |
| 375 | sizeof(__entry->mcast_rate)); | ||
| 336 | __entry->ht_operation_mode = info->ht_operation_mode; | 376 | __entry->ht_operation_mode = info->ht_operation_mode; |
| 377 | __entry->cqm_rssi_thold = info->cqm_rssi_thold; | ||
| 378 | __entry->cqm_rssi_hyst = info->cqm_rssi_hyst; | ||
| 379 | __entry->channel_width = info->chandef.width; | ||
| 380 | __entry->channel_cfreq1 = info->chandef.center_freq1; | ||
| 381 | memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, | ||
| 382 | sizeof(u32) * info->arp_addr_cnt); | ||
| 383 | __entry->arp_filter_enabled = info->arp_filter_enabled; | ||
| 384 | __entry->qos = info->qos; | ||
| 385 | __entry->idle = info->idle; | ||
| 386 | __entry->ps = info->ps; | ||
| 387 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); | ||
| 388 | __entry->hidden_ssid = info->hidden_ssid; | ||
| 389 | __entry->txpower = info->txpower; | ||
| 390 | __entry->p2p_ctwindow = info->p2p_ctwindow; | ||
| 391 | __entry->p2p_oppps = info->p2p_oppps; | ||
| 337 | ), | 392 | ), |
| 338 | 393 | ||
| 339 | TP_printk( | 394 | TP_printk( |
| @@ -971,28 +1026,31 @@ TRACE_EVENT(drv_get_antenna, | |||
| 971 | ); | 1026 | ); |
| 972 | 1027 | ||
| 973 | TRACE_EVENT(drv_remain_on_channel, | 1028 | TRACE_EVENT(drv_remain_on_channel, |
| 974 | TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan, | 1029 | TP_PROTO(struct ieee80211_local *local, |
| 975 | enum nl80211_channel_type chantype, unsigned int duration), | 1030 | struct ieee80211_sub_if_data *sdata, |
| 1031 | struct ieee80211_channel *chan, | ||
| 1032 | unsigned int duration), | ||
| 976 | 1033 | ||
| 977 | TP_ARGS(local, chan, chantype, duration), | 1034 | TP_ARGS(local, sdata, chan, duration), |
| 978 | 1035 | ||
| 979 | TP_STRUCT__entry( | 1036 | TP_STRUCT__entry( |
| 980 | LOCAL_ENTRY | 1037 | LOCAL_ENTRY |
| 1038 | VIF_ENTRY | ||
| 981 | __field(int, center_freq) | 1039 | __field(int, center_freq) |
| 982 | __field(int, channel_type) | ||
| 983 | __field(unsigned int, duration) | 1040 | __field(unsigned int, duration) |
| 984 | ), | 1041 | ), |
| 985 | 1042 | ||
| 986 | TP_fast_assign( | 1043 | TP_fast_assign( |
| 987 | LOCAL_ASSIGN; | 1044 | LOCAL_ASSIGN; |
| 1045 | VIF_ASSIGN; | ||
| 988 | __entry->center_freq = chan->center_freq; | 1046 | __entry->center_freq = chan->center_freq; |
| 989 | __entry->channel_type = chantype; | ||
| 990 | __entry->duration = duration; | 1047 | __entry->duration = duration; |
| 991 | ), | 1048 | ), |
| 992 | 1049 | ||
| 993 | TP_printk( | 1050 | TP_printk( |
| 994 | LOCAL_PR_FMT " freq:%dMHz duration:%dms", | 1051 | LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms", |
| 995 | LOCAL_PR_ARG, __entry->center_freq, __entry->duration | 1052 | LOCAL_PR_ARG, VIF_PR_ARG, |
| 1053 | __entry->center_freq, __entry->duration | ||
| 996 | ) | 1054 | ) |
| 997 | ); | 1055 | ); |
| 998 | 1056 | ||
| @@ -1001,34 +1059,6 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel, | |||
| 1001 | TP_ARGS(local) | 1059 | TP_ARGS(local) |
| 1002 | ); | 1060 | ); |
| 1003 | 1061 | ||
| 1004 | TRACE_EVENT(drv_offchannel_tx, | ||
| 1005 | TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb, | ||
| 1006 | struct ieee80211_channel *chan, | ||
| 1007 | enum nl80211_channel_type channel_type, | ||
| 1008 | unsigned int wait), | ||
| 1009 | |||
| 1010 | TP_ARGS(local, skb, chan, channel_type, wait), | ||
| 1011 | |||
| 1012 | TP_STRUCT__entry( | ||
| 1013 | LOCAL_ENTRY | ||
| 1014 | __field(int, center_freq) | ||
| 1015 | __field(int, channel_type) | ||
| 1016 | __field(unsigned int, wait) | ||
| 1017 | ), | ||
| 1018 | |||
| 1019 | TP_fast_assign( | ||
| 1020 | LOCAL_ASSIGN; | ||
| 1021 | __entry->center_freq = chan->center_freq; | ||
| 1022 | __entry->channel_type = channel_type; | ||
| 1023 | __entry->wait = wait; | ||
| 1024 | ), | ||
| 1025 | |||
| 1026 | TP_printk( | ||
| 1027 | LOCAL_PR_FMT " freq:%dMHz, wait:%dms", | ||
| 1028 | LOCAL_PR_ARG, __entry->center_freq, __entry->wait | ||
| 1029 | ) | ||
| 1030 | ); | ||
| 1031 | |||
| 1032 | TRACE_EVENT(drv_set_ringparam, | 1062 | TRACE_EVENT(drv_set_ringparam, |
| 1033 | TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), | 1063 | TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), |
| 1034 | 1064 | ||
| @@ -1256,6 +1286,146 @@ DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, | |||
| 1256 | TP_ARGS(local, sdata) | 1286 | TP_ARGS(local, sdata) |
| 1257 | ); | 1287 | ); |
| 1258 | 1288 | ||
| 1289 | DECLARE_EVENT_CLASS(local_chanctx, | ||
| 1290 | TP_PROTO(struct ieee80211_local *local, | ||
| 1291 | struct ieee80211_chanctx *ctx), | ||
| 1292 | |||
| 1293 | TP_ARGS(local, ctx), | ||
| 1294 | |||
| 1295 | TP_STRUCT__entry( | ||
| 1296 | LOCAL_ENTRY | ||
| 1297 | CHANCTX_ENTRY | ||
| 1298 | ), | ||
| 1299 | |||
| 1300 | TP_fast_assign( | ||
| 1301 | LOCAL_ASSIGN; | ||
| 1302 | CHANCTX_ASSIGN; | ||
| 1303 | ), | ||
| 1304 | |||
| 1305 | TP_printk( | ||
| 1306 | LOCAL_PR_FMT CHANCTX_PR_FMT, | ||
| 1307 | LOCAL_PR_ARG, CHANCTX_PR_ARG | ||
| 1308 | ) | ||
| 1309 | ); | ||
| 1310 | |||
| 1311 | DEFINE_EVENT(local_chanctx, drv_add_chanctx, | ||
| 1312 | TP_PROTO(struct ieee80211_local *local, | ||
| 1313 | struct ieee80211_chanctx *ctx), | ||
| 1314 | TP_ARGS(local, ctx) | ||
| 1315 | ); | ||
| 1316 | |||
| 1317 | DEFINE_EVENT(local_chanctx, drv_remove_chanctx, | ||
| 1318 | TP_PROTO(struct ieee80211_local *local, | ||
| 1319 | struct ieee80211_chanctx *ctx), | ||
| 1320 | TP_ARGS(local, ctx) | ||
| 1321 | ); | ||
| 1322 | |||
| 1323 | TRACE_EVENT(drv_change_chanctx, | ||
| 1324 | TP_PROTO(struct ieee80211_local *local, | ||
| 1325 | struct ieee80211_chanctx *ctx, | ||
| 1326 | u32 changed), | ||
| 1327 | |||
| 1328 | TP_ARGS(local, ctx, changed), | ||
| 1329 | |||
| 1330 | TP_STRUCT__entry( | ||
| 1331 | LOCAL_ENTRY | ||
| 1332 | CHANCTX_ENTRY | ||
| 1333 | __field(u32, changed) | ||
| 1334 | ), | ||
| 1335 | |||
| 1336 | TP_fast_assign( | ||
| 1337 | LOCAL_ASSIGN; | ||
| 1338 | CHANCTX_ASSIGN; | ||
| 1339 | __entry->changed = changed; | ||
| 1340 | ), | ||
| 1341 | |||
| 1342 | TP_printk( | ||
| 1343 | LOCAL_PR_FMT CHANCTX_PR_FMT " changed:%#x", | ||
| 1344 | LOCAL_PR_ARG, CHANCTX_PR_ARG, __entry->changed | ||
| 1345 | ) | ||
| 1346 | ); | ||
| 1347 | |||
| 1348 | DECLARE_EVENT_CLASS(local_sdata_chanctx, | ||
| 1349 | TP_PROTO(struct ieee80211_local *local, | ||
| 1350 | struct ieee80211_sub_if_data *sdata, | ||
| 1351 | struct ieee80211_chanctx *ctx), | ||
| 1352 | |||
| 1353 | TP_ARGS(local, sdata, ctx), | ||
| 1354 | |||
| 1355 | TP_STRUCT__entry( | ||
| 1356 | LOCAL_ENTRY | ||
| 1357 | VIF_ENTRY | ||
| 1358 | CHANCTX_ENTRY | ||
| 1359 | ), | ||
| 1360 | |||
| 1361 | TP_fast_assign( | ||
| 1362 | LOCAL_ASSIGN; | ||
| 1363 | VIF_ASSIGN; | ||
| 1364 | CHANCTX_ASSIGN; | ||
| 1365 | ), | ||
| 1366 | |||
| 1367 | TP_printk( | ||
| 1368 | LOCAL_PR_FMT VIF_PR_FMT CHANCTX_PR_FMT, | ||
| 1369 | LOCAL_PR_ARG, VIF_PR_ARG, CHANCTX_PR_ARG | ||
| 1370 | ) | ||
| 1371 | ); | ||
| 1372 | |||
| 1373 | DEFINE_EVENT(local_sdata_chanctx, drv_assign_vif_chanctx, | ||
| 1374 | TP_PROTO(struct ieee80211_local *local, | ||
| 1375 | struct ieee80211_sub_if_data *sdata, | ||
| 1376 | struct ieee80211_chanctx *ctx), | ||
| 1377 | TP_ARGS(local, sdata, ctx) | ||
| 1378 | ); | ||
| 1379 | |||
| 1380 | DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, | ||
| 1381 | TP_PROTO(struct ieee80211_local *local, | ||
| 1382 | struct ieee80211_sub_if_data *sdata, | ||
| 1383 | struct ieee80211_chanctx *ctx), | ||
| 1384 | TP_ARGS(local, sdata, ctx) | ||
| 1385 | ); | ||
| 1386 | |||
| 1387 | TRACE_EVENT(drv_start_ap, | ||
| 1388 | TP_PROTO(struct ieee80211_local *local, | ||
| 1389 | struct ieee80211_sub_if_data *sdata, | ||
| 1390 | struct ieee80211_bss_conf *info), | ||
| 1391 | |||
| 1392 | TP_ARGS(local, sdata, info), | ||
| 1393 | |||
| 1394 | TP_STRUCT__entry( | ||
| 1395 | LOCAL_ENTRY | ||
| 1396 | VIF_ENTRY | ||
| 1397 | __field(u8, dtimper) | ||
| 1398 | __field(u16, bcnint) | ||
| 1399 | __dynamic_array(u8, ssid, info->ssid_len); | ||
| 1400 | __field(bool, hidden_ssid); | ||
| 1401 | ), | ||
| 1402 | |||
| 1403 | TP_fast_assign( | ||
| 1404 | LOCAL_ASSIGN; | ||
| 1405 | VIF_ASSIGN; | ||
| 1406 | __entry->dtimper = info->dtim_period; | ||
| 1407 | __entry->bcnint = info->beacon_int; | ||
| 1408 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); | ||
| 1409 | __entry->hidden_ssid = info->hidden_ssid; | ||
| 1410 | ), | ||
| 1411 | |||
| 1412 | TP_printk( | ||
| 1413 | LOCAL_PR_FMT VIF_PR_FMT, | ||
| 1414 | LOCAL_PR_ARG, VIF_PR_ARG | ||
| 1415 | ) | ||
| 1416 | ); | ||
| 1417 | |||
| 1418 | DEFINE_EVENT(local_sdata_evt, drv_stop_ap, | ||
| 1419 | TP_PROTO(struct ieee80211_local *local, | ||
| 1420 | struct ieee80211_sub_if_data *sdata), | ||
| 1421 | TP_ARGS(local, sdata) | ||
| 1422 | ); | ||
| 1423 | |||
| 1424 | DEFINE_EVENT(local_only_evt, drv_restart_complete, | ||
| 1425 | TP_PROTO(struct ieee80211_local *local), | ||
| 1426 | TP_ARGS(local) | ||
| 1427 | ); | ||
| 1428 | |||
| 1259 | /* | 1429 | /* |
| 1260 | * Tracing for API calls that drivers call. | 1430 | * Tracing for API calls that drivers call. |
| 1261 | */ | 1431 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index b858ebe41fda..e9eadc40c09c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -324,22 +324,20 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
| 324 | struct ieee80211_sub_if_data *sdata; | 324 | struct ieee80211_sub_if_data *sdata; |
| 325 | struct sta_info *sta; | 325 | struct sta_info *sta; |
| 326 | 326 | ||
| 327 | /* | ||
| 328 | * virtual interfaces are protected by RCU | ||
| 329 | */ | ||
| 330 | rcu_read_lock(); | ||
| 331 | |||
| 332 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 327 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
| 333 | struct ieee80211_if_ap *ap; | 328 | struct ps_data *ps; |
| 334 | if (sdata->vif.type != NL80211_IFTYPE_AP) | 329 | |
| 330 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
| 331 | ps = &sdata->u.ap.ps; | ||
| 332 | else | ||
| 335 | continue; | 333 | continue; |
| 336 | ap = &sdata->u.ap; | 334 | |
| 337 | skb = skb_dequeue(&ap->ps_bc_buf); | 335 | skb = skb_dequeue(&ps->bc_buf); |
| 338 | if (skb) { | 336 | if (skb) { |
| 339 | purged++; | 337 | purged++; |
| 340 | dev_kfree_skb(skb); | 338 | dev_kfree_skb(skb); |
| 341 | } | 339 | } |
| 342 | total += skb_queue_len(&ap->ps_bc_buf); | 340 | total += skb_queue_len(&ps->bc_buf); |
| 343 | } | 341 | } |
| 344 | 342 | ||
| 345 | /* | 343 | /* |
| @@ -360,8 +358,6 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
| 360 | } | 358 | } |
| 361 | } | 359 | } |
| 362 | 360 | ||
| 363 | rcu_read_unlock(); | ||
| 364 | |||
| 365 | local->total_ps_buffered = total; | 361 | local->total_ps_buffered = total; |
| 366 | ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged); | 362 | ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged); |
| 367 | } | 363 | } |
| @@ -371,6 +367,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 371 | { | 367 | { |
| 372 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 368 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
| 373 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | 369 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; |
| 370 | struct ps_data *ps; | ||
| 374 | 371 | ||
| 375 | /* | 372 | /* |
| 376 | * broadcast/multicast frame | 373 | * broadcast/multicast frame |
| @@ -380,16 +377,24 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 380 | * This is done either by the hardware or us. | 377 | * This is done either by the hardware or us. |
| 381 | */ | 378 | */ |
| 382 | 379 | ||
| 383 | /* powersaving STAs only in AP/VLAN mode */ | 380 | /* powersaving STAs currently only in AP/VLAN mode */ |
| 384 | if (!tx->sdata->bss) | 381 | if (tx->sdata->vif.type == NL80211_IFTYPE_AP || |
| 382 | tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | ||
| 383 | if (!tx->sdata->bss) | ||
| 384 | return TX_CONTINUE; | ||
| 385 | |||
| 386 | ps = &tx->sdata->bss->ps; | ||
| 387 | } else { | ||
| 385 | return TX_CONTINUE; | 388 | return TX_CONTINUE; |
| 389 | } | ||
| 390 | |||
| 386 | 391 | ||
| 387 | /* no buffering for ordered frames */ | 392 | /* no buffering for ordered frames */ |
| 388 | if (ieee80211_has_order(hdr->frame_control)) | 393 | if (ieee80211_has_order(hdr->frame_control)) |
| 389 | return TX_CONTINUE; | 394 | return TX_CONTINUE; |
| 390 | 395 | ||
| 391 | /* no stations in PS mode */ | 396 | /* no stations in PS mode */ |
| 392 | if (!atomic_read(&tx->sdata->bss->num_sta_ps)) | 397 | if (!atomic_read(&ps->num_sta_ps)) |
| 393 | return TX_CONTINUE; | 398 | return TX_CONTINUE; |
| 394 | 399 | ||
| 395 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | 400 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; |
| @@ -404,14 +409,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
| 404 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) | 409 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) |
| 405 | purge_old_ps_buffers(tx->local); | 410 | purge_old_ps_buffers(tx->local); |
| 406 | 411 | ||
| 407 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { | 412 | if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) { |
| 408 | ps_dbg(tx->sdata, | 413 | ps_dbg(tx->sdata, |
| 409 | "BC TX buffer full - dropping the oldest frame\n"); | 414 | "BC TX buffer full - dropping the oldest frame\n"); |
| 410 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); | 415 | dev_kfree_skb(skb_dequeue(&ps->bc_buf)); |
| 411 | } else | 416 | } else |
| 412 | tx->local->total_ps_buffered++; | 417 | tx->local->total_ps_buffered++; |
| 413 | 418 | ||
| 414 | skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); | 419 | skb_queue_tail(&ps->bc_buf, tx->skb); |
| 415 | 420 | ||
| 416 | return TX_QUEUED; | 421 | return TX_QUEUED; |
| 417 | } | 422 | } |
| @@ -951,7 +956,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
| 951 | fragnum = 0; | 956 | fragnum = 0; |
| 952 | 957 | ||
| 953 | skb_queue_walk(&tx->skbs, skb) { | 958 | skb_queue_walk(&tx->skbs, skb) { |
| 954 | int next_len; | ||
| 955 | const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); | 959 | const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); |
| 956 | 960 | ||
| 957 | hdr = (void *)skb->data; | 961 | hdr = (void *)skb->data; |
| @@ -970,7 +974,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
| 970 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 974 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
| 971 | } else { | 975 | } else { |
| 972 | hdr->frame_control &= ~morefrags; | 976 | hdr->frame_control &= ~morefrags; |
| 973 | next_len = 0; | ||
| 974 | } | 977 | } |
| 975 | hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); | 978 | hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); |
| 976 | fragnum++; | 979 | fragnum++; |
| @@ -1372,7 +1375,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
| 1372 | * Returns false if the frame couldn't be transmitted but was queued instead. | 1375 | * Returns false if the frame couldn't be transmitted but was queued instead. |
| 1373 | */ | 1376 | */ |
| 1374 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | 1377 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, |
| 1375 | struct sk_buff *skb, bool txpending) | 1378 | struct sk_buff *skb, bool txpending, |
| 1379 | enum ieee80211_band band) | ||
| 1376 | { | 1380 | { |
| 1377 | struct ieee80211_local *local = sdata->local; | 1381 | struct ieee80211_local *local = sdata->local; |
| 1378 | struct ieee80211_tx_data tx; | 1382 | struct ieee80211_tx_data tx; |
| @@ -1386,20 +1390,18 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
| 1386 | return true; | 1390 | return true; |
| 1387 | } | 1391 | } |
| 1388 | 1392 | ||
| 1389 | rcu_read_lock(); | ||
| 1390 | |||
| 1391 | /* initialises tx */ | 1393 | /* initialises tx */ |
| 1392 | led_len = skb->len; | 1394 | led_len = skb->len; |
| 1393 | res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); | 1395 | res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); |
| 1394 | 1396 | ||
| 1395 | if (unlikely(res_prepare == TX_DROP)) { | 1397 | if (unlikely(res_prepare == TX_DROP)) { |
| 1396 | ieee80211_free_txskb(&local->hw, skb); | 1398 | ieee80211_free_txskb(&local->hw, skb); |
| 1397 | goto out; | 1399 | return true; |
| 1398 | } else if (unlikely(res_prepare == TX_QUEUED)) { | 1400 | } else if (unlikely(res_prepare == TX_QUEUED)) { |
| 1399 | goto out; | 1401 | return true; |
| 1400 | } | 1402 | } |
| 1401 | 1403 | ||
| 1402 | info->band = local->hw.conf.channel->band; | 1404 | info->band = band; |
| 1403 | 1405 | ||
| 1404 | /* set up hw_queue value early */ | 1406 | /* set up hw_queue value early */ |
| 1405 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || | 1407 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || |
| @@ -1410,8 +1412,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
| 1410 | if (!invoke_tx_handlers(&tx)) | 1412 | if (!invoke_tx_handlers(&tx)) |
| 1411 | result = __ieee80211_tx(local, &tx.skbs, led_len, | 1413 | result = __ieee80211_tx(local, &tx.skbs, led_len, |
| 1412 | tx.sta, txpending); | 1414 | tx.sta, txpending); |
| 1413 | out: | 1415 | |
| 1414 | rcu_read_unlock(); | ||
| 1415 | return result; | 1416 | return result; |
| 1416 | } | 1417 | } |
| 1417 | 1418 | ||
| @@ -1446,7 +1447,8 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, | |||
| 1446 | return 0; | 1447 | return 0; |
| 1447 | } | 1448 | } |
| 1448 | 1449 | ||
| 1449 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | 1450 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
| 1451 | enum ieee80211_band band) | ||
| 1450 | { | 1452 | { |
| 1451 | struct ieee80211_local *local = sdata->local; | 1453 | struct ieee80211_local *local = sdata->local; |
| 1452 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1454 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| @@ -1454,8 +1456,6 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
| 1454 | int headroom; | 1456 | int headroom; |
| 1455 | bool may_encrypt; | 1457 | bool may_encrypt; |
| 1456 | 1458 | ||
| 1457 | rcu_read_lock(); | ||
| 1458 | |||
| 1459 | may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); | 1459 | may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); |
| 1460 | 1460 | ||
| 1461 | headroom = local->tx_headroom; | 1461 | headroom = local->tx_headroom; |
| @@ -1466,7 +1466,6 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
| 1466 | 1466 | ||
| 1467 | if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { | 1467 | if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { |
| 1468 | ieee80211_free_txskb(&local->hw, skb); | 1468 | ieee80211_free_txskb(&local->hw, skb); |
| 1469 | rcu_read_unlock(); | ||
| 1470 | return; | 1469 | return; |
| 1471 | } | 1470 | } |
| 1472 | 1471 | ||
| @@ -1478,13 +1477,11 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
| 1478 | !is_multicast_ether_addr(hdr->addr1) && | 1477 | !is_multicast_ether_addr(hdr->addr1) && |
| 1479 | mesh_nexthop_resolve(skb, sdata)) { | 1478 | mesh_nexthop_resolve(skb, sdata)) { |
| 1480 | /* skb queued: don't free */ | 1479 | /* skb queued: don't free */ |
| 1481 | rcu_read_unlock(); | ||
| 1482 | return; | 1480 | return; |
| 1483 | } | 1481 | } |
| 1484 | 1482 | ||
| 1485 | ieee80211_set_qos_hdr(sdata, skb); | 1483 | ieee80211_set_qos_hdr(sdata, skb); |
| 1486 | ieee80211_tx(sdata, skb, false); | 1484 | ieee80211_tx(sdata, skb, false, band); |
| 1487 | rcu_read_unlock(); | ||
| 1488 | } | 1485 | } |
| 1489 | 1486 | ||
| 1490 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | 1487 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) |
| @@ -1574,7 +1571,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
| 1574 | struct net_device *dev) | 1571 | struct net_device *dev) |
| 1575 | { | 1572 | { |
| 1576 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1573 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
| 1577 | struct ieee80211_channel *chan = local->hw.conf.channel; | 1574 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 1575 | struct ieee80211_channel *chan; | ||
| 1578 | struct ieee80211_radiotap_header *prthdr = | 1576 | struct ieee80211_radiotap_header *prthdr = |
| 1579 | (struct ieee80211_radiotap_header *)skb->data; | 1577 | (struct ieee80211_radiotap_header *)skb->data; |
| 1580 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1578 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| @@ -1583,26 +1581,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
| 1583 | u16 len_rthdr; | 1581 | u16 len_rthdr; |
| 1584 | int hdrlen; | 1582 | int hdrlen; |
| 1585 | 1583 | ||
| 1586 | /* | ||
| 1587 | * Frame injection is not allowed if beaconing is not allowed | ||
| 1588 | * or if we need radar detection. Beaconing is usually not allowed when | ||
| 1589 | * the mode or operation (Adhoc, AP, Mesh) does not support DFS. | ||
| 1590 | * Passive scan is also used in world regulatory domains where | ||
| 1591 | * your country is not known and as such it should be treated as | ||
| 1592 | * NO TX unless the channel is explicitly allowed in which case | ||
| 1593 | * your current regulatory domain would not have the passive scan | ||
| 1594 | * flag. | ||
| 1595 | * | ||
| 1596 | * Since AP mode uses monitor interfaces to inject/TX management | ||
| 1597 | * frames we can make AP mode the exception to this rule once it | ||
| 1598 | * supports radar detection as its implementation can deal with | ||
| 1599 | * radar detection by itself. We can do that later by adding a | ||
| 1600 | * monitor flag interfaces used for AP support. | ||
| 1601 | */ | ||
| 1602 | if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR | | ||
| 1603 | IEEE80211_CHAN_PASSIVE_SCAN))) | ||
| 1604 | goto fail; | ||
| 1605 | |||
| 1606 | /* check for not even having the fixed radiotap header part */ | 1584 | /* check for not even having the fixed radiotap header part */ |
| 1607 | if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) | 1585 | if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) |
| 1608 | goto fail; /* too short to be possibly valid */ | 1586 | goto fail; /* too short to be possibly valid */ |
| @@ -1688,11 +1666,45 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
| 1688 | } | 1666 | } |
| 1689 | } | 1667 | } |
| 1690 | 1668 | ||
| 1691 | ieee80211_xmit(sdata, skb); | 1669 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 1670 | if (!chanctx_conf) { | ||
| 1671 | tmp_sdata = rcu_dereference(local->monitor_sdata); | ||
| 1672 | if (tmp_sdata) | ||
| 1673 | chanctx_conf = | ||
| 1674 | rcu_dereference(tmp_sdata->vif.chanctx_conf); | ||
| 1675 | } | ||
| 1676 | if (!chanctx_conf) | ||
| 1677 | goto fail_rcu; | ||
| 1678 | |||
| 1679 | chan = chanctx_conf->def.chan; | ||
| 1680 | |||
| 1681 | /* | ||
| 1682 | * Frame injection is not allowed if beaconing is not allowed | ||
| 1683 | * or if we need radar detection. Beaconing is usually not allowed when | ||
| 1684 | * the mode or operation (Adhoc, AP, Mesh) does not support DFS. | ||
| 1685 | * Passive scan is also used in world regulatory domains where | ||
| 1686 | * your country is not known and as such it should be treated as | ||
| 1687 | * NO TX unless the channel is explicitly allowed in which case | ||
| 1688 | * your current regulatory domain would not have the passive scan | ||
| 1689 | * flag. | ||
| 1690 | * | ||
| 1691 | * Since AP mode uses monitor interfaces to inject/TX management | ||
| 1692 | * frames we can make AP mode the exception to this rule once it | ||
| 1693 | * supports radar detection as its implementation can deal with | ||
| 1694 | * radar detection by itself. We can do that later by adding a | ||
| 1695 | * monitor flag interfaces used for AP support. | ||
| 1696 | */ | ||
| 1697 | if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR | | ||
| 1698 | IEEE80211_CHAN_PASSIVE_SCAN))) | ||
| 1699 | goto fail_rcu; | ||
| 1700 | |||
| 1701 | ieee80211_xmit(sdata, skb, chan->band); | ||
| 1692 | rcu_read_unlock(); | 1702 | rcu_read_unlock(); |
| 1693 | 1703 | ||
| 1694 | return NETDEV_TX_OK; | 1704 | return NETDEV_TX_OK; |
| 1695 | 1705 | ||
| 1706 | fail_rcu: | ||
| 1707 | rcu_read_unlock(); | ||
| 1696 | fail: | 1708 | fail: |
| 1697 | dev_kfree_skb(skb); | 1709 | dev_kfree_skb(skb); |
| 1698 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ | 1710 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ |
| @@ -1734,6 +1746,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1734 | bool multicast; | 1746 | bool multicast; |
| 1735 | u32 info_flags = 0; | 1747 | u32 info_flags = 0; |
| 1736 | u16 info_id = 0; | 1748 | u16 info_id = 0; |
| 1749 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 1750 | struct ieee80211_sub_if_data *ap_sdata; | ||
| 1751 | enum ieee80211_band band; | ||
| 1737 | 1752 | ||
| 1738 | if (unlikely(skb->len < ETH_HLEN)) | 1753 | if (unlikely(skb->len < ETH_HLEN)) |
| 1739 | goto fail; | 1754 | goto fail; |
| @@ -1743,9 +1758,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1743 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 1758 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
| 1744 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | 1759 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
| 1745 | 1760 | ||
| 1761 | rcu_read_lock(); | ||
| 1762 | |||
| 1746 | switch (sdata->vif.type) { | 1763 | switch (sdata->vif.type) { |
| 1747 | case NL80211_IFTYPE_AP_VLAN: | 1764 | case NL80211_IFTYPE_AP_VLAN: |
| 1748 | rcu_read_lock(); | ||
| 1749 | sta = rcu_dereference(sdata->u.vlan.sta); | 1765 | sta = rcu_dereference(sdata->u.vlan.sta); |
| 1750 | if (sta) { | 1766 | if (sta) { |
| 1751 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1767 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
| @@ -1758,7 +1774,12 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1758 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); | 1774 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); |
| 1759 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); | 1775 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); |
| 1760 | } | 1776 | } |
| 1761 | rcu_read_unlock(); | 1777 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
| 1778 | u.ap); | ||
| 1779 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); | ||
| 1780 | if (!chanctx_conf) | ||
| 1781 | goto fail_rcu; | ||
| 1782 | band = chanctx_conf->def.chan->band; | ||
| 1762 | if (sta) | 1783 | if (sta) |
| 1763 | break; | 1784 | break; |
| 1764 | /* fall through */ | 1785 | /* fall through */ |
| @@ -1769,6 +1790,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1769 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); | 1790 | memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); |
| 1770 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); | 1791 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); |
| 1771 | hdrlen = 24; | 1792 | hdrlen = 24; |
| 1793 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
| 1794 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 1795 | if (!chanctx_conf) | ||
| 1796 | goto fail_rcu; | ||
| 1797 | band = chanctx_conf->def.chan->band; | ||
| 1772 | break; | 1798 | break; |
| 1773 | case NL80211_IFTYPE_WDS: | 1799 | case NL80211_IFTYPE_WDS: |
| 1774 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1800 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
| @@ -1778,15 +1804,20 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1778 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1804 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
| 1779 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1805 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
| 1780 | hdrlen = 30; | 1806 | hdrlen = 30; |
| 1807 | /* | ||
| 1808 | * This is the exception! WDS style interfaces are prohibited | ||
| 1809 | * when channel contexts are in used so this must be valid | ||
| 1810 | */ | ||
| 1811 | band = local->hw.conf.channel->band; | ||
| 1781 | break; | 1812 | break; |
| 1782 | #ifdef CONFIG_MAC80211_MESH | 1813 | #ifdef CONFIG_MAC80211_MESH |
| 1783 | case NL80211_IFTYPE_MESH_POINT: | 1814 | case NL80211_IFTYPE_MESH_POINT: |
| 1784 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { | 1815 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { |
| 1785 | /* Do not send frames with mesh_ttl == 0 */ | 1816 | /* Do not send frames with mesh_ttl == 0 */ |
| 1786 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | 1817 | sdata->u.mesh.mshstats.dropped_frames_ttl++; |
| 1787 | goto fail; | 1818 | goto fail_rcu; |
| 1788 | } | 1819 | } |
| 1789 | rcu_read_lock(); | 1820 | |
| 1790 | if (!is_multicast_ether_addr(skb->data)) { | 1821 | if (!is_multicast_ether_addr(skb->data)) { |
| 1791 | mpath = mesh_path_lookup(skb->data, sdata); | 1822 | mpath = mesh_path_lookup(skb->data, sdata); |
| 1792 | if (!mpath) | 1823 | if (!mpath) |
| @@ -1803,7 +1834,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1803 | !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) { | 1834 | !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) { |
| 1804 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1835 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
| 1805 | skb->data, skb->data + ETH_ALEN); | 1836 | skb->data, skb->data + ETH_ALEN); |
| 1806 | rcu_read_unlock(); | ||
| 1807 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | 1837 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
| 1808 | sdata, NULL, NULL); | 1838 | sdata, NULL, NULL); |
| 1809 | } else { | 1839 | } else { |
| @@ -1819,7 +1849,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1819 | mesh_da = mppath->mpp; | 1849 | mesh_da = mppath->mpp; |
| 1820 | else if (mpath) | 1850 | else if (mpath) |
| 1821 | mesh_da = mpath->dst; | 1851 | mesh_da = mpath->dst; |
| 1822 | rcu_read_unlock(); | ||
| 1823 | 1852 | ||
| 1824 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | 1853 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
| 1825 | mesh_da, sdata->vif.addr); | 1854 | mesh_da, sdata->vif.addr); |
| @@ -1839,13 +1868,16 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1839 | skb->data + ETH_ALEN); | 1868 | skb->data + ETH_ALEN); |
| 1840 | 1869 | ||
| 1841 | } | 1870 | } |
| 1871 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 1872 | if (!chanctx_conf) | ||
| 1873 | goto fail_rcu; | ||
| 1874 | band = chanctx_conf->def.chan->band; | ||
| 1842 | break; | 1875 | break; |
| 1843 | #endif | 1876 | #endif |
| 1844 | case NL80211_IFTYPE_STATION: | 1877 | case NL80211_IFTYPE_STATION: |
| 1845 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1878 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
| 1846 | bool tdls_peer = false; | 1879 | bool tdls_peer = false; |
| 1847 | 1880 | ||
| 1848 | rcu_read_lock(); | ||
| 1849 | sta = sta_info_get(sdata, skb->data); | 1881 | sta = sta_info_get(sdata, skb->data); |
| 1850 | if (sta) { | 1882 | if (sta) { |
| 1851 | authorized = test_sta_flag(sta, | 1883 | authorized = test_sta_flag(sta, |
| @@ -1856,7 +1888,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1856 | tdls_auth = test_sta_flag(sta, | 1888 | tdls_auth = test_sta_flag(sta, |
| 1857 | WLAN_STA_TDLS_PEER_AUTH); | 1889 | WLAN_STA_TDLS_PEER_AUTH); |
| 1858 | } | 1890 | } |
| 1859 | rcu_read_unlock(); | ||
| 1860 | 1891 | ||
| 1861 | /* | 1892 | /* |
| 1862 | * If the TDLS link is enabled, send everything | 1893 | * If the TDLS link is enabled, send everything |
| @@ -1871,7 +1902,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1871 | if (tdls_direct) { | 1902 | if (tdls_direct) { |
| 1872 | /* link during setup - throw out frames to peer */ | 1903 | /* link during setup - throw out frames to peer */ |
| 1873 | if (!tdls_auth) | 1904 | if (!tdls_auth) |
| 1874 | goto fail; | 1905 | goto fail_rcu; |
| 1875 | 1906 | ||
| 1876 | /* DA SA BSSID */ | 1907 | /* DA SA BSSID */ |
| 1877 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1908 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
| @@ -1896,6 +1927,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1896 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1927 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
| 1897 | hdrlen = 24; | 1928 | hdrlen = 24; |
| 1898 | } | 1929 | } |
| 1930 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 1931 | if (!chanctx_conf) | ||
| 1932 | goto fail_rcu; | ||
| 1933 | band = chanctx_conf->def.chan->band; | ||
| 1899 | break; | 1934 | break; |
| 1900 | case NL80211_IFTYPE_ADHOC: | 1935 | case NL80211_IFTYPE_ADHOC: |
| 1901 | /* DA SA BSSID */ | 1936 | /* DA SA BSSID */ |
| @@ -1903,9 +1938,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1903 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1938 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
| 1904 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); | 1939 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); |
| 1905 | hdrlen = 24; | 1940 | hdrlen = 24; |
| 1941 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 1942 | if (!chanctx_conf) | ||
| 1943 | goto fail_rcu; | ||
| 1944 | band = chanctx_conf->def.chan->band; | ||
| 1906 | break; | 1945 | break; |
| 1907 | default: | 1946 | default: |
| 1908 | goto fail; | 1947 | goto fail_rcu; |
| 1909 | } | 1948 | } |
| 1910 | 1949 | ||
| 1911 | /* | 1950 | /* |
| @@ -1915,13 +1954,11 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1915 | */ | 1954 | */ |
| 1916 | multicast = is_multicast_ether_addr(hdr.addr1); | 1955 | multicast = is_multicast_ether_addr(hdr.addr1); |
| 1917 | if (!multicast) { | 1956 | if (!multicast) { |
| 1918 | rcu_read_lock(); | ||
| 1919 | sta = sta_info_get(sdata, hdr.addr1); | 1957 | sta = sta_info_get(sdata, hdr.addr1); |
| 1920 | if (sta) { | 1958 | if (sta) { |
| 1921 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); | 1959 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); |
| 1922 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); | 1960 | wme_sta = test_sta_flag(sta, WLAN_STA_WME); |
| 1923 | } | 1961 | } |
| 1924 | rcu_read_unlock(); | ||
| 1925 | } | 1962 | } |
| 1926 | 1963 | ||
| 1927 | /* For mesh, the use of the QoS header is mandatory */ | 1964 | /* For mesh, the use of the QoS header is mandatory */ |
| @@ -1949,7 +1986,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1949 | 1986 | ||
| 1950 | I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); | 1987 | I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); |
| 1951 | 1988 | ||
| 1952 | goto fail; | 1989 | goto fail_rcu; |
| 1953 | } | 1990 | } |
| 1954 | 1991 | ||
| 1955 | if (unlikely(!multicast && skb->sk && | 1992 | if (unlikely(!multicast && skb->sk && |
| @@ -2004,7 +2041,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 2004 | kfree_skb(tmp_skb); | 2041 | kfree_skb(tmp_skb); |
| 2005 | 2042 | ||
| 2006 | if (!skb) | 2043 | if (!skb) |
| 2007 | goto fail; | 2044 | goto fail_rcu; |
| 2008 | } | 2045 | } |
| 2009 | 2046 | ||
| 2010 | hdr.frame_control = fc; | 2047 | hdr.frame_control = fc; |
| @@ -2052,7 +2089,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 2052 | head_need = max_t(int, 0, head_need); | 2089 | head_need = max_t(int, 0, head_need); |
| 2053 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2090 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
| 2054 | ieee80211_free_txskb(&local->hw, skb); | 2091 | ieee80211_free_txskb(&local->hw, skb); |
| 2055 | return NETDEV_TX_OK; | 2092 | skb = NULL; |
| 2093 | goto fail_rcu; | ||
| 2056 | } | 2094 | } |
| 2057 | } | 2095 | } |
| 2058 | 2096 | ||
| @@ -2104,10 +2142,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 2104 | info->flags = info_flags; | 2142 | info->flags = info_flags; |
| 2105 | info->ack_frame_id = info_id; | 2143 | info->ack_frame_id = info_id; |
| 2106 | 2144 | ||
| 2107 | ieee80211_xmit(sdata, skb); | 2145 | ieee80211_xmit(sdata, skb, band); |
| 2146 | rcu_read_unlock(); | ||
| 2108 | 2147 | ||
| 2109 | return NETDEV_TX_OK; | 2148 | return NETDEV_TX_OK; |
| 2110 | 2149 | ||
| 2150 | fail_rcu: | ||
| 2151 | rcu_read_unlock(); | ||
| 2111 | fail: | 2152 | fail: |
| 2112 | dev_kfree_skb(skb); | 2153 | dev_kfree_skb(skb); |
| 2113 | return NETDEV_TX_OK; | 2154 | return NETDEV_TX_OK; |
| @@ -2142,11 +2183,18 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
| 2142 | struct sta_info *sta; | 2183 | struct sta_info *sta; |
| 2143 | struct ieee80211_hdr *hdr; | 2184 | struct ieee80211_hdr *hdr; |
| 2144 | bool result; | 2185 | bool result; |
| 2186 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 2145 | 2187 | ||
| 2146 | sdata = vif_to_sdata(info->control.vif); | 2188 | sdata = vif_to_sdata(info->control.vif); |
| 2147 | 2189 | ||
| 2148 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { | 2190 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { |
| 2149 | result = ieee80211_tx(sdata, skb, true); | 2191 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 2192 | if (unlikely(!chanctx_conf)) { | ||
| 2193 | dev_kfree_skb(skb); | ||
| 2194 | return true; | ||
| 2195 | } | ||
| 2196 | result = ieee80211_tx(sdata, skb, true, | ||
| 2197 | chanctx_conf->def.chan->band); | ||
| 2150 | } else { | 2198 | } else { |
| 2151 | struct sk_buff_head skbs; | 2199 | struct sk_buff_head skbs; |
| 2152 | 2200 | ||
| @@ -2214,9 +2262,8 @@ void ieee80211_tx_pending(unsigned long data) | |||
| 2214 | /* functions for drivers to get certain frames */ | 2262 | /* functions for drivers to get certain frames */ |
| 2215 | 2263 | ||
| 2216 | static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | 2264 | static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, |
| 2217 | struct ieee80211_if_ap *bss, | 2265 | struct ps_data *ps, |
| 2218 | struct sk_buff *skb, | 2266 | struct sk_buff *skb) |
| 2219 | struct beacon_data *beacon) | ||
| 2220 | { | 2267 | { |
| 2221 | u8 *pos, *tim; | 2268 | u8 *pos, *tim; |
| 2222 | int aid0 = 0; | 2269 | int aid0 = 0; |
| @@ -2224,27 +2271,27 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
| 2224 | 2271 | ||
| 2225 | /* Generate bitmap for TIM only if there are any STAs in power save | 2272 | /* Generate bitmap for TIM only if there are any STAs in power save |
| 2226 | * mode. */ | 2273 | * mode. */ |
| 2227 | if (atomic_read(&bss->num_sta_ps) > 0) | 2274 | if (atomic_read(&ps->num_sta_ps) > 0) |
| 2228 | /* in the hope that this is faster than | 2275 | /* in the hope that this is faster than |
| 2229 | * checking byte-for-byte */ | 2276 | * checking byte-for-byte */ |
| 2230 | have_bits = !bitmap_empty((unsigned long*)bss->tim, | 2277 | have_bits = !bitmap_empty((unsigned long*)ps->tim, |
| 2231 | IEEE80211_MAX_AID+1); | 2278 | IEEE80211_MAX_AID+1); |
| 2232 | 2279 | ||
| 2233 | if (bss->dtim_count == 0) | 2280 | if (ps->dtim_count == 0) |
| 2234 | bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1; | 2281 | ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1; |
| 2235 | else | 2282 | else |
| 2236 | bss->dtim_count--; | 2283 | ps->dtim_count--; |
| 2237 | 2284 | ||
| 2238 | tim = pos = (u8 *) skb_put(skb, 6); | 2285 | tim = pos = (u8 *) skb_put(skb, 6); |
| 2239 | *pos++ = WLAN_EID_TIM; | 2286 | *pos++ = WLAN_EID_TIM; |
| 2240 | *pos++ = 4; | 2287 | *pos++ = 4; |
| 2241 | *pos++ = bss->dtim_count; | 2288 | *pos++ = ps->dtim_count; |
| 2242 | *pos++ = sdata->vif.bss_conf.dtim_period; | 2289 | *pos++ = sdata->vif.bss_conf.dtim_period; |
| 2243 | 2290 | ||
| 2244 | if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) | 2291 | if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf)) |
| 2245 | aid0 = 1; | 2292 | aid0 = 1; |
| 2246 | 2293 | ||
| 2247 | bss->dtim_bc_mc = aid0 == 1; | 2294 | ps->dtim_bc_mc = aid0 == 1; |
| 2248 | 2295 | ||
| 2249 | if (have_bits) { | 2296 | if (have_bits) { |
| 2250 | /* Find largest even number N1 so that bits numbered 1 through | 2297 | /* Find largest even number N1 so that bits numbered 1 through |
| @@ -2252,14 +2299,14 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
| 2252 | * (N2 + 1) x 8 through 2007 are 0. */ | 2299 | * (N2 + 1) x 8 through 2007 are 0. */ |
| 2253 | n1 = 0; | 2300 | n1 = 0; |
| 2254 | for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) { | 2301 | for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) { |
| 2255 | if (bss->tim[i]) { | 2302 | if (ps->tim[i]) { |
| 2256 | n1 = i & 0xfe; | 2303 | n1 = i & 0xfe; |
| 2257 | break; | 2304 | break; |
| 2258 | } | 2305 | } |
| 2259 | } | 2306 | } |
| 2260 | n2 = n1; | 2307 | n2 = n1; |
| 2261 | for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) { | 2308 | for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) { |
| 2262 | if (bss->tim[i]) { | 2309 | if (ps->tim[i]) { |
| 2263 | n2 = i; | 2310 | n2 = i; |
| 2264 | break; | 2311 | break; |
| 2265 | } | 2312 | } |
| @@ -2269,7 +2316,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
| 2269 | *pos++ = n1 | aid0; | 2316 | *pos++ = n1 | aid0; |
| 2270 | /* Part Virt Bitmap */ | 2317 | /* Part Virt Bitmap */ |
| 2271 | skb_put(skb, n2 - n1); | 2318 | skb_put(skb, n2 - n1); |
| 2272 | memcpy(pos, bss->tim + n1, n2 - n1 + 1); | 2319 | memcpy(pos, ps->tim + n1, n2 - n1 + 1); |
| 2273 | 2320 | ||
| 2274 | tim[1] = n2 - n1 + 4; | 2321 | tim[1] = n2 - n1 + 4; |
| 2275 | } else { | 2322 | } else { |
| @@ -2286,16 +2333,16 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2286 | struct sk_buff *skb = NULL; | 2333 | struct sk_buff *skb = NULL; |
| 2287 | struct ieee80211_tx_info *info; | 2334 | struct ieee80211_tx_info *info; |
| 2288 | struct ieee80211_sub_if_data *sdata = NULL; | 2335 | struct ieee80211_sub_if_data *sdata = NULL; |
| 2289 | struct ieee80211_if_ap *ap = NULL; | 2336 | enum ieee80211_band band; |
| 2290 | struct beacon_data *beacon; | ||
| 2291 | enum ieee80211_band band = local->oper_channel->band; | ||
| 2292 | struct ieee80211_tx_rate_control txrc; | 2337 | struct ieee80211_tx_rate_control txrc; |
| 2338 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 2293 | 2339 | ||
| 2294 | rcu_read_lock(); | 2340 | rcu_read_lock(); |
| 2295 | 2341 | ||
| 2296 | sdata = vif_to_sdata(vif); | 2342 | sdata = vif_to_sdata(vif); |
| 2343 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 2297 | 2344 | ||
| 2298 | if (!ieee80211_sdata_running(sdata)) | 2345 | if (!ieee80211_sdata_running(sdata) || !chanctx_conf) |
| 2299 | goto out; | 2346 | goto out; |
| 2300 | 2347 | ||
| 2301 | if (tim_offset) | 2348 | if (tim_offset) |
| @@ -2304,8 +2351,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2304 | *tim_length = 0; | 2351 | *tim_length = 0; |
| 2305 | 2352 | ||
| 2306 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 2353 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
| 2307 | ap = &sdata->u.ap; | 2354 | struct ieee80211_if_ap *ap = &sdata->u.ap; |
| 2308 | beacon = rcu_dereference(ap->beacon); | 2355 | struct beacon_data *beacon = rcu_dereference(ap->beacon); |
| 2356 | |||
| 2309 | if (beacon) { | 2357 | if (beacon) { |
| 2310 | /* | 2358 | /* |
| 2311 | * headroom, head length, | 2359 | * headroom, head length, |
| @@ -2329,14 +2377,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2329 | * of the tim bitmap in mac80211 and the driver. | 2377 | * of the tim bitmap in mac80211 and the driver. |
| 2330 | */ | 2378 | */ |
| 2331 | if (local->tim_in_locked_section) { | 2379 | if (local->tim_in_locked_section) { |
| 2332 | ieee80211_beacon_add_tim(sdata, ap, skb, | 2380 | ieee80211_beacon_add_tim(sdata, &ap->ps, skb); |
| 2333 | beacon); | ||
| 2334 | } else { | 2381 | } else { |
| 2335 | unsigned long flags; | 2382 | unsigned long flags; |
| 2336 | 2383 | ||
| 2337 | spin_lock_irqsave(&local->tim_lock, flags); | 2384 | spin_lock_irqsave(&local->tim_lock, flags); |
| 2338 | ieee80211_beacon_add_tim(sdata, ap, skb, | 2385 | ieee80211_beacon_add_tim(sdata, &ap->ps, skb); |
| 2339 | beacon); | ||
| 2340 | spin_unlock_irqrestore(&local->tim_lock, flags); | 2386 | spin_unlock_irqrestore(&local->tim_lock, flags); |
| 2341 | } | 2387 | } |
| 2342 | 2388 | ||
| @@ -2412,6 +2458,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2412 | *pos++ = WLAN_EID_SSID; | 2458 | *pos++ = WLAN_EID_SSID; |
| 2413 | *pos++ = 0x0; | 2459 | *pos++ = 0x0; |
| 2414 | 2460 | ||
| 2461 | band = chanctx_conf->def.chan->band; | ||
| 2462 | |||
| 2415 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || | 2463 | if (ieee80211_add_srates_ie(sdata, skb, true, band) || |
| 2416 | mesh_add_ds_params_ie(skb, sdata) || | 2464 | mesh_add_ds_params_ie(skb, sdata) || |
| 2417 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || | 2465 | ieee80211_add_ext_srates_ie(sdata, skb, true, band) || |
| @@ -2429,6 +2477,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
| 2429 | goto out; | 2477 | goto out; |
| 2430 | } | 2478 | } |
| 2431 | 2479 | ||
| 2480 | band = chanctx_conf->def.chan->band; | ||
| 2481 | |||
| 2432 | info = IEEE80211_SKB_CB(skb); | 2482 | info = IEEE80211_SKB_CB(skb); |
| 2433 | 2483 | ||
| 2434 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 2484 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
| @@ -2573,7 +2623,7 @@ EXPORT_SYMBOL(ieee80211_nullfunc_get); | |||
| 2573 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | 2623 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, |
| 2574 | struct ieee80211_vif *vif, | 2624 | struct ieee80211_vif *vif, |
| 2575 | const u8 *ssid, size_t ssid_len, | 2625 | const u8 *ssid, size_t ssid_len, |
| 2576 | const u8 *ie, size_t ie_len) | 2626 | size_t tailroom) |
| 2577 | { | 2627 | { |
| 2578 | struct ieee80211_sub_if_data *sdata; | 2628 | struct ieee80211_sub_if_data *sdata; |
| 2579 | struct ieee80211_local *local; | 2629 | struct ieee80211_local *local; |
| @@ -2587,7 +2637,7 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | |||
| 2587 | ie_ssid_len = 2 + ssid_len; | 2637 | ie_ssid_len = 2 + ssid_len; |
| 2588 | 2638 | ||
| 2589 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + | 2639 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + |
| 2590 | ie_ssid_len + ie_len); | 2640 | ie_ssid_len + tailroom); |
| 2591 | if (!skb) | 2641 | if (!skb) |
| 2592 | return NULL; | 2642 | return NULL; |
| 2593 | 2643 | ||
| @@ -2608,11 +2658,6 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | |||
| 2608 | memcpy(pos, ssid, ssid_len); | 2658 | memcpy(pos, ssid, ssid_len); |
| 2609 | pos += ssid_len; | 2659 | pos += ssid_len; |
| 2610 | 2660 | ||
| 2611 | if (ie) { | ||
| 2612 | pos = skb_put(skb, ie_len); | ||
| 2613 | memcpy(pos, ie, ie_len); | ||
| 2614 | } | ||
| 2615 | |||
| 2616 | return skb; | 2661 | return skb; |
| 2617 | } | 2662 | } |
| 2618 | EXPORT_SYMBOL(ieee80211_probereq_get); | 2663 | EXPORT_SYMBOL(ieee80211_probereq_get); |
| @@ -2656,29 +2701,40 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
| 2656 | struct sk_buff *skb = NULL; | 2701 | struct sk_buff *skb = NULL; |
| 2657 | struct ieee80211_tx_data tx; | 2702 | struct ieee80211_tx_data tx; |
| 2658 | struct ieee80211_sub_if_data *sdata; | 2703 | struct ieee80211_sub_if_data *sdata; |
| 2659 | struct ieee80211_if_ap *bss = NULL; | 2704 | struct ps_data *ps; |
| 2660 | struct beacon_data *beacon; | ||
| 2661 | struct ieee80211_tx_info *info; | 2705 | struct ieee80211_tx_info *info; |
| 2706 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 2662 | 2707 | ||
| 2663 | sdata = vif_to_sdata(vif); | 2708 | sdata = vif_to_sdata(vif); |
| 2664 | bss = &sdata->u.ap; | ||
| 2665 | 2709 | ||
| 2666 | rcu_read_lock(); | 2710 | rcu_read_lock(); |
| 2667 | beacon = rcu_dereference(bss->beacon); | 2711 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
| 2712 | |||
| 2713 | if (!chanctx_conf) | ||
| 2714 | goto out; | ||
| 2668 | 2715 | ||
| 2669 | if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head) | 2716 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
| 2717 | struct beacon_data *beacon = | ||
| 2718 | rcu_dereference(sdata->u.ap.beacon); | ||
| 2719 | |||
| 2720 | if (!beacon || !beacon->head) | ||
| 2721 | goto out; | ||
| 2722 | |||
| 2723 | ps = &sdata->u.ap.ps; | ||
| 2724 | } else { | ||
| 2670 | goto out; | 2725 | goto out; |
| 2726 | } | ||
| 2671 | 2727 | ||
| 2672 | if (bss->dtim_count != 0 || !bss->dtim_bc_mc) | 2728 | if (ps->dtim_count != 0 || !ps->dtim_bc_mc) |
| 2673 | goto out; /* send buffered bc/mc only after DTIM beacon */ | 2729 | goto out; /* send buffered bc/mc only after DTIM beacon */ |
| 2674 | 2730 | ||
| 2675 | while (1) { | 2731 | while (1) { |
| 2676 | skb = skb_dequeue(&bss->ps_bc_buf); | 2732 | skb = skb_dequeue(&ps->bc_buf); |
| 2677 | if (!skb) | 2733 | if (!skb) |
| 2678 | goto out; | 2734 | goto out; |
| 2679 | local->total_ps_buffered--; | 2735 | local->total_ps_buffered--; |
| 2680 | 2736 | ||
| 2681 | if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) { | 2737 | if (!skb_queue_empty(&ps->bc_buf) && skb->len >= 2) { |
| 2682 | struct ieee80211_hdr *hdr = | 2738 | struct ieee80211_hdr *hdr = |
| 2683 | (struct ieee80211_hdr *) skb->data; | 2739 | (struct ieee80211_hdr *) skb->data; |
| 2684 | /* more buffered multicast/broadcast frames ==> set | 2740 | /* more buffered multicast/broadcast frames ==> set |
| @@ -2696,7 +2752,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
| 2696 | info = IEEE80211_SKB_CB(skb); | 2752 | info = IEEE80211_SKB_CB(skb); |
| 2697 | 2753 | ||
| 2698 | tx.flags |= IEEE80211_TX_PS_BUFFERED; | 2754 | tx.flags |= IEEE80211_TX_PS_BUFFERED; |
| 2699 | info->band = local->oper_channel->band; | 2755 | info->band = chanctx_conf->def.chan->band; |
| 2700 | 2756 | ||
| 2701 | if (invoke_tx_handlers(&tx)) | 2757 | if (invoke_tx_handlers(&tx)) |
| 2702 | skb = NULL; | 2758 | skb = NULL; |
| @@ -2707,8 +2763,9 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
| 2707 | } | 2763 | } |
| 2708 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); | 2764 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); |
| 2709 | 2765 | ||
| 2710 | void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, | 2766 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
| 2711 | struct sk_buff *skb, int tid) | 2767 | struct sk_buff *skb, int tid, |
| 2768 | enum ieee80211_band band) | ||
| 2712 | { | 2769 | { |
| 2713 | int ac = ieee802_1d_to_ac[tid & 7]; | 2770 | int ac = ieee802_1d_to_ac[tid & 7]; |
| 2714 | 2771 | ||
| @@ -2725,6 +2782,6 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, | |||
| 2725 | * requirements are that we do not come into tx with bhs on. | 2782 | * requirements are that we do not come into tx with bhs on. |
| 2726 | */ | 2783 | */ |
| 2727 | local_bh_disable(); | 2784 | local_bh_disable(); |
| 2728 | ieee80211_xmit(sdata, skb); | 2785 | ieee80211_xmit(sdata, skb, band); |
| 2729 | local_bh_enable(); | 2786 | local_bh_enable(); |
| 2730 | } | 2787 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0151ae33c4cd..f11e8c540db4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
| @@ -512,7 +512,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) | |||
| 512 | EXPORT_SYMBOL(ieee80211_wake_queues); | 512 | EXPORT_SYMBOL(ieee80211_wake_queues); |
| 513 | 513 | ||
| 514 | void ieee80211_iterate_active_interfaces( | 514 | void ieee80211_iterate_active_interfaces( |
| 515 | struct ieee80211_hw *hw, | 515 | struct ieee80211_hw *hw, u32 iter_flags, |
| 516 | void (*iterator)(void *data, u8 *mac, | 516 | void (*iterator)(void *data, u8 *mac, |
| 517 | struct ieee80211_vif *vif), | 517 | struct ieee80211_vif *vif), |
| 518 | void *data) | 518 | void *data) |
| @@ -530,6 +530,9 @@ void ieee80211_iterate_active_interfaces( | |||
| 530 | default: | 530 | default: |
| 531 | break; | 531 | break; |
| 532 | } | 532 | } |
| 533 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | ||
| 534 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 535 | continue; | ||
| 533 | if (ieee80211_sdata_running(sdata)) | 536 | if (ieee80211_sdata_running(sdata)) |
| 534 | iterator(data, sdata->vif.addr, | 537 | iterator(data, sdata->vif.addr, |
| 535 | &sdata->vif); | 538 | &sdata->vif); |
| @@ -537,7 +540,9 @@ void ieee80211_iterate_active_interfaces( | |||
| 537 | 540 | ||
| 538 | sdata = rcu_dereference_protected(local->monitor_sdata, | 541 | sdata = rcu_dereference_protected(local->monitor_sdata, |
| 539 | lockdep_is_held(&local->iflist_mtx)); | 542 | lockdep_is_held(&local->iflist_mtx)); |
| 540 | if (sdata) | 543 | if (sdata && |
| 544 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | ||
| 545 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 541 | iterator(data, sdata->vif.addr, &sdata->vif); | 546 | iterator(data, sdata->vif.addr, &sdata->vif); |
| 542 | 547 | ||
| 543 | mutex_unlock(&local->iflist_mtx); | 548 | mutex_unlock(&local->iflist_mtx); |
| @@ -545,7 +550,7 @@ void ieee80211_iterate_active_interfaces( | |||
| 545 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 550 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
| 546 | 551 | ||
| 547 | void ieee80211_iterate_active_interfaces_atomic( | 552 | void ieee80211_iterate_active_interfaces_atomic( |
| 548 | struct ieee80211_hw *hw, | 553 | struct ieee80211_hw *hw, u32 iter_flags, |
| 549 | void (*iterator)(void *data, u8 *mac, | 554 | void (*iterator)(void *data, u8 *mac, |
| 550 | struct ieee80211_vif *vif), | 555 | struct ieee80211_vif *vif), |
| 551 | void *data) | 556 | void *data) |
| @@ -563,13 +568,18 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
| 563 | default: | 568 | default: |
| 564 | break; | 569 | break; |
| 565 | } | 570 | } |
| 571 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | ||
| 572 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 573 | continue; | ||
| 566 | if (ieee80211_sdata_running(sdata)) | 574 | if (ieee80211_sdata_running(sdata)) |
| 567 | iterator(data, sdata->vif.addr, | 575 | iterator(data, sdata->vif.addr, |
| 568 | &sdata->vif); | 576 | &sdata->vif); |
| 569 | } | 577 | } |
| 570 | 578 | ||
| 571 | sdata = rcu_dereference(local->monitor_sdata); | 579 | sdata = rcu_dereference(local->monitor_sdata); |
| 572 | if (sdata) | 580 | if (sdata && |
| 581 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | ||
| 582 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
| 573 | iterator(data, sdata->vif.addr, &sdata->vif); | 583 | iterator(data, sdata->vif.addr, &sdata->vif); |
| 574 | 584 | ||
| 575 | rcu_read_unlock(); | 585 | rcu_read_unlock(); |
| @@ -769,6 +779,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
| 769 | else | 779 | else |
| 770 | elem_parse_failed = true; | 780 | elem_parse_failed = true; |
| 771 | break; | 781 | break; |
| 782 | case WLAN_EID_VHT_CAPABILITY: | ||
| 783 | if (elen >= sizeof(struct ieee80211_vht_cap)) | ||
| 784 | elems->vht_cap_elem = (void *)pos; | ||
| 785 | else | ||
| 786 | elem_parse_failed = true; | ||
| 787 | break; | ||
| 788 | case WLAN_EID_VHT_OPERATION: | ||
| 789 | if (elen >= sizeof(struct ieee80211_vht_operation)) | ||
| 790 | elems->vht_operation = (void *)pos; | ||
| 791 | else | ||
| 792 | elem_parse_failed = true; | ||
| 793 | break; | ||
| 772 | case WLAN_EID_MESH_ID: | 794 | case WLAN_EID_MESH_ID: |
| 773 | elems->mesh_id = pos; | 795 | elems->mesh_id = pos; |
| 774 | elems->mesh_id_len = elen; | 796 | elems->mesh_id_len = elen; |
| @@ -837,7 +859,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
| 837 | if (elem_parse_failed) | 859 | if (elem_parse_failed) |
| 838 | elems->parse_error = true; | 860 | elems->parse_error = true; |
| 839 | else | 861 | else |
| 840 | set_bit(id, seen_elems); | 862 | __set_bit(id, seen_elems); |
| 841 | 863 | ||
| 842 | left -= elen; | 864 | left -= elen; |
| 843 | pos += elen; | 865 | pos += elen; |
| @@ -860,6 +882,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
| 860 | { | 882 | { |
| 861 | struct ieee80211_local *local = sdata->local; | 883 | struct ieee80211_local *local = sdata->local; |
| 862 | struct ieee80211_tx_queue_params qparam; | 884 | struct ieee80211_tx_queue_params qparam; |
| 885 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
| 863 | int ac; | 886 | int ac; |
| 864 | bool use_11b, enable_qos; | 887 | bool use_11b, enable_qos; |
| 865 | int aCWmin, aCWmax; | 888 | int aCWmin, aCWmax; |
| @@ -872,8 +895,12 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
| 872 | 895 | ||
| 873 | memset(&qparam, 0, sizeof(qparam)); | 896 | memset(&qparam, 0, sizeof(qparam)); |
| 874 | 897 | ||
| 875 | use_11b = (local->oper_channel->band == IEEE80211_BAND_2GHZ) && | 898 | rcu_read_lock(); |
| 899 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 900 | use_11b = (chanctx_conf && | ||
| 901 | chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ) && | ||
| 876 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); | 902 | !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE); |
| 903 | rcu_read_unlock(); | ||
| 877 | 904 | ||
| 878 | /* | 905 | /* |
| 879 | * By default disable QoS in STA mode for old access points, which do | 906 | * By default disable QoS in STA mode for old access points, which do |
| @@ -952,7 +979,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
| 952 | const size_t supp_rates_len, | 979 | const size_t supp_rates_len, |
| 953 | const u8 *supp_rates) | 980 | const u8 *supp_rates) |
| 954 | { | 981 | { |
| 955 | struct ieee80211_local *local = sdata->local; | 982 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 956 | int i, have_higher_than_11mbit = 0; | 983 | int i, have_higher_than_11mbit = 0; |
| 957 | 984 | ||
| 958 | /* cf. IEEE 802.11 9.2.12 */ | 985 | /* cf. IEEE 802.11 9.2.12 */ |
| @@ -960,11 +987,16 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
| 960 | if ((supp_rates[i] & 0x7f) * 5 > 110) | 987 | if ((supp_rates[i] & 0x7f) * 5 > 110) |
| 961 | have_higher_than_11mbit = 1; | 988 | have_higher_than_11mbit = 1; |
| 962 | 989 | ||
| 963 | if (local->oper_channel->band == IEEE80211_BAND_2GHZ && | 990 | rcu_read_lock(); |
| 991 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 992 | |||
| 993 | if (chanctx_conf && | ||
| 994 | chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ && | ||
| 964 | have_higher_than_11mbit) | 995 | have_higher_than_11mbit) |
| 965 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 996 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
| 966 | else | 997 | else |
| 967 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 998 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
| 999 | rcu_read_unlock(); | ||
| 968 | 1000 | ||
| 969 | ieee80211_set_wmm_default(sdata, true); | 1001 | ieee80211_set_wmm_default(sdata, true); |
| 970 | } | 1002 | } |
| @@ -996,7 +1028,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
| 996 | } | 1028 | } |
| 997 | 1029 | ||
| 998 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1030 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
| 999 | u16 transaction, u16 auth_alg, | 1031 | u16 transaction, u16 auth_alg, u16 status, |
| 1000 | u8 *extra, size_t extra_len, const u8 *da, | 1032 | u8 *extra, size_t extra_len, const u8 *da, |
| 1001 | const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx) | 1033 | const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx) |
| 1002 | { | 1034 | { |
| @@ -1021,7 +1053,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
| 1021 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | 1053 | memcpy(mgmt->bssid, bssid, ETH_ALEN); |
| 1022 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); | 1054 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); |
| 1023 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | 1055 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); |
| 1024 | mgmt->u.auth.status_code = cpu_to_le16(0); | 1056 | mgmt->u.auth.status_code = cpu_to_le16(status); |
| 1025 | if (extra) | 1057 | if (extra) |
| 1026 | memcpy(skb_put(skb, extra_len), extra, extra_len); | 1058 | memcpy(skb_put(skb, extra_len), extra, extra_len); |
| 1027 | 1059 | ||
| @@ -1075,12 +1107,12 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
| 1075 | } | 1107 | } |
| 1076 | 1108 | ||
| 1077 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1109 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
| 1078 | const u8 *ie, size_t ie_len, | 1110 | size_t buffer_len, const u8 *ie, size_t ie_len, |
| 1079 | enum ieee80211_band band, u32 rate_mask, | 1111 | enum ieee80211_band band, u32 rate_mask, |
| 1080 | u8 channel) | 1112 | u8 channel) |
| 1081 | { | 1113 | { |
| 1082 | struct ieee80211_supported_band *sband; | 1114 | struct ieee80211_supported_band *sband; |
| 1083 | u8 *pos; | 1115 | u8 *pos = buffer, *end = buffer + buffer_len; |
| 1084 | size_t offset = 0, noffset; | 1116 | size_t offset = 0, noffset; |
| 1085 | int supp_rates_len, i; | 1117 | int supp_rates_len, i; |
| 1086 | u8 rates[32]; | 1118 | u8 rates[32]; |
| @@ -1091,8 +1123,6 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1091 | if (WARN_ON_ONCE(!sband)) | 1123 | if (WARN_ON_ONCE(!sband)) |
| 1092 | return 0; | 1124 | return 0; |
| 1093 | 1125 | ||
| 1094 | pos = buffer; | ||
| 1095 | |||
| 1096 | num_rates = 0; | 1126 | num_rates = 0; |
| 1097 | for (i = 0; i < sband->n_bitrates; i++) { | 1127 | for (i = 0; i < sband->n_bitrates; i++) { |
| 1098 | if ((BIT(i) & rate_mask) == 0) | 1128 | if ((BIT(i) & rate_mask) == 0) |
| @@ -1102,6 +1132,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1102 | 1132 | ||
| 1103 | supp_rates_len = min_t(int, num_rates, 8); | 1133 | supp_rates_len = min_t(int, num_rates, 8); |
| 1104 | 1134 | ||
| 1135 | if (end - pos < 2 + supp_rates_len) | ||
| 1136 | goto out_err; | ||
| 1105 | *pos++ = WLAN_EID_SUPP_RATES; | 1137 | *pos++ = WLAN_EID_SUPP_RATES; |
| 1106 | *pos++ = supp_rates_len; | 1138 | *pos++ = supp_rates_len; |
| 1107 | memcpy(pos, rates, supp_rates_len); | 1139 | memcpy(pos, rates, supp_rates_len); |
| @@ -1118,6 +1150,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1118 | before_extrates, | 1150 | before_extrates, |
| 1119 | ARRAY_SIZE(before_extrates), | 1151 | ARRAY_SIZE(before_extrates), |
| 1120 | offset); | 1152 | offset); |
| 1153 | if (end - pos < noffset - offset) | ||
| 1154 | goto out_err; | ||
| 1121 | memcpy(pos, ie + offset, noffset - offset); | 1155 | memcpy(pos, ie + offset, noffset - offset); |
| 1122 | pos += noffset - offset; | 1156 | pos += noffset - offset; |
| 1123 | offset = noffset; | 1157 | offset = noffset; |
| @@ -1125,6 +1159,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1125 | 1159 | ||
| 1126 | ext_rates_len = num_rates - supp_rates_len; | 1160 | ext_rates_len = num_rates - supp_rates_len; |
| 1127 | if (ext_rates_len > 0) { | 1161 | if (ext_rates_len > 0) { |
| 1162 | if (end - pos < 2 + ext_rates_len) | ||
| 1163 | goto out_err; | ||
| 1128 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 1164 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
| 1129 | *pos++ = ext_rates_len; | 1165 | *pos++ = ext_rates_len; |
| 1130 | memcpy(pos, rates + supp_rates_len, ext_rates_len); | 1166 | memcpy(pos, rates + supp_rates_len, ext_rates_len); |
| @@ -1132,6 +1168,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1132 | } | 1168 | } |
| 1133 | 1169 | ||
| 1134 | if (channel && sband->band == IEEE80211_BAND_2GHZ) { | 1170 | if (channel && sband->band == IEEE80211_BAND_2GHZ) { |
| 1171 | if (end - pos < 3) | ||
| 1172 | goto out_err; | ||
| 1135 | *pos++ = WLAN_EID_DS_PARAMS; | 1173 | *pos++ = WLAN_EID_DS_PARAMS; |
| 1136 | *pos++ = 1; | 1174 | *pos++ = 1; |
| 1137 | *pos++ = channel; | 1175 | *pos++ = channel; |
| @@ -1150,14 +1188,19 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1150 | noffset = ieee80211_ie_split(ie, ie_len, | 1188 | noffset = ieee80211_ie_split(ie, ie_len, |
| 1151 | before_ht, ARRAY_SIZE(before_ht), | 1189 | before_ht, ARRAY_SIZE(before_ht), |
| 1152 | offset); | 1190 | offset); |
| 1191 | if (end - pos < noffset - offset) | ||
| 1192 | goto out_err; | ||
| 1153 | memcpy(pos, ie + offset, noffset - offset); | 1193 | memcpy(pos, ie + offset, noffset - offset); |
| 1154 | pos += noffset - offset; | 1194 | pos += noffset - offset; |
| 1155 | offset = noffset; | 1195 | offset = noffset; |
| 1156 | } | 1196 | } |
| 1157 | 1197 | ||
| 1158 | if (sband->ht_cap.ht_supported) | 1198 | if (sband->ht_cap.ht_supported) { |
| 1199 | if (end - pos < 2 + sizeof(struct ieee80211_ht_cap)) | ||
| 1200 | goto out_err; | ||
| 1159 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, | 1201 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, |
| 1160 | sband->ht_cap.cap); | 1202 | sband->ht_cap.cap); |
| 1203 | } | ||
| 1161 | 1204 | ||
| 1162 | /* | 1205 | /* |
| 1163 | * If adding more here, adjust code in main.c | 1206 | * If adding more here, adjust code in main.c |
| @@ -1167,15 +1210,23 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
| 1167 | /* add any remaining custom IEs */ | 1210 | /* add any remaining custom IEs */ |
| 1168 | if (ie && ie_len) { | 1211 | if (ie && ie_len) { |
| 1169 | noffset = ie_len; | 1212 | noffset = ie_len; |
| 1213 | if (end - pos < noffset - offset) | ||
| 1214 | goto out_err; | ||
| 1170 | memcpy(pos, ie + offset, noffset - offset); | 1215 | memcpy(pos, ie + offset, noffset - offset); |
| 1171 | pos += noffset - offset; | 1216 | pos += noffset - offset; |
| 1172 | } | 1217 | } |
| 1173 | 1218 | ||
| 1174 | if (sband->vht_cap.vht_supported) | 1219 | if (sband->vht_cap.vht_supported) { |
| 1220 | if (end - pos < 2 + sizeof(struct ieee80211_vht_cap)) | ||
| 1221 | goto out_err; | ||
| 1175 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, | 1222 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, |
| 1176 | sband->vht_cap.cap); | 1223 | sband->vht_cap.cap); |
| 1224 | } | ||
| 1177 | 1225 | ||
| 1178 | return pos - buffer; | 1226 | return pos - buffer; |
| 1227 | out_err: | ||
| 1228 | WARN_ONCE(1, "not enough space for preq IEs\n"); | ||
| 1229 | return pos - buffer; | ||
| 1179 | } | 1230 | } |
| 1180 | 1231 | ||
| 1181 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1232 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
| @@ -1188,14 +1239,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 1188 | struct ieee80211_local *local = sdata->local; | 1239 | struct ieee80211_local *local = sdata->local; |
| 1189 | struct sk_buff *skb; | 1240 | struct sk_buff *skb; |
| 1190 | struct ieee80211_mgmt *mgmt; | 1241 | struct ieee80211_mgmt *mgmt; |
| 1191 | size_t buf_len; | ||
| 1192 | u8 *buf; | ||
| 1193 | u8 chan_no; | 1242 | u8 chan_no; |
| 1194 | 1243 | int ies_len; | |
| 1195 | /* FIXME: come up with a proper value */ | ||
| 1196 | buf = kmalloc(200 + ie_len, GFP_KERNEL); | ||
| 1197 | if (!buf) | ||
| 1198 | return NULL; | ||
| 1199 | 1244 | ||
| 1200 | /* | 1245 | /* |
| 1201 | * Do not send DS Channel parameter for directed probe requests | 1246 | * Do not send DS Channel parameter for directed probe requests |
| @@ -1207,14 +1252,16 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 1207 | else | 1252 | else |
| 1208 | chan_no = ieee80211_frequency_to_channel(chan->center_freq); | 1253 | chan_no = ieee80211_frequency_to_channel(chan->center_freq); |
| 1209 | 1254 | ||
| 1210 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band, | ||
| 1211 | ratemask, chan_no); | ||
| 1212 | |||
| 1213 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 1255 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
| 1214 | ssid, ssid_len, | 1256 | ssid, ssid_len, 100 + ie_len); |
| 1215 | buf, buf_len); | ||
| 1216 | if (!skb) | 1257 | if (!skb) |
| 1217 | goto out; | 1258 | return NULL; |
| 1259 | |||
| 1260 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), | ||
| 1261 | skb_tailroom(skb), | ||
| 1262 | ie, ie_len, chan->band, | ||
| 1263 | ratemask, chan_no); | ||
| 1264 | skb_put(skb, ies_len); | ||
| 1218 | 1265 | ||
| 1219 | if (dst) { | 1266 | if (dst) { |
| 1220 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1267 | mgmt = (struct ieee80211_mgmt *) skb->data; |
| @@ -1224,9 +1271,6 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
| 1224 | 1271 | ||
| 1225 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1272 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
| 1226 | 1273 | ||
| 1227 | out: | ||
| 1228 | kfree(buf); | ||
| 1229 | |||
| 1230 | return skb; | 1274 | return skb; |
| 1231 | } | 1275 | } |
| 1232 | 1276 | ||
| @@ -1234,7 +1278,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
| 1234 | const u8 *ssid, size_t ssid_len, | 1278 | const u8 *ssid, size_t ssid_len, |
| 1235 | const u8 *ie, size_t ie_len, | 1279 | const u8 *ie, size_t ie_len, |
| 1236 | u32 ratemask, bool directed, bool no_cck, | 1280 | u32 ratemask, bool directed, bool no_cck, |
| 1237 | struct ieee80211_channel *channel) | 1281 | struct ieee80211_channel *channel, bool scan) |
| 1238 | { | 1282 | { |
| 1239 | struct sk_buff *skb; | 1283 | struct sk_buff *skb; |
| 1240 | 1284 | ||
| @@ -1245,7 +1289,10 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
| 1245 | if (no_cck) | 1289 | if (no_cck) |
| 1246 | IEEE80211_SKB_CB(skb)->flags |= | 1290 | IEEE80211_SKB_CB(skb)->flags |= |
| 1247 | IEEE80211_TX_CTL_NO_CCK_RATE; | 1291 | IEEE80211_TX_CTL_NO_CCK_RATE; |
| 1248 | ieee80211_tx_skb(sdata, skb); | 1292 | if (scan) |
| 1293 | ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band); | ||
| 1294 | else | ||
| 1295 | ieee80211_tx_skb(sdata, skb); | ||
| 1249 | } | 1296 | } |
| 1250 | } | 1297 | } |
| 1251 | 1298 | ||
| @@ -1308,6 +1355,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1308 | { | 1355 | { |
| 1309 | struct ieee80211_hw *hw = &local->hw; | 1356 | struct ieee80211_hw *hw = &local->hw; |
| 1310 | struct ieee80211_sub_if_data *sdata; | 1357 | struct ieee80211_sub_if_data *sdata; |
| 1358 | struct ieee80211_chanctx *ctx; | ||
| 1311 | struct sta_info *sta; | 1359 | struct sta_info *sta; |
| 1312 | int res, i; | 1360 | int res, i; |
| 1313 | 1361 | ||
| @@ -1380,6 +1428,46 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1380 | res = drv_add_interface(local, sdata); | 1428 | res = drv_add_interface(local, sdata); |
| 1381 | } | 1429 | } |
| 1382 | 1430 | ||
| 1431 | /* add channel contexts */ | ||
| 1432 | if (local->use_chanctx) { | ||
| 1433 | mutex_lock(&local->chanctx_mtx); | ||
| 1434 | list_for_each_entry(ctx, &local->chanctx_list, list) | ||
| 1435 | WARN_ON(drv_add_chanctx(local, ctx)); | ||
| 1436 | mutex_unlock(&local->chanctx_mtx); | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 1440 | struct ieee80211_chanctx_conf *ctx_conf; | ||
| 1441 | |||
| 1442 | if (!ieee80211_sdata_running(sdata)) | ||
| 1443 | continue; | ||
| 1444 | |||
| 1445 | mutex_lock(&local->chanctx_mtx); | ||
| 1446 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 1447 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 1448 | if (ctx_conf) { | ||
| 1449 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
| 1450 | conf); | ||
| 1451 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
| 1452 | } | ||
| 1453 | mutex_unlock(&local->chanctx_mtx); | ||
| 1454 | } | ||
| 1455 | |||
| 1456 | sdata = rtnl_dereference(local->monitor_sdata); | ||
| 1457 | if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) { | ||
| 1458 | struct ieee80211_chanctx_conf *ctx_conf; | ||
| 1459 | |||
| 1460 | mutex_lock(&local->chanctx_mtx); | ||
| 1461 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
| 1462 | lockdep_is_held(&local->chanctx_mtx)); | ||
| 1463 | if (ctx_conf) { | ||
| 1464 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
| 1465 | conf); | ||
| 1466 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
| 1467 | } | ||
| 1468 | mutex_unlock(&local->chanctx_mtx); | ||
| 1469 | } | ||
| 1470 | |||
| 1383 | /* add STAs back */ | 1471 | /* add STAs back */ |
| 1384 | mutex_lock(&local->sta_mtx); | 1472 | mutex_lock(&local->sta_mtx); |
| 1385 | list_for_each_entry(sta, &local->sta_list, list) { | 1473 | list_for_each_entry(sta, &local->sta_list, list) { |
| @@ -1435,7 +1523,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1435 | BSS_CHANGED_BSSID | | 1523 | BSS_CHANGED_BSSID | |
| 1436 | BSS_CHANGED_CQM | | 1524 | BSS_CHANGED_CQM | |
| 1437 | BSS_CHANGED_QOS | | 1525 | BSS_CHANGED_QOS | |
| 1438 | BSS_CHANGED_IDLE; | 1526 | BSS_CHANGED_IDLE | |
| 1527 | BSS_CHANGED_TXPOWER; | ||
| 1439 | 1528 | ||
| 1440 | switch (sdata->vif.type) { | 1529 | switch (sdata->vif.type) { |
| 1441 | case NL80211_IFTYPE_STATION: | 1530 | case NL80211_IFTYPE_STATION: |
| @@ -1450,11 +1539,15 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1450 | changed |= BSS_CHANGED_IBSS; | 1539 | changed |= BSS_CHANGED_IBSS; |
| 1451 | /* fall through */ | 1540 | /* fall through */ |
| 1452 | case NL80211_IFTYPE_AP: | 1541 | case NL80211_IFTYPE_AP: |
| 1453 | changed |= BSS_CHANGED_SSID; | 1542 | changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS; |
| 1454 | 1543 | ||
| 1455 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1544 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
| 1456 | changed |= BSS_CHANGED_AP_PROBE_RESP; | 1545 | changed |= BSS_CHANGED_AP_PROBE_RESP; |
| 1457 | 1546 | ||
| 1547 | if (rcu_access_pointer(sdata->u.ap.beacon)) | ||
| 1548 | drv_start_ap(local, sdata); | ||
| 1549 | } | ||
| 1550 | |||
| 1458 | /* fall through */ | 1551 | /* fall through */ |
| 1459 | case NL80211_IFTYPE_MESH_POINT: | 1552 | case NL80211_IFTYPE_MESH_POINT: |
| 1460 | changed |= BSS_CHANGED_BEACON | | 1553 | changed |= BSS_CHANGED_BEACON | |
| @@ -1553,8 +1646,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
| 1553 | * If this is for hw restart things are still running. | 1646 | * If this is for hw restart things are still running. |
| 1554 | * We may want to change that later, however. | 1647 | * We may want to change that later, however. |
| 1555 | */ | 1648 | */ |
| 1556 | if (!local->suspended) | 1649 | if (!local->suspended) { |
| 1650 | drv_restart_complete(local); | ||
| 1557 | return 0; | 1651 | return 0; |
| 1652 | } | ||
| 1558 | 1653 | ||
| 1559 | #ifdef CONFIG_PM | 1654 | #ifdef CONFIG_PM |
| 1560 | /* first set suspended false, then resuming */ | 1655 | /* first set suspended false, then resuming */ |
| @@ -1617,68 +1712,24 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif) | |||
| 1617 | } | 1712 | } |
| 1618 | EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); | 1713 | EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect); |
| 1619 | 1714 | ||
| 1620 | static int check_mgd_smps(struct ieee80211_if_managed *ifmgd, | 1715 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata) |
| 1621 | enum ieee80211_smps_mode *smps_mode) | ||
| 1622 | { | ||
| 1623 | if (ifmgd->associated) { | ||
| 1624 | *smps_mode = ifmgd->ap_smps; | ||
| 1625 | |||
| 1626 | if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
| 1627 | if (ifmgd->powersave) | ||
| 1628 | *smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
| 1629 | else | ||
| 1630 | *smps_mode = IEEE80211_SMPS_OFF; | ||
| 1631 | } | ||
| 1632 | |||
| 1633 | return 1; | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | return 0; | ||
| 1637 | } | ||
| 1638 | |||
| 1639 | void ieee80211_recalc_smps(struct ieee80211_local *local) | ||
| 1640 | { | 1716 | { |
| 1641 | struct ieee80211_sub_if_data *sdata; | 1717 | struct ieee80211_local *local = sdata->local; |
| 1642 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF; | 1718 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 1643 | int count = 0; | 1719 | struct ieee80211_chanctx *chanctx; |
| 1644 | |||
| 1645 | mutex_lock(&local->iflist_mtx); | ||
| 1646 | |||
| 1647 | /* | ||
| 1648 | * This function could be improved to handle multiple | ||
| 1649 | * interfaces better, but right now it makes any | ||
| 1650 | * non-station interfaces force SM PS to be turned | ||
| 1651 | * off. If there are multiple station interfaces it | ||
| 1652 | * could also use the best possible mode, e.g. if | ||
| 1653 | * one is in static and the other in dynamic then | ||
| 1654 | * dynamic is ok. | ||
| 1655 | */ | ||
| 1656 | |||
| 1657 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 1658 | if (!ieee80211_sdata_running(sdata)) | ||
| 1659 | continue; | ||
| 1660 | if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) | ||
| 1661 | continue; | ||
| 1662 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 1663 | goto set; | ||
| 1664 | 1720 | ||
| 1665 | count += check_mgd_smps(&sdata->u.mgd, &smps_mode); | 1721 | mutex_lock(&local->chanctx_mtx); |
| 1666 | 1722 | ||
| 1667 | if (count > 1) { | 1723 | chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, |
| 1668 | smps_mode = IEEE80211_SMPS_OFF; | 1724 | lockdep_is_held(&local->chanctx_mtx)); |
| 1669 | break; | ||
| 1670 | } | ||
| 1671 | } | ||
| 1672 | 1725 | ||
| 1673 | if (smps_mode == local->smps_mode) | 1726 | if (WARN_ON_ONCE(!chanctx_conf)) |
| 1674 | goto unlock; | 1727 | goto unlock; |
| 1675 | 1728 | ||
| 1676 | set: | 1729 | chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf); |
| 1677 | local->smps_mode = smps_mode; | 1730 | ieee80211_recalc_smps_chanctx(local, chanctx); |
| 1678 | /* changed flag is auto-detected for this */ | ||
| 1679 | ieee80211_hw_config(local, 0); | ||
| 1680 | unlock: | 1731 | unlock: |
| 1681 | mutex_unlock(&local->iflist_mtx); | 1732 | mutex_unlock(&local->chanctx_mtx); |
| 1682 | } | 1733 | } |
| 1683 | 1734 | ||
| 1684 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | 1735 | static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) |
| @@ -1818,8 +1869,8 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
| 1818 | __le32 tmp; | 1869 | __le32 tmp; |
| 1819 | 1870 | ||
| 1820 | *pos++ = WLAN_EID_VHT_CAPABILITY; | 1871 | *pos++ = WLAN_EID_VHT_CAPABILITY; |
| 1821 | *pos++ = sizeof(struct ieee80211_vht_capabilities); | 1872 | *pos++ = sizeof(struct ieee80211_vht_cap); |
| 1822 | memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); | 1873 | memset(pos, 0, sizeof(struct ieee80211_vht_cap)); |
| 1823 | 1874 | ||
| 1824 | /* capability flags */ | 1875 | /* capability flags */ |
| 1825 | tmp = cpu_to_le32(cap); | 1876 | tmp = cpu_to_le32(cap); |
| @@ -1834,8 +1885,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
| 1834 | } | 1885 | } |
| 1835 | 1886 | ||
| 1836 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1887 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
| 1837 | struct ieee80211_channel *channel, | 1888 | const struct cfg80211_chan_def *chandef, |
| 1838 | enum nl80211_channel_type channel_type, | ||
| 1839 | u16 prot_mode) | 1889 | u16 prot_mode) |
| 1840 | { | 1890 | { |
| 1841 | struct ieee80211_ht_operation *ht_oper; | 1891 | struct ieee80211_ht_operation *ht_oper; |
| @@ -1843,23 +1893,25 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
| 1843 | *pos++ = WLAN_EID_HT_OPERATION; | 1893 | *pos++ = WLAN_EID_HT_OPERATION; |
| 1844 | *pos++ = sizeof(struct ieee80211_ht_operation); | 1894 | *pos++ = sizeof(struct ieee80211_ht_operation); |
| 1845 | ht_oper = (struct ieee80211_ht_operation *)pos; | 1895 | ht_oper = (struct ieee80211_ht_operation *)pos; |
| 1846 | ht_oper->primary_chan = | 1896 | ht_oper->primary_chan = ieee80211_frequency_to_channel( |
| 1847 | ieee80211_frequency_to_channel(channel->center_freq); | 1897 | chandef->chan->center_freq); |
| 1848 | switch (channel_type) { | 1898 | switch (chandef->width) { |
| 1849 | case NL80211_CHAN_HT40MINUS: | 1899 | case NL80211_CHAN_WIDTH_160: |
| 1850 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | 1900 | case NL80211_CHAN_WIDTH_80P80: |
| 1851 | break; | 1901 | case NL80211_CHAN_WIDTH_80: |
| 1852 | case NL80211_CHAN_HT40PLUS: | 1902 | case NL80211_CHAN_WIDTH_40: |
| 1853 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | 1903 | if (chandef->center_freq1 > chandef->chan->center_freq) |
| 1904 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
| 1905 | else | ||
| 1906 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
| 1854 | break; | 1907 | break; |
| 1855 | case NL80211_CHAN_HT20: | ||
| 1856 | default: | 1908 | default: |
| 1857 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; | 1909 | ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; |
| 1858 | break; | 1910 | break; |
| 1859 | } | 1911 | } |
| 1860 | if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && | 1912 | if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && |
| 1861 | channel_type != NL80211_CHAN_NO_HT && | 1913 | chandef->width != NL80211_CHAN_WIDTH_20_NOHT && |
| 1862 | channel_type != NL80211_CHAN_HT20) | 1914 | chandef->width != NL80211_CHAN_WIDTH_20) |
| 1863 | ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; | 1915 | ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; |
| 1864 | 1916 | ||
| 1865 | ht_oper->operation_mode = cpu_to_le16(prot_mode); | 1917 | ht_oper->operation_mode = cpu_to_le16(prot_mode); |
| @@ -1873,13 +1925,17 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
| 1873 | return pos + sizeof(struct ieee80211_ht_operation); | 1925 | return pos + sizeof(struct ieee80211_ht_operation); |
| 1874 | } | 1926 | } |
| 1875 | 1927 | ||
| 1876 | enum nl80211_channel_type | 1928 | void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan, |
| 1877 | ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) | 1929 | struct ieee80211_ht_operation *ht_oper, |
| 1930 | struct cfg80211_chan_def *chandef) | ||
| 1878 | { | 1931 | { |
| 1879 | enum nl80211_channel_type channel_type; | 1932 | enum nl80211_channel_type channel_type; |
| 1880 | 1933 | ||
| 1881 | if (!ht_oper) | 1934 | if (!ht_oper) { |
| 1882 | return NL80211_CHAN_NO_HT; | 1935 | cfg80211_chandef_create(chandef, control_chan, |
| 1936 | NL80211_CHAN_NO_HT); | ||
| 1937 | return; | ||
| 1938 | } | ||
| 1883 | 1939 | ||
| 1884 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 1940 | switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
| 1885 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | 1941 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: |
| @@ -1895,7 +1951,7 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) | |||
| 1895 | channel_type = NL80211_CHAN_NO_HT; | 1951 | channel_type = NL80211_CHAN_NO_HT; |
| 1896 | } | 1952 | } |
| 1897 | 1953 | ||
| 1898 | return channel_type; | 1954 | cfg80211_chandef_create(chandef, control_chan, channel_type); |
| 1899 | } | 1955 | } |
| 1900 | 1956 | ||
| 1901 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | 1957 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, |
| @@ -1977,3 +2033,84 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif) | |||
| 1977 | return ifmgd->ave_beacon_signal; | 2033 | return ifmgd->ave_beacon_signal; |
| 1978 | } | 2034 | } |
| 1979 | EXPORT_SYMBOL_GPL(ieee80211_ave_rssi); | 2035 | EXPORT_SYMBOL_GPL(ieee80211_ave_rssi); |
| 2036 | |||
| 2037 | u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs) | ||
| 2038 | { | ||
| 2039 | if (!mcs) | ||
| 2040 | return 1; | ||
| 2041 | |||
| 2042 | /* TODO: consider rx_highest */ | ||
| 2043 | |||
| 2044 | if (mcs->rx_mask[3]) | ||
| 2045 | return 4; | ||
| 2046 | if (mcs->rx_mask[2]) | ||
| 2047 | return 3; | ||
| 2048 | if (mcs->rx_mask[1]) | ||
| 2049 | return 2; | ||
| 2050 | return 1; | ||
| 2051 | } | ||
| 2052 | |||
| 2053 | /** | ||
| 2054 | * ieee80211_calculate_rx_timestamp - calculate timestamp in frame | ||
| 2055 | * @local: mac80211 hw info struct | ||
| 2056 | * @status: RX status | ||
| 2057 | * @mpdu_len: total MPDU length (including FCS) | ||
| 2058 | * @mpdu_offset: offset into MPDU to calculate timestamp at | ||
| 2059 | * | ||
| 2060 | * This function calculates the RX timestamp at the given MPDU offset, taking | ||
| 2061 | * into account what the RX timestamp was. An offset of 0 will just normalize | ||
| 2062 | * the timestamp to TSF at beginning of MPDU reception. | ||
| 2063 | */ | ||
| 2064 | u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, | ||
| 2065 | struct ieee80211_rx_status *status, | ||
| 2066 | unsigned int mpdu_len, | ||
| 2067 | unsigned int mpdu_offset) | ||
| 2068 | { | ||
| 2069 | u64 ts = status->mactime; | ||
| 2070 | struct rate_info ri; | ||
| 2071 | u16 rate; | ||
| 2072 | |||
| 2073 | if (WARN_ON(!ieee80211_have_rx_timestamp(status))) | ||
| 2074 | return 0; | ||
| 2075 | |||
| 2076 | memset(&ri, 0, sizeof(ri)); | ||
| 2077 | |||
| 2078 | /* Fill cfg80211 rate info */ | ||
| 2079 | if (status->flag & RX_FLAG_HT) { | ||
| 2080 | ri.mcs = status->rate_idx; | ||
| 2081 | ri.flags |= RATE_INFO_FLAGS_MCS; | ||
| 2082 | if (status->flag & RX_FLAG_40MHZ) | ||
| 2083 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
| 2084 | if (status->flag & RX_FLAG_SHORT_GI) | ||
| 2085 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
| 2086 | } else if (status->flag & RX_FLAG_VHT) { | ||
| 2087 | ri.flags |= RATE_INFO_FLAGS_VHT_MCS; | ||
| 2088 | ri.mcs = status->rate_idx; | ||
| 2089 | ri.nss = status->vht_nss; | ||
| 2090 | if (status->flag & RX_FLAG_40MHZ) | ||
| 2091 | ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | ||
| 2092 | if (status->flag & RX_FLAG_80MHZ) | ||
| 2093 | ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; | ||
| 2094 | if (status->flag & RX_FLAG_80P80MHZ) | ||
| 2095 | ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH; | ||
| 2096 | if (status->flag & RX_FLAG_160MHZ) | ||
| 2097 | ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH; | ||
| 2098 | if (status->flag & RX_FLAG_SHORT_GI) | ||
| 2099 | ri.flags |= RATE_INFO_FLAGS_SHORT_GI; | ||
| 2100 | } else { | ||
| 2101 | struct ieee80211_supported_band *sband; | ||
| 2102 | |||
| 2103 | sband = local->hw.wiphy->bands[status->band]; | ||
| 2104 | ri.legacy = sband->bitrates[status->rate_idx].bitrate; | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | rate = cfg80211_calculate_bitrate(&ri); | ||
| 2108 | |||
| 2109 | /* rewind from end of MPDU */ | ||
| 2110 | if (status->flag & RX_FLAG_MACTIME_END) | ||
| 2111 | ts -= mpdu_len * 8 * 10 / rate; | ||
| 2112 | |||
| 2113 | ts += mpdu_offset * 8 * 10 / rate; | ||
| 2114 | |||
| 2115 | return ts; | ||
| 2116 | } | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c new file mode 100644 index 000000000000..f311388aeedf --- /dev/null +++ b/net/mac80211/vht.c | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | /* | ||
| 2 | * VHT handling | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/ieee80211.h> | ||
| 10 | #include <linux/export.h> | ||
| 11 | #include <net/mac80211.h> | ||
| 12 | #include "ieee80211_i.h" | ||
| 13 | |||
| 14 | |||
| 15 | void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | ||
| 16 | struct ieee80211_supported_band *sband, | ||
| 17 | struct ieee80211_vht_cap *vht_cap_ie, | ||
| 18 | struct ieee80211_sta_vht_cap *vht_cap) | ||
| 19 | { | ||
| 20 | if (WARN_ON_ONCE(!vht_cap)) | ||
| 21 | return; | ||
| 22 | |||
| 23 | memset(vht_cap, 0, sizeof(*vht_cap)); | ||
| 24 | |||
| 25 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) | ||
| 26 | return; | ||
| 27 | |||
| 28 | vht_cap->vht_supported = true; | ||
| 29 | |||
| 30 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); | ||
| 31 | |||
| 32 | /* Copy peer MCS info, the driver might need them. */ | ||
| 33 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, | ||
| 34 | sizeof(struct ieee80211_vht_mcs_info)); | ||
| 35 | } | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index cea06e9f26f4..906f00cd6d2f 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
| @@ -160,31 +160,37 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
| 160 | return ieee80211_downgrade_queue(sdata, skb); | 160 | return ieee80211_downgrade_queue(sdata, skb); |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | /** | ||
| 164 | * ieee80211_set_qos_hdr - Fill in the QoS header if there is one. | ||
| 165 | * | ||
| 166 | * @sdata: local subif | ||
| 167 | * @skb: packet to be updated | ||
| 168 | */ | ||
| 163 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, | 169 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, |
| 164 | struct sk_buff *skb) | 170 | struct sk_buff *skb) |
| 165 | { | 171 | { |
| 166 | struct ieee80211_hdr *hdr = (void *)skb->data; | 172 | struct ieee80211_hdr *hdr = (void *)skb->data; |
| 167 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 173 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 174 | u8 *p; | ||
| 175 | u8 ack_policy, tid; | ||
| 168 | 176 | ||
| 169 | /* Fill in the QoS header if there is one. */ | 177 | if (!ieee80211_is_data_qos(hdr->frame_control)) |
| 170 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 178 | return; |
| 171 | u8 *p = ieee80211_get_qos_ctl(hdr); | ||
| 172 | u8 ack_policy, tid; | ||
| 173 | |||
| 174 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | ||
| 175 | 179 | ||
| 176 | /* preserve EOSP bit */ | 180 | p = ieee80211_get_qos_ctl(hdr); |
| 177 | ack_policy = *p & IEEE80211_QOS_CTL_EOSP; | 181 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
| 178 | 182 | ||
| 179 | if (is_multicast_ether_addr(hdr->addr1) || | 183 | /* preserve EOSP bit */ |
| 180 | sdata->noack_map & BIT(tid)) { | 184 | ack_policy = *p & IEEE80211_QOS_CTL_EOSP; |
| 181 | ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; | ||
| 182 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
| 183 | } | ||
| 184 | 185 | ||
| 185 | /* qos header is 2 bytes */ | 186 | if (is_multicast_ether_addr(hdr->addr1) || |
| 186 | *p++ = ack_policy | tid; | 187 | sdata->noack_map & BIT(tid)) { |
| 187 | *p = ieee80211_vif_is_mesh(&sdata->vif) ? | 188 | ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; |
| 188 | (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; | 189 | info->flags |= IEEE80211_TX_CTL_NO_ACK; |
| 189 | } | 190 | } |
| 191 | |||
| 192 | /* qos header is 2 bytes */ | ||
| 193 | *p++ = ack_policy | tid; | ||
| 194 | *p = ieee80211_vif_is_mesh(&sdata->vif) ? | ||
| 195 | (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0; | ||
| 190 | } | 196 | } |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 8bd2f5c6a56e..c175ee866ff4 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
| @@ -104,7 +104,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
| 104 | */ | 104 | */ |
| 105 | if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { | 105 | if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { |
| 106 | if (status->flag & RX_FLAG_MMIC_ERROR) | 106 | if (status->flag & RX_FLAG_MMIC_ERROR) |
| 107 | goto mic_fail; | 107 | goto mic_fail_no_key; |
| 108 | 108 | ||
| 109 | if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key && | 109 | if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key && |
| 110 | rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP) | 110 | rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP) |
| @@ -161,6 +161,9 @@ update_iv: | |||
| 161 | return RX_CONTINUE; | 161 | return RX_CONTINUE; |
| 162 | 162 | ||
| 163 | mic_fail: | 163 | mic_fail: |
| 164 | rx->key->u.tkip.mic_failures++; | ||
| 165 | |||
| 166 | mic_fail_no_key: | ||
| 164 | /* | 167 | /* |
| 165 | * In some cases the key can be unset - e.g. a multicast packet, in | 168 | * In some cases the key can be unset - e.g. a multicast packet, in |
| 166 | * a driver that supports HW encryption. Send up the key idx only if | 169 | * a driver that supports HW encryption. Send up the key idx only if |
