diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-03-08 15:52:21 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-03-08 15:52:21 -0500 |
commit | 3d5c203272b25c4391397247cdb0059a04fccddf (patch) | |
tree | 1cf51dc656c10fd7ea0c84c86afea1d73f3f76bc | |
parent | 7da060c1c01b103d181dba39bce9bd141a945f99 (diff) | |
parent | 87f59c70ce6d1abeaaf97594835be29f746b81a0 (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
59 files changed, 2523 insertions, 1897 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 752ffc4f4166..28c413f861a2 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -2990,13 +2990,15 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, | |||
2990 | { | 2990 | { |
2991 | struct ath6kl *ar = ath6kl_priv(dev); | 2991 | struct ath6kl *ar = ath6kl_priv(dev); |
2992 | struct ath6kl_vif *vif = netdev_priv(dev); | 2992 | struct ath6kl_vif *vif = netdev_priv(dev); |
2993 | int err; | ||
2993 | 2994 | ||
2994 | if (vif->nw_type != AP_NETWORK) | 2995 | if (vif->nw_type != AP_NETWORK) |
2995 | return -EOPNOTSUPP; | 2996 | return -EOPNOTSUPP; |
2996 | 2997 | ||
2997 | /* Use this only for authorizing/unauthorizing a station */ | 2998 | err = cfg80211_check_station_change(wiphy, params, |
2998 | if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) | 2999 | CFG80211_STA_AP_MLME_CLIENT); |
2999 | return -EOPNOTSUPP; | 3000 | if (err) |
3001 | return err; | ||
3000 | 3002 | ||
3001 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) | 3003 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) |
3002 | return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, | 3004 | return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, |
diff --git a/drivers/net/wireless/iwlegacy/3945.h b/drivers/net/wireless/iwlegacy/3945.h index 1d45075e0d5b..9a8703def0ba 100644 --- a/drivers/net/wireless/iwlegacy/3945.h +++ b/drivers/net/wireless/iwlegacy/3945.h | |||
@@ -150,10 +150,6 @@ struct il3945_frame { | |||
150 | struct list_head list; | 150 | struct list_head list; |
151 | }; | 151 | }; |
152 | 152 | ||
153 | #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) | ||
154 | #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) | ||
155 | #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) | ||
156 | |||
157 | #define SUP_RATE_11A_MAX_NUM_CHANNELS 8 | 153 | #define SUP_RATE_11A_MAX_NUM_CHANNELS 8 |
158 | #define SUP_RATE_11B_MAX_NUM_CHANNELS 4 | 154 | #define SUP_RATE_11B_MAX_NUM_CHANNELS 4 |
159 | #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 | 155 | #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 |
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 7941eb3a0166..c092fcbbe965 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c | |||
@@ -2258,7 +2258,7 @@ il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif, | |||
2258 | 2258 | ||
2259 | spin_lock_irqsave(&il->sta_lock, flags); | 2259 | spin_lock_irqsave(&il->sta_lock, flags); |
2260 | tid_data = &il->stations[sta_id].tid[tid]; | 2260 | tid_data = &il->stations[sta_id].tid[tid]; |
2261 | *ssn = SEQ_TO_SN(tid_data->seq_number); | 2261 | *ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
2262 | tid_data->agg.txq_id = txq_id; | 2262 | tid_data->agg.txq_id = txq_id; |
2263 | il_set_swq_id(&il->txq[txq_id], il4965_get_ac_from_tid(tid), txq_id); | 2263 | il_set_swq_id(&il->txq[txq_id], il4965_get_ac_from_tid(tid), txq_id); |
2264 | spin_unlock_irqrestore(&il->sta_lock, flags); | 2264 | spin_unlock_irqrestore(&il->sta_lock, flags); |
@@ -2408,7 +2408,7 @@ il4965_txq_check_empty(struct il_priv *il, int sta_id, u8 tid, int txq_id) | |||
2408 | /* aggregated HW queue */ | 2408 | /* aggregated HW queue */ |
2409 | if (txq_id == tid_data->agg.txq_id && | 2409 | if (txq_id == tid_data->agg.txq_id && |
2410 | q->read_ptr == q->write_ptr) { | 2410 | q->read_ptr == q->write_ptr) { |
2411 | u16 ssn = SEQ_TO_SN(tid_data->seq_number); | 2411 | u16 ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
2412 | int tx_fifo = il4965_get_fifo_from_tid(tid); | 2412 | int tx_fifo = il4965_get_fifo_from_tid(tid); |
2413 | D_HT("HW queue empty: continue DELBA flow\n"); | 2413 | D_HT("HW queue empty: continue DELBA flow\n"); |
2414 | il4965_txq_agg_disable(il, txq_id, ssn, tx_fifo); | 2414 | il4965_txq_agg_disable(il, txq_id, ssn, tx_fifo); |
@@ -2627,7 +2627,8 @@ il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr) | |||
2627 | static inline u32 | 2627 | static inline u32 |
2628 | il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp) | 2628 | il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp) |
2629 | { | 2629 | { |
2630 | return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN; | 2630 | return le32_to_cpup(&tx_resp->u.status + |
2631 | tx_resp->frame_count) & IEEE80211_MAX_SN; | ||
2631 | } | 2632 | } |
2632 | 2633 | ||
2633 | static inline u32 | 2634 | static inline u32 |
@@ -2717,15 +2718,15 @@ il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg, | |||
2717 | hdr = (struct ieee80211_hdr *) skb->data; | 2718 | hdr = (struct ieee80211_hdr *) skb->data; |
2718 | 2719 | ||
2719 | sc = le16_to_cpu(hdr->seq_ctrl); | 2720 | sc = le16_to_cpu(hdr->seq_ctrl); |
2720 | if (idx != (SEQ_TO_SN(sc) & 0xff)) { | 2721 | if (idx != (IEEE80211_SEQ_TO_SN(sc) & 0xff)) { |
2721 | IL_ERR("BUG_ON idx doesn't match seq control" | 2722 | IL_ERR("BUG_ON idx doesn't match seq control" |
2722 | " idx=%d, seq_idx=%d, seq=%d\n", idx, | 2723 | " idx=%d, seq_idx=%d, seq=%d\n", idx, |
2723 | SEQ_TO_SN(sc), hdr->seq_ctrl); | 2724 | IEEE80211_SEQ_TO_SN(sc), hdr->seq_ctrl); |
2724 | return -1; | 2725 | return -1; |
2725 | } | 2726 | } |
2726 | 2727 | ||
2727 | D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx, | 2728 | D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx, |
2728 | SEQ_TO_SN(sc)); | 2729 | IEEE80211_SEQ_TO_SN(sc)); |
2729 | 2730 | ||
2730 | sh = idx - start; | 2731 | sh = idx - start; |
2731 | if (sh > 64) { | 2732 | if (sh > 64) { |
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index 96f2025d936e..73bd3ef316c8 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h | |||
@@ -541,10 +541,6 @@ struct il_frame { | |||
541 | struct list_head list; | 541 | struct list_head list; |
542 | }; | 542 | }; |
543 | 543 | ||
544 | #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) | ||
545 | #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) | ||
546 | #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) | ||
547 | |||
548 | enum { | 544 | enum { |
549 | CMD_SYNC = 0, | 545 | CMD_SYNC = 0, |
550 | CMD_SIZE_NORMAL = 0, | 546 | CMD_SIZE_NORMAL = 0, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 323e4a33fcac..c7cd2dffa5cd 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -1137,7 +1137,8 @@ done: | |||
1137 | static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, | 1137 | static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, |
1138 | struct ieee80211_vif *vif, | 1138 | struct ieee80211_vif *vif, |
1139 | struct ieee80211_channel *channel, | 1139 | struct ieee80211_channel *channel, |
1140 | int duration) | 1140 | int duration, |
1141 | enum ieee80211_roc_type type) | ||
1141 | { | 1142 | { |
1142 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 1143 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
1143 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; | 1144 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 6aec2df3bb27..d499a0366fa6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -418,7 +418,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, | |||
418 | " Tx flags = 0x%08x, agg.state = %d", | 418 | " Tx flags = 0x%08x, agg.state = %d", |
419 | info->flags, tid_data->agg.state); | 419 | info->flags, tid_data->agg.state); |
420 | IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d", | 420 | IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d", |
421 | sta_id, tid, SEQ_TO_SN(tid_data->seq_number)); | 421 | sta_id, tid, |
422 | IEEE80211_SEQ_TO_SN(tid_data->seq_number)); | ||
422 | goto drop_unlock_sta; | 423 | goto drop_unlock_sta; |
423 | } | 424 | } |
424 | 425 | ||
@@ -569,7 +570,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
569 | return 0; | 570 | return 0; |
570 | } | 571 | } |
571 | 572 | ||
572 | tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number); | 573 | tid_data->agg.ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
573 | 574 | ||
574 | /* There are still packets for this RA / TID in the HW */ | 575 | /* There are still packets for this RA / TID in the HW */ |
575 | if (!test_bit(txq_id, priv->agg_q_alloc)) { | 576 | if (!test_bit(txq_id, priv->agg_q_alloc)) { |
@@ -651,7 +652,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
651 | 652 | ||
652 | spin_lock_bh(&priv->sta_lock); | 653 | spin_lock_bh(&priv->sta_lock); |
653 | tid_data = &priv->tid_data[sta_id][tid]; | 654 | tid_data = &priv->tid_data[sta_id][tid]; |
654 | tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number); | 655 | tid_data->agg.ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
655 | tid_data->agg.txq_id = txq_id; | 656 | tid_data->agg.txq_id = txq_id; |
656 | 657 | ||
657 | *ssn = tid_data->agg.ssn; | 658 | *ssn = tid_data->agg.ssn; |
@@ -911,7 +912,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status) | |||
911 | static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp) | 912 | static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp) |
912 | { | 913 | { |
913 | return le32_to_cpup((__le32 *)&tx_resp->status + | 914 | return le32_to_cpup((__le32 *)&tx_resp->status + |
914 | tx_resp->frame_count) & MAX_SN; | 915 | tx_resp->frame_count) & IEEE80211_MAX_SN; |
915 | } | 916 | } |
916 | 917 | ||
917 | static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, | 918 | static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, |
@@ -1148,7 +1149,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1148 | 1149 | ||
1149 | if (tx_resp->frame_count == 1) { | 1150 | if (tx_resp->frame_count == 1) { |
1150 | u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl); | 1151 | u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl); |
1151 | next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10); | 1152 | next_reclaimed = IEEE80211_SEQ_TO_SN(next_reclaimed + 0x10); |
1152 | 1153 | ||
1153 | if (is_agg) { | 1154 | if (is_agg) { |
1154 | /* If this is an aggregation queue, we can rely on the | 1155 | /* If this is an aggregation queue, we can rely on the |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8c7bec6b9a0b..00bdc5b00af3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -114,9 +114,6 @@ | |||
114 | * completely agnostic to these differences. | 114 | * completely agnostic to these differences. |
115 | * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode), | 115 | * The transport does provide helper functionnality (i.e. SYNC / ASYNC mode), |
116 | */ | 116 | */ |
117 | #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) | ||
118 | #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) | ||
119 | #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) | ||
120 | #define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) | 117 | #define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f) |
121 | #define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) | 118 | #define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) |
122 | #define SEQ_TO_INDEX(s) ((s) & 0xff) | 119 | #define SEQ_TO_INDEX(s) ((s) & 0xff) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e8264e11b12d..23460f4a4c75 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -1081,7 +1081,8 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw, | |||
1081 | static int iwl_mvm_roc(struct ieee80211_hw *hw, | 1081 | static int iwl_mvm_roc(struct ieee80211_hw *hw, |
1082 | struct ieee80211_vif *vif, | 1082 | struct ieee80211_vif *vif, |
1083 | struct ieee80211_channel *channel, | 1083 | struct ieee80211_channel *channel, |
1084 | int duration) | 1084 | int duration, |
1085 | enum ieee80211_roc_type type) | ||
1085 | { | 1086 | { |
1086 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1087 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1087 | struct cfg80211_chan_def chandef; | 1088 | struct cfg80211_chan_def chandef; |
@@ -1092,8 +1093,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, | |||
1092 | return -EINVAL; | 1093 | return -EINVAL; |
1093 | } | 1094 | } |
1094 | 1095 | ||
1095 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value, | 1096 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, |
1096 | duration); | 1097 | duration, type); |
1097 | 1098 | ||
1098 | mutex_lock(&mvm->mutex); | 1099 | mutex_lock(&mvm->mutex); |
1099 | 1100 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 861a7f9f8e7f..52aecf20d0df 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -686,7 +686,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
686 | 686 | ||
687 | spin_lock_bh(&mvmsta->lock); | 687 | spin_lock_bh(&mvmsta->lock); |
688 | tid_data = &mvmsta->tid_data[tid]; | 688 | tid_data = &mvmsta->tid_data[tid]; |
689 | tid_data->ssn = SEQ_TO_SN(tid_data->seq_number); | 689 | tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
690 | tid_data->txq_id = txq_id; | 690 | tid_data->txq_id = txq_id; |
691 | *ssn = tid_data->ssn; | 691 | *ssn = tid_data->ssn; |
692 | 692 | ||
@@ -779,7 +779,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
779 | 779 | ||
780 | switch (tid_data->state) { | 780 | switch (tid_data->state) { |
781 | case IWL_AGG_ON: | 781 | case IWL_AGG_ON: |
782 | tid_data->ssn = SEQ_TO_SN(tid_data->seq_number); | 782 | tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); |
783 | 783 | ||
784 | IWL_DEBUG_TX_QUEUES(mvm, | 784 | IWL_DEBUG_TX_QUEUES(mvm, |
785 | "ssn = %d, next_recl = %d\n", | 785 | "ssn = %d, next_recl = %d\n", |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 6b67ce3f679c..56df249b215e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -641,7 +641,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
641 | next_reclaimed = ssn; | 641 | next_reclaimed = ssn; |
642 | } else { | 642 | } else { |
643 | /* The next packet to be reclaimed is the one after this one */ | 643 | /* The next packet to be reclaimed is the one after this one */ |
644 | next_reclaimed = SEQ_TO_SN(seq_ctl + 0x10); | 644 | next_reclaimed = IEEE80211_SEQ_TO_SN(seq_ctl + 0x10); |
645 | } | 645 | } |
646 | 646 | ||
647 | IWL_DEBUG_TX_REPLY(mvm, | 647 | IWL_DEBUG_TX_REPLY(mvm, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8e9e3212fe78..ad7441dfa6fb 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -1581,7 +1581,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | |||
1581 | * Check here that the packets are in the right place on the ring. | 1581 | * Check here that the packets are in the right place on the ring. |
1582 | */ | 1582 | */ |
1583 | #ifdef CONFIG_IWLWIFI_DEBUG | 1583 | #ifdef CONFIG_IWLWIFI_DEBUG |
1584 | wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); | 1584 | wifi_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); |
1585 | WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) && | 1585 | WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) && |
1586 | ((wifi_seq & 0xff) != q->write_ptr), | 1586 | ((wifi_seq & 0xff) != q->write_ptr), |
1587 | "Q: %d WiFi Seq %d tfdNum %d", | 1587 | "Q: %d WiFi Seq %d tfdNum %d", |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index cffdf4fbf161..7490c4fc7177 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -1535,7 +1535,8 @@ static void hw_roc_done(struct work_struct *work) | |||
1535 | static int mac80211_hwsim_roc(struct ieee80211_hw *hw, | 1535 | static int mac80211_hwsim_roc(struct ieee80211_hw *hw, |
1536 | struct ieee80211_vif *vif, | 1536 | struct ieee80211_vif *vif, |
1537 | struct ieee80211_channel *chan, | 1537 | struct ieee80211_channel *chan, |
1538 | int duration) | 1538 | int duration, |
1539 | enum ieee80211_roc_type type) | ||
1539 | { | 1540 | { |
1540 | struct mac80211_hwsim_data *hwsim = hw->priv; | 1541 | struct mac80211_hwsim_data *hwsim = hw->priv; |
1541 | 1542 | ||
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index f13258a8d995..c3eff32acf6c 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h | |||
@@ -2127,9 +2127,6 @@ value to host byte ordering.*/ | |||
2127 | #define WLAN_FC_GET_TYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) | 2127 | #define WLAN_FC_GET_TYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) |
2128 | #define WLAN_FC_GET_STYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) | 2128 | #define WLAN_FC_GET_STYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) |
2129 | #define WLAN_FC_MORE_DATA(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA) | 2129 | #define WLAN_FC_MORE_DATA(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA) |
2130 | #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) | ||
2131 | #define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) | ||
2132 | #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) | ||
2133 | 2130 | ||
2134 | #define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */ | 2131 | #define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */ |
2135 | #define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */ | 2132 | #define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */ |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2c2ff3e1f849..d7e306333f6c 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -4956,7 +4956,8 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) | |||
4956 | static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, | 4956 | static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, |
4957 | struct ieee80211_vif *vif, | 4957 | struct ieee80211_vif *vif, |
4958 | struct ieee80211_channel *chan, | 4958 | struct ieee80211_channel *chan, |
4959 | int duration) | 4959 | int duration, |
4960 | enum ieee80211_roc_type type) | ||
4960 | { | 4961 | { |
4961 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | 4962 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); |
4962 | struct wl1271 *wl = hw->priv; | 4963 | struct wl1271 *wl = hw->priv; |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 7e24fe0cfbcd..4cf0c9e4dd99 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -113,6 +113,34 @@ | |||
113 | #define IEEE80211_CTL_EXT_SSW_FBACK 0x9000 | 113 | #define IEEE80211_CTL_EXT_SSW_FBACK 0x9000 |
114 | #define IEEE80211_CTL_EXT_SSW_ACK 0xa000 | 114 | #define IEEE80211_CTL_EXT_SSW_ACK 0xa000 |
115 | 115 | ||
116 | |||
117 | #define IEEE80211_SN_MASK ((IEEE80211_SCTL_SEQ) >> 4) | ||
118 | #define IEEE80211_MAX_SN IEEE80211_SN_MASK | ||
119 | #define IEEE80211_SN_MODULO (IEEE80211_MAX_SN + 1) | ||
120 | |||
121 | static inline int ieee80211_sn_less(u16 sn1, u16 sn2) | ||
122 | { | ||
123 | return ((sn1 - sn2) & IEEE80211_SN_MASK) > (IEEE80211_SN_MODULO >> 1); | ||
124 | } | ||
125 | |||
126 | static inline u16 ieee80211_sn_add(u16 sn1, u16 sn2) | ||
127 | { | ||
128 | return (sn1 + sn2) & IEEE80211_SN_MASK; | ||
129 | } | ||
130 | |||
131 | static inline u16 ieee80211_sn_inc(u16 sn) | ||
132 | { | ||
133 | return ieee80211_sn_add(sn, 1); | ||
134 | } | ||
135 | |||
136 | static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) | ||
137 | { | ||
138 | return (sn1 - sn2) & IEEE80211_SN_MASK; | ||
139 | } | ||
140 | |||
141 | #define IEEE80211_SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) | ||
142 | #define IEEE80211_SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) | ||
143 | |||
116 | /* miscellaneous IEEE 802.11 constants */ | 144 | /* miscellaneous IEEE 802.11 constants */ |
117 | #define IEEE80211_MAX_FRAG_THRESHOLD 2352 | 145 | #define IEEE80211_MAX_FRAG_THRESHOLD 2352 |
118 | #define IEEE80211_MAX_RTS_THRESHOLD 2353 | 146 | #define IEEE80211_MAX_RTS_THRESHOLD 2353 |
@@ -185,7 +213,7 @@ struct ieee80211_hdr { | |||
185 | u8 addr3[6]; | 213 | u8 addr3[6]; |
186 | __le16 seq_ctrl; | 214 | __le16 seq_ctrl; |
187 | u8 addr4[6]; | 215 | u8 addr4[6]; |
188 | } __packed; | 216 | } __packed __aligned(2); |
189 | 217 | ||
190 | struct ieee80211_hdr_3addr { | 218 | struct ieee80211_hdr_3addr { |
191 | __le16 frame_control; | 219 | __le16 frame_control; |
@@ -194,7 +222,7 @@ struct ieee80211_hdr_3addr { | |||
194 | u8 addr2[6]; | 222 | u8 addr2[6]; |
195 | u8 addr3[6]; | 223 | u8 addr3[6]; |
196 | __le16 seq_ctrl; | 224 | __le16 seq_ctrl; |
197 | } __packed; | 225 | } __packed __aligned(2); |
198 | 226 | ||
199 | struct ieee80211_qos_hdr { | 227 | struct ieee80211_qos_hdr { |
200 | __le16 frame_control; | 228 | __le16 frame_control; |
@@ -204,7 +232,7 @@ struct ieee80211_qos_hdr { | |||
204 | u8 addr3[6]; | 232 | u8 addr3[6]; |
205 | __le16 seq_ctrl; | 233 | __le16 seq_ctrl; |
206 | __le16 qos_ctrl; | 234 | __le16 qos_ctrl; |
207 | } __packed; | 235 | } __packed __aligned(2); |
208 | 236 | ||
209 | /** | 237 | /** |
210 | * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set | 238 | * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set |
@@ -581,7 +609,7 @@ struct ieee80211s_hdr { | |||
581 | __le32 seqnum; | 609 | __le32 seqnum; |
582 | u8 eaddr1[6]; | 610 | u8 eaddr1[6]; |
583 | u8 eaddr2[6]; | 611 | u8 eaddr2[6]; |
584 | } __packed; | 612 | } __packed __aligned(2); |
585 | 613 | ||
586 | /* Mesh flags */ | 614 | /* Mesh flags */ |
587 | #define MESH_FLAGS_AE_A4 0x1 | 615 | #define MESH_FLAGS_AE_A4 0x1 |
@@ -875,7 +903,7 @@ struct ieee80211_mgmt { | |||
875 | } u; | 903 | } u; |
876 | } __packed action; | 904 | } __packed action; |
877 | } u; | 905 | } u; |
878 | } __packed; | 906 | } __packed __aligned(2); |
879 | 907 | ||
880 | /* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */ | 908 | /* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */ |
881 | #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 | 909 | #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 |
@@ -906,20 +934,20 @@ struct ieee80211_rts { | |||
906 | __le16 duration; | 934 | __le16 duration; |
907 | u8 ra[6]; | 935 | u8 ra[6]; |
908 | u8 ta[6]; | 936 | u8 ta[6]; |
909 | } __packed; | 937 | } __packed __aligned(2); |
910 | 938 | ||
911 | struct ieee80211_cts { | 939 | struct ieee80211_cts { |
912 | __le16 frame_control; | 940 | __le16 frame_control; |
913 | __le16 duration; | 941 | __le16 duration; |
914 | u8 ra[6]; | 942 | u8 ra[6]; |
915 | } __packed; | 943 | } __packed __aligned(2); |
916 | 944 | ||
917 | struct ieee80211_pspoll { | 945 | struct ieee80211_pspoll { |
918 | __le16 frame_control; | 946 | __le16 frame_control; |
919 | __le16 aid; | 947 | __le16 aid; |
920 | u8 bssid[6]; | 948 | u8 bssid[6]; |
921 | u8 ta[6]; | 949 | u8 ta[6]; |
922 | } __packed; | 950 | } __packed __aligned(2); |
923 | 951 | ||
924 | /* TDLS */ | 952 | /* TDLS */ |
925 | 953 | ||
@@ -1290,11 +1318,6 @@ struct ieee80211_vht_operation { | |||
1290 | } __packed; | 1318 | } __packed; |
1291 | 1319 | ||
1292 | 1320 | ||
1293 | #define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0 | ||
1294 | #define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1 | ||
1295 | #define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT 2 | ||
1296 | #define IEEE80211_VHT_MCS_NOT_SUPPORTED 3 | ||
1297 | |||
1298 | /* 802.11ac VHT Capabilities */ | 1321 | /* 802.11ac VHT Capabilities */ |
1299 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 | 1322 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 |
1300 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001 | 1323 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001 |
@@ -1310,10 +1333,11 @@ struct ieee80211_vht_operation { | |||
1310 | #define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 | 1333 | #define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 |
1311 | #define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 | 1334 | #define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 |
1312 | #define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 | 1335 | #define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 |
1336 | #define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700 | ||
1313 | #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 | 1337 | #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 |
1314 | #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 | 1338 | #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 |
1315 | #define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000 | 1339 | #define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000 |
1316 | #define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000 | 1340 | #define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX 0x00030000 |
1317 | #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 | 1341 | #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 |
1318 | #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 | 1342 | #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 |
1319 | #define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 | 1343 | #define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index d581c6de5d64..bdba9b619064 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -611,22 +611,10 @@ struct cfg80211_ap_settings { | |||
611 | }; | 611 | }; |
612 | 612 | ||
613 | /** | 613 | /** |
614 | * enum plink_action - actions to perform in mesh peers | ||
615 | * | ||
616 | * @PLINK_ACTION_INVALID: action 0 is reserved | ||
617 | * @PLINK_ACTION_OPEN: start mesh peer link establishment | ||
618 | * @PLINK_ACTION_BLOCK: block traffic from this mesh peer | ||
619 | */ | ||
620 | enum plink_actions { | ||
621 | PLINK_ACTION_INVALID, | ||
622 | PLINK_ACTION_OPEN, | ||
623 | PLINK_ACTION_BLOCK, | ||
624 | }; | ||
625 | |||
626 | /** | ||
627 | * enum station_parameters_apply_mask - station parameter values to apply | 614 | * enum station_parameters_apply_mask - station parameter values to apply |
628 | * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) | 615 | * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) |
629 | * @STATION_PARAM_APPLY_CAPABILITY: apply new capability | 616 | * @STATION_PARAM_APPLY_CAPABILITY: apply new capability |
617 | * @STATION_PARAM_APPLY_PLINK_STATE: apply new plink state | ||
630 | * | 618 | * |
631 | * Not all station parameters have in-band "no change" signalling, | 619 | * Not all station parameters have in-band "no change" signalling, |
632 | * for those that don't these flags will are used. | 620 | * for those that don't these flags will are used. |
@@ -634,6 +622,7 @@ enum plink_actions { | |||
634 | enum station_parameters_apply_mask { | 622 | enum station_parameters_apply_mask { |
635 | STATION_PARAM_APPLY_UAPSD = BIT(0), | 623 | STATION_PARAM_APPLY_UAPSD = BIT(0), |
636 | STATION_PARAM_APPLY_CAPABILITY = BIT(1), | 624 | STATION_PARAM_APPLY_CAPABILITY = BIT(1), |
625 | STATION_PARAM_APPLY_PLINK_STATE = BIT(2), | ||
637 | }; | 626 | }; |
638 | 627 | ||
639 | /** | 628 | /** |
@@ -669,7 +658,7 @@ enum station_parameters_apply_mask { | |||
669 | * @ext_capab_len: number of extended capabilities | 658 | * @ext_capab_len: number of extended capabilities |
670 | */ | 659 | */ |
671 | struct station_parameters { | 660 | struct station_parameters { |
672 | u8 *supported_rates; | 661 | const u8 *supported_rates; |
673 | struct net_device *vlan; | 662 | struct net_device *vlan; |
674 | u32 sta_flags_mask, sta_flags_set; | 663 | u32 sta_flags_mask, sta_flags_set; |
675 | u32 sta_modify_mask; | 664 | u32 sta_modify_mask; |
@@ -678,17 +667,60 @@ struct station_parameters { | |||
678 | u8 supported_rates_len; | 667 | u8 supported_rates_len; |
679 | u8 plink_action; | 668 | u8 plink_action; |
680 | u8 plink_state; | 669 | u8 plink_state; |
681 | struct ieee80211_ht_cap *ht_capa; | 670 | const struct ieee80211_ht_cap *ht_capa; |
682 | struct ieee80211_vht_cap *vht_capa; | 671 | const struct ieee80211_vht_cap *vht_capa; |
683 | u8 uapsd_queues; | 672 | u8 uapsd_queues; |
684 | u8 max_sp; | 673 | u8 max_sp; |
685 | enum nl80211_mesh_power_mode local_pm; | 674 | enum nl80211_mesh_power_mode local_pm; |
686 | u16 capability; | 675 | u16 capability; |
687 | u8 *ext_capab; | 676 | const u8 *ext_capab; |
688 | u8 ext_capab_len; | 677 | u8 ext_capab_len; |
689 | }; | 678 | }; |
690 | 679 | ||
691 | /** | 680 | /** |
681 | * enum cfg80211_station_type - the type of station being modified | ||
682 | * @CFG80211_STA_AP_CLIENT: client of an AP interface | ||
683 | * @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has | ||
684 | * the AP MLME in the device | ||
685 | * @CFG80211_STA_AP_STA: AP station on managed interface | ||
686 | * @CFG80211_STA_IBSS: IBSS station | ||
687 | * @CFG80211_STA_TDLS_PEER_SETUP: TDLS peer on managed interface (dummy entry | ||
688 | * while TDLS setup is in progress, it moves out of this state when | ||
689 | * being marked authorized; use this only if TDLS with external setup is | ||
690 | * supported/used) | ||
691 | * @CFG80211_STA_TDLS_PEER_ACTIVE: TDLS peer on managed interface (active | ||
692 | * entry that is operating, has been marked authorized by userspace) | ||
693 | * @CFG80211_STA_MESH_PEER_KERNEL: peer on mesh interface (kernel managed) | ||
694 | * @CFG80211_STA_MESH_PEER_USER: peer on mesh interface (user managed) | ||
695 | */ | ||
696 | enum cfg80211_station_type { | ||
697 | CFG80211_STA_AP_CLIENT, | ||
698 | CFG80211_STA_AP_MLME_CLIENT, | ||
699 | CFG80211_STA_AP_STA, | ||
700 | CFG80211_STA_IBSS, | ||
701 | CFG80211_STA_TDLS_PEER_SETUP, | ||
702 | CFG80211_STA_TDLS_PEER_ACTIVE, | ||
703 | CFG80211_STA_MESH_PEER_KERNEL, | ||
704 | CFG80211_STA_MESH_PEER_USER, | ||
705 | }; | ||
706 | |||
707 | /** | ||
708 | * cfg80211_check_station_change - validate parameter changes | ||
709 | * @wiphy: the wiphy this operates on | ||
710 | * @params: the new parameters for a station | ||
711 | * @statype: the type of station being modified | ||
712 | * | ||
713 | * Utility function for the @change_station driver method. Call this function | ||
714 | * with the appropriate station type looking up the station (and checking that | ||
715 | * it exists). It will verify whether the station change is acceptable, and if | ||
716 | * not will return an error code. Note that it may modify the parameters for | ||
717 | * backward compatibility reasons, so don't use them before calling this. | ||
718 | */ | ||
719 | int cfg80211_check_station_change(struct wiphy *wiphy, | ||
720 | struct station_parameters *params, | ||
721 | enum cfg80211_station_type statype); | ||
722 | |||
723 | /** | ||
692 | * enum station_info_flags - station information flags | 724 | * enum station_info_flags - station information flags |
693 | * | 725 | * |
694 | * Used by the driver to indicate which info in &struct station_info | 726 | * Used by the driver to indicate which info in &struct station_info |
@@ -1119,6 +1151,7 @@ struct mesh_config { | |||
1119 | * @ie_len: length of vendor information elements | 1151 | * @ie_len: length of vendor information elements |
1120 | * @is_authenticated: this mesh requires authentication | 1152 | * @is_authenticated: this mesh requires authentication |
1121 | * @is_secure: this mesh uses security | 1153 | * @is_secure: this mesh uses security |
1154 | * @user_mpm: userspace handles all MPM functions | ||
1122 | * @dtim_period: DTIM period to use | 1155 | * @dtim_period: DTIM period to use |
1123 | * @beacon_interval: beacon interval to use | 1156 | * @beacon_interval: beacon interval to use |
1124 | * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a] | 1157 | * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a] |
@@ -1136,6 +1169,7 @@ struct mesh_setup { | |||
1136 | u8 ie_len; | 1169 | u8 ie_len; |
1137 | bool is_authenticated; | 1170 | bool is_authenticated; |
1138 | bool is_secure; | 1171 | bool is_secure; |
1172 | bool user_mpm; | ||
1139 | u8 dtim_period; | 1173 | u8 dtim_period; |
1140 | u16 beacon_interval; | 1174 | u16 beacon_interval; |
1141 | int mcast_rate[IEEE80211_NUM_BANDS]; | 1175 | int mcast_rate[IEEE80211_NUM_BANDS]; |
@@ -1398,9 +1432,11 @@ struct cfg80211_auth_request { | |||
1398 | * enum cfg80211_assoc_req_flags - Over-ride default behaviour in association. | 1432 | * enum cfg80211_assoc_req_flags - Over-ride default behaviour in association. |
1399 | * | 1433 | * |
1400 | * @ASSOC_REQ_DISABLE_HT: Disable HT (802.11n) | 1434 | * @ASSOC_REQ_DISABLE_HT: Disable HT (802.11n) |
1435 | * @ASSOC_REQ_DISABLE_VHT: Disable VHT | ||
1401 | */ | 1436 | */ |
1402 | enum cfg80211_assoc_req_flags { | 1437 | enum cfg80211_assoc_req_flags { |
1403 | ASSOC_REQ_DISABLE_HT = BIT(0), | 1438 | ASSOC_REQ_DISABLE_HT = BIT(0), |
1439 | ASSOC_REQ_DISABLE_VHT = BIT(1), | ||
1404 | }; | 1440 | }; |
1405 | 1441 | ||
1406 | /** | 1442 | /** |
@@ -1422,6 +1458,8 @@ enum cfg80211_assoc_req_flags { | |||
1422 | * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask | 1458 | * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask |
1423 | * will be used in ht_capa. Un-supported values will be ignored. | 1459 | * will be used in ht_capa. Un-supported values will be ignored. |
1424 | * @ht_capa_mask: The bits of ht_capa which are to be used. | 1460 | * @ht_capa_mask: The bits of ht_capa which are to be used. |
1461 | * @vht_capa: VHT capability override | ||
1462 | * @vht_capa_mask: VHT capability mask indicating which fields to use | ||
1425 | */ | 1463 | */ |
1426 | struct cfg80211_assoc_request { | 1464 | struct cfg80211_assoc_request { |
1427 | struct cfg80211_bss *bss; | 1465 | struct cfg80211_bss *bss; |
@@ -1432,6 +1470,7 @@ struct cfg80211_assoc_request { | |||
1432 | u32 flags; | 1470 | u32 flags; |
1433 | struct ieee80211_ht_cap ht_capa; | 1471 | struct ieee80211_ht_cap ht_capa; |
1434 | struct ieee80211_ht_cap ht_capa_mask; | 1472 | struct ieee80211_ht_cap ht_capa_mask; |
1473 | struct ieee80211_vht_cap vht_capa, vht_capa_mask; | ||
1435 | }; | 1474 | }; |
1436 | 1475 | ||
1437 | /** | 1476 | /** |
@@ -1542,6 +1581,8 @@ struct cfg80211_ibss_params { | |||
1542 | * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask | 1581 | * @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask |
1543 | * will be used in ht_capa. Un-supported values will be ignored. | 1582 | * will be used in ht_capa. Un-supported values will be ignored. |
1544 | * @ht_capa_mask: The bits of ht_capa which are to be used. | 1583 | * @ht_capa_mask: The bits of ht_capa which are to be used. |
1584 | * @vht_capa: VHT Capability overrides | ||
1585 | * @vht_capa_mask: The bits of vht_capa which are to be used. | ||
1545 | */ | 1586 | */ |
1546 | struct cfg80211_connect_params { | 1587 | struct cfg80211_connect_params { |
1547 | struct ieee80211_channel *channel; | 1588 | struct ieee80211_channel *channel; |
@@ -1560,6 +1601,8 @@ struct cfg80211_connect_params { | |||
1560 | int bg_scan_period; | 1601 | int bg_scan_period; |
1561 | struct ieee80211_ht_cap ht_capa; | 1602 | struct ieee80211_ht_cap ht_capa; |
1562 | struct ieee80211_ht_cap ht_capa_mask; | 1603 | struct ieee80211_ht_cap ht_capa_mask; |
1604 | struct ieee80211_vht_cap vht_capa; | ||
1605 | struct ieee80211_vht_cap vht_capa_mask; | ||
1563 | }; | 1606 | }; |
1564 | 1607 | ||
1565 | /** | 1608 | /** |
@@ -1722,6 +1765,21 @@ struct cfg80211_gtk_rekey_data { | |||
1722 | }; | 1765 | }; |
1723 | 1766 | ||
1724 | /** | 1767 | /** |
1768 | * struct cfg80211_update_ft_ies_params - FT IE Information | ||
1769 | * | ||
1770 | * This structure provides information needed to update the fast transition IE | ||
1771 | * | ||
1772 | * @md: The Mobility Domain ID, 2 Octet value | ||
1773 | * @ie: Fast Transition IEs | ||
1774 | * @ie_len: Length of ft_ie in octets | ||
1775 | */ | ||
1776 | struct cfg80211_update_ft_ies_params { | ||
1777 | u16 md; | ||
1778 | const u8 *ie; | ||
1779 | size_t ie_len; | ||
1780 | }; | ||
1781 | |||
1782 | /** | ||
1725 | * struct cfg80211_ops - backend description for wireless configuration | 1783 | * struct cfg80211_ops - backend description for wireless configuration |
1726 | * | 1784 | * |
1727 | * This struct is registered by fullmac card drivers and/or wireless stacks | 1785 | * This struct is registered by fullmac card drivers and/or wireless stacks |
@@ -1781,9 +1839,8 @@ struct cfg80211_gtk_rekey_data { | |||
1781 | * @change_station: Modify a given station. Note that flags changes are not much | 1839 | * @change_station: Modify a given station. Note that flags changes are not much |
1782 | * validated in cfg80211, in particular the auth/assoc/authorized flags | 1840 | * validated in cfg80211, in particular the auth/assoc/authorized flags |
1783 | * might come to the driver in invalid combinations -- make sure to check | 1841 | * might come to the driver in invalid combinations -- make sure to check |
1784 | * them, also against the existing state! Also, supported_rates changes are | 1842 | * them, also against the existing state! Drivers must call |
1785 | * not checked in station mode -- drivers need to reject (or ignore) them | 1843 | * cfg80211_check_station_change() to validate the information. |
1786 | * for anything but TDLS peers. | ||
1787 | * @get_station: get station information for the station identified by @mac | 1844 | * @get_station: get station information for the station identified by @mac |
1788 | * @dump_station: dump station callback -- resume dump at index @idx | 1845 | * @dump_station: dump station callback -- resume dump at index @idx |
1789 | * | 1846 | * |
@@ -2168,6 +2225,8 @@ struct cfg80211_ops { | |||
2168 | int (*start_radar_detection)(struct wiphy *wiphy, | 2225 | int (*start_radar_detection)(struct wiphy *wiphy, |
2169 | struct net_device *dev, | 2226 | struct net_device *dev, |
2170 | struct cfg80211_chan_def *chandef); | 2227 | struct cfg80211_chan_def *chandef); |
2228 | int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, | ||
2229 | struct cfg80211_update_ft_ies_params *ftie); | ||
2171 | }; | 2230 | }; |
2172 | 2231 | ||
2173 | /* | 2232 | /* |
@@ -2485,6 +2544,8 @@ struct wiphy_wowlan_support { | |||
2485 | * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features. | 2544 | * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features. |
2486 | * @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden. | 2545 | * @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden. |
2487 | * If null, then none can be over-ridden. | 2546 | * If null, then none can be over-ridden. |
2547 | * @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden. | ||
2548 | * If null, then none can be over-ridden. | ||
2488 | * | 2549 | * |
2489 | * @max_acl_mac_addrs: Maximum number of MAC addresses that the device | 2550 | * @max_acl_mac_addrs: Maximum number of MAC addresses that the device |
2490 | * supports for ACL. | 2551 | * supports for ACL. |
@@ -2593,6 +2654,7 @@ struct wiphy { | |||
2593 | struct dentry *debugfsdir; | 2654 | struct dentry *debugfsdir; |
2594 | 2655 | ||
2595 | const struct ieee80211_ht_cap *ht_capa_mod_mask; | 2656 | const struct ieee80211_ht_cap *ht_capa_mod_mask; |
2657 | const struct ieee80211_vht_cap *vht_capa_mod_mask; | ||
2596 | 2658 | ||
2597 | #ifdef CONFIG_NET_NS | 2659 | #ifdef CONFIG_NET_NS |
2598 | /* the network namespace this phy lives in currently */ | 2660 | /* the network namespace this phy lives in currently */ |
@@ -4002,6 +4064,30 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate); | |||
4002 | void cfg80211_unregister_wdev(struct wireless_dev *wdev); | 4064 | void cfg80211_unregister_wdev(struct wireless_dev *wdev); |
4003 | 4065 | ||
4004 | /** | 4066 | /** |
4067 | * struct cfg80211_ft_event - FT Information Elements | ||
4068 | * @ies: FT IEs | ||
4069 | * @ies_len: length of the FT IE in bytes | ||
4070 | * @target_ap: target AP's MAC address | ||
4071 | * @ric_ies: RIC IE | ||
4072 | * @ric_ies_len: length of the RIC IE in bytes | ||
4073 | */ | ||
4074 | struct cfg80211_ft_event_params { | ||
4075 | const u8 *ies; | ||
4076 | size_t ies_len; | ||
4077 | const u8 *target_ap; | ||
4078 | const u8 *ric_ies; | ||
4079 | size_t ric_ies_len; | ||
4080 | }; | ||
4081 | |||
4082 | /** | ||
4083 | * cfg80211_ft_event - notify userspace about FT IE and RIC IE | ||
4084 | * @netdev: network device | ||
4085 | * @ft_event: IE information | ||
4086 | */ | ||
4087 | void cfg80211_ft_event(struct net_device *netdev, | ||
4088 | struct cfg80211_ft_event_params *ft_event); | ||
4089 | |||
4090 | /** | ||
4005 | * cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer | 4091 | * cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer |
4006 | * @ies: the input IE buffer | 4092 | * @ies: the input IE buffer |
4007 | * @len: the input length | 4093 | * @len: the input length |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f7eba1300d82..cdd7cea1fd4c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1101,8 +1101,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) | |||
1101 | * These flags are used for communication about keys between the driver | 1101 | * These flags are used for communication about keys between the driver |
1102 | * and mac80211, with the @flags parameter of &struct ieee80211_key_conf. | 1102 | * and mac80211, with the @flags parameter of &struct ieee80211_key_conf. |
1103 | * | 1103 | * |
1104 | * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates | ||
1105 | * that the STA this key will be used with could be using QoS. | ||
1106 | * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the | 1104 | * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the |
1107 | * driver to indicate that it requires IV generation for this | 1105 | * driver to indicate that it requires IV generation for this |
1108 | * particular key. | 1106 | * particular key. |
@@ -1127,7 +1125,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) | |||
1127 | * %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW. | 1125 | * %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW. |
1128 | */ | 1126 | */ |
1129 | enum ieee80211_key_flags { | 1127 | enum ieee80211_key_flags { |
1130 | IEEE80211_KEY_FLAG_WMM_STA = 1<<0, | ||
1131 | IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, | 1128 | IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1, |
1132 | IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, | 1129 | IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2, |
1133 | IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, | 1130 | IEEE80211_KEY_FLAG_PAIRWISE = 1<<3, |
@@ -1231,9 +1228,8 @@ enum ieee80211_sta_rx_bandwidth { | |||
1231 | * @addr: MAC address | 1228 | * @addr: MAC address |
1232 | * @aid: AID we assigned to the station if we're an AP | 1229 | * @aid: AID we assigned to the station if we're an AP |
1233 | * @supp_rates: Bitmap of supported rates (per band) | 1230 | * @supp_rates: Bitmap of supported rates (per band) |
1234 | * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities | 1231 | * @ht_cap: HT capabilities of this STA; restricted to our own capabilities |
1235 | * @vht_cap: VHT capabilities of this STA; Not restricting any capabilities | 1232 | * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities |
1236 | * of remote STA. Taking as is. | ||
1237 | * @wme: indicates whether the STA supports WME. Only valid during AP-mode. | 1233 | * @wme: indicates whether the STA supports WME. Only valid during AP-mode. |
1238 | * @drv_priv: data area for driver use, will always be aligned to | 1234 | * @drv_priv: data area for driver use, will always be aligned to |
1239 | * sizeof(void *), size is determined in hw information. | 1235 | * sizeof(void *), size is determined in hw information. |
@@ -2135,6 +2131,24 @@ enum ieee80211_rate_control_changed { | |||
2135 | }; | 2131 | }; |
2136 | 2132 | ||
2137 | /** | 2133 | /** |
2134 | * enum ieee80211_roc_type - remain on channel type | ||
2135 | * | ||
2136 | * With the support for multi channel contexts and multi channel operations, | ||
2137 | * remain on channel operations might be limited/deferred/aborted by other | ||
2138 | * flows/operations which have higher priority (and vise versa). | ||
2139 | * Specifying the ROC type can be used by devices to prioritize the ROC | ||
2140 | * operations compared to other operations/flows. | ||
2141 | * | ||
2142 | * @IEEE80211_ROC_TYPE_NORMAL: There are no special requirements for this ROC. | ||
2143 | * @IEEE80211_ROC_TYPE_MGMT_TX: The remain on channel request is required | ||
2144 | * for sending managment frames offchannel. | ||
2145 | */ | ||
2146 | enum ieee80211_roc_type { | ||
2147 | IEEE80211_ROC_TYPE_NORMAL = 0, | ||
2148 | IEEE80211_ROC_TYPE_MGMT_TX, | ||
2149 | }; | ||
2150 | |||
2151 | /** | ||
2138 | * struct ieee80211_ops - callbacks from mac80211 to the driver | 2152 | * struct ieee80211_ops - callbacks from mac80211 to the driver |
2139 | * | 2153 | * |
2140 | * This structure contains various callbacks that the driver may | 2154 | * This structure contains various callbacks that the driver may |
@@ -2687,7 +2701,8 @@ struct ieee80211_ops { | |||
2687 | int (*remain_on_channel)(struct ieee80211_hw *hw, | 2701 | int (*remain_on_channel)(struct ieee80211_hw *hw, |
2688 | struct ieee80211_vif *vif, | 2702 | struct ieee80211_vif *vif, |
2689 | struct ieee80211_channel *chan, | 2703 | struct ieee80211_channel *chan, |
2690 | int duration); | 2704 | int duration, |
2705 | enum ieee80211_roc_type type); | ||
2691 | int (*cancel_remain_on_channel)(struct ieee80211_hw *hw); | 2706 | int (*cancel_remain_on_channel)(struct ieee80211_hw *hw); |
2692 | int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx); | 2707 | int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx); |
2693 | void (*get_ringparam)(struct ieee80211_hw *hw, | 2708 | void (*get_ringparam)(struct ieee80211_hw *hw, |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c46bb016f4e4..79da8710448e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -36,7 +36,21 @@ | |||
36 | * The station is still assumed to belong to the AP interface it was added | 36 | * The station is still assumed to belong to the AP interface it was added |
37 | * to. | 37 | * to. |
38 | * | 38 | * |
39 | * TODO: need more info? | 39 | * Station handling varies per interface type and depending on the driver's |
40 | * capabilities. | ||
41 | * | ||
42 | * For drivers supporting TDLS with external setup (WIPHY_FLAG_SUPPORTS_TDLS | ||
43 | * and WIPHY_FLAG_TDLS_EXTERNAL_SETUP), the station lifetime is as follows: | ||
44 | * - a setup station entry is added, not yet authorized, without any rate | ||
45 | * or capability information, this just exists to avoid race conditions | ||
46 | * - when the TDLS setup is done, a single NL80211_CMD_SET_STATION is valid | ||
47 | * to add rate and capability information to the station and at the same | ||
48 | * time mark it authorized. | ||
49 | * - %NL80211_TDLS_ENABLE_LINK is then used | ||
50 | * - after this, the only valid operation is to remove it by tearing down | ||
51 | * the TDLS link (%NL80211_TDLS_DISABLE_LINK) | ||
52 | * | ||
53 | * TODO: need more info for other interface types | ||
40 | */ | 54 | */ |
41 | 55 | ||
42 | /** | 56 | /** |
@@ -499,9 +513,11 @@ | |||
499 | * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a | 513 | * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a |
500 | * beacon or probe response from a compatible mesh peer. This is only | 514 | * beacon or probe response from a compatible mesh peer. This is only |
501 | * sent while no station information (sta_info) exists for the new peer | 515 | * sent while no station information (sta_info) exists for the new peer |
502 | * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On | 516 | * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH, |
503 | * reception of this notification, userspace may decide to create a new | 517 | * @NL80211_MESH_SETUP_USERSPACE_AMPE, or |
504 | * station (@NL80211_CMD_NEW_STATION). To stop this notification from | 518 | * @NL80211_MESH_SETUP_USERSPACE_MPM is set. On reception of this |
519 | * notification, userspace may decide to create a new station | ||
520 | * (@NL80211_CMD_NEW_STATION). To stop this notification from | ||
505 | * reoccurring, the userspace authentication daemon may want to create the | 521 | * reoccurring, the userspace authentication daemon may want to create the |
506 | * new station with the AUTHENTICATED flag unset and maybe change it later | 522 | * new station with the AUTHENTICATED flag unset and maybe change it later |
507 | * depending on the authentication result. | 523 | * depending on the authentication result. |
@@ -611,6 +627,18 @@ | |||
611 | * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the | 627 | * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the |
612 | * event. | 628 | * event. |
613 | * | 629 | * |
630 | * @NL80211_CMD_GET_PROTOCOL_FEATURES: Get global nl80211 protocol features, | ||
631 | * i.e. features for the nl80211 protocol rather than device features. | ||
632 | * Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap. | ||
633 | * | ||
634 | * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition | ||
635 | * Information Element to the WLAN driver | ||
636 | * | ||
637 | * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver | ||
638 | * to the supplicant. This will carry the target AP's MAC address along | ||
639 | * with the relevant Information Elements. This event is used to report | ||
640 | * received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE). | ||
641 | * | ||
614 | * @NL80211_CMD_MAX: highest used command number | 642 | * @NL80211_CMD_MAX: highest used command number |
615 | * @__NL80211_CMD_AFTER_LAST: internal use | 643 | * @__NL80211_CMD_AFTER_LAST: internal use |
616 | */ | 644 | */ |
@@ -765,6 +793,11 @@ enum nl80211_commands { | |||
765 | 793 | ||
766 | NL80211_CMD_RADAR_DETECT, | 794 | NL80211_CMD_RADAR_DETECT, |
767 | 795 | ||
796 | NL80211_CMD_GET_PROTOCOL_FEATURES, | ||
797 | |||
798 | NL80211_CMD_UPDATE_FT_IES, | ||
799 | NL80211_CMD_FT_EVENT, | ||
800 | |||
768 | /* add new commands above here */ | 801 | /* add new commands above here */ |
769 | 802 | ||
770 | /* used to define NL80211_CMD_MAX below */ | 803 | /* used to define NL80211_CMD_MAX below */ |
@@ -884,7 +917,8 @@ enum nl80211_commands { | |||
884 | * consisting of a nested array. | 917 | * consisting of a nested array. |
885 | * | 918 | * |
886 | * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). | 919 | * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). |
887 | * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link. | 920 | * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link |
921 | * (see &enum nl80211_plink_action). | ||
888 | * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. | 922 | * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. |
889 | * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path | 923 | * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path |
890 | * info given for %NL80211_CMD_GET_MPATH, nested attribute described at | 924 | * info given for %NL80211_CMD_GET_MPATH, nested attribute described at |
@@ -1167,10 +1201,10 @@ enum nl80211_commands { | |||
1167 | * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver | 1201 | * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver |
1168 | * allows auth frames in a mesh to be passed to userspace for processing via | 1202 | * allows auth frames in a mesh to be passed to userspace for processing via |
1169 | * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. | 1203 | * the @NL80211_MESH_SETUP_USERSPACE_AUTH flag. |
1170 | * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as | 1204 | * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as defined in |
1171 | * defined in &enum nl80211_plink_state. Used when userspace is | 1205 | * &enum nl80211_plink_state. Used when userspace is driving the peer link |
1172 | * driving the peer link management state machine. | 1206 | * management state machine. @NL80211_MESH_SETUP_USERSPACE_AMPE or |
1173 | * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled. | 1207 | * @NL80211_MESH_SETUP_USERSPACE_MPM must be enabled. |
1174 | * | 1208 | * |
1175 | * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy | 1209 | * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy |
1176 | * capabilities, the supported WoWLAN triggers | 1210 | * capabilities, the supported WoWLAN triggers |
@@ -1368,6 +1402,18 @@ enum nl80211_commands { | |||
1368 | * advertised to the driver, e.g., to enable TDLS off channel operations | 1402 | * advertised to the driver, e.g., to enable TDLS off channel operations |
1369 | * and PU-APSD. | 1403 | * and PU-APSD. |
1370 | * | 1404 | * |
1405 | * @NL80211_ATTR_PROTOCOL_FEATURES: global nl80211 feature flags, see | ||
1406 | * &enum nl80211_protocol_features, the attribute is a u32. | ||
1407 | * | ||
1408 | * @NL80211_ATTR_SPLIT_WIPHY_DUMP: flag attribute, userspace supports | ||
1409 | * receiving the data for a single wiphy split across multiple | ||
1410 | * messages, given with wiphy dump message | ||
1411 | * | ||
1412 | * @NL80211_ATTR_MDID: Mobility Domain Identifier | ||
1413 | * | ||
1414 | * @NL80211_ATTR_IE_RIC: Resource Information Container Information | ||
1415 | * Element | ||
1416 | * | ||
1371 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1417 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1372 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1418 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1373 | */ | 1419 | */ |
@@ -1654,6 +1700,15 @@ enum nl80211_attrs { | |||
1654 | NL80211_ATTR_STA_CAPABILITY, | 1700 | NL80211_ATTR_STA_CAPABILITY, |
1655 | NL80211_ATTR_STA_EXT_CAPABILITY, | 1701 | NL80211_ATTR_STA_EXT_CAPABILITY, |
1656 | 1702 | ||
1703 | NL80211_ATTR_PROTOCOL_FEATURES, | ||
1704 | NL80211_ATTR_SPLIT_WIPHY_DUMP, | ||
1705 | |||
1706 | NL80211_ATTR_DISABLE_VHT, | ||
1707 | NL80211_ATTR_VHT_CAPABILITY_MASK, | ||
1708 | |||
1709 | NL80211_ATTR_MDID, | ||
1710 | NL80211_ATTR_IE_RIC, | ||
1711 | |||
1657 | /* add attributes here, update the policy in nl80211.c */ | 1712 | /* add attributes here, update the policy in nl80211.c */ |
1658 | 1713 | ||
1659 | __NL80211_ATTR_AFTER_LAST, | 1714 | __NL80211_ATTR_AFTER_LAST, |
@@ -2412,8 +2467,10 @@ enum nl80211_mesh_power_mode { | |||
2412 | * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh | 2467 | * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh |
2413 | * point. | 2468 | * point. |
2414 | * | 2469 | * |
2415 | * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically | 2470 | * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically open |
2416 | * open peer links when we detect compatible mesh peers. | 2471 | * peer links when we detect compatible mesh peers. Disabled if |
2472 | * @NL80211_MESH_SETUP_USERSPACE_MPM or @NL80211_MESH_SETUP_USERSPACE_AMPE are | ||
2473 | * set. | ||
2417 | * | 2474 | * |
2418 | * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames | 2475 | * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames |
2419 | * containing a PREQ that an MP can send to a particular destination (path | 2476 | * containing a PREQ that an MP can send to a particular destination (path |
@@ -2559,6 +2616,9 @@ enum nl80211_meshconf_params { | |||
2559 | * vendor specific synchronization method or disable it to use the default | 2616 | * vendor specific synchronization method or disable it to use the default |
2560 | * neighbor offset synchronization | 2617 | * neighbor offset synchronization |
2561 | * | 2618 | * |
2619 | * @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will | ||
2620 | * implement an MPM which handles peer allocation and state. | ||
2621 | * | ||
2562 | * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number | 2622 | * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number |
2563 | * | 2623 | * |
2564 | * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use | 2624 | * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use |
@@ -2571,6 +2631,7 @@ enum nl80211_mesh_setup_params { | |||
2571 | NL80211_MESH_SETUP_USERSPACE_AUTH, | 2631 | NL80211_MESH_SETUP_USERSPACE_AUTH, |
2572 | NL80211_MESH_SETUP_USERSPACE_AMPE, | 2632 | NL80211_MESH_SETUP_USERSPACE_AMPE, |
2573 | NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, | 2633 | NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, |
2634 | NL80211_MESH_SETUP_USERSPACE_MPM, | ||
2574 | 2635 | ||
2575 | /* keep last */ | 2636 | /* keep last */ |
2576 | __NL80211_MESH_SETUP_ATTR_AFTER_LAST, | 2637 | __NL80211_MESH_SETUP_ATTR_AFTER_LAST, |
@@ -3307,6 +3368,23 @@ enum nl80211_plink_state { | |||
3307 | MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 | 3368 | MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 |
3308 | }; | 3369 | }; |
3309 | 3370 | ||
3371 | /** | ||
3372 | * enum nl80211_plink_action - actions to perform in mesh peers | ||
3373 | * | ||
3374 | * @NL80211_PLINK_ACTION_NO_ACTION: perform no action | ||
3375 | * @NL80211_PLINK_ACTION_OPEN: start mesh peer link establishment | ||
3376 | * @NL80211_PLINK_ACTION_BLOCK: block traffic from this mesh peer | ||
3377 | * @NUM_NL80211_PLINK_ACTIONS: number of possible actions | ||
3378 | */ | ||
3379 | enum plink_actions { | ||
3380 | NL80211_PLINK_ACTION_NO_ACTION, | ||
3381 | NL80211_PLINK_ACTION_OPEN, | ||
3382 | NL80211_PLINK_ACTION_BLOCK, | ||
3383 | |||
3384 | NUM_NL80211_PLINK_ACTIONS, | ||
3385 | }; | ||
3386 | |||
3387 | |||
3310 | #define NL80211_KCK_LEN 16 | 3388 | #define NL80211_KCK_LEN 16 |
3311 | #define NL80211_KEK_LEN 16 | 3389 | #define NL80211_KEK_LEN 16 |
3312 | #define NL80211_REPLAY_CTR_LEN 8 | 3390 | #define NL80211_REPLAY_CTR_LEN 8 |
@@ -3456,6 +3534,10 @@ enum nl80211_ap_sme_features { | |||
3456 | * stations the authenticated/associated bits have to be set in the mask. | 3534 | * stations the authenticated/associated bits have to be set in the mask. |
3457 | * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits | 3535 | * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits |
3458 | * (HT40, VHT 80/160 MHz) if this flag is set | 3536 | * (HT40, VHT 80/160 MHz) if this flag is set |
3537 | * @NL80211_FEATURE_USERSPACE_MPM: This driver supports a userspace Mesh | ||
3538 | * Peering Management entity which may be implemented by registering for | ||
3539 | * beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is | ||
3540 | * still generated by the driver. | ||
3459 | */ | 3541 | */ |
3460 | enum nl80211_feature_flags { | 3542 | enum nl80211_feature_flags { |
3461 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, | 3543 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, |
@@ -3474,6 +3556,7 @@ enum nl80211_feature_flags { | |||
3474 | /* bit 13 is reserved */ | 3556 | /* bit 13 is reserved */ |
3475 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, | 3557 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, |
3476 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, | 3558 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, |
3559 | NL80211_FEATURE_USERSPACE_MPM = 1 << 16, | ||
3477 | }; | 3560 | }; |
3478 | 3561 | ||
3479 | /** | 3562 | /** |
@@ -3587,4 +3670,16 @@ enum nl80211_dfs_state { | |||
3587 | NL80211_DFS_AVAILABLE, | 3670 | NL80211_DFS_AVAILABLE, |
3588 | }; | 3671 | }; |
3589 | 3672 | ||
3673 | /** | ||
3674 | * enum enum nl80211_protocol_features - nl80211 protocol features | ||
3675 | * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting | ||
3676 | * wiphy dumps (if requested by the application with the attribute | ||
3677 | * %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the | ||
3678 | * wiphy dump by %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFINDEX or | ||
3679 | * %NL80211_ATTR_WDEV. | ||
3680 | */ | ||
3681 | enum nl80211_protocol_features { | ||
3682 | NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0, | ||
3683 | }; | ||
3684 | |||
3590 | #endif /* __LINUX_NL80211_H */ | 3685 | #endif /* __LINUX_NL80211_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 09d96a8f6c2c..1d1ddabd89ca 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -254,7 +254,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
254 | goto out_unlock; | 254 | goto out_unlock; |
255 | } | 255 | } |
256 | 256 | ||
257 | __ieee80211_key_free(key); | 257 | __ieee80211_key_free(key, true); |
258 | 258 | ||
259 | ret = 0; | 259 | ret = 0; |
260 | out_unlock: | 260 | out_unlock: |
@@ -1035,9 +1035,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1035 | sta_info_flush_defer(vlan); | 1035 | sta_info_flush_defer(vlan); |
1036 | sta_info_flush_defer(sdata); | 1036 | sta_info_flush_defer(sdata); |
1037 | rcu_barrier(); | 1037 | rcu_barrier(); |
1038 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1038 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { |
1039 | sta_info_flush_cleanup(vlan); | 1039 | sta_info_flush_cleanup(vlan); |
1040 | ieee80211_free_keys(vlan); | ||
1041 | } | ||
1040 | sta_info_flush_cleanup(sdata); | 1042 | sta_info_flush_cleanup(sdata); |
1043 | ieee80211_free_keys(sdata); | ||
1041 | 1044 | ||
1042 | sdata->vif.bss_conf.enable_beacon = false; | 1045 | sdata->vif.bss_conf.enable_beacon = false; |
1043 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 1046 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
@@ -1177,6 +1180,18 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1177 | mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); | 1180 | mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); |
1178 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) | 1181 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) |
1179 | set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | 1182 | set |= BIT(NL80211_STA_FLAG_ASSOCIATED); |
1183 | } else if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
1184 | /* | ||
1185 | * TDLS -- everything follows authorized, but | ||
1186 | * only becoming authorized is possible, not | ||
1187 | * going back | ||
1188 | */ | ||
1189 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) { | ||
1190 | set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
1191 | BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
1192 | mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
1193 | BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
1194 | } | ||
1180 | } | 1195 | } |
1181 | 1196 | ||
1182 | ret = sta_apply_auth_flags(local, sta, mask, set); | 1197 | ret = sta_apply_auth_flags(local, sta, mask, set); |
@@ -1261,7 +1276,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1261 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 1276 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
1262 | #ifdef CONFIG_MAC80211_MESH | 1277 | #ifdef CONFIG_MAC80211_MESH |
1263 | u32 changed = 0; | 1278 | u32 changed = 0; |
1264 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) { | 1279 | |
1280 | if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) { | ||
1265 | switch (params->plink_state) { | 1281 | switch (params->plink_state) { |
1266 | case NL80211_PLINK_ESTAB: | 1282 | case NL80211_PLINK_ESTAB: |
1267 | if (sta->plink_state != NL80211_PLINK_ESTAB) | 1283 | if (sta->plink_state != NL80211_PLINK_ESTAB) |
@@ -1292,15 +1308,18 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1292 | /* nothing */ | 1308 | /* nothing */ |
1293 | break; | 1309 | break; |
1294 | } | 1310 | } |
1295 | } else { | 1311 | } |
1296 | switch (params->plink_action) { | 1312 | |
1297 | case PLINK_ACTION_OPEN: | 1313 | switch (params->plink_action) { |
1298 | changed |= mesh_plink_open(sta); | 1314 | case NL80211_PLINK_ACTION_NO_ACTION: |
1299 | break; | 1315 | /* nothing */ |
1300 | case PLINK_ACTION_BLOCK: | 1316 | break; |
1301 | changed |= mesh_plink_block(sta); | 1317 | case NL80211_PLINK_ACTION_OPEN: |
1302 | break; | 1318 | changed |= mesh_plink_open(sta); |
1303 | } | 1319 | break; |
1320 | case NL80211_PLINK_ACTION_BLOCK: | ||
1321 | changed |= mesh_plink_block(sta); | ||
1322 | break; | ||
1304 | } | 1323 | } |
1305 | 1324 | ||
1306 | if (params->local_pm) | 1325 | if (params->local_pm) |
@@ -1346,8 +1365,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
1346 | * defaults -- if userspace wants something else we'll | 1365 | * defaults -- if userspace wants something else we'll |
1347 | * change it accordingly in sta_apply_parameters() | 1366 | * change it accordingly in sta_apply_parameters() |
1348 | */ | 1367 | */ |
1349 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | 1368 | if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) { |
1350 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | 1369 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); |
1370 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | ||
1371 | } | ||
1351 | 1372 | ||
1352 | err = sta_apply_parameters(local, sta, params); | 1373 | err = sta_apply_parameters(local, sta, params); |
1353 | if (err) { | 1374 | if (err) { |
@@ -1356,8 +1377,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
1356 | } | 1377 | } |
1357 | 1378 | ||
1358 | /* | 1379 | /* |
1359 | * for TDLS, rate control should be initialized only when supported | 1380 | * for TDLS, rate control should be initialized only when |
1360 | * rates are known. | 1381 | * rates are known and station is marked authorized |
1361 | */ | 1382 | */ |
1362 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | 1383 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) |
1363 | rate_control_rate_init(sta); | 1384 | rate_control_rate_init(sta); |
@@ -1394,50 +1415,67 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
1394 | } | 1415 | } |
1395 | 1416 | ||
1396 | static int ieee80211_change_station(struct wiphy *wiphy, | 1417 | static int ieee80211_change_station(struct wiphy *wiphy, |
1397 | struct net_device *dev, | 1418 | struct net_device *dev, u8 *mac, |
1398 | u8 *mac, | ||
1399 | struct station_parameters *params) | 1419 | struct station_parameters *params) |
1400 | { | 1420 | { |
1401 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1421 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1402 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1422 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1403 | struct sta_info *sta; | 1423 | struct sta_info *sta; |
1404 | struct ieee80211_sub_if_data *vlansdata; | 1424 | struct ieee80211_sub_if_data *vlansdata; |
1425 | enum cfg80211_station_type statype; | ||
1405 | int err; | 1426 | int err; |
1406 | 1427 | ||
1407 | mutex_lock(&local->sta_mtx); | 1428 | mutex_lock(&local->sta_mtx); |
1408 | 1429 | ||
1409 | sta = sta_info_get_bss(sdata, mac); | 1430 | sta = sta_info_get_bss(sdata, mac); |
1410 | if (!sta) { | 1431 | if (!sta) { |
1411 | mutex_unlock(&local->sta_mtx); | 1432 | err = -ENOENT; |
1412 | return -ENOENT; | 1433 | goto out_err; |
1413 | } | 1434 | } |
1414 | 1435 | ||
1415 | /* in station mode, some updates are only valid with TDLS */ | 1436 | switch (sdata->vif.type) { |
1416 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1437 | case NL80211_IFTYPE_MESH_POINT: |
1417 | (params->supported_rates || params->ht_capa || params->vht_capa || | 1438 | if (sdata->u.mesh.user_mpm) |
1418 | params->sta_modify_mask || | 1439 | statype = CFG80211_STA_MESH_PEER_USER; |
1419 | (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) && | 1440 | else |
1420 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | 1441 | statype = CFG80211_STA_MESH_PEER_KERNEL; |
1421 | mutex_unlock(&local->sta_mtx); | 1442 | break; |
1422 | return -EINVAL; | 1443 | case NL80211_IFTYPE_ADHOC: |
1444 | statype = CFG80211_STA_IBSS; | ||
1445 | break; | ||
1446 | case NL80211_IFTYPE_STATION: | ||
1447 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
1448 | statype = CFG80211_STA_AP_STA; | ||
1449 | break; | ||
1450 | } | ||
1451 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1452 | statype = CFG80211_STA_TDLS_PEER_ACTIVE; | ||
1453 | else | ||
1454 | statype = CFG80211_STA_TDLS_PEER_SETUP; | ||
1455 | break; | ||
1456 | case NL80211_IFTYPE_AP: | ||
1457 | case NL80211_IFTYPE_AP_VLAN: | ||
1458 | statype = CFG80211_STA_AP_CLIENT; | ||
1459 | break; | ||
1460 | default: | ||
1461 | err = -EOPNOTSUPP; | ||
1462 | goto out_err; | ||
1423 | } | 1463 | } |
1424 | 1464 | ||
1465 | err = cfg80211_check_station_change(wiphy, params, statype); | ||
1466 | if (err) | ||
1467 | goto out_err; | ||
1468 | |||
1425 | if (params->vlan && params->vlan != sta->sdata->dev) { | 1469 | if (params->vlan && params->vlan != sta->sdata->dev) { |
1426 | bool prev_4addr = false; | 1470 | bool prev_4addr = false; |
1427 | bool new_4addr = false; | 1471 | bool new_4addr = false; |
1428 | 1472 | ||
1429 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 1473 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
1430 | 1474 | ||
1431 | if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||
1432 | vlansdata->vif.type != NL80211_IFTYPE_AP) { | ||
1433 | mutex_unlock(&local->sta_mtx); | ||
1434 | return -EINVAL; | ||
1435 | } | ||
1436 | |||
1437 | if (params->vlan->ieee80211_ptr->use_4addr) { | 1475 | if (params->vlan->ieee80211_ptr->use_4addr) { |
1438 | if (vlansdata->u.vlan.sta) { | 1476 | if (vlansdata->u.vlan.sta) { |
1439 | mutex_unlock(&local->sta_mtx); | 1477 | err = -EBUSY; |
1440 | return -EBUSY; | 1478 | goto out_err; |
1441 | } | 1479 | } |
1442 | 1480 | ||
1443 | rcu_assign_pointer(vlansdata->u.vlan.sta, sta); | 1481 | rcu_assign_pointer(vlansdata->u.vlan.sta, sta); |
@@ -1464,12 +1502,12 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
1464 | } | 1502 | } |
1465 | 1503 | ||
1466 | err = sta_apply_parameters(local, sta, params); | 1504 | err = sta_apply_parameters(local, sta, params); |
1467 | if (err) { | 1505 | if (err) |
1468 | mutex_unlock(&local->sta_mtx); | 1506 | goto out_err; |
1469 | return err; | ||
1470 | } | ||
1471 | 1507 | ||
1472 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates) | 1508 | /* When peer becomes authorized, init rate control as well */ |
1509 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && | ||
1510 | test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1473 | rate_control_rate_init(sta); | 1511 | rate_control_rate_init(sta); |
1474 | 1512 | ||
1475 | mutex_unlock(&local->sta_mtx); | 1513 | mutex_unlock(&local->sta_mtx); |
@@ -1479,7 +1517,11 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
1479 | ieee80211_recalc_ps(local, -1); | 1517 | ieee80211_recalc_ps(local, -1); |
1480 | ieee80211_recalc_ps_vif(sdata); | 1518 | ieee80211_recalc_ps_vif(sdata); |
1481 | } | 1519 | } |
1520 | |||
1482 | return 0; | 1521 | return 0; |
1522 | out_err: | ||
1523 | mutex_unlock(&local->sta_mtx); | ||
1524 | return err; | ||
1483 | } | 1525 | } |
1484 | 1526 | ||
1485 | #ifdef CONFIG_MAC80211_MESH | 1527 | #ifdef CONFIG_MAC80211_MESH |
@@ -1687,6 +1729,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1687 | ifmsh->mesh_sp_id = setup->sync_method; | 1729 | ifmsh->mesh_sp_id = setup->sync_method; |
1688 | ifmsh->mesh_pp_id = setup->path_sel_proto; | 1730 | ifmsh->mesh_pp_id = setup->path_sel_proto; |
1689 | ifmsh->mesh_pm_id = setup->path_metric; | 1731 | ifmsh->mesh_pm_id = setup->path_metric; |
1732 | ifmsh->user_mpm = setup->user_mpm; | ||
1690 | ifmsh->security = IEEE80211_MESH_SEC_NONE; | 1733 | ifmsh->security = IEEE80211_MESH_SEC_NONE; |
1691 | if (setup->is_authenticated) | 1734 | if (setup->is_authenticated) |
1692 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; | 1735 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; |
@@ -1730,8 +1773,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1730 | conf->dot11MeshTTL = nconf->dot11MeshTTL; | 1773 | conf->dot11MeshTTL = nconf->dot11MeshTTL; |
1731 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) | 1774 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) |
1732 | conf->element_ttl = nconf->element_ttl; | 1775 | conf->element_ttl = nconf->element_ttl; |
1733 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | 1776 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) { |
1777 | if (ifmsh->user_mpm) | ||
1778 | return -EBUSY; | ||
1734 | conf->auto_open_plinks = nconf->auto_open_plinks; | 1779 | conf->auto_open_plinks = nconf->auto_open_plinks; |
1780 | } | ||
1735 | if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) | 1781 | if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) |
1736 | conf->dot11MeshNbrOffsetMaxNeighbor = | 1782 | conf->dot11MeshNbrOffsetMaxNeighbor = |
1737 | nconf->dot11MeshNbrOffsetMaxNeighbor; | 1783 | nconf->dot11MeshNbrOffsetMaxNeighbor; |
@@ -2371,7 +2417,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2371 | struct ieee80211_sub_if_data *sdata, | 2417 | struct ieee80211_sub_if_data *sdata, |
2372 | struct ieee80211_channel *channel, | 2418 | struct ieee80211_channel *channel, |
2373 | unsigned int duration, u64 *cookie, | 2419 | unsigned int duration, u64 *cookie, |
2374 | struct sk_buff *txskb) | 2420 | struct sk_buff *txskb, |
2421 | enum ieee80211_roc_type type) | ||
2375 | { | 2422 | { |
2376 | struct ieee80211_roc_work *roc, *tmp; | 2423 | struct ieee80211_roc_work *roc, *tmp; |
2377 | bool queued = false; | 2424 | bool queued = false; |
@@ -2390,6 +2437,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2390 | roc->duration = duration; | 2437 | roc->duration = duration; |
2391 | roc->req_duration = duration; | 2438 | roc->req_duration = duration; |
2392 | roc->frame = txskb; | 2439 | roc->frame = txskb; |
2440 | roc->type = type; | ||
2393 | roc->mgmt_tx_cookie = (unsigned long)txskb; | 2441 | roc->mgmt_tx_cookie = (unsigned long)txskb; |
2394 | roc->sdata = sdata; | 2442 | roc->sdata = sdata; |
2395 | INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); | 2443 | INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); |
@@ -2420,7 +2468,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2420 | if (!duration) | 2468 | if (!duration) |
2421 | duration = 10; | 2469 | duration = 10; |
2422 | 2470 | ||
2423 | ret = drv_remain_on_channel(local, sdata, channel, duration); | 2471 | ret = drv_remain_on_channel(local, sdata, channel, duration, type); |
2424 | if (ret) { | 2472 | if (ret) { |
2425 | kfree(roc); | 2473 | kfree(roc); |
2426 | return ret; | 2474 | return ret; |
@@ -2439,10 +2487,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2439 | * | 2487 | * |
2440 | * If it hasn't started yet, just increase the duration | 2488 | * If it hasn't started yet, just increase the duration |
2441 | * and add the new one to the list of dependents. | 2489 | * and add the new one to the list of dependents. |
2490 | * If the type of the new ROC has higher priority, modify the | ||
2491 | * type of the previous one to match that of the new one. | ||
2442 | */ | 2492 | */ |
2443 | if (!tmp->started) { | 2493 | if (!tmp->started) { |
2444 | list_add_tail(&roc->list, &tmp->dependents); | 2494 | list_add_tail(&roc->list, &tmp->dependents); |
2445 | tmp->duration = max(tmp->duration, roc->duration); | 2495 | tmp->duration = max(tmp->duration, roc->duration); |
2496 | tmp->type = max(tmp->type, roc->type); | ||
2446 | queued = true; | 2497 | queued = true; |
2447 | break; | 2498 | break; |
2448 | } | 2499 | } |
@@ -2454,16 +2505,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2454 | /* | 2505 | /* |
2455 | * In the offloaded ROC case, if it hasn't begun, add | 2506 | * In the offloaded ROC case, if it hasn't begun, add |
2456 | * this new one to the dependent list to be handled | 2507 | * this new one to the dependent list to be handled |
2457 | * when the the master one begins. If it has begun, | 2508 | * when the master one begins. If it has begun, |
2458 | * check that there's still a minimum time left and | 2509 | * check that there's still a minimum time left and |
2459 | * if so, start this one, transmitting the frame, but | 2510 | * if so, start this one, transmitting the frame, but |
2460 | * add it to the list directly after this one with a | 2511 | * add it to the list directly after this one with |
2461 | * a reduced time so we'll ask the driver to execute | 2512 | * a reduced time so we'll ask the driver to execute |
2462 | * it right after finishing the previous one, in the | 2513 | * it right after finishing the previous one, in the |
2463 | * hope that it'll also be executed right afterwards, | 2514 | * hope that it'll also be executed right afterwards, |
2464 | * effectively extending the old one. | 2515 | * effectively extending the old one. |
2465 | * If there's no minimum time left, just add it to the | 2516 | * If there's no minimum time left, just add it to the |
2466 | * normal list. | 2517 | * normal list. |
2518 | * TODO: the ROC type is ignored here, assuming that it | ||
2519 | * is better to immediately use the current ROC. | ||
2467 | */ | 2520 | */ |
2468 | if (!tmp->hw_begun) { | 2521 | if (!tmp->hw_begun) { |
2469 | list_add_tail(&roc->list, &tmp->dependents); | 2522 | list_add_tail(&roc->list, &tmp->dependents); |
@@ -2557,7 +2610,8 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy, | |||
2557 | 2610 | ||
2558 | mutex_lock(&local->mtx); | 2611 | mutex_lock(&local->mtx); |
2559 | ret = ieee80211_start_roc_work(local, sdata, chan, | 2612 | ret = ieee80211_start_roc_work(local, sdata, chan, |
2560 | duration, cookie, NULL); | 2613 | duration, cookie, NULL, |
2614 | IEEE80211_ROC_TYPE_NORMAL); | ||
2561 | mutex_unlock(&local->mtx); | 2615 | mutex_unlock(&local->mtx); |
2562 | 2616 | ||
2563 | return ret; | 2617 | return ret; |
@@ -2790,7 +2844,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
2790 | 2844 | ||
2791 | /* This will handle all kinds of coalescing and immediate TX */ | 2845 | /* This will handle all kinds of coalescing and immediate TX */ |
2792 | ret = ieee80211_start_roc_work(local, sdata, chan, | 2846 | ret = ieee80211_start_roc_work(local, sdata, chan, |
2793 | wait, cookie, skb); | 2847 | wait, cookie, skb, |
2848 | IEEE80211_ROC_TYPE_MGMT_TX); | ||
2794 | if (ret) | 2849 | if (ret) |
2795 | kfree_skb(skb); | 2850 | kfree_skb(skb); |
2796 | out_unlock: | 2851 | out_unlock: |
@@ -3285,6 +3340,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, | |||
3285 | struct cfg80211_chan_def *chandef) | 3340 | struct cfg80211_chan_def *chandef) |
3286 | { | 3341 | { |
3287 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 3342 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
3343 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
3288 | struct ieee80211_chanctx_conf *chanctx_conf; | 3344 | struct ieee80211_chanctx_conf *chanctx_conf; |
3289 | int ret = -ENODATA; | 3345 | int ret = -ENODATA; |
3290 | 3346 | ||
@@ -3293,6 +3349,16 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy, | |||
3293 | if (chanctx_conf) { | 3349 | if (chanctx_conf) { |
3294 | *chandef = chanctx_conf->def; | 3350 | *chandef = chanctx_conf->def; |
3295 | ret = 0; | 3351 | ret = 0; |
3352 | } else if (local->open_count > 0 && | ||
3353 | local->open_count == local->monitors && | ||
3354 | sdata->vif.type == NL80211_IFTYPE_MONITOR) { | ||
3355 | if (local->use_chanctx) | ||
3356 | *chandef = local->monitor_chandef; | ||
3357 | else | ||
3358 | cfg80211_chandef_create(chandef, | ||
3359 | local->_oper_channel, | ||
3360 | local->_oper_channel_type); | ||
3361 | ret = 0; | ||
3296 | } | 3362 | } |
3297 | rcu_read_unlock(); | 3363 | rcu_read_unlock(); |
3298 | 3364 | ||
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index c7591f73dbc3..4f841fe559df 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -325,6 +325,36 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, | |||
325 | } | 325 | } |
326 | STA_OPS(ht_capa); | 326 | STA_OPS(ht_capa); |
327 | 327 | ||
328 | static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf, | ||
329 | size_t count, loff_t *ppos) | ||
330 | { | ||
331 | char buf[128], *p = buf; | ||
332 | struct sta_info *sta = file->private_data; | ||
333 | struct ieee80211_sta_vht_cap *vhtc = &sta->sta.vht_cap; | ||
334 | |||
335 | p += scnprintf(p, sizeof(buf) + buf - p, "VHT %ssupported\n", | ||
336 | vhtc->vht_supported ? "" : "not "); | ||
337 | if (vhtc->vht_supported) { | ||
338 | p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.8x\n", vhtc->cap); | ||
339 | |||
340 | p += scnprintf(p, sizeof(buf)+buf-p, "RX MCS: %.4x\n", | ||
341 | le16_to_cpu(vhtc->vht_mcs.rx_mcs_map)); | ||
342 | if (vhtc->vht_mcs.rx_highest) | ||
343 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
344 | "MCS RX highest: %d Mbps\n", | ||
345 | le16_to_cpu(vhtc->vht_mcs.rx_highest)); | ||
346 | p += scnprintf(p, sizeof(buf)+buf-p, "TX MCS: %.4x\n", | ||
347 | le16_to_cpu(vhtc->vht_mcs.tx_mcs_map)); | ||
348 | if (vhtc->vht_mcs.tx_highest) | ||
349 | p += scnprintf(p, sizeof(buf)+buf-p, | ||
350 | "MCS TX highest: %d Mbps\n", | ||
351 | le16_to_cpu(vhtc->vht_mcs.tx_highest)); | ||
352 | } | ||
353 | |||
354 | return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); | ||
355 | } | ||
356 | STA_OPS(vht_capa); | ||
357 | |||
328 | static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf, | 358 | static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf, |
329 | size_t count, loff_t *ppos) | 359 | size_t count, loff_t *ppos) |
330 | { | 360 | { |
@@ -405,6 +435,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
405 | DEBUGFS_ADD(dev); | 435 | DEBUGFS_ADD(dev); |
406 | DEBUGFS_ADD(last_signal); | 436 | DEBUGFS_ADD(last_signal); |
407 | DEBUGFS_ADD(ht_capa); | 437 | DEBUGFS_ADD(ht_capa); |
438 | DEBUGFS_ADD(vht_capa); | ||
408 | DEBUGFS_ADD(last_ack_signal); | 439 | DEBUGFS_ADD(last_ack_signal); |
409 | DEBUGFS_ADD(current_tx_rate); | 440 | DEBUGFS_ADD(current_tx_rate); |
410 | DEBUGFS_ADD(last_rx_rate); | 441 | DEBUGFS_ADD(last_rx_rate); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index ee56d0779d8b..832acea4a5cb 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -787,15 +787,16 @@ static inline int drv_get_antenna(struct ieee80211_local *local, | |||
787 | static inline int drv_remain_on_channel(struct ieee80211_local *local, | 787 | static inline int drv_remain_on_channel(struct ieee80211_local *local, |
788 | struct ieee80211_sub_if_data *sdata, | 788 | struct ieee80211_sub_if_data *sdata, |
789 | struct ieee80211_channel *chan, | 789 | struct ieee80211_channel *chan, |
790 | unsigned int duration) | 790 | unsigned int duration, |
791 | enum ieee80211_roc_type type) | ||
791 | { | 792 | { |
792 | int ret; | 793 | int ret; |
793 | 794 | ||
794 | might_sleep(); | 795 | might_sleep(); |
795 | 796 | ||
796 | trace_drv_remain_on_channel(local, sdata, chan, duration); | 797 | trace_drv_remain_on_channel(local, sdata, chan, duration, type); |
797 | ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, | 798 | ret = local->ops->remain_on_channel(&local->hw, &sdata->vif, |
798 | chan, duration); | 799 | chan, duration, type); |
799 | trace_drv_return_int(local, ret); | 800 | trace_drv_return_int(local, ret); |
800 | 801 | ||
801 | return ret; | 802 | return ret; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 0db25d4bb223..af8cee06e4f3 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -40,13 +40,6 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
40 | if (!ht_cap->ht_supported) | 40 | if (!ht_cap->ht_supported) |
41 | return; | 41 | return; |
42 | 42 | ||
43 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { | ||
44 | /* AP interfaces call this code when adding new stations, | ||
45 | * so just silently ignore non station interfaces. | ||
46 | */ | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | /* NOTE: If you add more over-rides here, update register_hw | 43 | /* NOTE: If you add more over-rides here, update register_hw |
51 | * ht_capa_mod_msk logic in main.c as well. | 44 | * ht_capa_mod_msk logic in main.c as well. |
52 | * And, if this method can ever change ht_cap.ht_supported, fix | 45 | * And, if this method can ever change ht_cap.ht_supported, fix |
@@ -97,7 +90,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
97 | const struct ieee80211_ht_cap *ht_cap_ie, | 90 | const struct ieee80211_ht_cap *ht_cap_ie, |
98 | struct sta_info *sta) | 91 | struct sta_info *sta) |
99 | { | 92 | { |
100 | struct ieee80211_sta_ht_cap ht_cap; | 93 | struct ieee80211_sta_ht_cap ht_cap, own_cap; |
101 | u8 ampdu_info, tx_mcs_set_cap; | 94 | u8 ampdu_info, tx_mcs_set_cap; |
102 | int i, max_tx_streams; | 95 | int i, max_tx_streams; |
103 | bool changed; | 96 | bool changed; |
@@ -111,6 +104,18 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
111 | 104 | ||
112 | ht_cap.ht_supported = true; | 105 | ht_cap.ht_supported = true; |
113 | 106 | ||
107 | own_cap = sband->ht_cap; | ||
108 | |||
109 | /* | ||
110 | * If user has specified capability over-rides, take care | ||
111 | * of that if the station we're setting up is the AP that | ||
112 | * we advertised a restricted capability set to. Override | ||
113 | * our own capabilities and then use those below. | ||
114 | */ | ||
115 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
116 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
117 | ieee80211_apply_htcap_overrides(sdata, &own_cap); | ||
118 | |||
114 | /* | 119 | /* |
115 | * The bits listed in this expression should be | 120 | * The bits listed in this expression should be |
116 | * the same for the peer and us, if the station | 121 | * the same for the peer and us, if the station |
@@ -118,21 +123,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
118 | * we mask them out. | 123 | * we mask them out. |
119 | */ | 124 | */ |
120 | ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) & | 125 | ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) & |
121 | (sband->ht_cap.cap | | 126 | (own_cap.cap | ~(IEEE80211_HT_CAP_LDPC_CODING | |
122 | ~(IEEE80211_HT_CAP_LDPC_CODING | | 127 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
123 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 128 | IEEE80211_HT_CAP_GRN_FLD | |
124 | IEEE80211_HT_CAP_GRN_FLD | | 129 | IEEE80211_HT_CAP_SGI_20 | |
125 | IEEE80211_HT_CAP_SGI_20 | | 130 | IEEE80211_HT_CAP_SGI_40 | |
126 | IEEE80211_HT_CAP_SGI_40 | | 131 | IEEE80211_HT_CAP_DSSSCCK40)); |
127 | IEEE80211_HT_CAP_DSSSCCK40)); | ||
128 | 132 | ||
129 | /* | 133 | /* |
130 | * The STBC bits are asymmetric -- if we don't have | 134 | * The STBC bits are asymmetric -- if we don't have |
131 | * TX then mask out the peer's RX and vice versa. | 135 | * TX then mask out the peer's RX and vice versa. |
132 | */ | 136 | */ |
133 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) | 137 | if (!(own_cap.cap & IEEE80211_HT_CAP_TX_STBC)) |
134 | ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC; | 138 | ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC; |
135 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) | 139 | if (!(own_cap.cap & IEEE80211_HT_CAP_RX_STBC)) |
136 | ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC; | 140 | ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC; |
137 | 141 | ||
138 | ampdu_info = ht_cap_ie->ampdu_params_info; | 142 | ampdu_info = ht_cap_ie->ampdu_params_info; |
@@ -142,7 +146,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
142 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; | 146 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; |
143 | 147 | ||
144 | /* own MCS TX capabilities */ | 148 | /* own MCS TX capabilities */ |
145 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | 149 | tx_mcs_set_cap = own_cap.mcs.tx_params; |
146 | 150 | ||
147 | /* Copy peer MCS TX capabilities, the driver might need them. */ | 151 | /* Copy peer MCS TX capabilities, the driver might need them. */ |
148 | ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params; | 152 | ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params; |
@@ -168,26 +172,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
168 | */ | 172 | */ |
169 | for (i = 0; i < max_tx_streams; i++) | 173 | for (i = 0; i < max_tx_streams; i++) |
170 | ht_cap.mcs.rx_mask[i] = | 174 | ht_cap.mcs.rx_mask[i] = |
171 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; | 175 | own_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; |
172 | 176 | ||
173 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) | 177 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) |
174 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; | 178 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; |
175 | i < IEEE80211_HT_MCS_MASK_LEN; i++) | 179 | i < IEEE80211_HT_MCS_MASK_LEN; i++) |
176 | ht_cap.mcs.rx_mask[i] = | 180 | ht_cap.mcs.rx_mask[i] = |
177 | sband->ht_cap.mcs.rx_mask[i] & | 181 | own_cap.mcs.rx_mask[i] & |
178 | ht_cap_ie->mcs.rx_mask[i]; | 182 | ht_cap_ie->mcs.rx_mask[i]; |
179 | 183 | ||
180 | /* handle MCS rate 32 too */ | 184 | /* handle MCS rate 32 too */ |
181 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 185 | if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
182 | ht_cap.mcs.rx_mask[32/8] |= 1; | 186 | ht_cap.mcs.rx_mask[32/8] |= 1; |
183 | 187 | ||
184 | apply: | 188 | apply: |
185 | /* | ||
186 | * If user has specified capability over-rides, take care | ||
187 | * of that here. | ||
188 | */ | ||
189 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
190 | |||
191 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | 189 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); |
192 | 190 | ||
193 | memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | 191 | memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 40b71dfcc79d..539d4a11b47b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -985,36 +985,9 @@ static void ieee80211_ibss_timer(unsigned long data) | |||
985 | { | 985 | { |
986 | struct ieee80211_sub_if_data *sdata = | 986 | struct ieee80211_sub_if_data *sdata = |
987 | (struct ieee80211_sub_if_data *) data; | 987 | (struct ieee80211_sub_if_data *) data; |
988 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
989 | struct ieee80211_local *local = sdata->local; | ||
990 | |||
991 | if (local->quiescing) { | ||
992 | ifibss->timer_running = true; | ||
993 | return; | ||
994 | } | ||
995 | |||
996 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
997 | } | ||
998 | |||
999 | #ifdef CONFIG_PM | ||
1000 | void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata) | ||
1001 | { | ||
1002 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
1003 | 988 | ||
1004 | if (del_timer_sync(&ifibss->timer)) | 989 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
1005 | ifibss->timer_running = true; | ||
1006 | } | ||
1007 | |||
1008 | void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata) | ||
1009 | { | ||
1010 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
1011 | |||
1012 | if (ifibss->timer_running) { | ||
1013 | add_timer(&ifibss->timer); | ||
1014 | ifibss->timer_running = false; | ||
1015 | } | ||
1016 | } | 990 | } |
1017 | #endif | ||
1018 | 991 | ||
1019 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | 992 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) |
1020 | { | 993 | { |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 388580a1bada..f4433f081e77 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -315,6 +315,7 @@ struct ieee80211_roc_work { | |||
315 | u32 duration, req_duration; | 315 | u32 duration, req_duration; |
316 | struct sk_buff *frame; | 316 | struct sk_buff *frame; |
317 | u64 cookie, mgmt_tx_cookie; | 317 | u64 cookie, mgmt_tx_cookie; |
318 | enum ieee80211_roc_type type; | ||
318 | }; | 319 | }; |
319 | 320 | ||
320 | /* flags used in struct ieee80211_if_managed.flags */ | 321 | /* flags used in struct ieee80211_if_managed.flags */ |
@@ -400,7 +401,6 @@ struct ieee80211_if_managed { | |||
400 | 401 | ||
401 | u16 aid; | 402 | u16 aid; |
402 | 403 | ||
403 | unsigned long timers_running; /* used for quiesce/restart */ | ||
404 | bool powersave; /* powersave requested for this iface */ | 404 | bool powersave; /* powersave requested for this iface */ |
405 | bool broken_ap; /* AP is broken -- turn off powersave */ | 405 | bool broken_ap; /* AP is broken -- turn off powersave */ |
406 | u8 dtim_period; | 406 | u8 dtim_period; |
@@ -479,6 +479,8 @@ struct ieee80211_if_managed { | |||
479 | 479 | ||
480 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ | 480 | struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */ |
481 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ | 481 | struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */ |
482 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ | ||
483 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ | ||
482 | }; | 484 | }; |
483 | 485 | ||
484 | struct ieee80211_if_ibss { | 486 | struct ieee80211_if_ibss { |
@@ -490,8 +492,6 @@ struct ieee80211_if_ibss { | |||
490 | 492 | ||
491 | u32 basic_rates; | 493 | u32 basic_rates; |
492 | 494 | ||
493 | bool timer_running; | ||
494 | |||
495 | bool fixed_bssid; | 495 | bool fixed_bssid; |
496 | bool fixed_channel; | 496 | bool fixed_channel; |
497 | bool privacy; | 497 | bool privacy; |
@@ -543,8 +543,6 @@ struct ieee80211_if_mesh { | |||
543 | struct timer_list mesh_path_timer; | 543 | struct timer_list mesh_path_timer; |
544 | struct timer_list mesh_path_root_timer; | 544 | struct timer_list mesh_path_root_timer; |
545 | 545 | ||
546 | unsigned long timers_running; | ||
547 | |||
548 | unsigned long wrkq_flags; | 546 | unsigned long wrkq_flags; |
549 | 547 | ||
550 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 548 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
@@ -590,6 +588,7 @@ struct ieee80211_if_mesh { | |||
590 | IEEE80211_MESH_SEC_AUTHED = 0x1, | 588 | IEEE80211_MESH_SEC_AUTHED = 0x1, |
591 | IEEE80211_MESH_SEC_SECURED = 0x2, | 589 | IEEE80211_MESH_SEC_SECURED = 0x2, |
592 | } security; | 590 | } security; |
591 | bool user_mpm; | ||
593 | /* Extensible Synchronization Framework */ | 592 | /* Extensible Synchronization Framework */ |
594 | const struct ieee80211_mesh_sync_ops *sync_ops; | 593 | const struct ieee80211_mesh_sync_ops *sync_ops; |
595 | s64 sync_offset_clockdrift_max; | 594 | s64 sync_offset_clockdrift_max; |
@@ -682,6 +681,8 @@ struct ieee80211_sub_if_data { | |||
682 | 681 | ||
683 | /* count for keys needing tailroom space allocation */ | 682 | /* count for keys needing tailroom space allocation */ |
684 | int crypto_tx_tailroom_needed_cnt; | 683 | int crypto_tx_tailroom_needed_cnt; |
684 | int crypto_tx_tailroom_pending_dec; | ||
685 | struct delayed_work dec_tailroom_needed_wk; | ||
685 | 686 | ||
686 | struct net_device *dev; | 687 | struct net_device *dev; |
687 | struct ieee80211_local *local; | 688 | struct ieee80211_local *local; |
@@ -765,10 +766,6 @@ struct ieee80211_sub_if_data { | |||
765 | } debugfs; | 766 | } debugfs; |
766 | #endif | 767 | #endif |
767 | 768 | ||
768 | #ifdef CONFIG_PM | ||
769 | struct ieee80211_bss_conf suspend_bss_conf; | ||
770 | #endif | ||
771 | |||
772 | /* must be last, dynamically sized area in this! */ | 769 | /* must be last, dynamically sized area in this! */ |
773 | struct ieee80211_vif vif; | 770 | struct ieee80211_vif vif; |
774 | }; | 771 | }; |
@@ -1136,11 +1133,6 @@ struct ieee80211_local { | |||
1136 | 1133 | ||
1137 | struct ieee80211_sub_if_data __rcu *p2p_sdata; | 1134 | struct ieee80211_sub_if_data __rcu *p2p_sdata; |
1138 | 1135 | ||
1139 | /* dummy netdev for use w/ NAPI */ | ||
1140 | struct net_device napi_dev; | ||
1141 | |||
1142 | struct napi_struct napi; | ||
1143 | |||
1144 | /* virtual monitor interface */ | 1136 | /* virtual monitor interface */ |
1145 | struct ieee80211_sub_if_data __rcu *monitor_sdata; | 1137 | struct ieee80211_sub_if_data __rcu *monitor_sdata; |
1146 | struct cfg80211_chan_def monitor_chandef; | 1138 | struct cfg80211_chan_def monitor_chandef; |
@@ -1283,8 +1275,6 @@ void | |||
1283 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1275 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1284 | const struct ieee80211_channel_sw_ie *sw_elem, | 1276 | const struct ieee80211_channel_sw_ie *sw_elem, |
1285 | struct ieee80211_bss *bss, u64 timestamp); | 1277 | struct ieee80211_bss *bss, u64 timestamp); |
1286 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); | ||
1287 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | ||
1288 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); | 1278 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); |
1289 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1279 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1290 | struct sk_buff *skb); | 1280 | struct sk_buff *skb); |
@@ -1302,8 +1292,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
1302 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 1292 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
1303 | struct cfg80211_ibss_params *params); | 1293 | struct cfg80211_ibss_params *params); |
1304 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | 1294 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); |
1305 | void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata); | ||
1306 | void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata); | ||
1307 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); | 1295 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); |
1308 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1296 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
1309 | struct sk_buff *skb); | 1297 | struct sk_buff *skb); |
@@ -1441,6 +1429,8 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta); | |||
1441 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, | 1429 | void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
1442 | struct sta_info *sta, u8 opmode, | 1430 | struct sta_info *sta, u8 opmode, |
1443 | enum ieee80211_band band, bool nss_only); | 1431 | enum ieee80211_band band, bool nss_only); |
1432 | void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
1433 | struct ieee80211_sta_vht_cap *vht_cap); | ||
1444 | 1434 | ||
1445 | /* Spectrum management */ | 1435 | /* Spectrum management */ |
1446 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1436 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2c059e54e885..d85282f64405 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -107,7 +107,7 @@ void ieee80211_recalc_idle(struct ieee80211_local *local) | |||
107 | 107 | ||
108 | lockdep_assert_held(&local->mtx); | 108 | lockdep_assert_held(&local->mtx); |
109 | 109 | ||
110 | active = !list_empty(&local->chanctx_list); | 110 | active = !list_empty(&local->chanctx_list) || local->monitors; |
111 | 111 | ||
112 | if (!local->ops->remain_on_channel) { | 112 | if (!local->ops->remain_on_channel) { |
113 | list_for_each_entry(roc, &local->roc_list, list) { | 113 | list_for_each_entry(roc, &local->roc_list, list) { |
@@ -485,8 +485,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
485 | res = drv_start(local); | 485 | res = drv_start(local); |
486 | if (res) | 486 | if (res) |
487 | goto err_del_bss; | 487 | goto err_del_bss; |
488 | if (local->ops->napi_poll) | ||
489 | napi_enable(&local->napi); | ||
490 | /* we're brought up, everything changes */ | 488 | /* we're brought up, everything changes */ |
491 | hw_reconf_flags = ~0; | 489 | hw_reconf_flags = ~0; |
492 | ieee80211_led_radio(local, true); | 490 | ieee80211_led_radio(local, true); |
@@ -541,6 +539,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
541 | 539 | ||
542 | ieee80211_adjust_monitor_flags(sdata, 1); | 540 | ieee80211_adjust_monitor_flags(sdata, 1); |
543 | ieee80211_configure_filter(local); | 541 | ieee80211_configure_filter(local); |
542 | mutex_lock(&local->mtx); | ||
543 | ieee80211_recalc_idle(local); | ||
544 | mutex_unlock(&local->mtx); | ||
544 | 545 | ||
545 | netif_carrier_on(dev); | 546 | netif_carrier_on(dev); |
546 | break; | 547 | break; |
@@ -812,6 +813,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
812 | 813 | ||
813 | ieee80211_adjust_monitor_flags(sdata, -1); | 814 | ieee80211_adjust_monitor_flags(sdata, -1); |
814 | ieee80211_configure_filter(local); | 815 | ieee80211_configure_filter(local); |
816 | mutex_lock(&local->mtx); | ||
817 | ieee80211_recalc_idle(local); | ||
818 | mutex_unlock(&local->mtx); | ||
815 | break; | 819 | break; |
816 | case NL80211_IFTYPE_P2P_DEVICE: | 820 | case NL80211_IFTYPE_P2P_DEVICE: |
817 | /* relies on synchronize_rcu() below */ | 821 | /* relies on synchronize_rcu() below */ |
@@ -832,14 +836,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
832 | rcu_barrier(); | 836 | rcu_barrier(); |
833 | sta_info_flush_cleanup(sdata); | 837 | sta_info_flush_cleanup(sdata); |
834 | 838 | ||
835 | skb_queue_purge(&sdata->skb_queue); | ||
836 | |||
837 | /* | 839 | /* |
838 | * Free all remaining keys, there shouldn't be any, | 840 | * Free all remaining keys, there shouldn't be any, |
839 | * except maybe group keys in AP more or WDS? | 841 | * except maybe in WDS mode? |
840 | */ | 842 | */ |
841 | ieee80211_free_keys(sdata); | 843 | ieee80211_free_keys(sdata); |
842 | 844 | ||
845 | /* fall through */ | ||
846 | case NL80211_IFTYPE_AP: | ||
847 | skb_queue_purge(&sdata->skb_queue); | ||
848 | |||
843 | drv_remove_interface_debugfs(local, sdata); | 849 | drv_remove_interface_debugfs(local, sdata); |
844 | 850 | ||
845 | if (going_down) | 851 | if (going_down) |
@@ -851,8 +857,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
851 | ieee80211_recalc_ps(local, -1); | 857 | ieee80211_recalc_ps(local, -1); |
852 | 858 | ||
853 | if (local->open_count == 0) { | 859 | if (local->open_count == 0) { |
854 | if (local->ops->napi_poll) | ||
855 | napi_disable(&local->napi); | ||
856 | ieee80211_clear_tx_pending(local); | 860 | ieee80211_clear_tx_pending(local); |
857 | ieee80211_stop_device(local); | 861 | ieee80211_stop_device(local); |
858 | 862 | ||
@@ -1541,6 +1545,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1541 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); | 1545 | INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk); |
1542 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, | 1546 | INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work, |
1543 | ieee80211_dfs_cac_timer_work); | 1547 | ieee80211_dfs_cac_timer_work); |
1548 | INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk, | ||
1549 | ieee80211_delayed_tailroom_dec); | ||
1544 | 1550 | ||
1545 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | 1551 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
1546 | struct ieee80211_supported_band *sband; | 1552 | struct ieee80211_supported_band *sband; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ef252eb58c36..99e9f6ae6a54 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -397,7 +397,8 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
397 | return key; | 397 | return key; |
398 | } | 398 | } |
399 | 399 | ||
400 | static void __ieee80211_key_destroy(struct ieee80211_key *key) | 400 | static void __ieee80211_key_destroy(struct ieee80211_key *key, |
401 | bool delay_tailroom) | ||
401 | { | 402 | { |
402 | if (!key) | 403 | if (!key) |
403 | return; | 404 | return; |
@@ -416,8 +417,18 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
416 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) | 417 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
417 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 418 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
418 | if (key->local) { | 419 | if (key->local) { |
420 | struct ieee80211_sub_if_data *sdata = key->sdata; | ||
421 | |||
419 | ieee80211_debugfs_key_remove(key); | 422 | ieee80211_debugfs_key_remove(key); |
420 | key->sdata->crypto_tx_tailroom_needed_cnt--; | 423 | |
424 | if (delay_tailroom) { | ||
425 | /* see ieee80211_delayed_tailroom_dec */ | ||
426 | sdata->crypto_tx_tailroom_pending_dec++; | ||
427 | schedule_delayed_work(&sdata->dec_tailroom_needed_wk, | ||
428 | HZ/2); | ||
429 | } else { | ||
430 | sdata->crypto_tx_tailroom_needed_cnt--; | ||
431 | } | ||
421 | } | 432 | } |
422 | 433 | ||
423 | kfree(key); | 434 | kfree(key); |
@@ -440,32 +451,6 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
440 | key->sdata = sdata; | 451 | key->sdata = sdata; |
441 | key->sta = sta; | 452 | key->sta = sta; |
442 | 453 | ||
443 | if (sta) { | ||
444 | /* | ||
445 | * some hardware cannot handle TKIP with QoS, so | ||
446 | * we indicate whether QoS could be in use. | ||
447 | */ | ||
448 | if (test_sta_flag(sta, WLAN_STA_WME)) | ||
449 | key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; | ||
450 | } else { | ||
451 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
452 | struct sta_info *ap; | ||
453 | |||
454 | /* | ||
455 | * We're getting a sta pointer in, so must be under | ||
456 | * appropriate locking for sta_info_get(). | ||
457 | */ | ||
458 | |||
459 | /* same here, the AP could be using QoS */ | ||
460 | ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid); | ||
461 | if (ap) { | ||
462 | if (test_sta_flag(ap, WLAN_STA_WME)) | ||
463 | key->conf.flags |= | ||
464 | IEEE80211_KEY_FLAG_WMM_STA; | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | |||
469 | mutex_lock(&sdata->local->key_mtx); | 454 | mutex_lock(&sdata->local->key_mtx); |
470 | 455 | ||
471 | if (sta && pairwise) | 456 | if (sta && pairwise) |
@@ -478,7 +463,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
478 | increment_tailroom_need_count(sdata); | 463 | increment_tailroom_need_count(sdata); |
479 | 464 | ||
480 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); | 465 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
481 | __ieee80211_key_destroy(old_key); | 466 | __ieee80211_key_destroy(old_key, true); |
482 | 467 | ||
483 | ieee80211_debugfs_key_add(key); | 468 | ieee80211_debugfs_key_add(key); |
484 | 469 | ||
@@ -489,7 +474,7 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
489 | return ret; | 474 | return ret; |
490 | } | 475 | } |
491 | 476 | ||
492 | void __ieee80211_key_free(struct ieee80211_key *key) | 477 | void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom) |
493 | { | 478 | { |
494 | if (!key) | 479 | if (!key) |
495 | return; | 480 | return; |
@@ -501,14 +486,14 @@ void __ieee80211_key_free(struct ieee80211_key *key) | |||
501 | __ieee80211_key_replace(key->sdata, key->sta, | 486 | __ieee80211_key_replace(key->sdata, key->sta, |
502 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, | 487 | key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, |
503 | key, NULL); | 488 | key, NULL); |
504 | __ieee80211_key_destroy(key); | 489 | __ieee80211_key_destroy(key, delay_tailroom); |
505 | } | 490 | } |
506 | 491 | ||
507 | void ieee80211_key_free(struct ieee80211_local *local, | 492 | void ieee80211_key_free(struct ieee80211_local *local, |
508 | struct ieee80211_key *key) | 493 | struct ieee80211_key *key) |
509 | { | 494 | { |
510 | mutex_lock(&local->key_mtx); | 495 | mutex_lock(&local->key_mtx); |
511 | __ieee80211_key_free(key); | 496 | __ieee80211_key_free(key, true); |
512 | mutex_unlock(&local->key_mtx); | 497 | mutex_unlock(&local->key_mtx); |
513 | } | 498 | } |
514 | 499 | ||
@@ -566,36 +551,60 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw, | |||
566 | } | 551 | } |
567 | EXPORT_SYMBOL(ieee80211_iter_keys); | 552 | EXPORT_SYMBOL(ieee80211_iter_keys); |
568 | 553 | ||
569 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) | ||
570 | { | ||
571 | struct ieee80211_key *key; | ||
572 | |||
573 | ASSERT_RTNL(); | ||
574 | |||
575 | mutex_lock(&sdata->local->key_mtx); | ||
576 | |||
577 | list_for_each_entry(key, &sdata->key_list, list) | ||
578 | ieee80211_key_disable_hw_accel(key); | ||
579 | |||
580 | mutex_unlock(&sdata->local->key_mtx); | ||
581 | } | ||
582 | |||
583 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 554 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) |
584 | { | 555 | { |
585 | struct ieee80211_key *key, *tmp; | 556 | struct ieee80211_key *key, *tmp; |
586 | 557 | ||
558 | cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk); | ||
559 | |||
587 | mutex_lock(&sdata->local->key_mtx); | 560 | mutex_lock(&sdata->local->key_mtx); |
588 | 561 | ||
562 | sdata->crypto_tx_tailroom_needed_cnt -= | ||
563 | sdata->crypto_tx_tailroom_pending_dec; | ||
564 | sdata->crypto_tx_tailroom_pending_dec = 0; | ||
565 | |||
589 | ieee80211_debugfs_key_remove_mgmt_default(sdata); | 566 | ieee80211_debugfs_key_remove_mgmt_default(sdata); |
590 | 567 | ||
591 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 568 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
592 | __ieee80211_key_free(key); | 569 | __ieee80211_key_free(key, false); |
593 | 570 | ||
594 | ieee80211_debugfs_key_update_default(sdata); | 571 | ieee80211_debugfs_key_update_default(sdata); |
595 | 572 | ||
573 | WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || | ||
574 | sdata->crypto_tx_tailroom_pending_dec); | ||
575 | |||
596 | mutex_unlock(&sdata->local->key_mtx); | 576 | mutex_unlock(&sdata->local->key_mtx); |
597 | } | 577 | } |
598 | 578 | ||
579 | void ieee80211_delayed_tailroom_dec(struct work_struct *wk) | ||
580 | { | ||
581 | struct ieee80211_sub_if_data *sdata; | ||
582 | |||
583 | sdata = container_of(wk, struct ieee80211_sub_if_data, | ||
584 | dec_tailroom_needed_wk.work); | ||
585 | |||
586 | /* | ||
587 | * The reason for the delayed tailroom needed decrementing is to | ||
588 | * make roaming faster: during roaming, all keys are first deleted | ||
589 | * and then new keys are installed. The first new key causes the | ||
590 | * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes | ||
591 | * the cost of synchronize_net() (which can be slow). Avoid this | ||
592 | * by deferring the crypto_tx_tailroom_needed_cnt decrementing on | ||
593 | * key removal for a while, so if we roam the value is larger than | ||
594 | * zero and no 0->1 transition happens. | ||
595 | * | ||
596 | * The cost is that if the AP switching was from an AP with keys | ||
597 | * to one without, we still allocate tailroom while it would no | ||
598 | * longer be needed. However, in the typical (fast) roaming case | ||
599 | * within an ESS this usually won't happen. | ||
600 | */ | ||
601 | |||
602 | mutex_lock(&sdata->local->key_mtx); | ||
603 | sdata->crypto_tx_tailroom_needed_cnt -= | ||
604 | sdata->crypto_tx_tailroom_pending_dec; | ||
605 | sdata->crypto_tx_tailroom_pending_dec = 0; | ||
606 | mutex_unlock(&sdata->local->key_mtx); | ||
607 | } | ||
599 | 608 | ||
600 | void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, | 609 | void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, |
601 | const u8 *replay_ctr, gfp_t gfp) | 610 | const u8 *replay_ctr, gfp_t gfp) |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 382dc44ed330..2a682d81cee9 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -134,7 +134,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
134 | int __must_check ieee80211_key_link(struct ieee80211_key *key, | 134 | int __must_check ieee80211_key_link(struct ieee80211_key *key, |
135 | struct ieee80211_sub_if_data *sdata, | 135 | struct ieee80211_sub_if_data *sdata, |
136 | struct sta_info *sta); | 136 | struct sta_info *sta); |
137 | void __ieee80211_key_free(struct ieee80211_key *key); | 137 | void __ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom); |
138 | void ieee80211_key_free(struct ieee80211_local *local, | 138 | void ieee80211_key_free(struct ieee80211_local *local, |
139 | struct ieee80211_key *key); | 139 | struct ieee80211_key *key); |
140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | 140 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
@@ -143,9 +143,10 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, | |||
143 | int idx); | 143 | int idx); |
144 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | 144 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); |
145 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 145 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
146 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); | ||
147 | 146 | ||
148 | #define key_mtx_dereference(local, ref) \ | 147 | #define key_mtx_dereference(local, ref) \ |
149 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) | 148 | rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) |
150 | 149 | ||
150 | void ieee80211_delayed_tailroom_dec(struct work_struct *wk); | ||
151 | |||
151 | #endif /* IEEE80211_KEY_H */ | 152 | #endif /* IEEE80211_KEY_H */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 1a8591b77a13..5a53aa5ede80 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -399,30 +399,6 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb, | |||
399 | } | 399 | } |
400 | #endif | 400 | #endif |
401 | 401 | ||
402 | static int ieee80211_napi_poll(struct napi_struct *napi, int budget) | ||
403 | { | ||
404 | struct ieee80211_local *local = | ||
405 | container_of(napi, struct ieee80211_local, napi); | ||
406 | |||
407 | return local->ops->napi_poll(&local->hw, budget); | ||
408 | } | ||
409 | |||
410 | void ieee80211_napi_schedule(struct ieee80211_hw *hw) | ||
411 | { | ||
412 | struct ieee80211_local *local = hw_to_local(hw); | ||
413 | |||
414 | napi_schedule(&local->napi); | ||
415 | } | ||
416 | EXPORT_SYMBOL(ieee80211_napi_schedule); | ||
417 | |||
418 | void ieee80211_napi_complete(struct ieee80211_hw *hw) | ||
419 | { | ||
420 | struct ieee80211_local *local = hw_to_local(hw); | ||
421 | |||
422 | napi_complete(&local->napi); | ||
423 | } | ||
424 | EXPORT_SYMBOL(ieee80211_napi_complete); | ||
425 | |||
426 | /* There isn't a lot of sense in it, but you can transmit anything you like */ | 402 | /* There isn't a lot of sense in it, but you can transmit anything you like */ |
427 | static const struct ieee80211_txrx_stypes | 403 | static const struct ieee80211_txrx_stypes |
428 | ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { | 404 | ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { |
@@ -501,6 +477,27 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { | |||
501 | }, | 477 | }, |
502 | }; | 478 | }; |
503 | 479 | ||
480 | static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { | ||
481 | .vht_cap_info = | ||
482 | cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC | | ||
483 | IEEE80211_VHT_CAP_SHORT_GI_80 | | ||
484 | IEEE80211_VHT_CAP_SHORT_GI_160 | | ||
485 | IEEE80211_VHT_CAP_RXSTBC_1 | | ||
486 | IEEE80211_VHT_CAP_RXSTBC_2 | | ||
487 | IEEE80211_VHT_CAP_RXSTBC_3 | | ||
488 | IEEE80211_VHT_CAP_RXSTBC_4 | | ||
489 | IEEE80211_VHT_CAP_TXSTBC | | ||
490 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | ||
491 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | ||
492 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | | ||
493 | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | | ||
494 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK), | ||
495 | .supp_mcs = { | ||
496 | .rx_mcs_map = cpu_to_le16(~0), | ||
497 | .tx_mcs_map = cpu_to_le16(~0), | ||
498 | }, | ||
499 | }; | ||
500 | |||
504 | static const u8 extended_capabilities[] = { | 501 | static const u8 extended_capabilities[] = { |
505 | 0, 0, 0, 0, 0, 0, 0, | 502 | 0, 0, 0, 0, 0, 0, 0, |
506 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | 503 | WLAN_EXT_CAPA8_OPMODE_NOTIF, |
@@ -572,7 +569,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
572 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | | 569 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | |
573 | NL80211_FEATURE_SAE | | 570 | NL80211_FEATURE_SAE | |
574 | NL80211_FEATURE_HT_IBSS | | 571 | NL80211_FEATURE_HT_IBSS | |
575 | NL80211_FEATURE_VIF_TXPOWER; | 572 | NL80211_FEATURE_VIF_TXPOWER | |
573 | NL80211_FEATURE_USERSPACE_MPM; | ||
576 | 574 | ||
577 | if (!ops->hw_scan) | 575 | if (!ops->hw_scan) |
578 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | | 576 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | |
@@ -609,6 +607,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
609 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; | 607 | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; |
610 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; | 608 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; |
611 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 609 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
610 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; | ||
612 | 611 | ||
613 | INIT_LIST_HEAD(&local->interfaces); | 612 | INIT_LIST_HEAD(&local->interfaces); |
614 | 613 | ||
@@ -664,9 +663,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
664 | skb_queue_head_init(&local->skb_queue); | 663 | skb_queue_head_init(&local->skb_queue); |
665 | skb_queue_head_init(&local->skb_queue_unreliable); | 664 | skb_queue_head_init(&local->skb_queue_unreliable); |
666 | 665 | ||
667 | /* init dummy netdev for use w/ NAPI */ | ||
668 | init_dummy_netdev(&local->napi_dev); | ||
669 | |||
670 | ieee80211_led_names(local); | 666 | ieee80211_led_names(local); |
671 | 667 | ||
672 | ieee80211_roc_setup(local); | 668 | ieee80211_roc_setup(local); |
@@ -1021,9 +1017,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1021 | goto fail_ifa6; | 1017 | goto fail_ifa6; |
1022 | #endif | 1018 | #endif |
1023 | 1019 | ||
1024 | netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, | ||
1025 | local->hw.napi_weight); | ||
1026 | |||
1027 | return 0; | 1020 | return 0; |
1028 | 1021 | ||
1029 | #if IS_ENABLED(CONFIG_IPV6) | 1022 | #if IS_ENABLED(CONFIG_IPV6) |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 29ce2aa87e7b..5ac017f3fcd2 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -13,10 +13,6 @@ | |||
13 | #include "ieee80211_i.h" | 13 | #include "ieee80211_i.h" |
14 | #include "mesh.h" | 14 | #include "mesh.h" |
15 | 15 | ||
16 | #define TMR_RUNNING_HK 0 | ||
17 | #define TMR_RUNNING_MP 1 | ||
18 | #define TMR_RUNNING_MPR 2 | ||
19 | |||
20 | static int mesh_allocated; | 16 | static int mesh_allocated; |
21 | static struct kmem_cache *rm_cache; | 17 | static struct kmem_cache *rm_cache; |
22 | 18 | ||
@@ -50,11 +46,6 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) | |||
50 | 46 | ||
51 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 47 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
52 | 48 | ||
53 | if (local->quiescing) { | ||
54 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | ||
55 | return; | ||
56 | } | ||
57 | |||
58 | ieee80211_queue_work(&local->hw, &sdata->work); | 49 | ieee80211_queue_work(&local->hw, &sdata->work); |
59 | } | 50 | } |
60 | 51 | ||
@@ -165,7 +156,7 @@ void mesh_sta_cleanup(struct sta_info *sta) | |||
165 | * an update. | 156 | * an update. |
166 | */ | 157 | */ |
167 | changed = mesh_accept_plinks_update(sdata); | 158 | changed = mesh_accept_plinks_update(sdata); |
168 | if (sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { | 159 | if (!sdata->u.mesh.user_mpm) { |
169 | changed |= mesh_plink_deactivate(sta); | 160 | changed |= mesh_plink_deactivate(sta); |
170 | del_timer_sync(&sta->plink_timer); | 161 | del_timer_sync(&sta->plink_timer); |
171 | } | 162 | } |
@@ -479,15 +470,8 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
479 | { | 470 | { |
480 | struct ieee80211_sub_if_data *sdata = | 471 | struct ieee80211_sub_if_data *sdata = |
481 | (struct ieee80211_sub_if_data *) data; | 472 | (struct ieee80211_sub_if_data *) data; |
482 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
483 | struct ieee80211_local *local = sdata->local; | ||
484 | |||
485 | if (local->quiescing) { | ||
486 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | ||
487 | return; | ||
488 | } | ||
489 | 473 | ||
490 | ieee80211_queue_work(&local->hw, &sdata->work); | 474 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
491 | } | 475 | } |
492 | 476 | ||
493 | static void ieee80211_mesh_path_root_timer(unsigned long data) | 477 | static void ieee80211_mesh_path_root_timer(unsigned long data) |
@@ -495,16 +479,10 @@ static void ieee80211_mesh_path_root_timer(unsigned long data) | |||
495 | struct ieee80211_sub_if_data *sdata = | 479 | struct ieee80211_sub_if_data *sdata = |
496 | (struct ieee80211_sub_if_data *) data; | 480 | (struct ieee80211_sub_if_data *) data; |
497 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 481 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
498 | struct ieee80211_local *local = sdata->local; | ||
499 | 482 | ||
500 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | 483 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); |
501 | 484 | ||
502 | if (local->quiescing) { | 485 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
503 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
508 | } | 486 | } |
509 | 487 | ||
510 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) | 488 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) |
@@ -622,35 +600,6 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) | |||
622 | round_jiffies(TU_TO_EXP_TIME(interval))); | 600 | round_jiffies(TU_TO_EXP_TIME(interval))); |
623 | } | 601 | } |
624 | 602 | ||
625 | #ifdef CONFIG_PM | ||
626 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | ||
627 | { | ||
628 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
629 | |||
630 | /* use atomic bitops in case all timers fire at the same time */ | ||
631 | |||
632 | if (del_timer_sync(&ifmsh->housekeeping_timer)) | ||
633 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | ||
634 | if (del_timer_sync(&ifmsh->mesh_path_timer)) | ||
635 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | ||
636 | if (del_timer_sync(&ifmsh->mesh_path_root_timer)) | ||
637 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
638 | } | ||
639 | |||
640 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | ||
641 | { | ||
642 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
643 | |||
644 | if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running)) | ||
645 | add_timer(&ifmsh->housekeeping_timer); | ||
646 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) | ||
647 | add_timer(&ifmsh->mesh_path_timer); | ||
648 | if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) | ||
649 | add_timer(&ifmsh->mesh_path_root_timer); | ||
650 | ieee80211_mesh_root_setup(ifmsh); | ||
651 | } | ||
652 | #endif | ||
653 | |||
654 | static int | 603 | static int |
655 | ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) | 604 | ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) |
656 | { | 605 | { |
@@ -871,8 +820,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
871 | local->fif_other_bss--; | 820 | local->fif_other_bss--; |
872 | atomic_dec(&local->iff_allmultis); | 821 | atomic_dec(&local->iff_allmultis); |
873 | ieee80211_configure_filter(local); | 822 | ieee80211_configure_filter(local); |
874 | |||
875 | sdata->u.mesh.timers_running = 0; | ||
876 | } | 823 | } |
877 | 824 | ||
878 | static void | 825 | static void |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 336c88a16687..6ffabbe99c46 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -313,8 +313,6 @@ void mesh_path_timer(unsigned long data); | |||
313 | void mesh_path_flush_by_nexthop(struct sta_info *sta); | 313 | void mesh_path_flush_by_nexthop(struct sta_info *sta); |
314 | void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata, | 314 | void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata, |
315 | struct sk_buff *skb); | 315 | struct sk_buff *skb); |
316 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | ||
317 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | ||
318 | void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); | 316 | void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); |
319 | 317 | ||
320 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); | 318 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); |
@@ -359,22 +357,12 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) | |||
359 | 357 | ||
360 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); | 358 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); |
361 | 359 | ||
362 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); | ||
363 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); | ||
364 | void mesh_plink_quiesce(struct sta_info *sta); | ||
365 | void mesh_plink_restart(struct sta_info *sta); | ||
366 | void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); | 360 | void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); |
367 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); | 361 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); |
368 | void ieee80211s_stop(void); | 362 | void ieee80211s_stop(void); |
369 | #else | 363 | #else |
370 | static inline void | 364 | static inline void |
371 | ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} | 365 | ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} |
372 | static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | ||
373 | {} | ||
374 | static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | ||
375 | {} | ||
376 | static inline void mesh_plink_quiesce(struct sta_info *sta) {} | ||
377 | static inline void mesh_plink_restart(struct sta_info *sta) {} | ||
378 | static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) | 366 | static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) |
379 | { return false; } | 367 | { return false; } |
380 | static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) | 368 | static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 07d396d57079..937e06fe8f2a 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -420,7 +420,6 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) | |||
420 | return NULL; | 420 | return NULL; |
421 | 421 | ||
422 | sta->plink_state = NL80211_PLINK_LISTEN; | 422 | sta->plink_state = NL80211_PLINK_LISTEN; |
423 | init_timer(&sta->plink_timer); | ||
424 | 423 | ||
425 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | 424 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); |
426 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); | 425 | sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); |
@@ -437,8 +436,9 @@ mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, | |||
437 | { | 436 | { |
438 | struct sta_info *sta = NULL; | 437 | struct sta_info *sta = NULL; |
439 | 438 | ||
440 | /* Userspace handles peer allocation when security is enabled */ | 439 | /* Userspace handles station allocation */ |
441 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) | 440 | if (sdata->u.mesh.user_mpm || |
441 | sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) | ||
442 | cfg80211_notify_new_peer_candidate(sdata->dev, addr, | 442 | cfg80211_notify_new_peer_candidate(sdata->dev, addr, |
443 | elems->ie_start, | 443 | elems->ie_start, |
444 | elems->total_len, | 444 | elems->total_len, |
@@ -534,10 +534,8 @@ static void mesh_plink_timer(unsigned long data) | |||
534 | */ | 534 | */ |
535 | sta = (struct sta_info *) data; | 535 | sta = (struct sta_info *) data; |
536 | 536 | ||
537 | if (sta->sdata->local->quiescing) { | 537 | if (sta->sdata->local->quiescing) |
538 | sta->plink_timer_was_running = true; | ||
539 | return; | 538 | return; |
540 | } | ||
541 | 539 | ||
542 | spin_lock_bh(&sta->lock); | 540 | spin_lock_bh(&sta->lock); |
543 | if (sta->ignore_plink_timer) { | 541 | if (sta->ignore_plink_timer) { |
@@ -598,29 +596,6 @@ static void mesh_plink_timer(unsigned long data) | |||
598 | } | 596 | } |
599 | } | 597 | } |
600 | 598 | ||
601 | #ifdef CONFIG_PM | ||
602 | void mesh_plink_quiesce(struct sta_info *sta) | ||
603 | { | ||
604 | if (!ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
605 | return; | ||
606 | |||
607 | /* no kernel mesh sta timers have been initialized */ | ||
608 | if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) | ||
609 | return; | ||
610 | |||
611 | if (del_timer_sync(&sta->plink_timer)) | ||
612 | sta->plink_timer_was_running = true; | ||
613 | } | ||
614 | |||
615 | void mesh_plink_restart(struct sta_info *sta) | ||
616 | { | ||
617 | if (sta->plink_timer_was_running) { | ||
618 | add_timer(&sta->plink_timer); | ||
619 | sta->plink_timer_was_running = false; | ||
620 | } | ||
621 | } | ||
622 | #endif | ||
623 | |||
624 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | 599 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) |
625 | { | 600 | { |
626 | sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); | 601 | sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); |
@@ -695,6 +670,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
695 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | 670 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) |
696 | return; | 671 | return; |
697 | 672 | ||
673 | if (sdata->u.mesh.user_mpm) | ||
674 | /* userspace must register for these */ | ||
675 | return; | ||
676 | |||
698 | if (is_multicast_ether_addr(mgmt->da)) { | 677 | if (is_multicast_ether_addr(mgmt->da)) { |
699 | mpl_dbg(sdata, | 678 | mpl_dbg(sdata, |
700 | "Mesh plink: ignore frame from multicast address\n"); | 679 | "Mesh plink: ignore frame from multicast address\n"); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9f6464f3e05f..fdc06e381c10 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -87,9 +87,6 @@ MODULE_PARM_DESC(probe_wait_ms, | |||
87 | */ | 87 | */ |
88 | #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 | 88 | #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 |
89 | 89 | ||
90 | #define TMR_RUNNING_TIMER 0 | ||
91 | #define TMR_RUNNING_CHANSW 1 | ||
92 | |||
93 | /* | 90 | /* |
94 | * All cfg80211 functions have to be called outside a locked | 91 | * All cfg80211 functions have to be called outside a locked |
95 | * section so that they can acquire a lock themselves... This | 92 | * section so that they can acquire a lock themselves... This |
@@ -609,6 +606,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
609 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); | 606 | BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap)); |
610 | 607 | ||
611 | memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); | 608 | memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); |
609 | ieee80211_apply_vhtcap_overrides(sdata, &vht_cap); | ||
612 | 610 | ||
613 | /* determine capability flags */ | 611 | /* determine capability flags */ |
614 | cap = vht_cap.cap; | 612 | cap = vht_cap.cap; |
@@ -647,6 +645,9 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, | |||
647 | our_mcs = (le16_to_cpu(vht_cap.vht_mcs.rx_mcs_map) & | 645 | our_mcs = (le16_to_cpu(vht_cap.vht_mcs.rx_mcs_map) & |
648 | mask) >> shift; | 646 | mask) >> shift; |
649 | 647 | ||
648 | if (our_mcs == IEEE80211_VHT_MCS_NOT_SUPPORTED) | ||
649 | continue; | ||
650 | |||
650 | switch (ap_mcs) { | 651 | switch (ap_mcs) { |
651 | default: | 652 | default: |
652 | if (our_mcs <= ap_mcs) | 653 | if (our_mcs <= ap_mcs) |
@@ -1035,14 +1036,8 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
1035 | { | 1036 | { |
1036 | struct ieee80211_sub_if_data *sdata = | 1037 | struct ieee80211_sub_if_data *sdata = |
1037 | (struct ieee80211_sub_if_data *) data; | 1038 | (struct ieee80211_sub_if_data *) data; |
1038 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1039 | 1039 | ||
1040 | if (sdata->local->quiescing) { | 1040 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work); |
1041 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
1042 | return; | ||
1043 | } | ||
1044 | |||
1045 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||
1046 | } | 1041 | } |
1047 | 1042 | ||
1048 | void | 1043 | void |
@@ -1799,9 +1794,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1799 | sdata->vif.bss_conf.p2p_ctwindow = 0; | 1794 | sdata->vif.bss_conf.p2p_ctwindow = 0; |
1800 | sdata->vif.bss_conf.p2p_oppps = false; | 1795 | sdata->vif.bss_conf.p2p_oppps = false; |
1801 | 1796 | ||
1802 | /* on the next assoc, re-program HT parameters */ | 1797 | /* on the next assoc, re-program HT/VHT parameters */ |
1803 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1798 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
1804 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1799 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
1800 | memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa)); | ||
1801 | memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask)); | ||
1805 | 1802 | ||
1806 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | 1803 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
1807 | 1804 | ||
@@ -1827,8 +1824,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1827 | del_timer_sync(&sdata->u.mgd.timer); | 1824 | del_timer_sync(&sdata->u.mgd.timer); |
1828 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | 1825 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
1829 | 1826 | ||
1830 | sdata->u.mgd.timers_running = 0; | ||
1831 | |||
1832 | sdata->vif.bss_conf.dtim_period = 0; | 1827 | sdata->vif.bss_conf.dtim_period = 0; |
1833 | 1828 | ||
1834 | ifmgd->flags = 0; | 1829 | ifmgd->flags = 0; |
@@ -3137,15 +3132,8 @@ static void ieee80211_sta_timer(unsigned long data) | |||
3137 | { | 3132 | { |
3138 | struct ieee80211_sub_if_data *sdata = | 3133 | struct ieee80211_sub_if_data *sdata = |
3139 | (struct ieee80211_sub_if_data *) data; | 3134 | (struct ieee80211_sub_if_data *) data; |
3140 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3141 | struct ieee80211_local *local = sdata->local; | ||
3142 | |||
3143 | if (local->quiescing) { | ||
3144 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
3145 | return; | ||
3146 | } | ||
3147 | 3135 | ||
3148 | ieee80211_queue_work(&local->hw, &sdata->work); | 3136 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
3149 | } | 3137 | } |
3150 | 3138 | ||
3151 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | 3139 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, |
@@ -3497,68 +3485,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
3497 | } | 3485 | } |
3498 | } | 3486 | } |
3499 | 3487 | ||
3500 | #ifdef CONFIG_PM | ||
3501 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | ||
3502 | { | ||
3503 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3504 | |||
3505 | /* | ||
3506 | * we need to use atomic bitops for the running bits | ||
3507 | * only because both timers might fire at the same | ||
3508 | * time -- the code here is properly synchronised. | ||
3509 | */ | ||
3510 | |||
3511 | cancel_work_sync(&ifmgd->request_smps_work); | ||
3512 | |||
3513 | cancel_work_sync(&ifmgd->monitor_work); | ||
3514 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | ||
3515 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | ||
3516 | if (del_timer_sync(&ifmgd->timer)) | ||
3517 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
3518 | |||
3519 | cancel_work_sync(&ifmgd->chswitch_work); | ||
3520 | if (del_timer_sync(&ifmgd->chswitch_timer)) | ||
3521 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
3522 | |||
3523 | /* these will just be re-established on connection */ | ||
3524 | del_timer_sync(&ifmgd->conn_mon_timer); | ||
3525 | del_timer_sync(&ifmgd->bcn_mon_timer); | ||
3526 | } | ||
3527 | |||
3528 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | ||
3529 | { | ||
3530 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3531 | |||
3532 | mutex_lock(&ifmgd->mtx); | ||
3533 | if (!ifmgd->associated) { | ||
3534 | mutex_unlock(&ifmgd->mtx); | ||
3535 | return; | ||
3536 | } | ||
3537 | |||
3538 | if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { | ||
3539 | sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; | ||
3540 | mlme_dbg(sdata, "driver requested disconnect after resume\n"); | ||
3541 | ieee80211_sta_connection_lost(sdata, | ||
3542 | ifmgd->associated->bssid, | ||
3543 | WLAN_REASON_UNSPECIFIED, | ||
3544 | true); | ||
3545 | mutex_unlock(&ifmgd->mtx); | ||
3546 | return; | ||
3547 | } | ||
3548 | mutex_unlock(&ifmgd->mtx); | ||
3549 | |||
3550 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) | ||
3551 | add_timer(&ifmgd->timer); | ||
3552 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | ||
3553 | add_timer(&ifmgd->chswitch_timer); | ||
3554 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
3555 | |||
3556 | mutex_lock(&sdata->local->mtx); | ||
3557 | ieee80211_restart_sta_timer(sdata); | ||
3558 | mutex_unlock(&sdata->local->mtx); | ||
3559 | } | ||
3560 | #endif | ||
3561 | |||
3562 | /* interface setup */ | 3488 | /* interface setup */ |
3563 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 3489 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
3564 | { | 3490 | { |
@@ -4064,6 +3990,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4064 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 3990 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
4065 | } | 3991 | } |
4066 | 3992 | ||
3993 | if (req->flags & ASSOC_REQ_DISABLE_VHT) | ||
3994 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | ||
3995 | |||
4067 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ | 3996 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ |
4068 | sband = local->hw.wiphy->bands[req->bss->channel->band]; | 3997 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
4069 | if (!sband->ht_cap.ht_supported || | 3998 | if (!sband->ht_cap.ht_supported || |
@@ -4087,6 +4016,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4087 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, | 4016 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, |
4088 | sizeof(ifmgd->ht_capa_mask)); | 4017 | sizeof(ifmgd->ht_capa_mask)); |
4089 | 4018 | ||
4019 | memcpy(&ifmgd->vht_capa, &req->vht_capa, sizeof(ifmgd->vht_capa)); | ||
4020 | memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask, | ||
4021 | sizeof(ifmgd->vht_capa_mask)); | ||
4022 | |||
4090 | if (req->ie && req->ie_len) { | 4023 | if (req->ie && req->ie_len) { |
4091 | memcpy(assoc_data->ie, req->ie, req->ie_len); | 4024 | memcpy(assoc_data->ie, req->ie, req->ie_len); |
4092 | assoc_data->ie_len = req->ie_len; | 4025 | assoc_data->ie_len = req->ie_len; |
@@ -4315,6 +4248,17 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4315 | { | 4248 | { |
4316 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 4249 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
4317 | 4250 | ||
4251 | /* | ||
4252 | * Make sure some work items will not run after this, | ||
4253 | * they will not do anything but might not have been | ||
4254 | * cancelled when disconnecting. | ||
4255 | */ | ||
4256 | cancel_work_sync(&ifmgd->monitor_work); | ||
4257 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | ||
4258 | cancel_work_sync(&ifmgd->request_smps_work); | ||
4259 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | ||
4260 | cancel_work_sync(&ifmgd->chswitch_work); | ||
4261 | |||
4318 | mutex_lock(&ifmgd->mtx); | 4262 | mutex_lock(&ifmgd->mtx); |
4319 | if (ifmgd->assoc_data) | 4263 | if (ifmgd->assoc_data) |
4320 | ieee80211_destroy_assoc_data(sdata, false); | 4264 | ieee80211_destroy_assoc_data(sdata, false); |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index cc79b4a2e821..db547fceaeb9 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -277,7 +277,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) | |||
277 | duration = 10; | 277 | duration = 10; |
278 | 278 | ||
279 | ret = drv_remain_on_channel(local, roc->sdata, roc->chan, | 279 | ret = drv_remain_on_channel(local, roc->sdata, roc->chan, |
280 | duration); | 280 | duration, roc->type); |
281 | 281 | ||
282 | roc->started = true; | 282 | roc->started = true; |
283 | 283 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index d0275f34bf70..b471a67f224d 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -6,32 +6,11 @@ | |||
6 | #include "driver-ops.h" | 6 | #include "driver-ops.h" |
7 | #include "led.h" | 7 | #include "led.h" |
8 | 8 | ||
9 | /* return value indicates whether the driver should be further notified */ | ||
10 | static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata) | ||
11 | { | ||
12 | switch (sdata->vif.type) { | ||
13 | case NL80211_IFTYPE_STATION: | ||
14 | ieee80211_sta_quiesce(sdata); | ||
15 | break; | ||
16 | case NL80211_IFTYPE_ADHOC: | ||
17 | ieee80211_ibss_quiesce(sdata); | ||
18 | break; | ||
19 | case NL80211_IFTYPE_MESH_POINT: | ||
20 | ieee80211_mesh_quiesce(sdata); | ||
21 | break; | ||
22 | default: | ||
23 | break; | ||
24 | } | ||
25 | |||
26 | cancel_work_sync(&sdata->work); | ||
27 | } | ||
28 | |||
29 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | 9 | int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) |
30 | { | 10 | { |
31 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
32 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
33 | struct sta_info *sta; | 13 | struct sta_info *sta; |
34 | struct ieee80211_chanctx *ctx; | ||
35 | 14 | ||
36 | if (!local->open_count) | 15 | if (!local->open_count) |
37 | goto suspend; | 16 | goto suspend; |
@@ -93,19 +72,12 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
93 | return err; | 72 | return err; |
94 | } else if (err > 0) { | 73 | } else if (err > 0) { |
95 | WARN_ON(err != 1); | 74 | WARN_ON(err != 1); |
96 | local->wowlan = false; | 75 | return err; |
97 | } else { | 76 | } else { |
98 | list_for_each_entry(sdata, &local->interfaces, list) | ||
99 | if (ieee80211_sdata_running(sdata)) | ||
100 | ieee80211_quiesce(sdata); | ||
101 | goto suspend; | 77 | goto suspend; |
102 | } | 78 | } |
103 | } | 79 | } |
104 | 80 | ||
105 | /* disable keys */ | ||
106 | list_for_each_entry(sdata, &local->interfaces, list) | ||
107 | ieee80211_disable_keys(sdata); | ||
108 | |||
109 | /* tear down aggregation sessions and remove STAs */ | 81 | /* tear down aggregation sessions and remove STAs */ |
110 | mutex_lock(&local->sta_mtx); | 82 | mutex_lock(&local->sta_mtx); |
111 | list_for_each_entry(sta, &local->sta_list, list) { | 83 | list_for_each_entry(sta, &local->sta_list, list) { |
@@ -117,100 +89,25 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
117 | WARN_ON(drv_sta_state(local, sta->sdata, sta, | 89 | WARN_ON(drv_sta_state(local, sta->sdata, sta, |
118 | state, state - 1)); | 90 | state, state - 1)); |
119 | } | 91 | } |
120 | |||
121 | mesh_plink_quiesce(sta); | ||
122 | } | 92 | } |
123 | mutex_unlock(&local->sta_mtx); | 93 | mutex_unlock(&local->sta_mtx); |
124 | 94 | ||
125 | /* remove all interfaces */ | 95 | /* remove all interfaces */ |
126 | list_for_each_entry(sdata, &local->interfaces, list) { | 96 | list_for_each_entry(sdata, &local->interfaces, list) { |
127 | static u8 zero_addr[ETH_ALEN] = {}; | ||
128 | u32 changed = 0; | ||
129 | |||
130 | if (!ieee80211_sdata_running(sdata)) | 97 | if (!ieee80211_sdata_running(sdata)) |
131 | continue; | 98 | continue; |
132 | |||
133 | switch (sdata->vif.type) { | ||
134 | case NL80211_IFTYPE_AP_VLAN: | ||
135 | case NL80211_IFTYPE_MONITOR: | ||
136 | /* skip these */ | ||
137 | continue; | ||
138 | case NL80211_IFTYPE_STATION: | ||
139 | if (sdata->vif.bss_conf.assoc) | ||
140 | changed = BSS_CHANGED_ASSOC | | ||
141 | BSS_CHANGED_BSSID | | ||
142 | BSS_CHANGED_IDLE; | ||
143 | break; | ||
144 | case NL80211_IFTYPE_AP: | ||
145 | case NL80211_IFTYPE_ADHOC: | ||
146 | case NL80211_IFTYPE_MESH_POINT: | ||
147 | if (sdata->vif.bss_conf.enable_beacon) | ||
148 | changed = BSS_CHANGED_BEACON_ENABLED; | ||
149 | break; | ||
150 | default: | ||
151 | break; | ||
152 | } | ||
153 | |||
154 | ieee80211_quiesce(sdata); | ||
155 | |||
156 | sdata->suspend_bss_conf = sdata->vif.bss_conf; | ||
157 | memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf)); | ||
158 | sdata->vif.bss_conf.idle = true; | ||
159 | if (sdata->suspend_bss_conf.bssid) | ||
160 | sdata->vif.bss_conf.bssid = zero_addr; | ||
161 | |||
162 | /* disable beaconing or remove association */ | ||
163 | ieee80211_bss_info_change_notify(sdata, changed); | ||
164 | |||
165 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
166 | rcu_access_pointer(sdata->u.ap.beacon)) | ||
167 | drv_stop_ap(local, sdata); | ||
168 | |||
169 | if (local->use_chanctx) { | ||
170 | struct ieee80211_chanctx_conf *conf; | ||
171 | |||
172 | mutex_lock(&local->chanctx_mtx); | ||
173 | conf = rcu_dereference_protected( | ||
174 | sdata->vif.chanctx_conf, | ||
175 | lockdep_is_held(&local->chanctx_mtx)); | ||
176 | if (conf) { | ||
177 | ctx = container_of(conf, | ||
178 | struct ieee80211_chanctx, | ||
179 | conf); | ||
180 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
181 | } | ||
182 | |||
183 | mutex_unlock(&local->chanctx_mtx); | ||
184 | } | ||
185 | drv_remove_interface(local, sdata); | 99 | drv_remove_interface(local, sdata); |
186 | } | 100 | } |
187 | 101 | ||
188 | sdata = rtnl_dereference(local->monitor_sdata); | 102 | sdata = rtnl_dereference(local->monitor_sdata); |
189 | if (sdata) { | 103 | if (sdata) |
190 | if (local->use_chanctx) { | ||
191 | struct ieee80211_chanctx_conf *conf; | ||
192 | |||
193 | mutex_lock(&local->chanctx_mtx); | ||
194 | conf = rcu_dereference_protected( | ||
195 | sdata->vif.chanctx_conf, | ||
196 | lockdep_is_held(&local->chanctx_mtx)); | ||
197 | if (conf) { | ||
198 | ctx = container_of(conf, | ||
199 | struct ieee80211_chanctx, | ||
200 | conf); | ||
201 | drv_unassign_vif_chanctx(local, sdata, ctx); | ||
202 | } | ||
203 | |||
204 | mutex_unlock(&local->chanctx_mtx); | ||
205 | } | ||
206 | |||
207 | drv_remove_interface(local, sdata); | 104 | drv_remove_interface(local, sdata); |
208 | } | ||
209 | 105 | ||
210 | mutex_lock(&local->chanctx_mtx); | 106 | /* |
211 | list_for_each_entry(ctx, &local->chanctx_list, list) | 107 | * We disconnected on all interfaces before suspend, all channel |
212 | drv_remove_chanctx(local, ctx); | 108 | * contexts should be released. |
213 | mutex_unlock(&local->chanctx_mtx); | 109 | */ |
110 | WARN_ON(!list_empty(&local->chanctx_list)); | ||
214 | 111 | ||
215 | /* stop hardware - this must stop RX */ | 112 | /* stop hardware - this must stop RX */ |
216 | if (local->open_count) | 113 | if (local->open_count) |
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index eea45a2c7c35..1c36c9b4fa4a 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -55,7 +55,6 @@ | |||
55 | #include "rate.h" | 55 | #include "rate.h" |
56 | #include "rc80211_minstrel.h" | 56 | #include "rc80211_minstrel.h" |
57 | 57 | ||
58 | #define SAMPLE_COLUMNS 10 | ||
59 | #define SAMPLE_TBL(_mi, _idx, _col) \ | 58 | #define SAMPLE_TBL(_mi, _idx, _col) \ |
60 | _mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col] | 59 | _mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col] |
61 | 60 | ||
@@ -70,16 +69,31 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix) | |||
70 | return i; | 69 | return i; |
71 | } | 70 | } |
72 | 71 | ||
72 | /* find & sort topmost throughput rates */ | ||
73 | static inline void | ||
74 | minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) | ||
75 | { | ||
76 | int j = MAX_THR_RATES; | ||
77 | |||
78 | while (j > 0 && mi->r[i].cur_tp > mi->r[tp_list[j - 1]].cur_tp) | ||
79 | j--; | ||
80 | if (j < MAX_THR_RATES - 1) | ||
81 | memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); | ||
82 | if (j < MAX_THR_RATES) | ||
83 | tp_list[j] = i; | ||
84 | } | ||
85 | |||
73 | static void | 86 | static void |
74 | minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | 87 | minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) |
75 | { | 88 | { |
76 | u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0; | 89 | u8 tmp_tp_rate[MAX_THR_RATES]; |
77 | u32 max_prob = 0, index_max_prob = 0; | 90 | u8 tmp_prob_rate = 0; |
78 | u32 usecs; | 91 | u32 usecs; |
79 | u32 p; | ||
80 | int i; | 92 | int i; |
81 | 93 | ||
82 | mi->stats_update = jiffies; | 94 | for (i=0; i < MAX_THR_RATES; i++) |
95 | tmp_tp_rate[i] = 0; | ||
96 | |||
83 | for (i = 0; i < mi->n_rates; i++) { | 97 | for (i = 0; i < mi->n_rates; i++) { |
84 | struct minstrel_rate *mr = &mi->r[i]; | 98 | struct minstrel_rate *mr = &mi->r[i]; |
85 | 99 | ||
@@ -87,27 +101,32 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
87 | if (!usecs) | 101 | if (!usecs) |
88 | usecs = 1000000; | 102 | usecs = 1000000; |
89 | 103 | ||
90 | /* To avoid rounding issues, probabilities scale from 0 (0%) | 104 | if (unlikely(mr->attempts > 0)) { |
91 | * to 18000 (100%) */ | 105 | mr->sample_skipped = 0; |
92 | if (mr->attempts) { | 106 | mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts); |
93 | p = (mr->success * 18000) / mr->attempts; | ||
94 | mr->succ_hist += mr->success; | 107 | mr->succ_hist += mr->success; |
95 | mr->att_hist += mr->attempts; | 108 | mr->att_hist += mr->attempts; |
96 | mr->cur_prob = p; | 109 | mr->probability = minstrel_ewma(mr->probability, |
97 | p = ((p * (100 - mp->ewma_level)) + (mr->probability * | 110 | mr->cur_prob, |
98 | mp->ewma_level)) / 100; | 111 | EWMA_LEVEL); |
99 | mr->probability = p; | 112 | } else |
100 | mr->cur_tp = p * (1000000 / usecs); | 113 | mr->sample_skipped++; |
101 | } | ||
102 | 114 | ||
103 | mr->last_success = mr->success; | 115 | mr->last_success = mr->success; |
104 | mr->last_attempts = mr->attempts; | 116 | mr->last_attempts = mr->attempts; |
105 | mr->success = 0; | 117 | mr->success = 0; |
106 | mr->attempts = 0; | 118 | mr->attempts = 0; |
107 | 119 | ||
120 | /* Update throughput per rate, reset thr. below 10% success */ | ||
121 | if (mr->probability < MINSTREL_FRAC(10, 100)) | ||
122 | mr->cur_tp = 0; | ||
123 | else | ||
124 | mr->cur_tp = mr->probability * (1000000 / usecs); | ||
125 | |||
108 | /* Sample less often below the 10% chance of success. | 126 | /* Sample less often below the 10% chance of success. |
109 | * Sample less often above the 95% chance of success. */ | 127 | * Sample less often above the 95% chance of success. */ |
110 | if ((mr->probability > 17100) || (mr->probability < 1800)) { | 128 | if (mr->probability > MINSTREL_FRAC(95, 100) || |
129 | mr->probability < MINSTREL_FRAC(10, 100)) { | ||
111 | mr->adjusted_retry_count = mr->retry_count >> 1; | 130 | mr->adjusted_retry_count = mr->retry_count >> 1; |
112 | if (mr->adjusted_retry_count > 2) | 131 | if (mr->adjusted_retry_count > 2) |
113 | mr->adjusted_retry_count = 2; | 132 | mr->adjusted_retry_count = 2; |
@@ -118,35 +137,30 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
118 | } | 137 | } |
119 | if (!mr->adjusted_retry_count) | 138 | if (!mr->adjusted_retry_count) |
120 | mr->adjusted_retry_count = 2; | 139 | mr->adjusted_retry_count = 2; |
121 | } | ||
122 | 140 | ||
123 | for (i = 0; i < mi->n_rates; i++) { | 141 | minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate); |
124 | struct minstrel_rate *mr = &mi->r[i]; | 142 | |
125 | if (max_tp < mr->cur_tp) { | 143 | /* To determine the most robust rate (max_prob_rate) used at |
126 | index_max_tp = i; | 144 | * 3rd mmr stage we distinct between two cases: |
127 | max_tp = mr->cur_tp; | 145 | * (1) if any success probabilitiy >= 95%, out of those rates |
128 | } | 146 | * choose the maximum throughput rate as max_prob_rate |
129 | if (max_prob < mr->probability) { | 147 | * (2) if all success probabilities < 95%, the rate with |
130 | index_max_prob = i; | 148 | * highest success probability is choosen as max_prob_rate */ |
131 | max_prob = mr->probability; | 149 | if (mr->probability >= MINSTREL_FRAC(95,100)) { |
150 | if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp) | ||
151 | tmp_prob_rate = i; | ||
152 | } else { | ||
153 | if (mr->probability >= mi->r[tmp_prob_rate].probability) | ||
154 | tmp_prob_rate = i; | ||
132 | } | 155 | } |
133 | } | 156 | } |
134 | 157 | ||
135 | max_tp = 0; | 158 | /* Assign the new rate set */ |
136 | for (i = 0; i < mi->n_rates; i++) { | 159 | memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate)); |
137 | struct minstrel_rate *mr = &mi->r[i]; | 160 | mi->max_prob_rate = tmp_prob_rate; |
138 | |||
139 | if (i == index_max_tp) | ||
140 | continue; | ||
141 | 161 | ||
142 | if (max_tp < mr->cur_tp) { | 162 | /* Reset update timer */ |
143 | index_max_tp2 = i; | 163 | mi->stats_update = jiffies; |
144 | max_tp = mr->cur_tp; | ||
145 | } | ||
146 | } | ||
147 | mi->max_tp_rate = index_max_tp; | ||
148 | mi->max_tp_rate2 = index_max_tp2; | ||
149 | mi->max_prob_rate = index_max_prob; | ||
150 | } | 164 | } |
151 | 165 | ||
152 | static void | 166 | static void |
@@ -207,10 +221,10 @@ static int | |||
207 | minstrel_get_next_sample(struct minstrel_sta_info *mi) | 221 | minstrel_get_next_sample(struct minstrel_sta_info *mi) |
208 | { | 222 | { |
209 | unsigned int sample_ndx; | 223 | unsigned int sample_ndx; |
210 | sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column); | 224 | sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column); |
211 | mi->sample_idx++; | 225 | mi->sample_row++; |
212 | if ((int) mi->sample_idx > (mi->n_rates - 2)) { | 226 | if ((int) mi->sample_row >= mi->n_rates) { |
213 | mi->sample_idx = 0; | 227 | mi->sample_row = 0; |
214 | mi->sample_column++; | 228 | mi->sample_column++; |
215 | if (mi->sample_column >= SAMPLE_COLUMNS) | 229 | if (mi->sample_column >= SAMPLE_COLUMNS) |
216 | mi->sample_column = 0; | 230 | mi->sample_column = 0; |
@@ -228,31 +242,37 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
228 | struct minstrel_priv *mp = priv; | 242 | struct minstrel_priv *mp = priv; |
229 | struct ieee80211_tx_rate *ar = info->control.rates; | 243 | struct ieee80211_tx_rate *ar = info->control.rates; |
230 | unsigned int ndx, sample_ndx = 0; | 244 | unsigned int ndx, sample_ndx = 0; |
231 | bool mrr; | 245 | bool mrr_capable; |
232 | bool sample_slower = false; | 246 | bool indirect_rate_sampling = false; |
233 | bool sample = false; | 247 | bool rate_sampling = false; |
234 | int i, delta; | 248 | int i, delta; |
235 | int mrr_ndx[3]; | 249 | int mrr_ndx[3]; |
236 | int sample_rate; | 250 | int sampling_ratio; |
237 | 251 | ||
252 | /* management/no-ack frames do not use rate control */ | ||
238 | if (rate_control_send_low(sta, priv_sta, txrc)) | 253 | if (rate_control_send_low(sta, priv_sta, txrc)) |
239 | return; | 254 | return; |
240 | 255 | ||
241 | mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot; | 256 | /* check multi-rate-retry capabilities & adjust lookaround_rate */ |
242 | 257 | mrr_capable = mp->has_mrr && | |
243 | ndx = mi->max_tp_rate; | 258 | !txrc->rts && |
244 | 259 | !txrc->bss_conf->use_cts_prot; | |
245 | if (mrr) | 260 | if (mrr_capable) |
246 | sample_rate = mp->lookaround_rate_mrr; | 261 | sampling_ratio = mp->lookaround_rate_mrr; |
247 | else | 262 | else |
248 | sample_rate = mp->lookaround_rate; | 263 | sampling_ratio = mp->lookaround_rate; |
264 | |||
265 | /* init rateindex [ndx] with max throughput rate */ | ||
266 | ndx = mi->max_tp_rate[0]; | ||
249 | 267 | ||
268 | /* increase sum packet counter */ | ||
250 | mi->packet_count++; | 269 | mi->packet_count++; |
251 | delta = (mi->packet_count * sample_rate / 100) - | 270 | |
271 | delta = (mi->packet_count * sampling_ratio / 100) - | ||
252 | (mi->sample_count + mi->sample_deferred / 2); | 272 | (mi->sample_count + mi->sample_deferred / 2); |
253 | 273 | ||
254 | /* delta > 0: sampling required */ | 274 | /* delta > 0: sampling required */ |
255 | if ((delta > 0) && (mrr || !mi->prev_sample)) { | 275 | if ((delta > 0) && (mrr_capable || !mi->prev_sample)) { |
256 | struct minstrel_rate *msr; | 276 | struct minstrel_rate *msr; |
257 | if (mi->packet_count >= 10000) { | 277 | if (mi->packet_count >= 10000) { |
258 | mi->sample_deferred = 0; | 278 | mi->sample_deferred = 0; |
@@ -271,21 +291,28 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
271 | mi->sample_count += (delta - mi->n_rates * 2); | 291 | mi->sample_count += (delta - mi->n_rates * 2); |
272 | } | 292 | } |
273 | 293 | ||
294 | /* get next random rate sample */ | ||
274 | sample_ndx = minstrel_get_next_sample(mi); | 295 | sample_ndx = minstrel_get_next_sample(mi); |
275 | msr = &mi->r[sample_ndx]; | 296 | msr = &mi->r[sample_ndx]; |
276 | sample = true; | 297 | rate_sampling = true; |
277 | sample_slower = mrr && (msr->perfect_tx_time > | 298 | |
278 | mi->r[ndx].perfect_tx_time); | 299 | /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage) |
279 | 300 | * rate sampling method should be used. | |
280 | if (!sample_slower) { | 301 | * Respect such rates that are not sampled for 20 interations. |
302 | */ | ||
303 | if (mrr_capable && | ||
304 | msr->perfect_tx_time > mi->r[ndx].perfect_tx_time && | ||
305 | msr->sample_skipped < 20) | ||
306 | indirect_rate_sampling = true; | ||
307 | |||
308 | if (!indirect_rate_sampling) { | ||
281 | if (msr->sample_limit != 0) { | 309 | if (msr->sample_limit != 0) { |
282 | ndx = sample_ndx; | 310 | ndx = sample_ndx; |
283 | mi->sample_count++; | 311 | mi->sample_count++; |
284 | if (msr->sample_limit > 0) | 312 | if (msr->sample_limit > 0) |
285 | msr->sample_limit--; | 313 | msr->sample_limit--; |
286 | } else { | 314 | } else |
287 | sample = false; | 315 | rate_sampling = false; |
288 | } | ||
289 | } else { | 316 | } else { |
290 | /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark | 317 | /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark |
291 | * packets that have the sampling rate deferred to the | 318 | * packets that have the sampling rate deferred to the |
@@ -297,34 +324,39 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, | |||
297 | mi->sample_deferred++; | 324 | mi->sample_deferred++; |
298 | } | 325 | } |
299 | } | 326 | } |
300 | mi->prev_sample = sample; | 327 | mi->prev_sample = rate_sampling; |
301 | 328 | ||
302 | /* If we're not using MRR and the sampling rate already | 329 | /* If we're not using MRR and the sampling rate already |
303 | * has a probability of >95%, we shouldn't be attempting | 330 | * has a probability of >95%, we shouldn't be attempting |
304 | * to use it, as this only wastes precious airtime */ | 331 | * to use it, as this only wastes precious airtime */ |
305 | if (!mrr && sample && (mi->r[ndx].probability > 17100)) | 332 | if (!mrr_capable && rate_sampling && |
306 | ndx = mi->max_tp_rate; | 333 | (mi->r[ndx].probability > MINSTREL_FRAC(95, 100))) |
334 | ndx = mi->max_tp_rate[0]; | ||
307 | 335 | ||
336 | /* mrr setup for 1st stage */ | ||
308 | ar[0].idx = mi->r[ndx].rix; | 337 | ar[0].idx = mi->r[ndx].rix; |
309 | ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info); | 338 | ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info); |
310 | 339 | ||
311 | if (!mrr) { | 340 | /* non mrr setup for 2nd stage */ |
312 | if (!sample) | 341 | if (!mrr_capable) { |
342 | if (!rate_sampling) | ||
313 | ar[0].count = mp->max_retry; | 343 | ar[0].count = mp->max_retry; |
314 | ar[1].idx = mi->lowest_rix; | 344 | ar[1].idx = mi->lowest_rix; |
315 | ar[1].count = mp->max_retry; | 345 | ar[1].count = mp->max_retry; |
316 | return; | 346 | return; |
317 | } | 347 | } |
318 | 348 | ||
319 | /* MRR setup */ | 349 | /* mrr setup for 2nd stage */ |
320 | if (sample) { | 350 | if (rate_sampling) { |
321 | if (sample_slower) | 351 | if (indirect_rate_sampling) |
322 | mrr_ndx[0] = sample_ndx; | 352 | mrr_ndx[0] = sample_ndx; |
323 | else | 353 | else |
324 | mrr_ndx[0] = mi->max_tp_rate; | 354 | mrr_ndx[0] = mi->max_tp_rate[0]; |
325 | } else { | 355 | } else { |
326 | mrr_ndx[0] = mi->max_tp_rate2; | 356 | mrr_ndx[0] = mi->max_tp_rate[1]; |
327 | } | 357 | } |
358 | |||
359 | /* mrr setup for 3rd & 4th stage */ | ||
328 | mrr_ndx[1] = mi->max_prob_rate; | 360 | mrr_ndx[1] = mi->max_prob_rate; |
329 | mrr_ndx[2] = 0; | 361 | mrr_ndx[2] = 0; |
330 | for (i = 1; i < 4; i++) { | 362 | for (i = 1; i < 4; i++) { |
@@ -351,26 +383,21 @@ static void | |||
351 | init_sample_table(struct minstrel_sta_info *mi) | 383 | init_sample_table(struct minstrel_sta_info *mi) |
352 | { | 384 | { |
353 | unsigned int i, col, new_idx; | 385 | unsigned int i, col, new_idx; |
354 | unsigned int n_srates = mi->n_rates - 1; | ||
355 | u8 rnd[8]; | 386 | u8 rnd[8]; |
356 | 387 | ||
357 | mi->sample_column = 0; | 388 | mi->sample_column = 0; |
358 | mi->sample_idx = 0; | 389 | mi->sample_row = 0; |
359 | memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates); | 390 | memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); |
360 | 391 | ||
361 | for (col = 0; col < SAMPLE_COLUMNS; col++) { | 392 | for (col = 0; col < SAMPLE_COLUMNS; col++) { |
362 | for (i = 0; i < n_srates; i++) { | 393 | for (i = 0; i < mi->n_rates; i++) { |
363 | get_random_bytes(rnd, sizeof(rnd)); | 394 | get_random_bytes(rnd, sizeof(rnd)); |
364 | new_idx = (i + rnd[i & 7]) % n_srates; | 395 | new_idx = (i + rnd[i & 7]) % mi->n_rates; |
365 | 396 | ||
366 | while (SAMPLE_TBL(mi, new_idx, col) != 0) | 397 | while (SAMPLE_TBL(mi, new_idx, col) != 0xff) |
367 | new_idx = (new_idx + 1) % n_srates; | 398 | new_idx = (new_idx + 1) % mi->n_rates; |
368 | 399 | ||
369 | /* Don't sample the slowest rate (i.e. slowest base | 400 | SAMPLE_TBL(mi, new_idx, col) = i; |
370 | * rate). We must presume that the slowest rate works | ||
371 | * fine, or else other management frames will also be | ||
372 | * failing and the link will break */ | ||
373 | SAMPLE_TBL(mi, new_idx, col) = i + 1; | ||
374 | } | 401 | } |
375 | } | 402 | } |
376 | } | 403 | } |
@@ -542,9 +569,6 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | |||
542 | mp->lookaround_rate = 5; | 569 | mp->lookaround_rate = 5; |
543 | mp->lookaround_rate_mrr = 10; | 570 | mp->lookaround_rate_mrr = 10; |
544 | 571 | ||
545 | /* moving average weight for EWMA */ | ||
546 | mp->ewma_level = 75; | ||
547 | |||
548 | /* maximum time that the hw is allowed to stay in one MRR segment */ | 572 | /* maximum time that the hw is allowed to stay in one MRR segment */ |
549 | mp->segment_size = 6000; | 573 | mp->segment_size = 6000; |
550 | 574 | ||
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 5ecf757817f2..85ebf42cb46d 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
@@ -9,6 +9,28 @@ | |||
9 | #ifndef __RC_MINSTREL_H | 9 | #ifndef __RC_MINSTREL_H |
10 | #define __RC_MINSTREL_H | 10 | #define __RC_MINSTREL_H |
11 | 11 | ||
12 | #define EWMA_LEVEL 75 /* ewma weighting factor [%] */ | ||
13 | #define SAMPLE_COLUMNS 10 /* number of columns in sample table */ | ||
14 | |||
15 | |||
16 | /* scaled fraction values */ | ||
17 | #define MINSTREL_SCALE 16 | ||
18 | #define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) | ||
19 | #define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) | ||
20 | |||
21 | /* number of highest throughput rates to consider*/ | ||
22 | #define MAX_THR_RATES 4 | ||
23 | |||
24 | /* | ||
25 | * Perform EWMA (Exponentially Weighted Moving Average) calculation | ||
26 | */ | ||
27 | static inline int | ||
28 | minstrel_ewma(int old, int new, int weight) | ||
29 | { | ||
30 | return (new * (100 - weight) + old * weight) / 100; | ||
31 | } | ||
32 | |||
33 | |||
12 | struct minstrel_rate { | 34 | struct minstrel_rate { |
13 | int bitrate; | 35 | int bitrate; |
14 | int rix; | 36 | int rix; |
@@ -26,6 +48,7 @@ struct minstrel_rate { | |||
26 | u32 attempts; | 48 | u32 attempts; |
27 | u32 last_attempts; | 49 | u32 last_attempts; |
28 | u32 last_success; | 50 | u32 last_success; |
51 | u8 sample_skipped; | ||
29 | 52 | ||
30 | /* parts per thousand */ | 53 | /* parts per thousand */ |
31 | u32 cur_prob; | 54 | u32 cur_prob; |
@@ -45,14 +68,13 @@ struct minstrel_sta_info { | |||
45 | 68 | ||
46 | unsigned int lowest_rix; | 69 | unsigned int lowest_rix; |
47 | 70 | ||
48 | unsigned int max_tp_rate; | 71 | u8 max_tp_rate[MAX_THR_RATES]; |
49 | unsigned int max_tp_rate2; | 72 | u8 max_prob_rate; |
50 | unsigned int max_prob_rate; | ||
51 | unsigned int packet_count; | 73 | unsigned int packet_count; |
52 | unsigned int sample_count; | 74 | unsigned int sample_count; |
53 | int sample_deferred; | 75 | int sample_deferred; |
54 | 76 | ||
55 | unsigned int sample_idx; | 77 | unsigned int sample_row; |
56 | unsigned int sample_column; | 78 | unsigned int sample_column; |
57 | 79 | ||
58 | int n_rates; | 80 | int n_rates; |
@@ -73,7 +95,6 @@ struct minstrel_priv { | |||
73 | unsigned int cw_min; | 95 | unsigned int cw_min; |
74 | unsigned int cw_max; | 96 | unsigned int cw_max; |
75 | unsigned int max_retry; | 97 | unsigned int max_retry; |
76 | unsigned int ewma_level; | ||
77 | unsigned int segment_size; | 98 | unsigned int segment_size; |
78 | unsigned int update_interval; | 99 | unsigned int update_interval; |
79 | unsigned int lookaround_rate; | 100 | unsigned int lookaround_rate; |
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index d5a56226e675..d1048348d399 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c | |||
@@ -73,15 +73,17 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
73 | for (i = 0; i < mi->n_rates; i++) { | 73 | for (i = 0; i < mi->n_rates; i++) { |
74 | struct minstrel_rate *mr = &mi->r[i]; | 74 | struct minstrel_rate *mr = &mi->r[i]; |
75 | 75 | ||
76 | *(p++) = (i == mi->max_tp_rate) ? 'T' : ' '; | 76 | *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; |
77 | *(p++) = (i == mi->max_tp_rate2) ? 't' : ' '; | 77 | *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; |
78 | *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' '; | ||
79 | *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' '; | ||
78 | *(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; | 80 | *(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; |
79 | p += sprintf(p, "%3u%s", mr->bitrate / 2, | 81 | p += sprintf(p, "%3u%s", mr->bitrate / 2, |
80 | (mr->bitrate & 1 ? ".5" : " ")); | 82 | (mr->bitrate & 1 ? ".5" : " ")); |
81 | 83 | ||
82 | tp = mr->cur_tp / ((18000 << 10) / 96); | 84 | tp = MINSTREL_TRUNC(mr->cur_tp / 10); |
83 | prob = mr->cur_prob / 18; | 85 | prob = MINSTREL_TRUNC(mr->cur_prob * 1000); |
84 | eprob = mr->probability / 18; | 86 | eprob = MINSTREL_TRUNC(mr->probability * 1000); |
85 | 87 | ||
86 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " | 88 | p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u " |
87 | "%3u(%3u) %8llu %8llu\n", | 89 | "%3u(%3u) %8llu %8llu\n", |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 3af141c69712..749552bdcfe1 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -17,8 +17,6 @@ | |||
17 | #include "rc80211_minstrel_ht.h" | 17 | #include "rc80211_minstrel_ht.h" |
18 | 18 | ||
19 | #define AVG_PKT_SIZE 1200 | 19 | #define AVG_PKT_SIZE 1200 |
20 | #define SAMPLE_COLUMNS 10 | ||
21 | #define EWMA_LEVEL 75 | ||
22 | 20 | ||
23 | /* Number of bits for an average sized packet */ | 21 | /* Number of bits for an average sized packet */ |
24 | #define MCS_NBITS (AVG_PKT_SIZE << 3) | 22 | #define MCS_NBITS (AVG_PKT_SIZE << 3) |
@@ -26,11 +24,11 @@ | |||
26 | /* Number of symbols for a packet with (bps) bits per symbol */ | 24 | /* Number of symbols for a packet with (bps) bits per symbol */ |
27 | #define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps)) | 25 | #define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps)) |
28 | 26 | ||
29 | /* Transmission time for a packet containing (syms) symbols */ | 27 | /* Transmission time (nanoseconds) for a packet containing (syms) symbols */ |
30 | #define MCS_SYMBOL_TIME(sgi, syms) \ | 28 | #define MCS_SYMBOL_TIME(sgi, syms) \ |
31 | (sgi ? \ | 29 | (sgi ? \ |
32 | ((syms) * 18 + 4) / 5 : /* syms * 3.6 us */ \ | 30 | ((syms) * 18000 + 4000) / 5 : /* syms * 3.6 us */ \ |
33 | (syms) << 2 /* syms * 4 us */ \ | 31 | ((syms) * 1000) << 2 /* syms * 4 us */ \ |
34 | ) | 32 | ) |
35 | 33 | ||
36 | /* Transmit duration for the raw data part of an average sized packet */ | 34 | /* Transmit duration for the raw data part of an average sized packet */ |
@@ -64,9 +62,9 @@ | |||
64 | } | 62 | } |
65 | 63 | ||
66 | #define CCK_DURATION(_bitrate, _short, _len) \ | 64 | #define CCK_DURATION(_bitrate, _short, _len) \ |
67 | (10 /* SIFS */ + \ | 65 | (1000 * (10 /* SIFS */ + \ |
68 | (_short ? 72 + 24 : 144 + 48 ) + \ | 66 | (_short ? 72 + 24 : 144 + 48 ) + \ |
69 | (8 * (_len + 4) * 10) / (_bitrate)) | 67 | (8 * (_len + 4) * 10) / (_bitrate))) |
70 | 68 | ||
71 | #define CCK_ACK_DURATION(_bitrate, _short) \ | 69 | #define CCK_ACK_DURATION(_bitrate, _short) \ |
72 | (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ | 70 | (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ |
@@ -129,15 +127,6 @@ const struct mcs_group minstrel_mcs_groups[] = { | |||
129 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; | 127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; |
130 | 128 | ||
131 | /* | 129 | /* |
132 | * Perform EWMA (Exponentially Weighted Moving Average) calculation | ||
133 | */ | ||
134 | static int | ||
135 | minstrel_ewma(int old, int new, int weight) | ||
136 | { | ||
137 | return (new * (100 - weight) + old * weight) / 100; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Look up an MCS group index based on mac80211 rate information | 130 | * Look up an MCS group index based on mac80211 rate information |
142 | */ | 131 | */ |
143 | static int | 132 | static int |
@@ -211,7 +200,8 @@ static void | |||
211 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | 200 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) |
212 | { | 201 | { |
213 | struct minstrel_rate_stats *mr; | 202 | struct minstrel_rate_stats *mr; |
214 | unsigned int usecs = 0; | 203 | unsigned int nsecs = 0; |
204 | unsigned int tp; | ||
215 | 205 | ||
216 | mr = &mi->groups[group].rates[rate]; | 206 | mr = &mi->groups[group].rates[rate]; |
217 | 207 | ||
@@ -221,10 +211,12 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | |||
221 | } | 211 | } |
222 | 212 | ||
223 | if (group != MINSTREL_CCK_GROUP) | 213 | if (group != MINSTREL_CCK_GROUP) |
224 | usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); | 214 | nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); |
225 | 215 | ||
226 | usecs += minstrel_mcs_groups[group].duration[rate]; | 216 | nsecs += minstrel_mcs_groups[group].duration[rate]; |
227 | mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); | 217 | tp = 1000000 * ((mr->probability * 1000) / nsecs); |
218 | |||
219 | mr->cur_tp = MINSTREL_TRUNC(tp); | ||
228 | } | 220 | } |
229 | 221 | ||
230 | /* | 222 | /* |
@@ -308,8 +300,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
308 | } | 300 | } |
309 | } | 301 | } |
310 | 302 | ||
311 | /* try to sample up to half of the available rates during each interval */ | 303 | /* try to sample all available rates during each interval */ |
312 | mi->sample_count *= 4; | 304 | mi->sample_count *= 8; |
313 | 305 | ||
314 | cur_prob = 0; | 306 | cur_prob = 0; |
315 | cur_prob_tp = 0; | 307 | cur_prob_tp = 0; |
@@ -320,20 +312,13 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
320 | if (!mg->supported) | 312 | if (!mg->supported) |
321 | continue; | 313 | continue; |
322 | 314 | ||
323 | mr = minstrel_get_ratestats(mi, mg->max_prob_rate); | ||
324 | if (cur_prob_tp < mr->cur_tp && | ||
325 | minstrel_mcs_groups[group].streams == 1) { | ||
326 | mi->max_prob_rate = mg->max_prob_rate; | ||
327 | cur_prob = mr->cur_prob; | ||
328 | cur_prob_tp = mr->cur_tp; | ||
329 | } | ||
330 | |||
331 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate); | 315 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate); |
332 | if (cur_tp < mr->cur_tp) { | 316 | if (cur_tp < mr->cur_tp) { |
333 | mi->max_tp_rate2 = mi->max_tp_rate; | 317 | mi->max_tp_rate2 = mi->max_tp_rate; |
334 | cur_tp2 = cur_tp; | 318 | cur_tp2 = cur_tp; |
335 | mi->max_tp_rate = mg->max_tp_rate; | 319 | mi->max_tp_rate = mg->max_tp_rate; |
336 | cur_tp = mr->cur_tp; | 320 | cur_tp = mr->cur_tp; |
321 | mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1; | ||
337 | } | 322 | } |
338 | 323 | ||
339 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); | 324 | mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); |
@@ -343,6 +328,23 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
343 | } | 328 | } |
344 | } | 329 | } |
345 | 330 | ||
331 | if (mi->max_prob_streams < 1) | ||
332 | mi->max_prob_streams = 1; | ||
333 | |||
334 | for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { | ||
335 | mg = &mi->groups[group]; | ||
336 | if (!mg->supported) | ||
337 | continue; | ||
338 | mr = minstrel_get_ratestats(mi, mg->max_prob_rate); | ||
339 | if (cur_prob_tp < mr->cur_tp && | ||
340 | minstrel_mcs_groups[group].streams <= mi->max_prob_streams) { | ||
341 | mi->max_prob_rate = mg->max_prob_rate; | ||
342 | cur_prob = mr->cur_prob; | ||
343 | cur_prob_tp = mr->cur_tp; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | |||
346 | mi->stats_update = jiffies; | 348 | mi->stats_update = jiffies; |
347 | } | 349 | } |
348 | 350 | ||
@@ -467,7 +469,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
467 | 469 | ||
468 | if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { | 470 | if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { |
469 | mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); | 471 | mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); |
470 | mi->sample_tries = 2; | 472 | mi->sample_tries = 1; |
471 | mi->sample_count--; | 473 | mi->sample_count--; |
472 | } | 474 | } |
473 | 475 | ||
@@ -536,7 +538,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
536 | mr->retry_updated = true; | 538 | mr->retry_updated = true; |
537 | 539 | ||
538 | group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 540 | group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
539 | tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len; | 541 | tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000; |
540 | 542 | ||
541 | /* Contention time for first 2 tries */ | 543 | /* Contention time for first 2 tries */ |
542 | ctime = (t_slot * cw) >> 1; | 544 | ctime = (t_slot * cw) >> 1; |
@@ -616,6 +618,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
616 | { | 618 | { |
617 | struct minstrel_rate_stats *mr; | 619 | struct minstrel_rate_stats *mr; |
618 | struct minstrel_mcs_group_data *mg; | 620 | struct minstrel_mcs_group_data *mg; |
621 | unsigned int sample_dur, sample_group; | ||
619 | int sample_idx = 0; | 622 | int sample_idx = 0; |
620 | 623 | ||
621 | if (mi->sample_wait > 0) { | 624 | if (mi->sample_wait > 0) { |
@@ -626,11 +629,11 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
626 | if (!mi->sample_tries) | 629 | if (!mi->sample_tries) |
627 | return -1; | 630 | return -1; |
628 | 631 | ||
629 | mi->sample_tries--; | ||
630 | mg = &mi->groups[mi->sample_group]; | 632 | mg = &mi->groups[mi->sample_group]; |
631 | sample_idx = sample_table[mg->column][mg->index]; | 633 | sample_idx = sample_table[mg->column][mg->index]; |
632 | mr = &mg->rates[sample_idx]; | 634 | mr = &mg->rates[sample_idx]; |
633 | sample_idx += mi->sample_group * MCS_GROUP_RATES; | 635 | sample_group = mi->sample_group; |
636 | sample_idx += sample_group * MCS_GROUP_RATES; | ||
634 | minstrel_next_sample_idx(mi); | 637 | minstrel_next_sample_idx(mi); |
635 | 638 | ||
636 | /* | 639 | /* |
@@ -651,14 +654,18 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
651 | * Make sure that lower rates get sampled only occasionally, | 654 | * Make sure that lower rates get sampled only occasionally, |
652 | * if the link is working perfectly. | 655 | * if the link is working perfectly. |
653 | */ | 656 | */ |
654 | if (minstrel_get_duration(sample_idx) > | 657 | sample_dur = minstrel_get_duration(sample_idx); |
655 | minstrel_get_duration(mi->max_tp_rate)) { | 658 | if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) && |
659 | (mi->max_prob_streams < | ||
660 | minstrel_mcs_groups[sample_group].streams || | ||
661 | sample_dur >= minstrel_get_duration(mi->max_prob_rate))) { | ||
656 | if (mr->sample_skipped < 20) | 662 | if (mr->sample_skipped < 20) |
657 | return -1; | 663 | return -1; |
658 | 664 | ||
659 | if (mi->sample_slow++ > 2) | 665 | if (mi->sample_slow++ > 2) |
660 | return -1; | 666 | return -1; |
661 | } | 667 | } |
668 | mi->sample_tries--; | ||
662 | 669 | ||
663 | return sample_idx; | 670 | return sample_idx; |
664 | } | 671 | } |
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 302dbd52180d..9b16e9de9923 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -16,11 +16,6 @@ | |||
16 | #define MINSTREL_MAX_STREAMS 3 | 16 | #define MINSTREL_MAX_STREAMS 3 |
17 | #define MINSTREL_STREAM_GROUPS 4 | 17 | #define MINSTREL_STREAM_GROUPS 4 |
18 | 18 | ||
19 | /* scaled fraction values */ | ||
20 | #define MINSTREL_SCALE 16 | ||
21 | #define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) | ||
22 | #define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) | ||
23 | |||
24 | #define MCS_GROUP_RATES 8 | 19 | #define MCS_GROUP_RATES 8 |
25 | 20 | ||
26 | struct mcs_group { | 21 | struct mcs_group { |
@@ -85,6 +80,7 @@ struct minstrel_ht_sta { | |||
85 | 80 | ||
86 | /* best probability rate */ | 81 | /* best probability rate */ |
87 | unsigned int max_prob_rate; | 82 | unsigned int max_prob_rate; |
83 | unsigned int max_prob_streams; | ||
88 | 84 | ||
89 | /* time of last status update */ | 85 | /* time of last status update */ |
90 | unsigned long stats_update; | 86 | unsigned long stats_update; |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bb73ed2d20b9..5b4492af4e85 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -648,24 +648,6 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
648 | return RX_CONTINUE; | 648 | return RX_CONTINUE; |
649 | } | 649 | } |
650 | 650 | ||
651 | #define SEQ_MODULO 0x1000 | ||
652 | #define SEQ_MASK 0xfff | ||
653 | |||
654 | static inline int seq_less(u16 sq1, u16 sq2) | ||
655 | { | ||
656 | return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); | ||
657 | } | ||
658 | |||
659 | static inline u16 seq_inc(u16 sq) | ||
660 | { | ||
661 | return (sq + 1) & SEQ_MASK; | ||
662 | } | ||
663 | |||
664 | static inline u16 seq_sub(u16 sq1, u16 sq2) | ||
665 | { | ||
666 | return (sq1 - sq2) & SEQ_MASK; | ||
667 | } | ||
668 | |||
669 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | 651 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, |
670 | struct tid_ampdu_rx *tid_agg_rx, | 652 | struct tid_ampdu_rx *tid_agg_rx, |
671 | int index, | 653 | int index, |
@@ -687,7 +669,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | |||
687 | __skb_queue_tail(frames, skb); | 669 | __skb_queue_tail(frames, skb); |
688 | 670 | ||
689 | no_frame: | 671 | no_frame: |
690 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 672 | tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num); |
691 | } | 673 | } |
692 | 674 | ||
693 | static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, | 675 | static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, |
@@ -699,8 +681,9 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata | |||
699 | 681 | ||
700 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 682 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
701 | 683 | ||
702 | while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { | 684 | while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) { |
703 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 685 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, |
686 | tid_agg_rx->ssn) % | ||
704 | tid_agg_rx->buf_size; | 687 | tid_agg_rx->buf_size; |
705 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 688 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
706 | frames); | 689 | frames); |
@@ -727,8 +710,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
727 | lockdep_assert_held(&tid_agg_rx->reorder_lock); | 710 | lockdep_assert_held(&tid_agg_rx->reorder_lock); |
728 | 711 | ||
729 | /* release the buffer until next missing frame */ | 712 | /* release the buffer until next missing frame */ |
730 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 713 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, |
731 | tid_agg_rx->buf_size; | 714 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; |
732 | if (!tid_agg_rx->reorder_buf[index] && | 715 | if (!tid_agg_rx->reorder_buf[index] && |
733 | tid_agg_rx->stored_mpdu_num) { | 716 | tid_agg_rx->stored_mpdu_num) { |
734 | /* | 717 | /* |
@@ -756,19 +739,22 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, | |||
756 | * Increment the head seq# also for the skipped slots. | 739 | * Increment the head seq# also for the skipped slots. |
757 | */ | 740 | */ |
758 | tid_agg_rx->head_seq_num = | 741 | tid_agg_rx->head_seq_num = |
759 | (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK; | 742 | (tid_agg_rx->head_seq_num + |
743 | skipped) & IEEE80211_SN_MASK; | ||
760 | skipped = 0; | 744 | skipped = 0; |
761 | } | 745 | } |
762 | } else while (tid_agg_rx->reorder_buf[index]) { | 746 | } else while (tid_agg_rx->reorder_buf[index]) { |
763 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, | 747 | ieee80211_release_reorder_frame(sdata, tid_agg_rx, index, |
764 | frames); | 748 | frames); |
765 | index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % | 749 | index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, |
750 | tid_agg_rx->ssn) % | ||
766 | tid_agg_rx->buf_size; | 751 | tid_agg_rx->buf_size; |
767 | } | 752 | } |
768 | 753 | ||
769 | if (tid_agg_rx->stored_mpdu_num) { | 754 | if (tid_agg_rx->stored_mpdu_num) { |
770 | j = index = seq_sub(tid_agg_rx->head_seq_num, | 755 | j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num, |
771 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | 756 | tid_agg_rx->ssn) % |
757 | tid_agg_rx->buf_size; | ||
772 | 758 | ||
773 | for (; j != (index - 1) % tid_agg_rx->buf_size; | 759 | for (; j != (index - 1) % tid_agg_rx->buf_size; |
774 | j = (j + 1) % tid_agg_rx->buf_size) { | 760 | j = (j + 1) % tid_agg_rx->buf_size) { |
@@ -809,7 +795,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
809 | head_seq_num = tid_agg_rx->head_seq_num; | 795 | head_seq_num = tid_agg_rx->head_seq_num; |
810 | 796 | ||
811 | /* frame with out of date sequence number */ | 797 | /* frame with out of date sequence number */ |
812 | if (seq_less(mpdu_seq_num, head_seq_num)) { | 798 | if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) { |
813 | dev_kfree_skb(skb); | 799 | dev_kfree_skb(skb); |
814 | goto out; | 800 | goto out; |
815 | } | 801 | } |
@@ -818,8 +804,9 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
818 | * If frame the sequence number exceeds our buffering window | 804 | * If frame the sequence number exceeds our buffering window |
819 | * size release some previous frames to make room for this one. | 805 | * size release some previous frames to make room for this one. |
820 | */ | 806 | */ |
821 | if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { | 807 | if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) { |
822 | head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); | 808 | head_seq_num = ieee80211_sn_inc( |
809 | ieee80211_sn_sub(mpdu_seq_num, buf_size)); | ||
823 | /* release stored frames up to new head to stack */ | 810 | /* release stored frames up to new head to stack */ |
824 | ieee80211_release_reorder_frames(sdata, tid_agg_rx, | 811 | ieee80211_release_reorder_frames(sdata, tid_agg_rx, |
825 | head_seq_num, frames); | 812 | head_seq_num, frames); |
@@ -827,7 +814,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
827 | 814 | ||
828 | /* Now the new frame is always in the range of the reordering buffer */ | 815 | /* Now the new frame is always in the range of the reordering buffer */ |
829 | 816 | ||
830 | index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; | 817 | index = ieee80211_sn_sub(mpdu_seq_num, |
818 | tid_agg_rx->ssn) % tid_agg_rx->buf_size; | ||
831 | 819 | ||
832 | /* check if we already stored this frame */ | 820 | /* check if we already stored this frame */ |
833 | if (tid_agg_rx->reorder_buf[index]) { | 821 | if (tid_agg_rx->reorder_buf[index]) { |
@@ -843,7 +831,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata | |||
843 | */ | 831 | */ |
844 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && | 832 | if (mpdu_seq_num == tid_agg_rx->head_seq_num && |
845 | tid_agg_rx->stored_mpdu_num == 0) { | 833 | tid_agg_rx->stored_mpdu_num == 0) { |
846 | tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); | 834 | tid_agg_rx->head_seq_num = |
835 | ieee80211_sn_inc(tid_agg_rx->head_seq_num); | ||
847 | ret = false; | 836 | ret = false; |
848 | goto out; | 837 | goto out; |
849 | } | 838 | } |
@@ -1894,8 +1883,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1894 | * 'align' will only take the values 0 or 2 here | 1883 | * 'align' will only take the values 0 or 2 here |
1895 | * since all frames are required to be aligned | 1884 | * since all frames are required to be aligned |
1896 | * to 2-byte boundaries when being passed to | 1885 | * to 2-byte boundaries when being passed to |
1897 | * mac80211. That also explains the __skb_push() | 1886 | * mac80211; the code here works just as well if |
1898 | * below. | 1887 | * that isn't true, but mac80211 assumes it can |
1888 | * access fields as 2-byte aligned (e.g. for | ||
1889 | * compare_ether_addr) | ||
1899 | */ | 1890 | */ |
1900 | align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; | 1891 | align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3; |
1901 | if (align) { | 1892 | if (align) { |
@@ -2552,7 +2543,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2552 | case WLAN_SP_MESH_PEERING_CONFIRM: | 2543 | case WLAN_SP_MESH_PEERING_CONFIRM: |
2553 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2544 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2554 | goto invalid; | 2545 | goto invalid; |
2555 | if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE) | 2546 | if (sdata->u.mesh.user_mpm) |
2556 | /* userspace handles this frame */ | 2547 | /* userspace handles this frame */ |
2557 | break; | 2548 | break; |
2558 | goto queue; | 2549 | goto queue; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a79ce820cb50..3644ad79688a 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -342,6 +342,11 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
342 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 342 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
343 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 343 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
344 | mutex_init(&sta->ampdu_mlme.mtx); | 344 | mutex_init(&sta->ampdu_mlme.mtx); |
345 | #ifdef CONFIG_MAC80211_MESH | ||
346 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
347 | !sdata->u.mesh.user_mpm) | ||
348 | init_timer(&sta->plink_timer); | ||
349 | #endif | ||
345 | 350 | ||
346 | memcpy(sta->sta.addr, addr, ETH_ALEN); | 351 | memcpy(sta->sta.addr, addr, ETH_ALEN); |
347 | sta->local = local; | 352 | sta->local = local; |
@@ -794,9 +799,11 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
794 | 799 | ||
795 | mutex_lock(&local->key_mtx); | 800 | mutex_lock(&local->key_mtx); |
796 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 801 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
797 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); | 802 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]), |
803 | true); | ||
798 | if (sta->ptk) | 804 | if (sta->ptk) |
799 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk)); | 805 | __ieee80211_key_free(key_mtx_dereference(local, sta->ptk), |
806 | true); | ||
800 | mutex_unlock(&local->key_mtx); | 807 | mutex_unlock(&local->key_mtx); |
801 | 808 | ||
802 | sta->dead = true; | 809 | sta->dead = true; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4947341a2a82..e5868c32d1a3 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -281,7 +281,6 @@ struct sta_ampdu_mlme { | |||
281 | * @plink_state: peer link state | 281 | * @plink_state: peer link state |
282 | * @plink_timeout: timeout of peer link | 282 | * @plink_timeout: timeout of peer link |
283 | * @plink_timer: peer link watch timer | 283 | * @plink_timer: peer link watch timer |
284 | * @plink_timer_was_running: used by suspend/resume to restore timers | ||
285 | * @t_offset: timing offset relative to this host | 284 | * @t_offset: timing offset relative to this host |
286 | * @t_offset_setpoint: reference timing offset of this sta to be used when | 285 | * @t_offset_setpoint: reference timing offset of this sta to be used when |
287 | * calculating clockdrift | 286 | * calculating clockdrift |
@@ -379,7 +378,6 @@ struct sta_info { | |||
379 | __le16 reason; | 378 | __le16 reason; |
380 | u8 plink_retries; | 379 | u8 plink_retries; |
381 | bool ignore_plink_timer; | 380 | bool ignore_plink_timer; |
382 | bool plink_timer_was_running; | ||
383 | enum nl80211_plink_state plink_state; | 381 | enum nl80211_plink_state plink_state; |
384 | u32 plink_timeout; | 382 | u32 plink_timeout; |
385 | struct timer_list plink_timer; | 383 | struct timer_list plink_timer; |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 3d7cd2a0582f..e7db2b804e0c 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1042,15 +1042,17 @@ TRACE_EVENT(drv_remain_on_channel, | |||
1042 | TP_PROTO(struct ieee80211_local *local, | 1042 | TP_PROTO(struct ieee80211_local *local, |
1043 | struct ieee80211_sub_if_data *sdata, | 1043 | struct ieee80211_sub_if_data *sdata, |
1044 | struct ieee80211_channel *chan, | 1044 | struct ieee80211_channel *chan, |
1045 | unsigned int duration), | 1045 | unsigned int duration, |
1046 | enum ieee80211_roc_type type), | ||
1046 | 1047 | ||
1047 | TP_ARGS(local, sdata, chan, duration), | 1048 | TP_ARGS(local, sdata, chan, duration, type), |
1048 | 1049 | ||
1049 | TP_STRUCT__entry( | 1050 | TP_STRUCT__entry( |
1050 | LOCAL_ENTRY | 1051 | LOCAL_ENTRY |
1051 | VIF_ENTRY | 1052 | VIF_ENTRY |
1052 | __field(int, center_freq) | 1053 | __field(int, center_freq) |
1053 | __field(unsigned int, duration) | 1054 | __field(unsigned int, duration) |
1055 | __field(u32, type) | ||
1054 | ), | 1056 | ), |
1055 | 1057 | ||
1056 | TP_fast_assign( | 1058 | TP_fast_assign( |
@@ -1058,12 +1060,13 @@ TRACE_EVENT(drv_remain_on_channel, | |||
1058 | VIF_ASSIGN; | 1060 | VIF_ASSIGN; |
1059 | __entry->center_freq = chan->center_freq; | 1061 | __entry->center_freq = chan->center_freq; |
1060 | __entry->duration = duration; | 1062 | __entry->duration = duration; |
1063 | __entry->type = type; | ||
1061 | ), | 1064 | ), |
1062 | 1065 | ||
1063 | TP_printk( | 1066 | TP_printk( |
1064 | LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms", | 1067 | LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms type=%d", |
1065 | LOCAL_PR_ARG, VIF_PR_ARG, | 1068 | LOCAL_PR_ARG, VIF_PR_ARG, |
1066 | __entry->center_freq, __entry->duration | 1069 | __entry->center_freq, __entry->duration, __entry->type |
1067 | ) | 1070 | ) |
1068 | ); | 1071 | ); |
1069 | 1072 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index de8548bf0a7f..8914d2d2881a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1231,34 +1231,40 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local, | |||
1231 | if (local->queue_stop_reasons[q] || | 1231 | if (local->queue_stop_reasons[q] || |
1232 | (!txpending && !skb_queue_empty(&local->pending[q]))) { | 1232 | (!txpending && !skb_queue_empty(&local->pending[q]))) { |
1233 | if (unlikely(info->flags & | 1233 | if (unlikely(info->flags & |
1234 | IEEE80211_TX_INTFL_OFFCHAN_TX_OK && | 1234 | IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) { |
1235 | local->queue_stop_reasons[q] & | 1235 | if (local->queue_stop_reasons[q] & |
1236 | ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL))) { | 1236 | ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL)) { |
1237 | /* | ||
1238 | * Drop off-channel frames if queues | ||
1239 | * are stopped for any reason other | ||
1240 | * than off-channel operation. Never | ||
1241 | * queue them. | ||
1242 | */ | ||
1243 | spin_unlock_irqrestore( | ||
1244 | &local->queue_stop_reason_lock, | ||
1245 | flags); | ||
1246 | ieee80211_purge_tx_queue(&local->hw, | ||
1247 | skbs); | ||
1248 | return true; | ||
1249 | } | ||
1250 | } else { | ||
1251 | |||
1237 | /* | 1252 | /* |
1238 | * Drop off-channel frames if queues are stopped | 1253 | * Since queue is stopped, queue up frames for |
1239 | * for any reason other than off-channel | 1254 | * later transmission from the tx-pending |
1240 | * operation. Never queue them. | 1255 | * tasklet when the queue is woken again. |
1241 | */ | 1256 | */ |
1242 | spin_unlock_irqrestore( | 1257 | if (txpending) |
1243 | &local->queue_stop_reason_lock, flags); | 1258 | skb_queue_splice_init(skbs, |
1244 | ieee80211_purge_tx_queue(&local->hw, skbs); | 1259 | &local->pending[q]); |
1245 | return true; | 1260 | else |
1261 | skb_queue_splice_tail_init(skbs, | ||
1262 | &local->pending[q]); | ||
1263 | |||
1264 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
1265 | flags); | ||
1266 | return false; | ||
1246 | } | 1267 | } |
1247 | |||
1248 | /* | ||
1249 | * Since queue is stopped, queue up frames for later | ||
1250 | * transmission from the tx-pending tasklet when the | ||
1251 | * queue is woken again. | ||
1252 | */ | ||
1253 | if (txpending) | ||
1254 | skb_queue_splice_init(skbs, &local->pending[q]); | ||
1255 | else | ||
1256 | skb_queue_splice_tail_init(skbs, | ||
1257 | &local->pending[q]); | ||
1258 | |||
1259 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
1260 | flags); | ||
1261 | return false; | ||
1262 | } | 1268 | } |
1263 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 1269 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
1264 | 1270 | ||
@@ -1844,9 +1850,24 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1844 | } | 1850 | } |
1845 | 1851 | ||
1846 | if (!is_multicast_ether_addr(skb->data)) { | 1852 | if (!is_multicast_ether_addr(skb->data)) { |
1853 | struct sta_info *next_hop; | ||
1854 | bool mpp_lookup = true; | ||
1855 | |||
1847 | mpath = mesh_path_lookup(sdata, skb->data); | 1856 | mpath = mesh_path_lookup(sdata, skb->data); |
1848 | if (!mpath) | 1857 | if (mpath) { |
1858 | mpp_lookup = false; | ||
1859 | next_hop = rcu_dereference(mpath->next_hop); | ||
1860 | if (!next_hop || | ||
1861 | !(mpath->flags & (MESH_PATH_ACTIVE | | ||
1862 | MESH_PATH_RESOLVING))) | ||
1863 | mpp_lookup = true; | ||
1864 | } | ||
1865 | |||
1866 | if (mpp_lookup) | ||
1849 | mppath = mpp_path_lookup(sdata, skb->data); | 1867 | mppath = mpp_path_lookup(sdata, skb->data); |
1868 | |||
1869 | if (mppath && mpath) | ||
1870 | mesh_path_del(mpath->sdata, mpath->dst); | ||
1850 | } | 1871 | } |
1851 | 1872 | ||
1852 | /* | 1873 | /* |
@@ -2350,9 +2371,9 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, | |||
2350 | if (local->tim_in_locked_section) { | 2371 | if (local->tim_in_locked_section) { |
2351 | __ieee80211_beacon_add_tim(sdata, ps, skb); | 2372 | __ieee80211_beacon_add_tim(sdata, ps, skb); |
2352 | } else { | 2373 | } else { |
2353 | spin_lock(&local->tim_lock); | 2374 | spin_lock_bh(&local->tim_lock); |
2354 | __ieee80211_beacon_add_tim(sdata, ps, skb); | 2375 | __ieee80211_beacon_add_tim(sdata, ps, skb); |
2355 | spin_unlock(&local->tim_lock); | 2376 | spin_unlock_bh(&local->tim_lock); |
2356 | } | 2377 | } |
2357 | 2378 | ||
2358 | return 0; | 2379 | return 0; |
@@ -2724,7 +2745,8 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2724 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 2745 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
2725 | } | 2746 | } |
2726 | 2747 | ||
2727 | sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); | 2748 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
2749 | sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); | ||
2728 | if (!ieee80211_tx_prepare(sdata, &tx, skb)) | 2750 | if (!ieee80211_tx_prepare(sdata, &tx, skb)) |
2729 | break; | 2751 | break; |
2730 | dev_kfree_skb_any(skb); | 2752 | dev_kfree_skb_any(skb); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0f38f43ac62e..b7a856e3281b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1357,6 +1357,25 @@ void ieee80211_stop_device(struct ieee80211_local *local) | |||
1357 | drv_stop(local); | 1357 | drv_stop(local); |
1358 | } | 1358 | } |
1359 | 1359 | ||
1360 | static void ieee80211_assign_chanctx(struct ieee80211_local *local, | ||
1361 | struct ieee80211_sub_if_data *sdata) | ||
1362 | { | ||
1363 | struct ieee80211_chanctx_conf *conf; | ||
1364 | struct ieee80211_chanctx *ctx; | ||
1365 | |||
1366 | if (!local->use_chanctx) | ||
1367 | return; | ||
1368 | |||
1369 | mutex_lock(&local->chanctx_mtx); | ||
1370 | conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1371 | lockdep_is_held(&local->chanctx_mtx)); | ||
1372 | if (conf) { | ||
1373 | ctx = container_of(conf, struct ieee80211_chanctx, conf); | ||
1374 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
1375 | } | ||
1376 | mutex_unlock(&local->chanctx_mtx); | ||
1377 | } | ||
1378 | |||
1360 | int ieee80211_reconfig(struct ieee80211_local *local) | 1379 | int ieee80211_reconfig(struct ieee80211_local *local) |
1361 | { | 1380 | { |
1362 | struct ieee80211_hw *hw = &local->hw; | 1381 | struct ieee80211_hw *hw = &local->hw; |
@@ -1445,36 +1464,14 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1445 | } | 1464 | } |
1446 | 1465 | ||
1447 | list_for_each_entry(sdata, &local->interfaces, list) { | 1466 | list_for_each_entry(sdata, &local->interfaces, list) { |
1448 | struct ieee80211_chanctx_conf *ctx_conf; | ||
1449 | |||
1450 | if (!ieee80211_sdata_running(sdata)) | 1467 | if (!ieee80211_sdata_running(sdata)) |
1451 | continue; | 1468 | continue; |
1452 | 1469 | ieee80211_assign_chanctx(local, sdata); | |
1453 | mutex_lock(&local->chanctx_mtx); | ||
1454 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1455 | lockdep_is_held(&local->chanctx_mtx)); | ||
1456 | if (ctx_conf) { | ||
1457 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
1458 | conf); | ||
1459 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
1460 | } | ||
1461 | mutex_unlock(&local->chanctx_mtx); | ||
1462 | } | 1470 | } |
1463 | 1471 | ||
1464 | sdata = rtnl_dereference(local->monitor_sdata); | 1472 | sdata = rtnl_dereference(local->monitor_sdata); |
1465 | if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) { | 1473 | if (sdata && ieee80211_sdata_running(sdata)) |
1466 | struct ieee80211_chanctx_conf *ctx_conf; | 1474 | ieee80211_assign_chanctx(local, sdata); |
1467 | |||
1468 | mutex_lock(&local->chanctx_mtx); | ||
1469 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1470 | lockdep_is_held(&local->chanctx_mtx)); | ||
1471 | if (ctx_conf) { | ||
1472 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
1473 | conf); | ||
1474 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
1475 | } | ||
1476 | mutex_unlock(&local->chanctx_mtx); | ||
1477 | } | ||
1478 | 1475 | ||
1479 | /* add STAs back */ | 1476 | /* add STAs back */ |
1480 | mutex_lock(&local->sta_mtx); | 1477 | mutex_lock(&local->sta_mtx); |
@@ -1534,11 +1531,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1534 | BSS_CHANGED_IDLE | | 1531 | BSS_CHANGED_IDLE | |
1535 | BSS_CHANGED_TXPOWER; | 1532 | BSS_CHANGED_TXPOWER; |
1536 | 1533 | ||
1537 | #ifdef CONFIG_PM | ||
1538 | if (local->resuming && !reconfig_due_to_wowlan) | ||
1539 | sdata->vif.bss_conf = sdata->suspend_bss_conf; | ||
1540 | #endif | ||
1541 | |||
1542 | switch (sdata->vif.type) { | 1534 | switch (sdata->vif.type) { |
1543 | case NL80211_IFTYPE_STATION: | 1535 | case NL80211_IFTYPE_STATION: |
1544 | changed |= BSS_CHANGED_ASSOC | | 1536 | changed |= BSS_CHANGED_ASSOC | |
@@ -1678,28 +1670,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1678 | mb(); | 1670 | mb(); |
1679 | local->resuming = false; | 1671 | local->resuming = false; |
1680 | 1672 | ||
1681 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1682 | switch(sdata->vif.type) { | ||
1683 | case NL80211_IFTYPE_STATION: | ||
1684 | ieee80211_sta_restart(sdata); | ||
1685 | break; | ||
1686 | case NL80211_IFTYPE_ADHOC: | ||
1687 | ieee80211_ibss_restart(sdata); | ||
1688 | break; | ||
1689 | case NL80211_IFTYPE_MESH_POINT: | ||
1690 | ieee80211_mesh_restart(sdata); | ||
1691 | break; | ||
1692 | default: | ||
1693 | break; | ||
1694 | } | ||
1695 | } | ||
1696 | |||
1697 | mod_timer(&local->sta_cleanup, jiffies + 1); | 1673 | mod_timer(&local->sta_cleanup, jiffies + 1); |
1698 | |||
1699 | mutex_lock(&local->sta_mtx); | ||
1700 | list_for_each_entry(sta, &local->sta_list, list) | ||
1701 | mesh_plink_restart(sta); | ||
1702 | mutex_unlock(&local->sta_mtx); | ||
1703 | #else | 1674 | #else |
1704 | WARN_ON(1); | 1675 | WARN_ON(1); |
1705 | #endif | 1676 | #endif |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index a2c2258bc84e..171344d4eb7c 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -13,6 +13,104 @@ | |||
13 | #include "rate.h" | 13 | #include "rate.h" |
14 | 14 | ||
15 | 15 | ||
16 | static void __check_vhtcap_disable(struct ieee80211_sub_if_data *sdata, | ||
17 | struct ieee80211_sta_vht_cap *vht_cap, | ||
18 | u32 flag) | ||
19 | { | ||
20 | __le32 le_flag = cpu_to_le32(flag); | ||
21 | |||
22 | if (sdata->u.mgd.vht_capa_mask.vht_cap_info & le_flag && | ||
23 | !(sdata->u.mgd.vht_capa.vht_cap_info & le_flag)) | ||
24 | vht_cap->cap &= ~flag; | ||
25 | } | ||
26 | |||
27 | void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, | ||
28 | struct ieee80211_sta_vht_cap *vht_cap) | ||
29 | { | ||
30 | int i; | ||
31 | u16 rxmcs_mask, rxmcs_cap, rxmcs_n, txmcs_mask, txmcs_cap, txmcs_n; | ||
32 | |||
33 | if (!vht_cap->vht_supported) | ||
34 | return; | ||
35 | |||
36 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
37 | return; | ||
38 | |||
39 | __check_vhtcap_disable(sdata, vht_cap, | ||
40 | IEEE80211_VHT_CAP_RXLDPC); | ||
41 | __check_vhtcap_disable(sdata, vht_cap, | ||
42 | IEEE80211_VHT_CAP_SHORT_GI_80); | ||
43 | __check_vhtcap_disable(sdata, vht_cap, | ||
44 | IEEE80211_VHT_CAP_SHORT_GI_160); | ||
45 | __check_vhtcap_disable(sdata, vht_cap, | ||
46 | IEEE80211_VHT_CAP_TXSTBC); | ||
47 | __check_vhtcap_disable(sdata, vht_cap, | ||
48 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); | ||
49 | __check_vhtcap_disable(sdata, vht_cap, | ||
50 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); | ||
51 | __check_vhtcap_disable(sdata, vht_cap, | ||
52 | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN); | ||
53 | __check_vhtcap_disable(sdata, vht_cap, | ||
54 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN); | ||
55 | |||
56 | /* Allow user to decrease AMPDU length exponent */ | ||
57 | if (sdata->u.mgd.vht_capa_mask.vht_cap_info & | ||
58 | cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) { | ||
59 | u32 cap, n; | ||
60 | |||
61 | n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) & | ||
62 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
63 | n >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
64 | cap = vht_cap->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
65 | cap >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
66 | |||
67 | if (n < cap) { | ||
68 | vht_cap->cap &= | ||
69 | ~IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; | ||
70 | vht_cap->cap |= | ||
71 | n << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | /* Allow the user to decrease MCSes */ | ||
76 | rxmcs_mask = | ||
77 | le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.rx_mcs_map); | ||
78 | rxmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.rx_mcs_map); | ||
79 | rxmcs_n &= rxmcs_mask; | ||
80 | rxmcs_cap = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); | ||
81 | |||
82 | txmcs_mask = | ||
83 | le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.tx_mcs_map); | ||
84 | txmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.tx_mcs_map); | ||
85 | txmcs_n &= txmcs_mask; | ||
86 | txmcs_cap = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); | ||
87 | for (i = 0; i < 8; i++) { | ||
88 | u8 m, n, c; | ||
89 | |||
90 | m = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
91 | n = (rxmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
92 | c = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
93 | |||
94 | if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) || | ||
95 | n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) { | ||
96 | rxmcs_cap &= ~(3 << 2*i); | ||
97 | rxmcs_cap |= (rxmcs_n & (3 << 2*i)); | ||
98 | } | ||
99 | |||
100 | m = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
101 | n = (txmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
102 | c = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
103 | |||
104 | if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) || | ||
105 | n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) { | ||
106 | txmcs_cap &= ~(3 << 2*i); | ||
107 | txmcs_cap |= (txmcs_n & (3 << 2*i)); | ||
108 | } | ||
109 | } | ||
110 | vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_cap); | ||
111 | vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_cap); | ||
112 | } | ||
113 | |||
16 | void | 114 | void |
17 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 115 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
18 | struct ieee80211_supported_band *sband, | 116 | struct ieee80211_supported_band *sband, |
@@ -20,6 +118,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
20 | struct sta_info *sta) | 118 | struct sta_info *sta) |
21 | { | 119 | { |
22 | struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; | 120 | struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; |
121 | struct ieee80211_sta_vht_cap own_cap; | ||
122 | u32 cap_info, i; | ||
23 | 123 | ||
24 | memset(vht_cap, 0, sizeof(*vht_cap)); | 124 | memset(vht_cap, 0, sizeof(*vht_cap)); |
25 | 125 | ||
@@ -35,12 +135,122 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
35 | 135 | ||
36 | vht_cap->vht_supported = true; | 136 | vht_cap->vht_supported = true; |
37 | 137 | ||
38 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); | 138 | own_cap = sband->vht_cap; |
139 | /* | ||
140 | * If user has specified capability overrides, take care | ||
141 | * of that if the station we're setting up is the AP that | ||
142 | * we advertised a restricted capability set to. Override | ||
143 | * our own capabilities and then use those below. | ||
144 | */ | ||
145 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
146 | !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
147 | ieee80211_apply_vhtcap_overrides(sdata, &own_cap); | ||
148 | |||
149 | /* take some capabilities as-is */ | ||
150 | cap_info = le32_to_cpu(vht_cap_ie->vht_cap_info); | ||
151 | vht_cap->cap = cap_info; | ||
152 | vht_cap->cap &= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 | | ||
153 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | | ||
154 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | | ||
155 | IEEE80211_VHT_CAP_RXLDPC | | ||
156 | IEEE80211_VHT_CAP_VHT_TXOP_PS | | ||
157 | IEEE80211_VHT_CAP_HTC_VHT | | ||
158 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | | ||
159 | IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB | | ||
160 | IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB | | ||
161 | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | | ||
162 | IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; | ||
163 | |||
164 | /* and some based on our own capabilities */ | ||
165 | switch (own_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { | ||
166 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: | ||
167 | vht_cap->cap |= cap_info & | ||
168 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; | ||
169 | break; | ||
170 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: | ||
171 | vht_cap->cap |= cap_info & | ||
172 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; | ||
173 | break; | ||
174 | default: | ||
175 | /* nothing */ | ||
176 | break; | ||
177 | } | ||
178 | |||
179 | /* symmetric capabilities */ | ||
180 | vht_cap->cap |= cap_info & own_cap.cap & | ||
181 | (IEEE80211_VHT_CAP_SHORT_GI_80 | | ||
182 | IEEE80211_VHT_CAP_SHORT_GI_160); | ||
183 | |||
184 | /* remaining ones */ | ||
185 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { | ||
186 | vht_cap->cap |= cap_info & | ||
187 | (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | | ||
188 | IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX | | ||
189 | IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); | ||
190 | } | ||
191 | |||
192 | if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) | ||
193 | vht_cap->cap |= cap_info & | ||
194 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; | ||
195 | |||
196 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) | ||
197 | vht_cap->cap |= cap_info & | ||
198 | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; | ||
199 | |||
200 | if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) | ||
201 | vht_cap->cap |= cap_info & | ||
202 | IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; | ||
203 | |||
204 | if (own_cap.cap & IEEE80211_VHT_CAP_TXSTBC) | ||
205 | vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_RXSTBC_MASK; | ||
206 | |||
207 | if (own_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) | ||
208 | vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_TXSTBC; | ||
39 | 209 | ||
40 | /* Copy peer MCS info, the driver might need them. */ | 210 | /* Copy peer MCS info, the driver might need them. */ |
41 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, | 211 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, |
42 | sizeof(struct ieee80211_vht_mcs_info)); | 212 | sizeof(struct ieee80211_vht_mcs_info)); |
43 | 213 | ||
214 | /* but also restrict MCSes */ | ||
215 | for (i = 0; i < 8; i++) { | ||
216 | u16 own_rx, own_tx, peer_rx, peer_tx; | ||
217 | |||
218 | own_rx = le16_to_cpu(own_cap.vht_mcs.rx_mcs_map); | ||
219 | own_rx = (own_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
220 | |||
221 | own_tx = le16_to_cpu(own_cap.vht_mcs.tx_mcs_map); | ||
222 | own_tx = (own_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
223 | |||
224 | peer_rx = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); | ||
225 | peer_rx = (peer_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
226 | |||
227 | peer_tx = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); | ||
228 | peer_tx = (peer_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
229 | |||
230 | if (peer_tx != IEEE80211_VHT_MCS_NOT_SUPPORTED) { | ||
231 | if (own_rx == IEEE80211_VHT_MCS_NOT_SUPPORTED) | ||
232 | peer_tx = IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
233 | else if (own_rx < peer_tx) | ||
234 | peer_tx = own_rx; | ||
235 | } | ||
236 | |||
237 | if (peer_rx != IEEE80211_VHT_MCS_NOT_SUPPORTED) { | ||
238 | if (own_tx == IEEE80211_VHT_MCS_NOT_SUPPORTED) | ||
239 | peer_rx = IEEE80211_VHT_MCS_NOT_SUPPORTED; | ||
240 | else if (own_tx < peer_rx) | ||
241 | peer_rx = own_tx; | ||
242 | } | ||
243 | |||
244 | vht_cap->vht_mcs.rx_mcs_map &= | ||
245 | ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2); | ||
246 | vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(peer_rx << i * 2); | ||
247 | |||
248 | vht_cap->vht_mcs.tx_mcs_map &= | ||
249 | ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2); | ||
250 | vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2); | ||
251 | } | ||
252 | |||
253 | /* finally set up the bandwidth */ | ||
44 | switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { | 254 | switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { |
45 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: | 255 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: |
46 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: | 256 | case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: |
diff --git a/net/rfkill/rfkill-regulator.c b/net/rfkill/rfkill-regulator.c index 4b5ab21ecb24..d11ac79246e4 100644 --- a/net/rfkill/rfkill-regulator.c +++ b/net/rfkill/rfkill-regulator.c | |||
@@ -51,7 +51,7 @@ static int rfkill_regulator_set_block(void *data, bool blocked) | |||
51 | return 0; | 51 | return 0; |
52 | } | 52 | } |
53 | 53 | ||
54 | struct rfkill_ops rfkill_regulator_ops = { | 54 | static struct rfkill_ops rfkill_regulator_ops = { |
55 | .set_block = rfkill_regulator_set_block, | 55 | .set_block = rfkill_regulator_set_block, |
56 | }; | 56 | }; |
57 | 57 | ||
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index a4a14e8f55cc..324e8d851dc4 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
@@ -46,65 +46,3 @@ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
46 | 46 | ||
47 | return err; | 47 | return err; |
48 | } | 48 | } |
49 | |||
50 | void cfg80211_ch_switch_notify(struct net_device *dev, | ||
51 | struct cfg80211_chan_def *chandef) | ||
52 | { | ||
53 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
54 | struct wiphy *wiphy = wdev->wiphy; | ||
55 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
56 | |||
57 | trace_cfg80211_ch_switch_notify(dev, chandef); | ||
58 | |||
59 | wdev_lock(wdev); | ||
60 | |||
61 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
62 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) | ||
63 | goto out; | ||
64 | |||
65 | wdev->channel = chandef->chan; | ||
66 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | ||
67 | out: | ||
68 | wdev_unlock(wdev); | ||
69 | return; | ||
70 | } | ||
71 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | ||
72 | |||
73 | bool cfg80211_rx_spurious_frame(struct net_device *dev, | ||
74 | const u8 *addr, gfp_t gfp) | ||
75 | { | ||
76 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
77 | bool ret; | ||
78 | |||
79 | trace_cfg80211_rx_spurious_frame(dev, addr); | ||
80 | |||
81 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
82 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) { | ||
83 | trace_cfg80211_return_bool(false); | ||
84 | return false; | ||
85 | } | ||
86 | ret = nl80211_unexpected_frame(dev, addr, gfp); | ||
87 | trace_cfg80211_return_bool(ret); | ||
88 | return ret; | ||
89 | } | ||
90 | EXPORT_SYMBOL(cfg80211_rx_spurious_frame); | ||
91 | |||
92 | bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, | ||
93 | const u8 *addr, gfp_t gfp) | ||
94 | { | ||
95 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
96 | bool ret; | ||
97 | |||
98 | trace_cfg80211_rx_unexpected_4addr_frame(dev, addr); | ||
99 | |||
100 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
101 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | ||
102 | wdev->iftype != NL80211_IFTYPE_AP_VLAN)) { | ||
103 | trace_cfg80211_return_bool(false); | ||
104 | return false; | ||
105 | } | ||
106 | ret = nl80211_unexpected_4addr_frame(dev, addr, gfp); | ||
107 | trace_cfg80211_return_bool(ret); | ||
108 | return ret; | ||
109 | } | ||
110 | EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 5ffff039b017..f382cae983ba 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -367,8 +367,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
367 | rdev->wiphy.rts_threshold = (u32) -1; | 367 | rdev->wiphy.rts_threshold = (u32) -1; |
368 | rdev->wiphy.coverage_class = 0; | 368 | rdev->wiphy.coverage_class = 0; |
369 | 369 | ||
370 | rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH | | 370 | rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH; |
371 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | ||
372 | 371 | ||
373 | return &rdev->wiphy; | 372 | return &rdev->wiphy; |
374 | } | 373 | } |
@@ -815,6 +814,46 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | |||
815 | rdev->num_running_monitor_ifaces += num; | 814 | rdev->num_running_monitor_ifaces += num; |
816 | } | 815 | } |
817 | 816 | ||
817 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||
818 | struct wireless_dev *wdev) | ||
819 | { | ||
820 | struct net_device *dev = wdev->netdev; | ||
821 | |||
822 | switch (wdev->iftype) { | ||
823 | case NL80211_IFTYPE_ADHOC: | ||
824 | cfg80211_leave_ibss(rdev, dev, true); | ||
825 | break; | ||
826 | case NL80211_IFTYPE_P2P_CLIENT: | ||
827 | case NL80211_IFTYPE_STATION: | ||
828 | mutex_lock(&rdev->sched_scan_mtx); | ||
829 | __cfg80211_stop_sched_scan(rdev, false); | ||
830 | mutex_unlock(&rdev->sched_scan_mtx); | ||
831 | |||
832 | wdev_lock(wdev); | ||
833 | #ifdef CONFIG_CFG80211_WEXT | ||
834 | kfree(wdev->wext.ie); | ||
835 | wdev->wext.ie = NULL; | ||
836 | wdev->wext.ie_len = 0; | ||
837 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | ||
838 | #endif | ||
839 | __cfg80211_disconnect(rdev, dev, | ||
840 | WLAN_REASON_DEAUTH_LEAVING, true); | ||
841 | cfg80211_mlme_down(rdev, dev); | ||
842 | wdev_unlock(wdev); | ||
843 | break; | ||
844 | case NL80211_IFTYPE_MESH_POINT: | ||
845 | cfg80211_leave_mesh(rdev, dev); | ||
846 | break; | ||
847 | case NL80211_IFTYPE_AP: | ||
848 | cfg80211_stop_ap(rdev, dev); | ||
849 | break; | ||
850 | default: | ||
851 | break; | ||
852 | } | ||
853 | |||
854 | wdev->beacon_interval = 0; | ||
855 | } | ||
856 | |||
818 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 857 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
819 | unsigned long state, | 858 | unsigned long state, |
820 | void *ndev) | 859 | void *ndev) |
@@ -883,38 +922,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
883 | dev->priv_flags |= IFF_DONT_BRIDGE; | 922 | dev->priv_flags |= IFF_DONT_BRIDGE; |
884 | break; | 923 | break; |
885 | case NETDEV_GOING_DOWN: | 924 | case NETDEV_GOING_DOWN: |
886 | switch (wdev->iftype) { | 925 | cfg80211_leave(rdev, wdev); |
887 | case NL80211_IFTYPE_ADHOC: | ||
888 | cfg80211_leave_ibss(rdev, dev, true); | ||
889 | break; | ||
890 | case NL80211_IFTYPE_P2P_CLIENT: | ||
891 | case NL80211_IFTYPE_STATION: | ||
892 | mutex_lock(&rdev->sched_scan_mtx); | ||
893 | __cfg80211_stop_sched_scan(rdev, false); | ||
894 | mutex_unlock(&rdev->sched_scan_mtx); | ||
895 | |||
896 | wdev_lock(wdev); | ||
897 | #ifdef CONFIG_CFG80211_WEXT | ||
898 | kfree(wdev->wext.ie); | ||
899 | wdev->wext.ie = NULL; | ||
900 | wdev->wext.ie_len = 0; | ||
901 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | ||
902 | #endif | ||
903 | __cfg80211_disconnect(rdev, dev, | ||
904 | WLAN_REASON_DEAUTH_LEAVING, true); | ||
905 | cfg80211_mlme_down(rdev, dev); | ||
906 | wdev_unlock(wdev); | ||
907 | break; | ||
908 | case NL80211_IFTYPE_MESH_POINT: | ||
909 | cfg80211_leave_mesh(rdev, dev); | ||
910 | break; | ||
911 | case NL80211_IFTYPE_AP: | ||
912 | cfg80211_stop_ap(rdev, dev); | ||
913 | break; | ||
914 | default: | ||
915 | break; | ||
916 | } | ||
917 | wdev->beacon_interval = 0; | ||
918 | break; | 926 | break; |
919 | case NETDEV_DOWN: | 927 | case NETDEV_DOWN: |
920 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | 928 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 3aec0e429d8a..d5d06fdea961 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -330,20 +330,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
330 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 330 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
331 | struct net_device *dev, | 331 | struct net_device *dev, |
332 | struct ieee80211_channel *chan, | 332 | struct ieee80211_channel *chan, |
333 | const u8 *bssid, const u8 *prev_bssid, | 333 | const u8 *bssid, |
334 | const u8 *ssid, int ssid_len, | 334 | const u8 *ssid, int ssid_len, |
335 | const u8 *ie, int ie_len, bool use_mfp, | 335 | struct cfg80211_assoc_request *req); |
336 | struct cfg80211_crypto_settings *crypt, | ||
337 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
338 | struct ieee80211_ht_cap *ht_capa_mask); | ||
339 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 336 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, struct ieee80211_channel *chan, | 337 | struct net_device *dev, |
341 | const u8 *bssid, const u8 *prev_bssid, | 338 | struct ieee80211_channel *chan, |
339 | const u8 *bssid, | ||
342 | const u8 *ssid, int ssid_len, | 340 | const u8 *ssid, int ssid_len, |
343 | const u8 *ie, int ie_len, bool use_mfp, | 341 | struct cfg80211_assoc_request *req); |
344 | struct cfg80211_crypto_settings *crypt, | ||
345 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
346 | struct ieee80211_ht_cap *ht_capa_mask); | ||
347 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 342 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
348 | struct net_device *dev, const u8 *bssid, | 343 | struct net_device *dev, const u8 *bssid, |
349 | const u8 *ie, int ie_len, u16 reason, | 344 | const u8 *ie, int ie_len, u16 reason, |
@@ -375,6 +370,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
375 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); | 370 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); |
376 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | 371 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, |
377 | const struct ieee80211_ht_cap *ht_capa_mask); | 372 | const struct ieee80211_ht_cap *ht_capa_mask); |
373 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | ||
374 | const struct ieee80211_vht_cap *vht_capa_mask); | ||
378 | 375 | ||
379 | /* SME */ | 376 | /* SME */ |
380 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 377 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
@@ -503,6 +500,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
503 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | 500 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, |
504 | enum nl80211_iftype iftype, int num); | 501 | enum nl80211_iftype iftype, int num); |
505 | 502 | ||
503 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||
504 | struct wireless_dev *wdev); | ||
505 | |||
506 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | 506 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 |
507 | 507 | ||
508 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 508 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 55957a284f6c..0bb93f3061a4 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -85,6 +85,7 @@ const struct mesh_setup default_mesh_setup = { | |||
85 | .ie = NULL, | 85 | .ie = NULL, |
86 | .ie_len = 0, | 86 | .ie_len = 0, |
87 | .is_secure = false, | 87 | .is_secure = false, |
88 | .user_mpm = false, | ||
88 | .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL, | 89 | .beacon_interval = MESH_DEFAULT_BEACON_INTERVAL, |
89 | .dtim_period = MESH_DEFAULT_DTIM_PERIOD, | 90 | .dtim_period = MESH_DEFAULT_DTIM_PERIOD, |
90 | }; | 91 | }; |
@@ -233,20 +234,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
233 | return 0; | 234 | return 0; |
234 | } | 235 | } |
235 | 236 | ||
236 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, | ||
237 | const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp) | ||
238 | { | ||
239 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
240 | |||
241 | trace_cfg80211_notify_new_peer_candidate(dev, macaddr); | ||
242 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | ||
243 | return; | ||
244 | |||
245 | nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev, | ||
246 | macaddr, ie, ie_len, gfp); | ||
247 | } | ||
248 | EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate); | ||
249 | |||
250 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | 237 | static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, |
251 | struct net_device *dev) | 238 | struct net_device *dev) |
252 | { | 239 | { |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index caddca35d686..390198bf4b36 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -187,30 +187,6 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) | |||
187 | } | 187 | } |
188 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 188 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
189 | 189 | ||
190 | void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, | ||
191 | size_t len) | ||
192 | { | ||
193 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
194 | struct wiphy *wiphy = wdev->wiphy; | ||
195 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
196 | |||
197 | trace_cfg80211_send_unprot_deauth(dev); | ||
198 | nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC); | ||
199 | } | ||
200 | EXPORT_SYMBOL(cfg80211_send_unprot_deauth); | ||
201 | |||
202 | void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, | ||
203 | size_t len) | ||
204 | { | ||
205 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
206 | struct wiphy *wiphy = wdev->wiphy; | ||
207 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
208 | |||
209 | trace_cfg80211_send_unprot_disassoc(dev); | ||
210 | nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC); | ||
211 | } | ||
212 | EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); | ||
213 | |||
214 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | 190 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) |
215 | { | 191 | { |
216 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 192 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -367,27 +343,38 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | |||
367 | p1[i] &= p2[i]; | 343 | p1[i] &= p2[i]; |
368 | } | 344 | } |
369 | 345 | ||
346 | /* Do a logical ht_capa &= ht_capa_mask. */ | ||
347 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | ||
348 | const struct ieee80211_vht_cap *vht_capa_mask) | ||
349 | { | ||
350 | int i; | ||
351 | u8 *p1, *p2; | ||
352 | if (!vht_capa_mask) { | ||
353 | memset(vht_capa, 0, sizeof(*vht_capa)); | ||
354 | return; | ||
355 | } | ||
356 | |||
357 | p1 = (u8*)(vht_capa); | ||
358 | p2 = (u8*)(vht_capa_mask); | ||
359 | for (i = 0; i < sizeof(*vht_capa); i++) | ||
360 | p1[i] &= p2[i]; | ||
361 | } | ||
362 | |||
370 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 363 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
371 | struct net_device *dev, | 364 | struct net_device *dev, |
372 | struct ieee80211_channel *chan, | 365 | struct ieee80211_channel *chan, |
373 | const u8 *bssid, const u8 *prev_bssid, | 366 | const u8 *bssid, |
374 | const u8 *ssid, int ssid_len, | 367 | const u8 *ssid, int ssid_len, |
375 | const u8 *ie, int ie_len, bool use_mfp, | 368 | struct cfg80211_assoc_request *req) |
376 | struct cfg80211_crypto_settings *crypt, | ||
377 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
378 | struct ieee80211_ht_cap *ht_capa_mask) | ||
379 | { | 369 | { |
380 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 370 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
381 | struct cfg80211_assoc_request req; | ||
382 | int err; | 371 | int err; |
383 | bool was_connected = false; | 372 | bool was_connected = false; |
384 | 373 | ||
385 | ASSERT_WDEV_LOCK(wdev); | 374 | ASSERT_WDEV_LOCK(wdev); |
386 | 375 | ||
387 | memset(&req, 0, sizeof(req)); | 376 | if (wdev->current_bss && req->prev_bssid && |
388 | 377 | ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) { | |
389 | if (wdev->current_bss && prev_bssid && | ||
390 | ether_addr_equal(wdev->current_bss->pub.bssid, prev_bssid)) { | ||
391 | /* | 378 | /* |
392 | * Trying to reassociate: Allow this to proceed and let the old | 379 | * Trying to reassociate: Allow this to proceed and let the old |
393 | * association to be dropped when the new one is completed. | 380 | * association to be dropped when the new one is completed. |
@@ -399,40 +386,30 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
399 | } else if (wdev->current_bss) | 386 | } else if (wdev->current_bss) |
400 | return -EALREADY; | 387 | return -EALREADY; |
401 | 388 | ||
402 | req.ie = ie; | 389 | cfg80211_oper_and_ht_capa(&req->ht_capa_mask, |
403 | req.ie_len = ie_len; | ||
404 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); | ||
405 | req.use_mfp = use_mfp; | ||
406 | req.prev_bssid = prev_bssid; | ||
407 | req.flags = assoc_flags; | ||
408 | if (ht_capa) | ||
409 | memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa)); | ||
410 | if (ht_capa_mask) | ||
411 | memcpy(&req.ht_capa_mask, ht_capa_mask, | ||
412 | sizeof(req.ht_capa_mask)); | ||
413 | cfg80211_oper_and_ht_capa(&req.ht_capa_mask, | ||
414 | rdev->wiphy.ht_capa_mod_mask); | 390 | rdev->wiphy.ht_capa_mod_mask); |
391 | cfg80211_oper_and_vht_capa(&req->vht_capa_mask, | ||
392 | rdev->wiphy.vht_capa_mod_mask); | ||
415 | 393 | ||
416 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 394 | req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
417 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 395 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
418 | if (!req.bss) { | 396 | if (!req->bss) { |
419 | if (was_connected) | 397 | if (was_connected) |
420 | wdev->sme_state = CFG80211_SME_CONNECTED; | 398 | wdev->sme_state = CFG80211_SME_CONNECTED; |
421 | return -ENOENT; | 399 | return -ENOENT; |
422 | } | 400 | } |
423 | 401 | ||
424 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | 402 | err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED); |
425 | CHAN_MODE_SHARED); | ||
426 | if (err) | 403 | if (err) |
427 | goto out; | 404 | goto out; |
428 | 405 | ||
429 | err = rdev_assoc(rdev, dev, &req); | 406 | err = rdev_assoc(rdev, dev, req); |
430 | 407 | ||
431 | out: | 408 | out: |
432 | if (err) { | 409 | if (err) { |
433 | if (was_connected) | 410 | if (was_connected) |
434 | wdev->sme_state = CFG80211_SME_CONNECTED; | 411 | wdev->sme_state = CFG80211_SME_CONNECTED; |
435 | cfg80211_put_bss(&rdev->wiphy, req.bss); | 412 | cfg80211_put_bss(&rdev->wiphy, req->bss); |
436 | } | 413 | } |
437 | 414 | ||
438 | return err; | 415 | return err; |
@@ -441,21 +418,17 @@ out: | |||
441 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 418 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
442 | struct net_device *dev, | 419 | struct net_device *dev, |
443 | struct ieee80211_channel *chan, | 420 | struct ieee80211_channel *chan, |
444 | const u8 *bssid, const u8 *prev_bssid, | 421 | const u8 *bssid, |
445 | const u8 *ssid, int ssid_len, | 422 | const u8 *ssid, int ssid_len, |
446 | const u8 *ie, int ie_len, bool use_mfp, | 423 | struct cfg80211_assoc_request *req) |
447 | struct cfg80211_crypto_settings *crypt, | ||
448 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
449 | struct ieee80211_ht_cap *ht_capa_mask) | ||
450 | { | 424 | { |
451 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 425 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
452 | int err; | 426 | int err; |
453 | 427 | ||
454 | mutex_lock(&rdev->devlist_mtx); | 428 | mutex_lock(&rdev->devlist_mtx); |
455 | wdev_lock(wdev); | 429 | wdev_lock(wdev); |
456 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 430 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, |
457 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, | 431 | ssid, ssid_len, req); |
458 | assoc_flags, ht_capa, ht_capa_mask); | ||
459 | wdev_unlock(wdev); | 432 | wdev_unlock(wdev); |
460 | mutex_unlock(&rdev->devlist_mtx); | 433 | mutex_unlock(&rdev->devlist_mtx); |
461 | 434 | ||
@@ -577,62 +550,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
577 | } | 550 | } |
578 | } | 551 | } |
579 | 552 | ||
580 | void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, | ||
581 | struct ieee80211_channel *chan, | ||
582 | unsigned int duration, gfp_t gfp) | ||
583 | { | ||
584 | struct wiphy *wiphy = wdev->wiphy; | ||
585 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
586 | |||
587 | trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration); | ||
588 | nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, duration, gfp); | ||
589 | } | ||
590 | EXPORT_SYMBOL(cfg80211_ready_on_channel); | ||
591 | |||
592 | void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, | ||
593 | struct ieee80211_channel *chan, | ||
594 | gfp_t gfp) | ||
595 | { | ||
596 | struct wiphy *wiphy = wdev->wiphy; | ||
597 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
598 | |||
599 | trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan); | ||
600 | nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp); | ||
601 | } | ||
602 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | ||
603 | |||
604 | void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | ||
605 | struct station_info *sinfo, gfp_t gfp) | ||
606 | { | ||
607 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
608 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
609 | |||
610 | trace_cfg80211_new_sta(dev, mac_addr, sinfo); | ||
611 | nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); | ||
612 | } | ||
613 | EXPORT_SYMBOL(cfg80211_new_sta); | ||
614 | |||
615 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) | ||
616 | { | ||
617 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
618 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
619 | |||
620 | trace_cfg80211_del_sta(dev, mac_addr); | ||
621 | nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp); | ||
622 | } | ||
623 | EXPORT_SYMBOL(cfg80211_del_sta); | ||
624 | |||
625 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, | ||
626 | enum nl80211_connect_failed_reason reason, | ||
627 | gfp_t gfp) | ||
628 | { | ||
629 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
630 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
631 | |||
632 | nl80211_send_conn_failed_event(rdev, dev, mac_addr, reason, gfp); | ||
633 | } | ||
634 | EXPORT_SYMBOL(cfg80211_conn_failed); | ||
635 | |||
636 | struct cfg80211_mgmt_registration { | 553 | struct cfg80211_mgmt_registration { |
637 | struct list_head list; | 554 | struct list_head list; |
638 | 555 | ||
@@ -909,85 +826,6 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, | |||
909 | } | 826 | } |
910 | EXPORT_SYMBOL(cfg80211_rx_mgmt); | 827 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
911 | 828 | ||
912 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, | ||
913 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | ||
914 | { | ||
915 | struct wiphy *wiphy = wdev->wiphy; | ||
916 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
917 | |||
918 | trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); | ||
919 | |||
920 | /* Indicate TX status of the Action frame to user space */ | ||
921 | nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp); | ||
922 | } | ||
923 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | ||
924 | |||
925 | void cfg80211_cqm_rssi_notify(struct net_device *dev, | ||
926 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
927 | gfp_t gfp) | ||
928 | { | ||
929 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
930 | struct wiphy *wiphy = wdev->wiphy; | ||
931 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
932 | |||
933 | trace_cfg80211_cqm_rssi_notify(dev, rssi_event); | ||
934 | |||
935 | /* Indicate roaming trigger event to user space */ | ||
936 | nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp); | ||
937 | } | ||
938 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); | ||
939 | |||
940 | void cfg80211_cqm_pktloss_notify(struct net_device *dev, | ||
941 | const u8 *peer, u32 num_packets, gfp_t gfp) | ||
942 | { | ||
943 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
944 | struct wiphy *wiphy = wdev->wiphy; | ||
945 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
946 | |||
947 | trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets); | ||
948 | |||
949 | /* Indicate roaming trigger event to user space */ | ||
950 | nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp); | ||
951 | } | ||
952 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | ||
953 | |||
954 | void cfg80211_cqm_txe_notify(struct net_device *dev, | ||
955 | const u8 *peer, u32 num_packets, | ||
956 | u32 rate, u32 intvl, gfp_t gfp) | ||
957 | { | ||
958 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
959 | struct wiphy *wiphy = wdev->wiphy; | ||
960 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
961 | |||
962 | nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets, | ||
963 | rate, intvl, gfp); | ||
964 | } | ||
965 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | ||
966 | |||
967 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, | ||
968 | const u8 *replay_ctr, gfp_t gfp) | ||
969 | { | ||
970 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
971 | struct wiphy *wiphy = wdev->wiphy; | ||
972 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
973 | |||
974 | trace_cfg80211_gtk_rekey_notify(dev, bssid); | ||
975 | nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); | ||
976 | } | ||
977 | EXPORT_SYMBOL(cfg80211_gtk_rekey_notify); | ||
978 | |||
979 | void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, | ||
980 | const u8 *bssid, bool preauth, gfp_t gfp) | ||
981 | { | ||
982 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
983 | struct wiphy *wiphy = wdev->wiphy; | ||
984 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
985 | |||
986 | trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth); | ||
987 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); | ||
988 | } | ||
989 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | ||
990 | |||
991 | void cfg80211_dfs_channels_update_work(struct work_struct *work) | 829 | void cfg80211_dfs_channels_update_work(struct work_struct *work) |
992 | { | 830 | { |
993 | struct delayed_work *delayed_work; | 831 | struct delayed_work *delayed_work; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 35545ccc30fd..f924d45af1b8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -370,6 +370,14 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
370 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, | 370 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, |
371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, | 371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, |
372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, | 372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, |
373 | [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, }, | ||
374 | [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG }, | ||
375 | [NL80211_ATTR_VHT_CAPABILITY_MASK] = { | ||
376 | .len = NL80211_VHT_CAPABILITY_LEN, | ||
377 | }, | ||
378 | [NL80211_ATTR_MDID] = { .type = NLA_U16 }, | ||
379 | [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY, | ||
380 | .len = IEEE80211_MAX_DATA_LEN }, | ||
373 | }; | 381 | }; |
374 | 382 | ||
375 | /* policy for the key attributes */ | 383 | /* policy for the key attributes */ |
@@ -539,7 +547,8 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq, | |||
539 | } | 547 | } |
540 | 548 | ||
541 | static int nl80211_msg_put_channel(struct sk_buff *msg, | 549 | static int nl80211_msg_put_channel(struct sk_buff *msg, |
542 | struct ieee80211_channel *chan) | 550 | struct ieee80211_channel *chan, |
551 | bool large) | ||
543 | { | 552 | { |
544 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ, | 553 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ, |
545 | chan->center_freq)) | 554 | chan->center_freq)) |
@@ -555,27 +564,36 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
555 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) | 564 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) |
556 | goto nla_put_failure; | 565 | goto nla_put_failure; |
557 | if (chan->flags & IEEE80211_CHAN_RADAR) { | 566 | if (chan->flags & IEEE80211_CHAN_RADAR) { |
558 | u32 time = elapsed_jiffies_msecs(chan->dfs_state_entered); | ||
559 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | 567 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) |
560 | goto nla_put_failure; | 568 | goto nla_put_failure; |
561 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE, | 569 | if (large) { |
562 | chan->dfs_state)) | 570 | u32 time; |
571 | |||
572 | time = elapsed_jiffies_msecs(chan->dfs_state_entered); | ||
573 | |||
574 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE, | ||
575 | chan->dfs_state)) | ||
576 | goto nla_put_failure; | ||
577 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, | ||
578 | time)) | ||
579 | goto nla_put_failure; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | if (large) { | ||
584 | if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) && | ||
585 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS)) | ||
586 | goto nla_put_failure; | ||
587 | if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) && | ||
588 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS)) | ||
589 | goto nla_put_failure; | ||
590 | if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) && | ||
591 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ)) | ||
563 | goto nla_put_failure; | 592 | goto nla_put_failure; |
564 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time)) | 593 | if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) && |
594 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ)) | ||
565 | goto nla_put_failure; | 595 | goto nla_put_failure; |
566 | } | 596 | } |
567 | if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) && | ||
568 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS)) | ||
569 | goto nla_put_failure; | ||
570 | if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) && | ||
571 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS)) | ||
572 | goto nla_put_failure; | ||
573 | if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) && | ||
574 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ)) | ||
575 | goto nla_put_failure; | ||
576 | if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) && | ||
577 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ)) | ||
578 | goto nla_put_failure; | ||
579 | 597 | ||
580 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 598 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
581 | DBM_TO_MBM(chan->max_power))) | 599 | DBM_TO_MBM(chan->max_power))) |
@@ -851,7 +869,8 @@ nla_put_failure: | |||
851 | } | 869 | } |
852 | 870 | ||
853 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, | 871 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, |
854 | struct sk_buff *msg) | 872 | struct sk_buff *msg, |
873 | bool large) | ||
855 | { | 874 | { |
856 | struct nlattr *nl_combis; | 875 | struct nlattr *nl_combis; |
857 | int i, j; | 876 | int i, j; |
@@ -900,7 +919,8 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy, | |||
900 | nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, | 919 | nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM, |
901 | c->max_interfaces)) | 920 | c->max_interfaces)) |
902 | goto nla_put_failure; | 921 | goto nla_put_failure; |
903 | if (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, | 922 | if (large && |
923 | nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, | ||
904 | c->radar_detect_widths)) | 924 | c->radar_detect_widths)) |
905 | goto nla_put_failure; | 925 | goto nla_put_failure; |
906 | 926 | ||
@@ -954,426 +974,571 @@ static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, | |||
954 | nla_nest_end(msg, nl_tcp); | 974 | nla_nest_end(msg, nl_tcp); |
955 | return 0; | 975 | return 0; |
956 | } | 976 | } |
957 | #endif | ||
958 | 977 | ||
959 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 978 | static int nl80211_send_wowlan(struct sk_buff *msg, |
960 | struct cfg80211_registered_device *dev) | 979 | struct cfg80211_registered_device *dev, |
980 | bool large) | ||
961 | { | 981 | { |
962 | void *hdr; | 982 | struct nlattr *nl_wowlan; |
963 | struct nlattr *nl_bands, *nl_band; | ||
964 | struct nlattr *nl_freqs, *nl_freq; | ||
965 | struct nlattr *nl_rates, *nl_rate; | ||
966 | struct nlattr *nl_cmds; | ||
967 | enum ieee80211_band band; | ||
968 | struct ieee80211_channel *chan; | ||
969 | struct ieee80211_rate *rate; | ||
970 | int i; | ||
971 | const struct ieee80211_txrx_stypes *mgmt_stypes = | ||
972 | dev->wiphy.mgmt_stypes; | ||
973 | 983 | ||
974 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); | 984 | if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns) |
975 | if (!hdr) | 985 | return 0; |
976 | return -1; | ||
977 | 986 | ||
978 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || | 987 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); |
979 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)) || | 988 | if (!nl_wowlan) |
980 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | 989 | return -ENOBUFS; |
981 | cfg80211_rdev_list_generation) || | ||
982 | nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | ||
983 | dev->wiphy.retry_short) || | ||
984 | nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | ||
985 | dev->wiphy.retry_long) || | ||
986 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | ||
987 | dev->wiphy.frag_threshold) || | ||
988 | nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | ||
989 | dev->wiphy.rts_threshold) || | ||
990 | nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
991 | dev->wiphy.coverage_class) || | ||
992 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | ||
993 | dev->wiphy.max_scan_ssids) || | ||
994 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||
995 | dev->wiphy.max_sched_scan_ssids) || | ||
996 | nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | ||
997 | dev->wiphy.max_scan_ie_len) || | ||
998 | nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||
999 | dev->wiphy.max_sched_scan_ie_len) || | ||
1000 | nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS, | ||
1001 | dev->wiphy.max_match_sets)) | ||
1002 | goto nla_put_failure; | ||
1003 | 990 | ||
1004 | if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && | 991 | if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) && |
1005 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN)) | 992 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || |
1006 | goto nla_put_failure; | 993 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) && |
1007 | if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && | 994 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || |
1008 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH)) | 995 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) && |
1009 | goto nla_put_failure; | 996 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || |
1010 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && | 997 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && |
1011 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD)) | 998 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) || |
1012 | goto nla_put_failure; | 999 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
1013 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) && | 1000 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || |
1014 | nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT)) | 1001 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && |
1015 | goto nla_put_failure; | 1002 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || |
1016 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && | 1003 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && |
1017 | nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT)) | 1004 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || |
1018 | goto nla_put_failure; | 1005 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) && |
1019 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && | 1006 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) |
1020 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) | 1007 | return -ENOBUFS; |
1021 | goto nla_put_failure; | ||
1022 | 1008 | ||
1023 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | 1009 | if (dev->wiphy.wowlan.n_patterns) { |
1024 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 1010 | struct nl80211_wowlan_pattern_support pat = { |
1025 | dev->wiphy.cipher_suites)) | 1011 | .max_patterns = dev->wiphy.wowlan.n_patterns, |
1026 | goto nla_put_failure; | 1012 | .min_pattern_len = dev->wiphy.wowlan.pattern_min_len, |
1013 | .max_pattern_len = dev->wiphy.wowlan.pattern_max_len, | ||
1014 | .max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset, | ||
1015 | }; | ||
1027 | 1016 | ||
1028 | if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, | 1017 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, |
1029 | dev->wiphy.max_num_pmkids)) | 1018 | sizeof(pat), &pat)) |
1030 | goto nla_put_failure; | 1019 | return -ENOBUFS; |
1020 | } | ||
1031 | 1021 | ||
1032 | if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && | 1022 | if (large && nl80211_send_wowlan_tcp_caps(dev, msg)) |
1033 | nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE)) | 1023 | return -ENOBUFS; |
1034 | goto nla_put_failure; | ||
1035 | 1024 | ||
1036 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, | 1025 | nla_nest_end(msg, nl_wowlan); |
1037 | dev->wiphy.available_antennas_tx) || | ||
1038 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, | ||
1039 | dev->wiphy.available_antennas_rx)) | ||
1040 | goto nla_put_failure; | ||
1041 | 1026 | ||
1042 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) && | 1027 | return 0; |
1043 | nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, | 1028 | } |
1044 | dev->wiphy.probe_resp_offload)) | 1029 | #endif |
1045 | goto nla_put_failure; | ||
1046 | 1030 | ||
1047 | if ((dev->wiphy.available_antennas_tx || | 1031 | static int nl80211_send_band_rateinfo(struct sk_buff *msg, |
1048 | dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) { | 1032 | struct ieee80211_supported_band *sband) |
1049 | u32 tx_ant = 0, rx_ant = 0; | 1033 | { |
1050 | int res; | 1034 | struct nlattr *nl_rates, *nl_rate; |
1051 | res = rdev_get_antenna(dev, &tx_ant, &rx_ant); | 1035 | struct ieee80211_rate *rate; |
1052 | if (!res) { | 1036 | int i; |
1053 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, | ||
1054 | tx_ant) || | ||
1055 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, | ||
1056 | rx_ant)) | ||
1057 | goto nla_put_failure; | ||
1058 | } | ||
1059 | } | ||
1060 | 1037 | ||
1061 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, | 1038 | /* add HT info */ |
1062 | dev->wiphy.interface_modes)) | 1039 | if (sband->ht_cap.ht_supported && |
1063 | goto nla_put_failure; | 1040 | (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET, |
1041 | sizeof(sband->ht_cap.mcs), | ||
1042 | &sband->ht_cap.mcs) || | ||
1043 | nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA, | ||
1044 | sband->ht_cap.cap) || | ||
1045 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, | ||
1046 | sband->ht_cap.ampdu_factor) || | ||
1047 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, | ||
1048 | sband->ht_cap.ampdu_density))) | ||
1049 | return -ENOBUFS; | ||
1064 | 1050 | ||
1065 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 1051 | /* add VHT info */ |
1066 | if (!nl_bands) | 1052 | if (sband->vht_cap.vht_supported && |
1067 | goto nla_put_failure; | 1053 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, |
1054 | sizeof(sband->vht_cap.vht_mcs), | ||
1055 | &sband->vht_cap.vht_mcs) || | ||
1056 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
1057 | sband->vht_cap.cap))) | ||
1058 | return -ENOBUFS; | ||
1068 | 1059 | ||
1069 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1060 | /* add bitrates */ |
1070 | if (!dev->wiphy.bands[band]) | 1061 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); |
1071 | continue; | 1062 | if (!nl_rates) |
1063 | return -ENOBUFS; | ||
1072 | 1064 | ||
1073 | nl_band = nla_nest_start(msg, band); | 1065 | for (i = 0; i < sband->n_bitrates; i++) { |
1074 | if (!nl_band) | 1066 | nl_rate = nla_nest_start(msg, i); |
1075 | goto nla_put_failure; | 1067 | if (!nl_rate) |
1068 | return -ENOBUFS; | ||
1076 | 1069 | ||
1077 | /* add HT info */ | 1070 | rate = &sband->bitrates[i]; |
1078 | if (dev->wiphy.bands[band]->ht_cap.ht_supported && | 1071 | if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE, |
1079 | (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET, | 1072 | rate->bitrate)) |
1080 | sizeof(dev->wiphy.bands[band]->ht_cap.mcs), | 1073 | return -ENOBUFS; |
1081 | &dev->wiphy.bands[band]->ht_cap.mcs) || | 1074 | if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && |
1082 | nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA, | 1075 | nla_put_flag(msg, |
1083 | dev->wiphy.bands[band]->ht_cap.cap) || | 1076 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE)) |
1084 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, | 1077 | return -ENOBUFS; |
1085 | dev->wiphy.bands[band]->ht_cap.ampdu_factor) || | ||
1086 | nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, | ||
1087 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | ||
1088 | goto nla_put_failure; | ||
1089 | 1078 | ||
1090 | /* add VHT info */ | 1079 | nla_nest_end(msg, nl_rate); |
1091 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | 1080 | } |
1092 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | ||
1093 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | ||
1094 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | ||
1095 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
1096 | dev->wiphy.bands[band]->vht_cap.cap))) | ||
1097 | goto nla_put_failure; | ||
1098 | 1081 | ||
1099 | /* add frequencies */ | 1082 | nla_nest_end(msg, nl_rates); |
1100 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | ||
1101 | if (!nl_freqs) | ||
1102 | goto nla_put_failure; | ||
1103 | 1083 | ||
1104 | for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { | 1084 | return 0; |
1105 | nl_freq = nla_nest_start(msg, i); | 1085 | } |
1106 | if (!nl_freq) | 1086 | |
1107 | goto nla_put_failure; | 1087 | static int |
1088 | nl80211_send_mgmt_stypes(struct sk_buff *msg, | ||
1089 | const struct ieee80211_txrx_stypes *mgmt_stypes) | ||
1090 | { | ||
1091 | u16 stypes; | ||
1092 | struct nlattr *nl_ftypes, *nl_ifs; | ||
1093 | enum nl80211_iftype ift; | ||
1094 | int i; | ||
1108 | 1095 | ||
1109 | chan = &dev->wiphy.bands[band]->channels[i]; | 1096 | if (!mgmt_stypes) |
1097 | return 0; | ||
1110 | 1098 | ||
1111 | if (nl80211_msg_put_channel(msg, chan)) | 1099 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); |
1112 | goto nla_put_failure; | 1100 | if (!nl_ifs) |
1101 | return -ENOBUFS; | ||
1113 | 1102 | ||
1114 | nla_nest_end(msg, nl_freq); | 1103 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { |
1104 | nl_ftypes = nla_nest_start(msg, ift); | ||
1105 | if (!nl_ftypes) | ||
1106 | return -ENOBUFS; | ||
1107 | i = 0; | ||
1108 | stypes = mgmt_stypes[ift].tx; | ||
1109 | while (stypes) { | ||
1110 | if ((stypes & 1) && | ||
1111 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1112 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1113 | return -ENOBUFS; | ||
1114 | stypes >>= 1; | ||
1115 | i++; | ||
1115 | } | 1116 | } |
1117 | nla_nest_end(msg, nl_ftypes); | ||
1118 | } | ||
1116 | 1119 | ||
1117 | nla_nest_end(msg, nl_freqs); | 1120 | nla_nest_end(msg, nl_ifs); |
1118 | 1121 | ||
1119 | /* add bitrates */ | 1122 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); |
1120 | nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); | 1123 | if (!nl_ifs) |
1121 | if (!nl_rates) | 1124 | return -ENOBUFS; |
1122 | goto nla_put_failure; | ||
1123 | 1125 | ||
1124 | for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { | 1126 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { |
1125 | nl_rate = nla_nest_start(msg, i); | 1127 | nl_ftypes = nla_nest_start(msg, ift); |
1126 | if (!nl_rate) | 1128 | if (!nl_ftypes) |
1127 | goto nla_put_failure; | 1129 | return -ENOBUFS; |
1130 | i = 0; | ||
1131 | stypes = mgmt_stypes[ift].rx; | ||
1132 | while (stypes) { | ||
1133 | if ((stypes & 1) && | ||
1134 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1135 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1136 | return -ENOBUFS; | ||
1137 | stypes >>= 1; | ||
1138 | i++; | ||
1139 | } | ||
1140 | nla_nest_end(msg, nl_ftypes); | ||
1141 | } | ||
1142 | nla_nest_end(msg, nl_ifs); | ||
1128 | 1143 | ||
1129 | rate = &dev->wiphy.bands[band]->bitrates[i]; | 1144 | return 0; |
1130 | if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE, | 1145 | } |
1131 | rate->bitrate)) | ||
1132 | goto nla_put_failure; | ||
1133 | if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && | ||
1134 | nla_put_flag(msg, | ||
1135 | NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE)) | ||
1136 | goto nla_put_failure; | ||
1137 | 1146 | ||
1138 | nla_nest_end(msg, nl_rate); | 1147 | static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, |
1139 | } | 1148 | struct sk_buff *msg, u32 portid, u32 seq, |
1149 | int flags, bool split, long *split_start, | ||
1150 | long *band_start, long *chan_start) | ||
1151 | { | ||
1152 | void *hdr; | ||
1153 | struct nlattr *nl_bands, *nl_band; | ||
1154 | struct nlattr *nl_freqs, *nl_freq; | ||
1155 | struct nlattr *nl_cmds; | ||
1156 | enum ieee80211_band band; | ||
1157 | struct ieee80211_channel *chan; | ||
1158 | int i; | ||
1159 | const struct ieee80211_txrx_stypes *mgmt_stypes = | ||
1160 | dev->wiphy.mgmt_stypes; | ||
1161 | long start = 0, start_chan = 0, start_band = 0; | ||
1162 | u32 features; | ||
1140 | 1163 | ||
1141 | nla_nest_end(msg, nl_rates); | 1164 | hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY); |
1165 | if (!hdr) | ||
1166 | return -ENOBUFS; | ||
1142 | 1167 | ||
1143 | nla_nest_end(msg, nl_band); | 1168 | /* allow always using the variables */ |
1169 | if (!split) { | ||
1170 | split_start = &start; | ||
1171 | band_start = &start_band; | ||
1172 | chan_start = &start_chan; | ||
1144 | } | 1173 | } |
1145 | nla_nest_end(msg, nl_bands); | ||
1146 | 1174 | ||
1147 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | 1175 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) || |
1148 | if (!nl_cmds) | 1176 | nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, |
1149 | goto nla_put_failure; | 1177 | wiphy_name(&dev->wiphy)) || |
1178 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | ||
1179 | cfg80211_rdev_list_generation)) | ||
1180 | goto nla_put_failure; | ||
1181 | |||
1182 | switch (*split_start) { | ||
1183 | case 0: | ||
1184 | if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | ||
1185 | dev->wiphy.retry_short) || | ||
1186 | nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | ||
1187 | dev->wiphy.retry_long) || | ||
1188 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | ||
1189 | dev->wiphy.frag_threshold) || | ||
1190 | nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | ||
1191 | dev->wiphy.rts_threshold) || | ||
1192 | nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
1193 | dev->wiphy.coverage_class) || | ||
1194 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | ||
1195 | dev->wiphy.max_scan_ssids) || | ||
1196 | nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||
1197 | dev->wiphy.max_sched_scan_ssids) || | ||
1198 | nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | ||
1199 | dev->wiphy.max_scan_ie_len) || | ||
1200 | nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||
1201 | dev->wiphy.max_sched_scan_ie_len) || | ||
1202 | nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS, | ||
1203 | dev->wiphy.max_match_sets)) | ||
1204 | goto nla_put_failure; | ||
1150 | 1205 | ||
1151 | i = 0; | 1206 | if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) && |
1152 | #define CMD(op, n) \ | 1207 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN)) |
1153 | do { \ | ||
1154 | if (dev->ops->op) { \ | ||
1155 | i++; \ | ||
1156 | if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \ | ||
1157 | goto nla_put_failure; \ | ||
1158 | } \ | ||
1159 | } while (0) | ||
1160 | |||
1161 | CMD(add_virtual_intf, NEW_INTERFACE); | ||
1162 | CMD(change_virtual_intf, SET_INTERFACE); | ||
1163 | CMD(add_key, NEW_KEY); | ||
1164 | CMD(start_ap, START_AP); | ||
1165 | CMD(add_station, NEW_STATION); | ||
1166 | CMD(add_mpath, NEW_MPATH); | ||
1167 | CMD(update_mesh_config, SET_MESH_CONFIG); | ||
1168 | CMD(change_bss, SET_BSS); | ||
1169 | CMD(auth, AUTHENTICATE); | ||
1170 | CMD(assoc, ASSOCIATE); | ||
1171 | CMD(deauth, DEAUTHENTICATE); | ||
1172 | CMD(disassoc, DISASSOCIATE); | ||
1173 | CMD(join_ibss, JOIN_IBSS); | ||
1174 | CMD(join_mesh, JOIN_MESH); | ||
1175 | CMD(set_pmksa, SET_PMKSA); | ||
1176 | CMD(del_pmksa, DEL_PMKSA); | ||
1177 | CMD(flush_pmksa, FLUSH_PMKSA); | ||
1178 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) | ||
1179 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||
1180 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | ||
1181 | CMD(mgmt_tx, FRAME); | ||
1182 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); | ||
1183 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | ||
1184 | i++; | ||
1185 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | ||
1186 | goto nla_put_failure; | 1208 | goto nla_put_failure; |
1187 | } | 1209 | if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) && |
1188 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || | 1210 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH)) |
1189 | dev->ops->join_mesh) { | ||
1190 | i++; | ||
1191 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | ||
1192 | goto nla_put_failure; | 1211 | goto nla_put_failure; |
1193 | } | 1212 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && |
1194 | CMD(set_wds_peer, SET_WDS_PEER); | 1213 | nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD)) |
1195 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1214 | goto nla_put_failure; |
1196 | CMD(tdls_mgmt, TDLS_MGMT); | 1215 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) && |
1197 | CMD(tdls_oper, TDLS_OPER); | 1216 | nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT)) |
1198 | } | 1217 | goto nla_put_failure; |
1199 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | 1218 | if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && |
1200 | CMD(sched_scan_start, START_SCHED_SCAN); | 1219 | nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT)) |
1201 | CMD(probe_client, PROBE_CLIENT); | 1220 | goto nla_put_failure; |
1202 | CMD(set_noack_map, SET_NOACK_MAP); | 1221 | if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && |
1203 | if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { | 1222 | nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) |
1204 | i++; | ||
1205 | if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS)) | ||
1206 | goto nla_put_failure; | 1223 | goto nla_put_failure; |
1207 | } | ||
1208 | CMD(start_p2p_device, START_P2P_DEVICE); | ||
1209 | CMD(set_mcast_rate, SET_MCAST_RATE); | ||
1210 | 1224 | ||
1211 | #ifdef CONFIG_NL80211_TESTMODE | 1225 | (*split_start)++; |
1212 | CMD(testmode_cmd, TESTMODE); | 1226 | if (split) |
1213 | #endif | 1227 | break; |
1228 | case 1: | ||
1229 | if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES, | ||
1230 | sizeof(u32) * dev->wiphy.n_cipher_suites, | ||
1231 | dev->wiphy.cipher_suites)) | ||
1232 | goto nla_put_failure; | ||
1214 | 1233 | ||
1215 | #undef CMD | 1234 | if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS, |
1235 | dev->wiphy.max_num_pmkids)) | ||
1236 | goto nla_put_failure; | ||
1216 | 1237 | ||
1217 | if (dev->ops->connect || dev->ops->auth) { | 1238 | if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) && |
1218 | i++; | 1239 | nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE)) |
1219 | if (nla_put_u32(msg, i, NL80211_CMD_CONNECT)) | ||
1220 | goto nla_put_failure; | 1240 | goto nla_put_failure; |
1221 | } | ||
1222 | 1241 | ||
1223 | if (dev->ops->disconnect || dev->ops->deauth) { | 1242 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, |
1224 | i++; | 1243 | dev->wiphy.available_antennas_tx) || |
1225 | if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT)) | 1244 | nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, |
1245 | dev->wiphy.available_antennas_rx)) | ||
1246 | goto nla_put_failure; | ||
1247 | |||
1248 | if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) && | ||
1249 | nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD, | ||
1250 | dev->wiphy.probe_resp_offload)) | ||
1226 | goto nla_put_failure; | 1251 | goto nla_put_failure; |
1227 | } | ||
1228 | 1252 | ||
1229 | nla_nest_end(msg, nl_cmds); | 1253 | if ((dev->wiphy.available_antennas_tx || |
1254 | dev->wiphy.available_antennas_rx) && | ||
1255 | dev->ops->get_antenna) { | ||
1256 | u32 tx_ant = 0, rx_ant = 0; | ||
1257 | int res; | ||
1258 | res = rdev_get_antenna(dev, &tx_ant, &rx_ant); | ||
1259 | if (!res) { | ||
1260 | if (nla_put_u32(msg, | ||
1261 | NL80211_ATTR_WIPHY_ANTENNA_TX, | ||
1262 | tx_ant) || | ||
1263 | nla_put_u32(msg, | ||
1264 | NL80211_ATTR_WIPHY_ANTENNA_RX, | ||
1265 | rx_ant)) | ||
1266 | goto nla_put_failure; | ||
1267 | } | ||
1268 | } | ||
1230 | 1269 | ||
1231 | if (dev->ops->remain_on_channel && | 1270 | (*split_start)++; |
1232 | (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && | 1271 | if (split) |
1233 | nla_put_u32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | 1272 | break; |
1234 | dev->wiphy.max_remain_on_channel_duration)) | 1273 | case 2: |
1235 | goto nla_put_failure; | 1274 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
1275 | dev->wiphy.interface_modes)) | ||
1276 | goto nla_put_failure; | ||
1277 | (*split_start)++; | ||
1278 | if (split) | ||
1279 | break; | ||
1280 | case 3: | ||
1281 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | ||
1282 | if (!nl_bands) | ||
1283 | goto nla_put_failure; | ||
1236 | 1284 | ||
1237 | if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) && | 1285 | for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) { |
1238 | nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) | 1286 | struct ieee80211_supported_band *sband; |
1239 | goto nla_put_failure; | ||
1240 | 1287 | ||
1241 | if (mgmt_stypes) { | 1288 | sband = dev->wiphy.bands[band]; |
1242 | u16 stypes; | ||
1243 | struct nlattr *nl_ftypes, *nl_ifs; | ||
1244 | enum nl80211_iftype ift; | ||
1245 | 1289 | ||
1246 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); | 1290 | if (!sband) |
1247 | if (!nl_ifs) | 1291 | continue; |
1248 | goto nla_put_failure; | ||
1249 | 1292 | ||
1250 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | 1293 | nl_band = nla_nest_start(msg, band); |
1251 | nl_ftypes = nla_nest_start(msg, ift); | 1294 | if (!nl_band) |
1252 | if (!nl_ftypes) | ||
1253 | goto nla_put_failure; | 1295 | goto nla_put_failure; |
1254 | i = 0; | 1296 | |
1255 | stypes = mgmt_stypes[ift].tx; | 1297 | switch (*chan_start) { |
1256 | while (stypes) { | 1298 | case 0: |
1257 | if ((stypes & 1) && | 1299 | if (nl80211_send_band_rateinfo(msg, sband)) |
1258 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1259 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1260 | goto nla_put_failure; | 1300 | goto nla_put_failure; |
1261 | stypes >>= 1; | 1301 | (*chan_start)++; |
1262 | i++; | 1302 | if (split) |
1303 | break; | ||
1304 | default: | ||
1305 | /* add frequencies */ | ||
1306 | nl_freqs = nla_nest_start( | ||
1307 | msg, NL80211_BAND_ATTR_FREQS); | ||
1308 | if (!nl_freqs) | ||
1309 | goto nla_put_failure; | ||
1310 | |||
1311 | for (i = *chan_start - 1; | ||
1312 | i < sband->n_channels; | ||
1313 | i++) { | ||
1314 | nl_freq = nla_nest_start(msg, i); | ||
1315 | if (!nl_freq) | ||
1316 | goto nla_put_failure; | ||
1317 | |||
1318 | chan = &sband->channels[i]; | ||
1319 | |||
1320 | if (nl80211_msg_put_channel(msg, chan, | ||
1321 | split)) | ||
1322 | goto nla_put_failure; | ||
1323 | |||
1324 | nla_nest_end(msg, nl_freq); | ||
1325 | if (split) | ||
1326 | break; | ||
1327 | } | ||
1328 | if (i < sband->n_channels) | ||
1329 | *chan_start = i + 2; | ||
1330 | else | ||
1331 | *chan_start = 0; | ||
1332 | nla_nest_end(msg, nl_freqs); | ||
1333 | } | ||
1334 | |||
1335 | nla_nest_end(msg, nl_band); | ||
1336 | |||
1337 | if (split) { | ||
1338 | /* start again here */ | ||
1339 | if (*chan_start) | ||
1340 | band--; | ||
1341 | break; | ||
1263 | } | 1342 | } |
1264 | nla_nest_end(msg, nl_ftypes); | ||
1265 | } | 1343 | } |
1344 | nla_nest_end(msg, nl_bands); | ||
1266 | 1345 | ||
1267 | nla_nest_end(msg, nl_ifs); | 1346 | if (band < IEEE80211_NUM_BANDS) |
1347 | *band_start = band + 1; | ||
1348 | else | ||
1349 | *band_start = 0; | ||
1268 | 1350 | ||
1269 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); | 1351 | /* if bands & channels are done, continue outside */ |
1270 | if (!nl_ifs) | 1352 | if (*band_start == 0 && *chan_start == 0) |
1353 | (*split_start)++; | ||
1354 | if (split) | ||
1355 | break; | ||
1356 | case 4: | ||
1357 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | ||
1358 | if (!nl_cmds) | ||
1271 | goto nla_put_failure; | 1359 | goto nla_put_failure; |
1272 | 1360 | ||
1273 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | 1361 | i = 0; |
1274 | nl_ftypes = nla_nest_start(msg, ift); | 1362 | #define CMD(op, n) \ |
1275 | if (!nl_ftypes) | 1363 | do { \ |
1364 | if (dev->ops->op) { \ | ||
1365 | i++; \ | ||
1366 | if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \ | ||
1367 | goto nla_put_failure; \ | ||
1368 | } \ | ||
1369 | } while (0) | ||
1370 | |||
1371 | CMD(add_virtual_intf, NEW_INTERFACE); | ||
1372 | CMD(change_virtual_intf, SET_INTERFACE); | ||
1373 | CMD(add_key, NEW_KEY); | ||
1374 | CMD(start_ap, START_AP); | ||
1375 | CMD(add_station, NEW_STATION); | ||
1376 | CMD(add_mpath, NEW_MPATH); | ||
1377 | CMD(update_mesh_config, SET_MESH_CONFIG); | ||
1378 | CMD(change_bss, SET_BSS); | ||
1379 | CMD(auth, AUTHENTICATE); | ||
1380 | CMD(assoc, ASSOCIATE); | ||
1381 | CMD(deauth, DEAUTHENTICATE); | ||
1382 | CMD(disassoc, DISASSOCIATE); | ||
1383 | CMD(join_ibss, JOIN_IBSS); | ||
1384 | CMD(join_mesh, JOIN_MESH); | ||
1385 | CMD(set_pmksa, SET_PMKSA); | ||
1386 | CMD(del_pmksa, DEL_PMKSA); | ||
1387 | CMD(flush_pmksa, FLUSH_PMKSA); | ||
1388 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) | ||
1389 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||
1390 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | ||
1391 | CMD(mgmt_tx, FRAME); | ||
1392 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); | ||
1393 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | ||
1394 | i++; | ||
1395 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | ||
1276 | goto nla_put_failure; | 1396 | goto nla_put_failure; |
1277 | i = 0; | ||
1278 | stypes = mgmt_stypes[ift].rx; | ||
1279 | while (stypes) { | ||
1280 | if ((stypes & 1) && | ||
1281 | nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, | ||
1282 | (i << 4) | IEEE80211_FTYPE_MGMT)) | ||
1283 | goto nla_put_failure; | ||
1284 | stypes >>= 1; | ||
1285 | i++; | ||
1286 | } | ||
1287 | nla_nest_end(msg, nl_ftypes); | ||
1288 | } | 1397 | } |
1289 | nla_nest_end(msg, nl_ifs); | 1398 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || |
1290 | } | 1399 | dev->ops->join_mesh) { |
1400 | i++; | ||
1401 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | ||
1402 | goto nla_put_failure; | ||
1403 | } | ||
1404 | CMD(set_wds_peer, SET_WDS_PEER); | ||
1405 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | ||
1406 | CMD(tdls_mgmt, TDLS_MGMT); | ||
1407 | CMD(tdls_oper, TDLS_OPER); | ||
1408 | } | ||
1409 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | ||
1410 | CMD(sched_scan_start, START_SCHED_SCAN); | ||
1411 | CMD(probe_client, PROBE_CLIENT); | ||
1412 | CMD(set_noack_map, SET_NOACK_MAP); | ||
1413 | if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) { | ||
1414 | i++; | ||
1415 | if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS)) | ||
1416 | goto nla_put_failure; | ||
1417 | } | ||
1418 | CMD(start_p2p_device, START_P2P_DEVICE); | ||
1419 | CMD(set_mcast_rate, SET_MCAST_RATE); | ||
1291 | 1420 | ||
1292 | #ifdef CONFIG_PM | 1421 | #ifdef CONFIG_NL80211_TESTMODE |
1293 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1422 | CMD(testmode_cmd, TESTMODE); |
1294 | struct nlattr *nl_wowlan; | 1423 | #endif |
1295 | 1424 | ||
1296 | nl_wowlan = nla_nest_start(msg, | 1425 | #undef CMD |
1297 | NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); | ||
1298 | if (!nl_wowlan) | ||
1299 | goto nla_put_failure; | ||
1300 | 1426 | ||
1301 | if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) && | 1427 | if (dev->ops->connect || dev->ops->auth) { |
1302 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || | 1428 | i++; |
1303 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) && | 1429 | if (nla_put_u32(msg, i, NL80211_CMD_CONNECT)) |
1304 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || | ||
1305 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) && | ||
1306 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || | ||
1307 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) && | ||
1308 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) || | ||
1309 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | ||
1310 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || | ||
1311 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) && | ||
1312 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || | ||
1313 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) && | ||
1314 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || | ||
1315 | ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) && | ||
1316 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | ||
1317 | goto nla_put_failure; | ||
1318 | if (dev->wiphy.wowlan.n_patterns) { | ||
1319 | struct nl80211_wowlan_pattern_support pat = { | ||
1320 | .max_patterns = dev->wiphy.wowlan.n_patterns, | ||
1321 | .min_pattern_len = | ||
1322 | dev->wiphy.wowlan.pattern_min_len, | ||
1323 | .max_pattern_len = | ||
1324 | dev->wiphy.wowlan.pattern_max_len, | ||
1325 | .max_pkt_offset = | ||
1326 | dev->wiphy.wowlan.max_pkt_offset, | ||
1327 | }; | ||
1328 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | ||
1329 | sizeof(pat), &pat)) | ||
1330 | goto nla_put_failure; | 1430 | goto nla_put_failure; |
1331 | } | 1431 | } |
1332 | 1432 | ||
1333 | if (nl80211_send_wowlan_tcp_caps(dev, msg)) | 1433 | if (dev->ops->disconnect || dev->ops->deauth) { |
1434 | i++; | ||
1435 | if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT)) | ||
1436 | goto nla_put_failure; | ||
1437 | } | ||
1438 | |||
1439 | nla_nest_end(msg, nl_cmds); | ||
1440 | (*split_start)++; | ||
1441 | if (split) | ||
1442 | break; | ||
1443 | case 5: | ||
1444 | if (dev->ops->remain_on_channel && | ||
1445 | (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) && | ||
1446 | nla_put_u32(msg, | ||
1447 | NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | ||
1448 | dev->wiphy.max_remain_on_channel_duration)) | ||
1449 | goto nla_put_failure; | ||
1450 | |||
1451 | if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) && | ||
1452 | nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) | ||
1334 | goto nla_put_failure; | 1453 | goto nla_put_failure; |
1335 | 1454 | ||
1336 | nla_nest_end(msg, nl_wowlan); | 1455 | if (nl80211_send_mgmt_stypes(msg, mgmt_stypes)) |
1337 | } | 1456 | goto nla_put_failure; |
1457 | (*split_start)++; | ||
1458 | if (split) | ||
1459 | break; | ||
1460 | case 6: | ||
1461 | #ifdef CONFIG_PM | ||
1462 | if (nl80211_send_wowlan(msg, dev, split)) | ||
1463 | goto nla_put_failure; | ||
1464 | (*split_start)++; | ||
1465 | if (split) | ||
1466 | break; | ||
1467 | #else | ||
1468 | (*split_start)++; | ||
1338 | #endif | 1469 | #endif |
1470 | case 7: | ||
1471 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | ||
1472 | dev->wiphy.software_iftypes)) | ||
1473 | goto nla_put_failure; | ||
1339 | 1474 | ||
1340 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1475 | if (nl80211_put_iface_combinations(&dev->wiphy, msg, split)) |
1341 | dev->wiphy.software_iftypes)) | 1476 | goto nla_put_failure; |
1342 | goto nla_put_failure; | ||
1343 | 1477 | ||
1344 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) | 1478 | (*split_start)++; |
1345 | goto nla_put_failure; | 1479 | if (split) |
1480 | break; | ||
1481 | case 8: | ||
1482 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | ||
1483 | nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, | ||
1484 | dev->wiphy.ap_sme_capa)) | ||
1485 | goto nla_put_failure; | ||
1346 | 1486 | ||
1347 | if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) && | 1487 | features = dev->wiphy.features; |
1348 | nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME, | 1488 | /* |
1349 | dev->wiphy.ap_sme_capa)) | 1489 | * We can only add the per-channel limit information if the |
1350 | goto nla_put_failure; | 1490 | * dump is split, otherwise it makes it too big. Therefore |
1491 | * only advertise it in that case. | ||
1492 | */ | ||
1493 | if (split) | ||
1494 | features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; | ||
1495 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features)) | ||
1496 | goto nla_put_failure; | ||
1351 | 1497 | ||
1352 | if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, | 1498 | if (dev->wiphy.ht_capa_mod_mask && |
1353 | dev->wiphy.features)) | 1499 | nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, |
1354 | goto nla_put_failure; | 1500 | sizeof(*dev->wiphy.ht_capa_mod_mask), |
1501 | dev->wiphy.ht_capa_mod_mask)) | ||
1502 | goto nla_put_failure; | ||
1355 | 1503 | ||
1356 | if (dev->wiphy.ht_capa_mod_mask && | 1504 | if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && |
1357 | nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, | 1505 | dev->wiphy.max_acl_mac_addrs && |
1358 | sizeof(*dev->wiphy.ht_capa_mod_mask), | 1506 | nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX, |
1359 | dev->wiphy.ht_capa_mod_mask)) | 1507 | dev->wiphy.max_acl_mac_addrs)) |
1360 | goto nla_put_failure; | 1508 | goto nla_put_failure; |
1361 | 1509 | ||
1362 | if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME && | 1510 | /* |
1363 | dev->wiphy.max_acl_mac_addrs && | 1511 | * Any information below this point is only available to |
1364 | nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX, | 1512 | * applications that can deal with it being split. This |
1365 | dev->wiphy.max_acl_mac_addrs)) | 1513 | * helps ensure that newly added capabilities don't break |
1366 | goto nla_put_failure; | 1514 | * older tools by overrunning their buffers. |
1515 | * | ||
1516 | * We still increment split_start so that in the split | ||
1517 | * case we'll continue with more data in the next round, | ||
1518 | * but break unconditionally so unsplit data stops here. | ||
1519 | */ | ||
1520 | (*split_start)++; | ||
1521 | break; | ||
1522 | case 9: | ||
1523 | if (dev->wiphy.extended_capabilities && | ||
1524 | (nla_put(msg, NL80211_ATTR_EXT_CAPA, | ||
1525 | dev->wiphy.extended_capabilities_len, | ||
1526 | dev->wiphy.extended_capabilities) || | ||
1527 | nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK, | ||
1528 | dev->wiphy.extended_capabilities_len, | ||
1529 | dev->wiphy.extended_capabilities_mask))) | ||
1530 | goto nla_put_failure; | ||
1367 | 1531 | ||
1368 | if (dev->wiphy.extended_capabilities && | 1532 | if (dev->wiphy.vht_capa_mod_mask && |
1369 | (nla_put(msg, NL80211_ATTR_EXT_CAPA, | 1533 | nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, |
1370 | dev->wiphy.extended_capabilities_len, | 1534 | sizeof(*dev->wiphy.vht_capa_mod_mask), |
1371 | dev->wiphy.extended_capabilities) || | 1535 | dev->wiphy.vht_capa_mod_mask)) |
1372 | nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK, | 1536 | goto nla_put_failure; |
1373 | dev->wiphy.extended_capabilities_len, | ||
1374 | dev->wiphy.extended_capabilities_mask))) | ||
1375 | goto nla_put_failure; | ||
1376 | 1537 | ||
1538 | /* done */ | ||
1539 | *split_start = 0; | ||
1540 | break; | ||
1541 | } | ||
1377 | return genlmsg_end(msg, hdr); | 1542 | return genlmsg_end(msg, hdr); |
1378 | 1543 | ||
1379 | nla_put_failure: | 1544 | nla_put_failure: |
@@ -1383,22 +1548,83 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1383 | 1548 | ||
1384 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | 1549 | static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) |
1385 | { | 1550 | { |
1386 | int idx = 0; | 1551 | int idx = 0, ret; |
1387 | int start = cb->args[0]; | 1552 | int start = cb->args[0]; |
1388 | struct cfg80211_registered_device *dev; | 1553 | struct cfg80211_registered_device *dev; |
1554 | s64 filter_wiphy = -1; | ||
1555 | bool split = false; | ||
1556 | struct nlattr **tb = nl80211_fam.attrbuf; | ||
1557 | int res; | ||
1389 | 1558 | ||
1390 | mutex_lock(&cfg80211_mutex); | 1559 | mutex_lock(&cfg80211_mutex); |
1560 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
1561 | tb, nl80211_fam.maxattr, nl80211_policy); | ||
1562 | if (res == 0) { | ||
1563 | split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP]; | ||
1564 | if (tb[NL80211_ATTR_WIPHY]) | ||
1565 | filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | ||
1566 | if (tb[NL80211_ATTR_WDEV]) | ||
1567 | filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32; | ||
1568 | if (tb[NL80211_ATTR_IFINDEX]) { | ||
1569 | struct net_device *netdev; | ||
1570 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | ||
1571 | |||
1572 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | ||
1573 | if (!netdev) { | ||
1574 | mutex_unlock(&cfg80211_mutex); | ||
1575 | return -ENODEV; | ||
1576 | } | ||
1577 | if (netdev->ieee80211_ptr) { | ||
1578 | dev = wiphy_to_dev( | ||
1579 | netdev->ieee80211_ptr->wiphy); | ||
1580 | filter_wiphy = dev->wiphy_idx; | ||
1581 | } | ||
1582 | dev_put(netdev); | ||
1583 | } | ||
1584 | } | ||
1585 | |||
1391 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 1586 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { |
1392 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 1587 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) |
1393 | continue; | 1588 | continue; |
1394 | if (++idx <= start) | 1589 | if (++idx <= start) |
1395 | continue; | 1590 | continue; |
1396 | if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).portid, | 1591 | if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy) |
1397 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1592 | continue; |
1398 | dev) < 0) { | 1593 | /* attempt to fit multiple wiphy data chunks into the skb */ |
1399 | idx--; | 1594 | do { |
1400 | break; | 1595 | ret = nl80211_send_wiphy(dev, skb, |
1401 | } | 1596 | NETLINK_CB(cb->skb).portid, |
1597 | cb->nlh->nlmsg_seq, | ||
1598 | NLM_F_MULTI, | ||
1599 | split, &cb->args[1], | ||
1600 | &cb->args[2], | ||
1601 | &cb->args[3]); | ||
1602 | if (ret < 0) { | ||
1603 | /* | ||
1604 | * If sending the wiphy data didn't fit (ENOBUFS | ||
1605 | * or EMSGSIZE returned), this SKB is still | ||
1606 | * empty (so it's not too big because another | ||
1607 | * wiphy dataset is already in the skb) and | ||
1608 | * we've not tried to adjust the dump allocation | ||
1609 | * yet ... then adjust the alloc size to be | ||
1610 | * bigger, and return 1 but with the empty skb. | ||
1611 | * This results in an empty message being RX'ed | ||
1612 | * in userspace, but that is ignored. | ||
1613 | * | ||
1614 | * We can then retry with the larger buffer. | ||
1615 | */ | ||
1616 | if ((ret == -ENOBUFS || ret == -EMSGSIZE) && | ||
1617 | !skb->len && | ||
1618 | cb->min_dump_alloc < 4096) { | ||
1619 | cb->min_dump_alloc = 4096; | ||
1620 | mutex_unlock(&cfg80211_mutex); | ||
1621 | return 1; | ||
1622 | } | ||
1623 | idx--; | ||
1624 | break; | ||
1625 | } | ||
1626 | } while (cb->args[1] > 0); | ||
1627 | break; | ||
1402 | } | 1628 | } |
1403 | mutex_unlock(&cfg80211_mutex); | 1629 | mutex_unlock(&cfg80211_mutex); |
1404 | 1630 | ||
@@ -1412,11 +1638,12 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1412 | struct sk_buff *msg; | 1638 | struct sk_buff *msg; |
1413 | struct cfg80211_registered_device *dev = info->user_ptr[0]; | 1639 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1414 | 1640 | ||
1415 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1641 | msg = nlmsg_new(4096, GFP_KERNEL); |
1416 | if (!msg) | 1642 | if (!msg) |
1417 | return -ENOMEM; | 1643 | return -ENOMEM; |
1418 | 1644 | ||
1419 | if (nl80211_send_wiphy(msg, info->snd_portid, info->snd_seq, 0, dev) < 0) { | 1645 | if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0, |
1646 | false, NULL, NULL, NULL) < 0) { | ||
1420 | nlmsg_free(msg); | 1647 | nlmsg_free(msg); |
1421 | return -ENOBUFS; | 1648 | return -ENOBUFS; |
1422 | } | 1649 | } |
@@ -3023,6 +3250,7 @@ static int parse_station_flags(struct genl_info *info, | |||
3023 | sta_flags = nla_data(nla); | 3250 | sta_flags = nla_data(nla); |
3024 | params->sta_flags_mask = sta_flags->mask; | 3251 | params->sta_flags_mask = sta_flags->mask; |
3025 | params->sta_flags_set = sta_flags->set; | 3252 | params->sta_flags_set = sta_flags->set; |
3253 | params->sta_flags_set &= params->sta_flags_mask; | ||
3026 | if ((params->sta_flags_mask | | 3254 | if ((params->sta_flags_mask | |
3027 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) | 3255 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) |
3028 | return -EINVAL; | 3256 | return -EINVAL; |
@@ -3376,6 +3604,136 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
3376 | return genlmsg_reply(msg, info); | 3604 | return genlmsg_reply(msg, info); |
3377 | } | 3605 | } |
3378 | 3606 | ||
3607 | int cfg80211_check_station_change(struct wiphy *wiphy, | ||
3608 | struct station_parameters *params, | ||
3609 | enum cfg80211_station_type statype) | ||
3610 | { | ||
3611 | if (params->listen_interval != -1) | ||
3612 | return -EINVAL; | ||
3613 | if (params->aid) | ||
3614 | return -EINVAL; | ||
3615 | |||
3616 | /* When you run into this, adjust the code below for the new flag */ | ||
3617 | BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); | ||
3618 | |||
3619 | switch (statype) { | ||
3620 | case CFG80211_STA_MESH_PEER_KERNEL: | ||
3621 | case CFG80211_STA_MESH_PEER_USER: | ||
3622 | /* | ||
3623 | * No ignoring the TDLS flag here -- the userspace mesh | ||
3624 | * code doesn't have the bug of including TDLS in the | ||
3625 | * mask everywhere. | ||
3626 | */ | ||
3627 | if (params->sta_flags_mask & | ||
3628 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3629 | BIT(NL80211_STA_FLAG_MFP) | | ||
3630 | BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
3631 | return -EINVAL; | ||
3632 | break; | ||
3633 | case CFG80211_STA_TDLS_PEER_SETUP: | ||
3634 | case CFG80211_STA_TDLS_PEER_ACTIVE: | ||
3635 | if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
3636 | return -EINVAL; | ||
3637 | /* ignore since it can't change */ | ||
3638 | params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3639 | break; | ||
3640 | default: | ||
3641 | /* disallow mesh-specific things */ | ||
3642 | if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION) | ||
3643 | return -EINVAL; | ||
3644 | if (params->local_pm) | ||
3645 | return -EINVAL; | ||
3646 | if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) | ||
3647 | return -EINVAL; | ||
3648 | } | ||
3649 | |||
3650 | if (statype != CFG80211_STA_TDLS_PEER_SETUP && | ||
3651 | statype != CFG80211_STA_TDLS_PEER_ACTIVE) { | ||
3652 | /* TDLS can't be set, ... */ | ||
3653 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | ||
3654 | return -EINVAL; | ||
3655 | /* | ||
3656 | * ... but don't bother the driver with it. This works around | ||
3657 | * a hostapd/wpa_supplicant issue -- it always includes the | ||
3658 | * TLDS_PEER flag in the mask even for AP mode. | ||
3659 | */ | ||
3660 | params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3661 | } | ||
3662 | |||
3663 | if (statype != CFG80211_STA_TDLS_PEER_SETUP) { | ||
3664 | /* reject other things that can't change */ | ||
3665 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) | ||
3666 | return -EINVAL; | ||
3667 | if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY) | ||
3668 | return -EINVAL; | ||
3669 | if (params->supported_rates) | ||
3670 | return -EINVAL; | ||
3671 | if (params->ext_capab || params->ht_capa || params->vht_capa) | ||
3672 | return -EINVAL; | ||
3673 | } | ||
3674 | |||
3675 | if (statype != CFG80211_STA_AP_CLIENT) { | ||
3676 | if (params->vlan) | ||
3677 | return -EINVAL; | ||
3678 | } | ||
3679 | |||
3680 | switch (statype) { | ||
3681 | case CFG80211_STA_AP_MLME_CLIENT: | ||
3682 | /* Use this only for authorizing/unauthorizing a station */ | ||
3683 | if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
3684 | return -EOPNOTSUPP; | ||
3685 | break; | ||
3686 | case CFG80211_STA_AP_CLIENT: | ||
3687 | /* accept only the listed bits */ | ||
3688 | if (params->sta_flags_mask & | ||
3689 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3690 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3691 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
3692 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
3693 | BIT(NL80211_STA_FLAG_WME) | | ||
3694 | BIT(NL80211_STA_FLAG_MFP))) | ||
3695 | return -EINVAL; | ||
3696 | |||
3697 | /* but authenticated/associated only if driver handles it */ | ||
3698 | if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) && | ||
3699 | params->sta_flags_mask & | ||
3700 | (BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3701 | BIT(NL80211_STA_FLAG_ASSOCIATED))) | ||
3702 | return -EINVAL; | ||
3703 | break; | ||
3704 | case CFG80211_STA_IBSS: | ||
3705 | case CFG80211_STA_AP_STA: | ||
3706 | /* reject any changes other than AUTHORIZED */ | ||
3707 | if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
3708 | return -EINVAL; | ||
3709 | break; | ||
3710 | case CFG80211_STA_TDLS_PEER_SETUP: | ||
3711 | /* reject any changes other than AUTHORIZED or WME */ | ||
3712 | if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3713 | BIT(NL80211_STA_FLAG_WME))) | ||
3714 | return -EINVAL; | ||
3715 | /* force (at least) rates when authorizing */ | ||
3716 | if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) && | ||
3717 | !params->supported_rates) | ||
3718 | return -EINVAL; | ||
3719 | break; | ||
3720 | case CFG80211_STA_TDLS_PEER_ACTIVE: | ||
3721 | /* reject any changes */ | ||
3722 | return -EINVAL; | ||
3723 | case CFG80211_STA_MESH_PEER_KERNEL: | ||
3724 | if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) | ||
3725 | return -EINVAL; | ||
3726 | break; | ||
3727 | case CFG80211_STA_MESH_PEER_USER: | ||
3728 | if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION) | ||
3729 | return -EINVAL; | ||
3730 | break; | ||
3731 | } | ||
3732 | |||
3733 | return 0; | ||
3734 | } | ||
3735 | EXPORT_SYMBOL(cfg80211_check_station_change); | ||
3736 | |||
3379 | /* | 3737 | /* |
3380 | * Get vlan interface making sure it is running and on the right wiphy. | 3738 | * Get vlan interface making sure it is running and on the right wiphy. |
3381 | */ | 3739 | */ |
@@ -3398,6 +3756,13 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
3398 | goto error; | 3756 | goto error; |
3399 | } | 3757 | } |
3400 | 3758 | ||
3759 | if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | ||
3760 | v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
3761 | v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { | ||
3762 | ret = -EINVAL; | ||
3763 | goto error; | ||
3764 | } | ||
3765 | |||
3401 | if (!netif_running(v)) { | 3766 | if (!netif_running(v)) { |
3402 | ret = -ENETDOWN; | 3767 | ret = -ENETDOWN; |
3403 | goto error; | 3768 | goto error; |
@@ -3415,21 +3780,13 @@ nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | |||
3415 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | 3780 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, |
3416 | }; | 3781 | }; |
3417 | 3782 | ||
3418 | static int nl80211_set_station_tdls(struct genl_info *info, | 3783 | static int nl80211_parse_sta_wme(struct genl_info *info, |
3419 | struct station_parameters *params) | 3784 | struct station_parameters *params) |
3420 | { | 3785 | { |
3421 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | 3786 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; |
3422 | struct nlattr *nla; | 3787 | struct nlattr *nla; |
3423 | int err; | 3788 | int err; |
3424 | 3789 | ||
3425 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
3426 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3427 | params->ht_capa = | ||
3428 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
3429 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3430 | params->vht_capa = | ||
3431 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
3432 | |||
3433 | /* parse WME attributes if present */ | 3790 | /* parse WME attributes if present */ |
3434 | if (!info->attrs[NL80211_ATTR_STA_WME]) | 3791 | if (!info->attrs[NL80211_ATTR_STA_WME]) |
3435 | return 0; | 3792 | return 0; |
@@ -3457,18 +3814,34 @@ static int nl80211_set_station_tdls(struct genl_info *info, | |||
3457 | return 0; | 3814 | return 0; |
3458 | } | 3815 | } |
3459 | 3816 | ||
3817 | static int nl80211_set_station_tdls(struct genl_info *info, | ||
3818 | struct station_parameters *params) | ||
3819 | { | ||
3820 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
3821 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3822 | params->ht_capa = | ||
3823 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
3824 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3825 | params->vht_capa = | ||
3826 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
3827 | |||
3828 | return nl80211_parse_sta_wme(info, params); | ||
3829 | } | ||
3830 | |||
3460 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 3831 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
3461 | { | 3832 | { |
3462 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3833 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3463 | int err; | ||
3464 | struct net_device *dev = info->user_ptr[1]; | 3834 | struct net_device *dev = info->user_ptr[1]; |
3465 | struct station_parameters params; | 3835 | struct station_parameters params; |
3466 | u8 *mac_addr = NULL; | 3836 | u8 *mac_addr; |
3837 | int err; | ||
3467 | 3838 | ||
3468 | memset(¶ms, 0, sizeof(params)); | 3839 | memset(¶ms, 0, sizeof(params)); |
3469 | 3840 | ||
3470 | params.listen_interval = -1; | 3841 | params.listen_interval = -1; |
3471 | params.plink_state = -1; | 3842 | |
3843 | if (!rdev->ops->change_station) | ||
3844 | return -EOPNOTSUPP; | ||
3472 | 3845 | ||
3473 | if (info->attrs[NL80211_ATTR_STA_AID]) | 3846 | if (info->attrs[NL80211_ATTR_STA_AID]) |
3474 | return -EINVAL; | 3847 | return -EINVAL; |
@@ -3501,19 +3874,23 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3501 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 3874 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
3502 | return -EINVAL; | 3875 | return -EINVAL; |
3503 | 3876 | ||
3504 | if (!rdev->ops->change_station) | ||
3505 | return -EOPNOTSUPP; | ||
3506 | |||
3507 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) | 3877 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) |
3508 | return -EINVAL; | 3878 | return -EINVAL; |
3509 | 3879 | ||
3510 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 3880 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { |
3511 | params.plink_action = | 3881 | params.plink_action = |
3512 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 3882 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
3883 | if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS) | ||
3884 | return -EINVAL; | ||
3885 | } | ||
3513 | 3886 | ||
3514 | if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) | 3887 | if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) { |
3515 | params.plink_state = | 3888 | params.plink_state = |
3516 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); | 3889 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); |
3890 | if (params.plink_state >= NUM_NL80211_PLINK_STATES) | ||
3891 | return -EINVAL; | ||
3892 | params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE; | ||
3893 | } | ||
3517 | 3894 | ||
3518 | if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) { | 3895 | if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) { |
3519 | enum nl80211_mesh_power_mode pm = nla_get_u32( | 3896 | enum nl80211_mesh_power_mode pm = nla_get_u32( |
@@ -3526,127 +3903,33 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3526 | params.local_pm = pm; | 3903 | params.local_pm = pm; |
3527 | } | 3904 | } |
3528 | 3905 | ||
3906 | /* Include parameters for TDLS peer (will check later) */ | ||
3907 | err = nl80211_set_station_tdls(info, ¶ms); | ||
3908 | if (err) | ||
3909 | return err; | ||
3910 | |||
3911 | params.vlan = get_vlan(info, rdev); | ||
3912 | if (IS_ERR(params.vlan)) | ||
3913 | return PTR_ERR(params.vlan); | ||
3914 | |||
3529 | switch (dev->ieee80211_ptr->iftype) { | 3915 | switch (dev->ieee80211_ptr->iftype) { |
3530 | case NL80211_IFTYPE_AP: | 3916 | case NL80211_IFTYPE_AP: |
3531 | case NL80211_IFTYPE_AP_VLAN: | 3917 | case NL80211_IFTYPE_AP_VLAN: |
3532 | case NL80211_IFTYPE_P2P_GO: | 3918 | case NL80211_IFTYPE_P2P_GO: |
3533 | /* disallow mesh-specific things */ | ||
3534 | if (params.plink_action) | ||
3535 | return -EINVAL; | ||
3536 | if (params.local_pm) | ||
3537 | return -EINVAL; | ||
3538 | |||
3539 | /* TDLS can't be set, ... */ | ||
3540 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | ||
3541 | return -EINVAL; | ||
3542 | /* | ||
3543 | * ... but don't bother the driver with it. This works around | ||
3544 | * a hostapd/wpa_supplicant issue -- it always includes the | ||
3545 | * TLDS_PEER flag in the mask even for AP mode. | ||
3546 | */ | ||
3547 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3548 | |||
3549 | /* accept only the listed bits */ | ||
3550 | if (params.sta_flags_mask & | ||
3551 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3552 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3553 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
3554 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
3555 | BIT(NL80211_STA_FLAG_WME) | | ||
3556 | BIT(NL80211_STA_FLAG_MFP))) | ||
3557 | return -EINVAL; | ||
3558 | |||
3559 | /* but authenticated/associated only if driver handles it */ | ||
3560 | if (!(rdev->wiphy.features & | ||
3561 | NL80211_FEATURE_FULL_AP_CLIENT_STATE) && | ||
3562 | params.sta_flags_mask & | ||
3563 | (BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3564 | BIT(NL80211_STA_FLAG_ASSOCIATED))) | ||
3565 | return -EINVAL; | ||
3566 | |||
3567 | /* reject other things that can't change */ | ||
3568 | if (params.supported_rates) | ||
3569 | return -EINVAL; | ||
3570 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
3571 | return -EINVAL; | ||
3572 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
3573 | return -EINVAL; | ||
3574 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3575 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3576 | return -EINVAL; | ||
3577 | |||
3578 | /* must be last in here for error handling */ | ||
3579 | params.vlan = get_vlan(info, rdev); | ||
3580 | if (IS_ERR(params.vlan)) | ||
3581 | return PTR_ERR(params.vlan); | ||
3582 | break; | ||
3583 | case NL80211_IFTYPE_P2P_CLIENT: | 3919 | case NL80211_IFTYPE_P2P_CLIENT: |
3584 | case NL80211_IFTYPE_STATION: | 3920 | case NL80211_IFTYPE_STATION: |
3585 | /* | ||
3586 | * Don't allow userspace to change the TDLS_PEER flag, | ||
3587 | * but silently ignore attempts to change it since we | ||
3588 | * don't have state here to verify that it doesn't try | ||
3589 | * to change the flag. | ||
3590 | */ | ||
3591 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
3592 | /* Include parameters for TDLS peer (driver will check) */ | ||
3593 | err = nl80211_set_station_tdls(info, ¶ms); | ||
3594 | if (err) | ||
3595 | return err; | ||
3596 | /* disallow things sta doesn't support */ | ||
3597 | if (params.plink_action) | ||
3598 | return -EINVAL; | ||
3599 | if (params.local_pm) | ||
3600 | return -EINVAL; | ||
3601 | /* reject any changes other than AUTHORIZED or WME (for TDLS) */ | ||
3602 | if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3603 | BIT(NL80211_STA_FLAG_WME))) | ||
3604 | return -EINVAL; | ||
3605 | break; | ||
3606 | case NL80211_IFTYPE_ADHOC: | 3921 | case NL80211_IFTYPE_ADHOC: |
3607 | /* disallow things sta doesn't support */ | ||
3608 | if (params.plink_action) | ||
3609 | return -EINVAL; | ||
3610 | if (params.local_pm) | ||
3611 | return -EINVAL; | ||
3612 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3613 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3614 | return -EINVAL; | ||
3615 | /* reject any changes other than AUTHORIZED */ | ||
3616 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
3617 | return -EINVAL; | ||
3618 | break; | ||
3619 | case NL80211_IFTYPE_MESH_POINT: | 3922 | case NL80211_IFTYPE_MESH_POINT: |
3620 | /* disallow things mesh doesn't support */ | ||
3621 | if (params.vlan) | ||
3622 | return -EINVAL; | ||
3623 | if (params.supported_rates) | ||
3624 | return -EINVAL; | ||
3625 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
3626 | return -EINVAL; | ||
3627 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
3628 | return -EINVAL; | ||
3629 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3630 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3631 | return -EINVAL; | ||
3632 | /* | ||
3633 | * No special handling for TDLS here -- the userspace | ||
3634 | * mesh code doesn't have this bug. | ||
3635 | */ | ||
3636 | if (params.sta_flags_mask & | ||
3637 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
3638 | BIT(NL80211_STA_FLAG_MFP) | | ||
3639 | BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
3640 | return -EINVAL; | ||
3641 | break; | 3923 | break; |
3642 | default: | 3924 | default: |
3643 | return -EOPNOTSUPP; | 3925 | err = -EOPNOTSUPP; |
3926 | goto out_put_vlan; | ||
3644 | } | 3927 | } |
3645 | 3928 | ||
3646 | /* be aware of params.vlan when changing code here */ | 3929 | /* driver will call cfg80211_check_station_change() */ |
3647 | |||
3648 | err = rdev_change_station(rdev, dev, mac_addr, ¶ms); | 3930 | err = rdev_change_station(rdev, dev, mac_addr, ¶ms); |
3649 | 3931 | ||
3932 | out_put_vlan: | ||
3650 | if (params.vlan) | 3933 | if (params.vlan) |
3651 | dev_put(params.vlan); | 3934 | dev_put(params.vlan); |
3652 | 3935 | ||
@@ -3663,6 +3946,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3663 | 3946 | ||
3664 | memset(¶ms, 0, sizeof(params)); | 3947 | memset(¶ms, 0, sizeof(params)); |
3665 | 3948 | ||
3949 | if (!rdev->ops->add_station) | ||
3950 | return -EOPNOTSUPP; | ||
3951 | |||
3666 | if (!info->attrs[NL80211_ATTR_MAC]) | 3952 | if (!info->attrs[NL80211_ATTR_MAC]) |
3667 | return -EINVAL; | 3953 | return -EINVAL; |
3668 | 3954 | ||
@@ -3708,50 +3994,32 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3708 | params.vht_capa = | 3994 | params.vht_capa = |
3709 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | 3995 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); |
3710 | 3996 | ||
3711 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 3997 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) { |
3712 | params.plink_action = | 3998 | params.plink_action = |
3713 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 3999 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
4000 | if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS) | ||
4001 | return -EINVAL; | ||
4002 | } | ||
3714 | 4003 | ||
3715 | if (!rdev->ops->add_station) | 4004 | err = nl80211_parse_sta_wme(info, ¶ms); |
3716 | return -EOPNOTSUPP; | 4005 | if (err) |
4006 | return err; | ||
3717 | 4007 | ||
3718 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) | 4008 | if (parse_station_flags(info, dev->ieee80211_ptr->iftype, ¶ms)) |
3719 | return -EINVAL; | 4009 | return -EINVAL; |
3720 | 4010 | ||
4011 | /* When you run into this, adjust the code below for the new flag */ | ||
4012 | BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7); | ||
4013 | |||
3721 | switch (dev->ieee80211_ptr->iftype) { | 4014 | switch (dev->ieee80211_ptr->iftype) { |
3722 | case NL80211_IFTYPE_AP: | 4015 | case NL80211_IFTYPE_AP: |
3723 | case NL80211_IFTYPE_AP_VLAN: | 4016 | case NL80211_IFTYPE_AP_VLAN: |
3724 | case NL80211_IFTYPE_P2P_GO: | 4017 | case NL80211_IFTYPE_P2P_GO: |
3725 | /* parse WME attributes if sta is WME capable */ | 4018 | /* ignore WME attributes if iface/sta is not capable */ |
3726 | if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) && | 4019 | if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) || |
3727 | (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) && | 4020 | !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) |
3728 | info->attrs[NL80211_ATTR_STA_WME]) { | 4021 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; |
3729 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | ||
3730 | struct nlattr *nla; | ||
3731 | |||
3732 | nla = info->attrs[NL80211_ATTR_STA_WME]; | ||
3733 | err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, | ||
3734 | nl80211_sta_wme_policy); | ||
3735 | if (err) | ||
3736 | return err; | ||
3737 | |||
3738 | if (tb[NL80211_STA_WME_UAPSD_QUEUES]) | ||
3739 | params.uapsd_queues = | ||
3740 | nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]); | ||
3741 | if (params.uapsd_queues & | ||
3742 | ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
3743 | return -EINVAL; | ||
3744 | 4022 | ||
3745 | if (tb[NL80211_STA_WME_MAX_SP]) | ||
3746 | params.max_sp = | ||
3747 | nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); | ||
3748 | |||
3749 | if (params.max_sp & | ||
3750 | ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
3751 | return -EINVAL; | ||
3752 | |||
3753 | params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | ||
3754 | } | ||
3755 | /* TDLS peers cannot be added */ | 4023 | /* TDLS peers cannot be added */ |
3756 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) | 4024 | if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) |
3757 | return -EINVAL; | 4025 | return -EINVAL; |
@@ -3772,6 +4040,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3772 | return PTR_ERR(params.vlan); | 4040 | return PTR_ERR(params.vlan); |
3773 | break; | 4041 | break; |
3774 | case NL80211_IFTYPE_MESH_POINT: | 4042 | case NL80211_IFTYPE_MESH_POINT: |
4043 | /* ignore uAPSD data */ | ||
4044 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; | ||
4045 | |||
3775 | /* associated is disallowed */ | 4046 | /* associated is disallowed */ |
3776 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | 4047 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) |
3777 | return -EINVAL; | 4048 | return -EINVAL; |
@@ -3780,8 +4051,14 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3780 | return -EINVAL; | 4051 | return -EINVAL; |
3781 | break; | 4052 | break; |
3782 | case NL80211_IFTYPE_STATION: | 4053 | case NL80211_IFTYPE_STATION: |
3783 | /* associated is disallowed */ | 4054 | case NL80211_IFTYPE_P2P_CLIENT: |
3784 | if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) | 4055 | /* ignore uAPSD data */ |
4056 | params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD; | ||
4057 | |||
4058 | /* these are disallowed */ | ||
4059 | if (params.sta_flags_mask & | ||
4060 | (BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
4061 | BIT(NL80211_STA_FLAG_AUTHENTICATED))) | ||
3785 | return -EINVAL; | 4062 | return -EINVAL; |
3786 | /* Only TDLS peers can be added */ | 4063 | /* Only TDLS peers can be added */ |
3787 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | 4064 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) |
@@ -3792,6 +4069,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3792 | /* ... with external setup is supported */ | 4069 | /* ... with external setup is supported */ |
3793 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) | 4070 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) |
3794 | return -EOPNOTSUPP; | 4071 | return -EOPNOTSUPP; |
4072 | /* | ||
4073 | * Older wpa_supplicant versions always mark the TDLS peer | ||
4074 | * as authorized, but it shouldn't yet be. | ||
4075 | */ | ||
4076 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
3795 | break; | 4077 | break; |
3796 | default: | 4078 | default: |
3797 | return -EOPNOTSUPP; | 4079 | return -EOPNOTSUPP; |
@@ -4336,6 +4618,7 @@ static const struct nla_policy | |||
4336 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, | 4618 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, |
4337 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | 4619 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, |
4338 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, | 4620 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
4621 | [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG }, | ||
4339 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | 4622 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, |
4340 | .len = IEEE80211_MAX_DATA_LEN }, | 4623 | .len = IEEE80211_MAX_DATA_LEN }, |
4341 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, | 4624 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, |
@@ -4474,6 +4757,7 @@ do { \ | |||
4474 | static int nl80211_parse_mesh_setup(struct genl_info *info, | 4757 | static int nl80211_parse_mesh_setup(struct genl_info *info, |
4475 | struct mesh_setup *setup) | 4758 | struct mesh_setup *setup) |
4476 | { | 4759 | { |
4760 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4477 | struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; | 4761 | struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1]; |
4478 | 4762 | ||
4479 | if (!info->attrs[NL80211_ATTR_MESH_SETUP]) | 4763 | if (!info->attrs[NL80211_ATTR_MESH_SETUP]) |
@@ -4510,8 +4794,14 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, | |||
4510 | setup->ie = nla_data(ieattr); | 4794 | setup->ie = nla_data(ieattr); |
4511 | setup->ie_len = nla_len(ieattr); | 4795 | setup->ie_len = nla_len(ieattr); |
4512 | } | 4796 | } |
4797 | if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] && | ||
4798 | !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM)) | ||
4799 | return -EINVAL; | ||
4800 | setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]); | ||
4513 | setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); | 4801 | setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); |
4514 | setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); | 4802 | setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); |
4803 | if (setup->is_secure) | ||
4804 | setup->user_mpm = true; | ||
4515 | 4805 | ||
4516 | return 0; | 4806 | return 0; |
4517 | } | 4807 | } |
@@ -5706,14 +5996,10 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
5706 | { | 5996 | { |
5707 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5997 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5708 | struct net_device *dev = info->user_ptr[1]; | 5998 | struct net_device *dev = info->user_ptr[1]; |
5709 | struct cfg80211_crypto_settings crypto; | ||
5710 | struct ieee80211_channel *chan; | 5999 | struct ieee80211_channel *chan; |
5711 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 6000 | struct cfg80211_assoc_request req = {}; |
5712 | int err, ssid_len, ie_len = 0; | 6001 | const u8 *bssid, *ssid; |
5713 | bool use_mfp = false; | 6002 | int err, ssid_len = 0; |
5714 | u32 flags = 0; | ||
5715 | struct ieee80211_ht_cap *ht_capa = NULL; | ||
5716 | struct ieee80211_ht_cap *ht_capa_mask = NULL; | ||
5717 | 6003 | ||
5718 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 6004 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
5719 | return -EINVAL; | 6005 | return -EINVAL; |
@@ -5741,41 +6027,58 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
5741 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 6027 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
5742 | 6028 | ||
5743 | if (info->attrs[NL80211_ATTR_IE]) { | 6029 | if (info->attrs[NL80211_ATTR_IE]) { |
5744 | ie = nla_data(info->attrs[NL80211_ATTR_IE]); | 6030 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); |
5745 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 6031 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
5746 | } | 6032 | } |
5747 | 6033 | ||
5748 | if (info->attrs[NL80211_ATTR_USE_MFP]) { | 6034 | if (info->attrs[NL80211_ATTR_USE_MFP]) { |
5749 | enum nl80211_mfp mfp = | 6035 | enum nl80211_mfp mfp = |
5750 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | 6036 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); |
5751 | if (mfp == NL80211_MFP_REQUIRED) | 6037 | if (mfp == NL80211_MFP_REQUIRED) |
5752 | use_mfp = true; | 6038 | req.use_mfp = true; |
5753 | else if (mfp != NL80211_MFP_NO) | 6039 | else if (mfp != NL80211_MFP_NO) |
5754 | return -EINVAL; | 6040 | return -EINVAL; |
5755 | } | 6041 | } |
5756 | 6042 | ||
5757 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 6043 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
5758 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 6044 | req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
5759 | 6045 | ||
5760 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | 6046 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) |
5761 | flags |= ASSOC_REQ_DISABLE_HT; | 6047 | req.flags |= ASSOC_REQ_DISABLE_HT; |
5762 | 6048 | ||
5763 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | 6049 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) |
5764 | ht_capa_mask = | 6050 | memcpy(&req.ht_capa_mask, |
5765 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]); | 6051 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]), |
6052 | sizeof(req.ht_capa_mask)); | ||
5766 | 6053 | ||
5767 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | 6054 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { |
5768 | if (!ht_capa_mask) | 6055 | if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) |
6056 | return -EINVAL; | ||
6057 | memcpy(&req.ht_capa, | ||
6058 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]), | ||
6059 | sizeof(req.ht_capa)); | ||
6060 | } | ||
6061 | |||
6062 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT])) | ||
6063 | req.flags |= ASSOC_REQ_DISABLE_VHT; | ||
6064 | |||
6065 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6066 | memcpy(&req.vht_capa_mask, | ||
6067 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), | ||
6068 | sizeof(req.vht_capa_mask)); | ||
6069 | |||
6070 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { | ||
6071 | if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
5769 | return -EINVAL; | 6072 | return -EINVAL; |
5770 | ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 6073 | memcpy(&req.vht_capa, |
6074 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]), | ||
6075 | sizeof(req.vht_capa)); | ||
5771 | } | 6076 | } |
5772 | 6077 | ||
5773 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); | 6078 | err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); |
5774 | if (!err) | 6079 | if (!err) |
5775 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 6080 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, |
5776 | ssid, ssid_len, ie, ie_len, use_mfp, | 6081 | ssid, ssid_len, &req); |
5777 | &crypto, flags, ht_capa, | ||
5778 | ht_capa_mask); | ||
5779 | 6082 | ||
5780 | return err; | 6083 | return err; |
5781 | } | 6084 | } |
@@ -6355,6 +6658,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
6355 | sizeof(connect.ht_capa)); | 6658 | sizeof(connect.ht_capa)); |
6356 | } | 6659 | } |
6357 | 6660 | ||
6661 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT])) | ||
6662 | connect.flags |= ASSOC_REQ_DISABLE_VHT; | ||
6663 | |||
6664 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6665 | memcpy(&connect.vht_capa_mask, | ||
6666 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), | ||
6667 | sizeof(connect.vht_capa_mask)); | ||
6668 | |||
6669 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { | ||
6670 | if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) { | ||
6671 | kfree(connkeys); | ||
6672 | return -EINVAL; | ||
6673 | } | ||
6674 | memcpy(&connect.vht_capa, | ||
6675 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]), | ||
6676 | sizeof(connect.vht_capa)); | ||
6677 | } | ||
6678 | |||
6358 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 6679 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
6359 | if (err) | 6680 | if (err) |
6360 | kfree(connkeys); | 6681 | kfree(connkeys); |
@@ -7128,6 +7449,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
7128 | return err; | 7449 | return err; |
7129 | } | 7450 | } |
7130 | 7451 | ||
7452 | if (setup.user_mpm) | ||
7453 | cfg.auto_open_plinks = false; | ||
7454 | |||
7131 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 7455 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
7132 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); | 7456 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); |
7133 | if (err) | 7457 | if (err) |
@@ -7327,7 +7651,8 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | |||
7327 | return -EINVAL; | 7651 | return -EINVAL; |
7328 | 7652 | ||
7329 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > | 7653 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > |
7330 | rdev->wiphy.wowlan.tcp->data_interval_max) | 7654 | rdev->wiphy.wowlan.tcp->data_interval_max || |
7655 | nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0) | ||
7331 | return -EINVAL; | 7656 | return -EINVAL; |
7332 | 7657 | ||
7333 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); | 7658 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); |
@@ -7823,6 +8148,54 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
7823 | return 0; | 8148 | return 0; |
7824 | } | 8149 | } |
7825 | 8150 | ||
8151 | static int nl80211_get_protocol_features(struct sk_buff *skb, | ||
8152 | struct genl_info *info) | ||
8153 | { | ||
8154 | void *hdr; | ||
8155 | struct sk_buff *msg; | ||
8156 | |||
8157 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
8158 | if (!msg) | ||
8159 | return -ENOMEM; | ||
8160 | |||
8161 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | ||
8162 | NL80211_CMD_GET_PROTOCOL_FEATURES); | ||
8163 | if (!hdr) | ||
8164 | goto nla_put_failure; | ||
8165 | |||
8166 | if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES, | ||
8167 | NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)) | ||
8168 | goto nla_put_failure; | ||
8169 | |||
8170 | genlmsg_end(msg, hdr); | ||
8171 | return genlmsg_reply(msg, info); | ||
8172 | |||
8173 | nla_put_failure: | ||
8174 | kfree_skb(msg); | ||
8175 | return -ENOBUFS; | ||
8176 | } | ||
8177 | |||
8178 | static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info) | ||
8179 | { | ||
8180 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8181 | struct cfg80211_update_ft_ies_params ft_params; | ||
8182 | struct net_device *dev = info->user_ptr[1]; | ||
8183 | |||
8184 | if (!rdev->ops->update_ft_ies) | ||
8185 | return -EOPNOTSUPP; | ||
8186 | |||
8187 | if (!info->attrs[NL80211_ATTR_MDID] || | ||
8188 | !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
8189 | return -EINVAL; | ||
8190 | |||
8191 | memset(&ft_params, 0, sizeof(ft_params)); | ||
8192 | ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]); | ||
8193 | ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
8194 | ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
8195 | |||
8196 | return rdev_update_ft_ies(rdev, dev, &ft_params); | ||
8197 | } | ||
8198 | |||
7826 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 8199 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
7827 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 8200 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
7828 | #define NL80211_FLAG_NEED_RTNL 0x04 | 8201 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -8499,6 +8872,19 @@ static struct genl_ops nl80211_ops[] = { | |||
8499 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 8872 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
8500 | NL80211_FLAG_NEED_RTNL, | 8873 | NL80211_FLAG_NEED_RTNL, |
8501 | }, | 8874 | }, |
8875 | { | ||
8876 | .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, | ||
8877 | .doit = nl80211_get_protocol_features, | ||
8878 | .policy = nl80211_policy, | ||
8879 | }, | ||
8880 | { | ||
8881 | .cmd = NL80211_CMD_UPDATE_FT_IES, | ||
8882 | .doit = nl80211_update_ft_ies, | ||
8883 | .policy = nl80211_policy, | ||
8884 | .flags = GENL_ADMIN_PERM, | ||
8885 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
8886 | NL80211_FLAG_NEED_RTNL, | ||
8887 | }, | ||
8502 | }; | 8888 | }; |
8503 | 8889 | ||
8504 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 8890 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -8526,7 +8912,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
8526 | if (!msg) | 8912 | if (!msg) |
8527 | return; | 8913 | return; |
8528 | 8914 | ||
8529 | if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { | 8915 | if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, |
8916 | false, NULL, NULL, NULL) < 0) { | ||
8530 | nlmsg_free(msg); | 8917 | nlmsg_free(msg); |
8531 | return; | 8918 | return; |
8532 | } | 8919 | } |
@@ -8850,21 +9237,31 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | |||
8850 | NL80211_CMD_DISASSOCIATE, gfp); | 9237 | NL80211_CMD_DISASSOCIATE, gfp); |
8851 | } | 9238 | } |
8852 | 9239 | ||
8853 | void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, | 9240 | void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf, |
8854 | struct net_device *netdev, const u8 *buf, | 9241 | size_t len) |
8855 | size_t len, gfp_t gfp) | ||
8856 | { | 9242 | { |
8857 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 9243 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
8858 | NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp); | 9244 | struct wiphy *wiphy = wdev->wiphy; |
9245 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9246 | |||
9247 | trace_cfg80211_send_unprot_deauth(dev); | ||
9248 | nl80211_send_mlme_event(rdev, dev, buf, len, | ||
9249 | NL80211_CMD_UNPROT_DEAUTHENTICATE, GFP_ATOMIC); | ||
8859 | } | 9250 | } |
9251 | EXPORT_SYMBOL(cfg80211_send_unprot_deauth); | ||
8860 | 9252 | ||
8861 | void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, | 9253 | void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf, |
8862 | struct net_device *netdev, const u8 *buf, | 9254 | size_t len) |
8863 | size_t len, gfp_t gfp) | ||
8864 | { | 9255 | { |
8865 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 9256 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
8866 | NL80211_CMD_UNPROT_DISASSOCIATE, gfp); | 9257 | struct wiphy *wiphy = wdev->wiphy; |
9258 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9259 | |||
9260 | trace_cfg80211_send_unprot_disassoc(dev); | ||
9261 | nl80211_send_mlme_event(rdev, dev, buf, len, | ||
9262 | NL80211_CMD_UNPROT_DISASSOCIATE, GFP_ATOMIC); | ||
8867 | } | 9263 | } |
9264 | EXPORT_SYMBOL(cfg80211_send_unprot_disassoc); | ||
8868 | 9265 | ||
8869 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | 9266 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, |
8870 | struct net_device *netdev, int cmd, | 9267 | struct net_device *netdev, int cmd, |
@@ -9067,14 +9464,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
9067 | nlmsg_free(msg); | 9464 | nlmsg_free(msg); |
9068 | } | 9465 | } |
9069 | 9466 | ||
9070 | void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | 9467 | void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, |
9071 | struct net_device *netdev, | 9468 | const u8* ie, u8 ie_len, gfp_t gfp) |
9072 | const u8 *macaddr, const u8* ie, u8 ie_len, | ||
9073 | gfp_t gfp) | ||
9074 | { | 9469 | { |
9470 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9471 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
9075 | struct sk_buff *msg; | 9472 | struct sk_buff *msg; |
9076 | void *hdr; | 9473 | void *hdr; |
9077 | 9474 | ||
9475 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | ||
9476 | return; | ||
9477 | |||
9478 | trace_cfg80211_notify_new_peer_candidate(dev, addr); | ||
9479 | |||
9078 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9480 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9079 | if (!msg) | 9481 | if (!msg) |
9080 | return; | 9482 | return; |
@@ -9086,8 +9488,8 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | |||
9086 | } | 9488 | } |
9087 | 9489 | ||
9088 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 9490 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9089 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 9491 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9090 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr) || | 9492 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || |
9091 | (ie_len && ie && | 9493 | (ie_len && ie && |
9092 | nla_put(msg, NL80211_ATTR_IE, ie_len , ie))) | 9494 | nla_put(msg, NL80211_ATTR_IE, ie_len , ie))) |
9093 | goto nla_put_failure; | 9495 | goto nla_put_failure; |
@@ -9102,6 +9504,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | |||
9102 | genlmsg_cancel(msg, hdr); | 9504 | genlmsg_cancel(msg, hdr); |
9103 | nlmsg_free(msg); | 9505 | nlmsg_free(msg); |
9104 | } | 9506 | } |
9507 | EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate); | ||
9105 | 9508 | ||
9106 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 9509 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
9107 | struct net_device *netdev, const u8 *addr, | 9510 | struct net_device *netdev, const u8 *addr, |
@@ -9170,7 +9573,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
9170 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); | 9573 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); |
9171 | if (!nl_freq) | 9574 | if (!nl_freq) |
9172 | goto nla_put_failure; | 9575 | goto nla_put_failure; |
9173 | if (nl80211_msg_put_channel(msg, channel_before)) | 9576 | if (nl80211_msg_put_channel(msg, channel_before, false)) |
9174 | goto nla_put_failure; | 9577 | goto nla_put_failure; |
9175 | nla_nest_end(msg, nl_freq); | 9578 | nla_nest_end(msg, nl_freq); |
9176 | 9579 | ||
@@ -9178,7 +9581,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | |||
9178 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); | 9581 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); |
9179 | if (!nl_freq) | 9582 | if (!nl_freq) |
9180 | goto nla_put_failure; | 9583 | goto nla_put_failure; |
9181 | if (nl80211_msg_put_channel(msg, channel_after)) | 9584 | if (nl80211_msg_put_channel(msg, channel_after, false)) |
9182 | goto nla_put_failure; | 9585 | goto nla_put_failure; |
9183 | nla_nest_end(msg, nl_freq); | 9586 | nla_nest_end(msg, nl_freq); |
9184 | 9587 | ||
@@ -9240,31 +9643,42 @@ static void nl80211_send_remain_on_chan_event( | |||
9240 | nlmsg_free(msg); | 9643 | nlmsg_free(msg); |
9241 | } | 9644 | } |
9242 | 9645 | ||
9243 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 9646 | void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, |
9244 | struct wireless_dev *wdev, u64 cookie, | 9647 | struct ieee80211_channel *chan, |
9245 | struct ieee80211_channel *chan, | 9648 | unsigned int duration, gfp_t gfp) |
9246 | unsigned int duration, gfp_t gfp) | ||
9247 | { | 9649 | { |
9650 | struct wiphy *wiphy = wdev->wiphy; | ||
9651 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9652 | |||
9653 | trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration); | ||
9248 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | 9654 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, |
9249 | rdev, wdev, cookie, chan, | 9655 | rdev, wdev, cookie, chan, |
9250 | duration, gfp); | 9656 | duration, gfp); |
9251 | } | 9657 | } |
9658 | EXPORT_SYMBOL(cfg80211_ready_on_channel); | ||
9252 | 9659 | ||
9253 | void nl80211_send_remain_on_channel_cancel( | 9660 | void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, |
9254 | struct cfg80211_registered_device *rdev, | 9661 | struct ieee80211_channel *chan, |
9255 | struct wireless_dev *wdev, | 9662 | gfp_t gfp) |
9256 | u64 cookie, struct ieee80211_channel *chan, gfp_t gfp) | ||
9257 | { | 9663 | { |
9664 | struct wiphy *wiphy = wdev->wiphy; | ||
9665 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9666 | |||
9667 | trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan); | ||
9258 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 9668 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
9259 | rdev, wdev, cookie, chan, 0, gfp); | 9669 | rdev, wdev, cookie, chan, 0, gfp); |
9260 | } | 9670 | } |
9671 | EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | ||
9261 | 9672 | ||
9262 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | 9673 | void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, |
9263 | struct net_device *dev, const u8 *mac_addr, | 9674 | struct station_info *sinfo, gfp_t gfp) |
9264 | struct station_info *sinfo, gfp_t gfp) | ||
9265 | { | 9675 | { |
9676 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9677 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9266 | struct sk_buff *msg; | 9678 | struct sk_buff *msg; |
9267 | 9679 | ||
9680 | trace_cfg80211_new_sta(dev, mac_addr, sinfo); | ||
9681 | |||
9268 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9682 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9269 | if (!msg) | 9683 | if (!msg) |
9270 | return; | 9684 | return; |
@@ -9278,14 +9692,17 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
9278 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | 9692 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, |
9279 | nl80211_mlme_mcgrp.id, gfp); | 9693 | nl80211_mlme_mcgrp.id, gfp); |
9280 | } | 9694 | } |
9695 | EXPORT_SYMBOL(cfg80211_new_sta); | ||
9281 | 9696 | ||
9282 | void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | 9697 | void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) |
9283 | struct net_device *dev, const u8 *mac_addr, | ||
9284 | gfp_t gfp) | ||
9285 | { | 9698 | { |
9699 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9700 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9286 | struct sk_buff *msg; | 9701 | struct sk_buff *msg; |
9287 | void *hdr; | 9702 | void *hdr; |
9288 | 9703 | ||
9704 | trace_cfg80211_del_sta(dev, mac_addr); | ||
9705 | |||
9289 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9706 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9290 | if (!msg) | 9707 | if (!msg) |
9291 | return; | 9708 | return; |
@@ -9310,12 +9727,14 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
9310 | genlmsg_cancel(msg, hdr); | 9727 | genlmsg_cancel(msg, hdr); |
9311 | nlmsg_free(msg); | 9728 | nlmsg_free(msg); |
9312 | } | 9729 | } |
9730 | EXPORT_SYMBOL(cfg80211_del_sta); | ||
9313 | 9731 | ||
9314 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | 9732 | void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, |
9315 | struct net_device *dev, const u8 *mac_addr, | 9733 | enum nl80211_connect_failed_reason reason, |
9316 | enum nl80211_connect_failed_reason reason, | 9734 | gfp_t gfp) |
9317 | gfp_t gfp) | ||
9318 | { | 9735 | { |
9736 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
9737 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9319 | struct sk_buff *msg; | 9738 | struct sk_buff *msg; |
9320 | void *hdr; | 9739 | void *hdr; |
9321 | 9740 | ||
@@ -9344,6 +9763,7 @@ void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | |||
9344 | genlmsg_cancel(msg, hdr); | 9763 | genlmsg_cancel(msg, hdr); |
9345 | nlmsg_free(msg); | 9764 | nlmsg_free(msg); |
9346 | } | 9765 | } |
9766 | EXPORT_SYMBOL(cfg80211_conn_failed); | ||
9347 | 9767 | ||
9348 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | 9768 | static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, |
9349 | const u8 *addr, gfp_t gfp) | 9769 | const u8 *addr, gfp_t gfp) |
@@ -9388,19 +9808,47 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, | |||
9388 | return true; | 9808 | return true; |
9389 | } | 9809 | } |
9390 | 9810 | ||
9391 | bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp) | 9811 | bool cfg80211_rx_spurious_frame(struct net_device *dev, |
9812 | const u8 *addr, gfp_t gfp) | ||
9392 | { | 9813 | { |
9393 | return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, | 9814 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
9394 | addr, gfp); | 9815 | bool ret; |
9816 | |||
9817 | trace_cfg80211_rx_spurious_frame(dev, addr); | ||
9818 | |||
9819 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
9820 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) { | ||
9821 | trace_cfg80211_return_bool(false); | ||
9822 | return false; | ||
9823 | } | ||
9824 | ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME, | ||
9825 | addr, gfp); | ||
9826 | trace_cfg80211_return_bool(ret); | ||
9827 | return ret; | ||
9395 | } | 9828 | } |
9829 | EXPORT_SYMBOL(cfg80211_rx_spurious_frame); | ||
9396 | 9830 | ||
9397 | bool nl80211_unexpected_4addr_frame(struct net_device *dev, | 9831 | bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, |
9398 | const u8 *addr, gfp_t gfp) | 9832 | const u8 *addr, gfp_t gfp) |
9399 | { | 9833 | { |
9400 | return __nl80211_unexpected_frame(dev, | 9834 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
9401 | NL80211_CMD_UNEXPECTED_4ADDR_FRAME, | 9835 | bool ret; |
9402 | addr, gfp); | 9836 | |
9837 | trace_cfg80211_rx_unexpected_4addr_frame(dev, addr); | ||
9838 | |||
9839 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
9840 | wdev->iftype != NL80211_IFTYPE_P2P_GO && | ||
9841 | wdev->iftype != NL80211_IFTYPE_AP_VLAN)) { | ||
9842 | trace_cfg80211_return_bool(false); | ||
9843 | return false; | ||
9844 | } | ||
9845 | ret = __nl80211_unexpected_frame(dev, | ||
9846 | NL80211_CMD_UNEXPECTED_4ADDR_FRAME, | ||
9847 | addr, gfp); | ||
9848 | trace_cfg80211_return_bool(ret); | ||
9849 | return ret; | ||
9403 | } | 9850 | } |
9851 | EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame); | ||
9404 | 9852 | ||
9405 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 9853 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
9406 | struct wireless_dev *wdev, u32 nlportid, | 9854 | struct wireless_dev *wdev, u32 nlportid, |
@@ -9440,15 +9888,17 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
9440 | return -ENOBUFS; | 9888 | return -ENOBUFS; |
9441 | } | 9889 | } |
9442 | 9890 | ||
9443 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | 9891 | void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, |
9444 | struct wireless_dev *wdev, u64 cookie, | 9892 | const u8 *buf, size_t len, bool ack, gfp_t gfp) |
9445 | const u8 *buf, size_t len, bool ack, | ||
9446 | gfp_t gfp) | ||
9447 | { | 9893 | { |
9894 | struct wiphy *wiphy = wdev->wiphy; | ||
9895 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9448 | struct net_device *netdev = wdev->netdev; | 9896 | struct net_device *netdev = wdev->netdev; |
9449 | struct sk_buff *msg; | 9897 | struct sk_buff *msg; |
9450 | void *hdr; | 9898 | void *hdr; |
9451 | 9899 | ||
9900 | trace_cfg80211_mgmt_tx_status(wdev, cookie, ack); | ||
9901 | |||
9452 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9902 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9453 | if (!msg) | 9903 | if (!msg) |
9454 | return; | 9904 | return; |
@@ -9476,17 +9926,21 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | |||
9476 | genlmsg_cancel(msg, hdr); | 9926 | genlmsg_cancel(msg, hdr); |
9477 | nlmsg_free(msg); | 9927 | nlmsg_free(msg); |
9478 | } | 9928 | } |
9929 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); | ||
9479 | 9930 | ||
9480 | void | 9931 | void cfg80211_cqm_rssi_notify(struct net_device *dev, |
9481 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | 9932 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
9482 | struct net_device *netdev, | 9933 | gfp_t gfp) |
9483 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
9484 | gfp_t gfp) | ||
9485 | { | 9934 | { |
9935 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
9936 | struct wiphy *wiphy = wdev->wiphy; | ||
9937 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9486 | struct sk_buff *msg; | 9938 | struct sk_buff *msg; |
9487 | struct nlattr *pinfoattr; | 9939 | struct nlattr *pinfoattr; |
9488 | void *hdr; | 9940 | void *hdr; |
9489 | 9941 | ||
9942 | trace_cfg80211_cqm_rssi_notify(dev, rssi_event); | ||
9943 | |||
9490 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 9944 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9491 | if (!msg) | 9945 | if (!msg) |
9492 | return; | 9946 | return; |
@@ -9498,7 +9952,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
9498 | } | 9952 | } |
9499 | 9953 | ||
9500 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 9954 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9501 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) | 9955 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) |
9502 | goto nla_put_failure; | 9956 | goto nla_put_failure; |
9503 | 9957 | ||
9504 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | 9958 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); |
@@ -9521,10 +9975,11 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
9521 | genlmsg_cancel(msg, hdr); | 9975 | genlmsg_cancel(msg, hdr); |
9522 | nlmsg_free(msg); | 9976 | nlmsg_free(msg); |
9523 | } | 9977 | } |
9978 | EXPORT_SYMBOL(cfg80211_cqm_rssi_notify); | ||
9524 | 9979 | ||
9525 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | 9980 | static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, |
9526 | struct net_device *netdev, const u8 *bssid, | 9981 | struct net_device *netdev, const u8 *bssid, |
9527 | const u8 *replay_ctr, gfp_t gfp) | 9982 | const u8 *replay_ctr, gfp_t gfp) |
9528 | { | 9983 | { |
9529 | struct sk_buff *msg; | 9984 | struct sk_buff *msg; |
9530 | struct nlattr *rekey_attr; | 9985 | struct nlattr *rekey_attr; |
@@ -9566,9 +10021,22 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | |||
9566 | nlmsg_free(msg); | 10021 | nlmsg_free(msg); |
9567 | } | 10022 | } |
9568 | 10023 | ||
9569 | void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | 10024 | void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, |
9570 | struct net_device *netdev, int index, | 10025 | const u8 *replay_ctr, gfp_t gfp) |
9571 | const u8 *bssid, bool preauth, gfp_t gfp) | 10026 | { |
10027 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10028 | struct wiphy *wiphy = wdev->wiphy; | ||
10029 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10030 | |||
10031 | trace_cfg80211_gtk_rekey_notify(dev, bssid); | ||
10032 | nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp); | ||
10033 | } | ||
10034 | EXPORT_SYMBOL(cfg80211_gtk_rekey_notify); | ||
10035 | |||
10036 | static void | ||
10037 | nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | ||
10038 | struct net_device *netdev, int index, | ||
10039 | const u8 *bssid, bool preauth, gfp_t gfp) | ||
9572 | { | 10040 | { |
9573 | struct sk_buff *msg; | 10041 | struct sk_buff *msg; |
9574 | struct nlattr *attr; | 10042 | struct nlattr *attr; |
@@ -9611,9 +10079,22 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
9611 | nlmsg_free(msg); | 10079 | nlmsg_free(msg); |
9612 | } | 10080 | } |
9613 | 10081 | ||
9614 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | 10082 | void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, |
9615 | struct net_device *netdev, | 10083 | const u8 *bssid, bool preauth, gfp_t gfp) |
9616 | struct cfg80211_chan_def *chandef, gfp_t gfp) | 10084 | { |
10085 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10086 | struct wiphy *wiphy = wdev->wiphy; | ||
10087 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10088 | |||
10089 | trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth); | ||
10090 | nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); | ||
10091 | } | ||
10092 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | ||
10093 | |||
10094 | static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | ||
10095 | struct net_device *netdev, | ||
10096 | struct cfg80211_chan_def *chandef, | ||
10097 | gfp_t gfp) | ||
9617 | { | 10098 | { |
9618 | struct sk_buff *msg; | 10099 | struct sk_buff *msg; |
9619 | void *hdr; | 10100 | void *hdr; |
@@ -9645,11 +10126,36 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
9645 | nlmsg_free(msg); | 10126 | nlmsg_free(msg); |
9646 | } | 10127 | } |
9647 | 10128 | ||
9648 | void | 10129 | void cfg80211_ch_switch_notify(struct net_device *dev, |
9649 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | 10130 | struct cfg80211_chan_def *chandef) |
9650 | struct net_device *netdev, const u8 *peer, | 10131 | { |
9651 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) | 10132 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
10133 | struct wiphy *wiphy = wdev->wiphy; | ||
10134 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10135 | |||
10136 | trace_cfg80211_ch_switch_notify(dev, chandef); | ||
10137 | |||
10138 | wdev_lock(wdev); | ||
10139 | |||
10140 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | ||
10141 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) | ||
10142 | goto out; | ||
10143 | |||
10144 | wdev->channel = chandef->chan; | ||
10145 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | ||
10146 | out: | ||
10147 | wdev_unlock(wdev); | ||
10148 | return; | ||
10149 | } | ||
10150 | EXPORT_SYMBOL(cfg80211_ch_switch_notify); | ||
10151 | |||
10152 | void cfg80211_cqm_txe_notify(struct net_device *dev, | ||
10153 | const u8 *peer, u32 num_packets, | ||
10154 | u32 rate, u32 intvl, gfp_t gfp) | ||
9652 | { | 10155 | { |
10156 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10157 | struct wiphy *wiphy = wdev->wiphy; | ||
10158 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9653 | struct sk_buff *msg; | 10159 | struct sk_buff *msg; |
9654 | struct nlattr *pinfoattr; | 10160 | struct nlattr *pinfoattr; |
9655 | void *hdr; | 10161 | void *hdr; |
@@ -9665,7 +10171,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
9665 | } | 10171 | } |
9666 | 10172 | ||
9667 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 10173 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9668 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 10174 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9669 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | 10175 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) |
9670 | goto nla_put_failure; | 10176 | goto nla_put_failure; |
9671 | 10177 | ||
@@ -9694,6 +10200,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
9694 | genlmsg_cancel(msg, hdr); | 10200 | genlmsg_cancel(msg, hdr); |
9695 | nlmsg_free(msg); | 10201 | nlmsg_free(msg); |
9696 | } | 10202 | } |
10203 | EXPORT_SYMBOL(cfg80211_cqm_txe_notify); | ||
9697 | 10204 | ||
9698 | void | 10205 | void |
9699 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 10206 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
@@ -9746,15 +10253,18 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
9746 | nlmsg_free(msg); | 10253 | nlmsg_free(msg); |
9747 | } | 10254 | } |
9748 | 10255 | ||
9749 | void | 10256 | void cfg80211_cqm_pktloss_notify(struct net_device *dev, |
9750 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 10257 | const u8 *peer, u32 num_packets, gfp_t gfp) |
9751 | struct net_device *netdev, const u8 *peer, | ||
9752 | u32 num_packets, gfp_t gfp) | ||
9753 | { | 10258 | { |
10259 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
10260 | struct wiphy *wiphy = wdev->wiphy; | ||
10261 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
9754 | struct sk_buff *msg; | 10262 | struct sk_buff *msg; |
9755 | struct nlattr *pinfoattr; | 10263 | struct nlattr *pinfoattr; |
9756 | void *hdr; | 10264 | void *hdr; |
9757 | 10265 | ||
10266 | trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets); | ||
10267 | |||
9758 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | 10268 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
9759 | if (!msg) | 10269 | if (!msg) |
9760 | return; | 10270 | return; |
@@ -9766,7 +10276,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
9766 | } | 10276 | } |
9767 | 10277 | ||
9768 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 10278 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
9769 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 10279 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
9770 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | 10280 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) |
9771 | goto nla_put_failure; | 10281 | goto nla_put_failure; |
9772 | 10282 | ||
@@ -9789,6 +10299,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
9789 | genlmsg_cancel(msg, hdr); | 10299 | genlmsg_cancel(msg, hdr); |
9790 | nlmsg_free(msg); | 10300 | nlmsg_free(msg); |
9791 | } | 10301 | } |
10302 | EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); | ||
9792 | 10303 | ||
9793 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | 10304 | void cfg80211_probe_status(struct net_device *dev, const u8 *addr, |
9794 | u64 cookie, bool acked, gfp_t gfp) | 10305 | u64 cookie, bool acked, gfp_t gfp) |
@@ -10075,6 +10586,50 @@ static struct notifier_block nl80211_netlink_notifier = { | |||
10075 | .notifier_call = nl80211_netlink_notify, | 10586 | .notifier_call = nl80211_netlink_notify, |
10076 | }; | 10587 | }; |
10077 | 10588 | ||
10589 | void cfg80211_ft_event(struct net_device *netdev, | ||
10590 | struct cfg80211_ft_event_params *ft_event) | ||
10591 | { | ||
10592 | struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy; | ||
10593 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
10594 | struct sk_buff *msg; | ||
10595 | void *hdr; | ||
10596 | int err; | ||
10597 | |||
10598 | trace_cfg80211_ft_event(wiphy, netdev, ft_event); | ||
10599 | |||
10600 | if (!ft_event->target_ap) | ||
10601 | return; | ||
10602 | |||
10603 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
10604 | if (!msg) | ||
10605 | return; | ||
10606 | |||
10607 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT); | ||
10608 | if (!hdr) { | ||
10609 | nlmsg_free(msg); | ||
10610 | return; | ||
10611 | } | ||
10612 | |||
10613 | nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
10614 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
10615 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap); | ||
10616 | if (ft_event->ies) | ||
10617 | nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies); | ||
10618 | if (ft_event->ric_ies) | ||
10619 | nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len, | ||
10620 | ft_event->ric_ies); | ||
10621 | |||
10622 | err = genlmsg_end(msg, hdr); | ||
10623 | if (err < 0) { | ||
10624 | nlmsg_free(msg); | ||
10625 | return; | ||
10626 | } | ||
10627 | |||
10628 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
10629 | nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
10630 | } | ||
10631 | EXPORT_SYMBOL(cfg80211_ft_event); | ||
10632 | |||
10078 | /* initialisation/exit functions */ | 10633 | /* initialisation/exit functions */ |
10079 | 10634 | ||
10080 | int nl80211_init(void) | 10635 | int nl80211_init(void) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b061da4919e1..a4073e808c13 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -29,12 +29,6 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev, | |||
29 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, | 29 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, |
30 | struct net_device *netdev, | 30 | struct net_device *netdev, |
31 | const u8 *buf, size_t len, gfp_t gfp); | 31 | const u8 *buf, size_t len, gfp_t gfp); |
32 | void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev, | ||
33 | struct net_device *netdev, | ||
34 | const u8 *buf, size_t len, gfp_t gfp); | ||
35 | void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev, | ||
36 | struct net_device *netdev, | ||
37 | const u8 *buf, size_t len, gfp_t gfp); | ||
38 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, | 32 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, |
39 | struct net_device *netdev, | 33 | struct net_device *netdev, |
40 | const u8 *addr, gfp_t gfp); | 34 | const u8 *addr, gfp_t gfp); |
@@ -54,10 +48,6 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
54 | struct net_device *netdev, u16 reason, | 48 | struct net_device *netdev, u16 reason, |
55 | const u8 *ie, size_t ie_len, bool from_ap); | 49 | const u8 *ie, size_t ie_len, bool from_ap); |
56 | 50 | ||
57 | void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | ||
58 | struct net_device *netdev, | ||
59 | const u8 *macaddr, const u8* ie, u8 ie_len, | ||
60 | gfp_t gfp); | ||
61 | void | 51 | void |
62 | nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 52 | nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
63 | struct net_device *netdev, const u8 *addr, | 53 | struct net_device *netdev, const u8 *addr, |
@@ -73,41 +63,10 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
73 | struct net_device *netdev, const u8 *bssid, | 63 | struct net_device *netdev, const u8 *bssid, |
74 | gfp_t gfp); | 64 | gfp_t gfp); |
75 | 65 | ||
76 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | ||
77 | struct wireless_dev *wdev, u64 cookie, | ||
78 | struct ieee80211_channel *chan, | ||
79 | unsigned int duration, gfp_t gfp); | ||
80 | void nl80211_send_remain_on_channel_cancel( | ||
81 | struct cfg80211_registered_device *rdev, | ||
82 | struct wireless_dev *wdev, | ||
83 | u64 cookie, struct ieee80211_channel *chan, gfp_t gfp); | ||
84 | |||
85 | void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | ||
86 | struct net_device *dev, const u8 *mac_addr, | ||
87 | struct station_info *sinfo, gfp_t gfp); | ||
88 | void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | ||
89 | struct net_device *dev, const u8 *mac_addr, | ||
90 | gfp_t gfp); | ||
91 | |||
92 | void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev, | ||
93 | struct net_device *dev, const u8 *mac_addr, | ||
94 | enum nl80211_connect_failed_reason reason, | ||
95 | gfp_t gfp); | ||
96 | |||
97 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 66 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
98 | struct wireless_dev *wdev, u32 nlpid, | 67 | struct wireless_dev *wdev, u32 nlpid, |
99 | int freq, int sig_dbm, | 68 | int freq, int sig_dbm, |
100 | const u8 *buf, size_t len, gfp_t gfp); | 69 | const u8 *buf, size_t len, gfp_t gfp); |
101 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | ||
102 | struct wireless_dev *wdev, u64 cookie, | ||
103 | const u8 *buf, size_t len, bool ack, | ||
104 | gfp_t gfp); | ||
105 | |||
106 | void | ||
107 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | ||
108 | struct net_device *netdev, | ||
109 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
110 | gfp_t gfp); | ||
111 | 70 | ||
112 | void | 71 | void |
113 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | 72 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, |
@@ -115,31 +74,4 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, | |||
115 | enum nl80211_radar_event event, | 74 | enum nl80211_radar_event event, |
116 | struct net_device *netdev, gfp_t gfp); | 75 | struct net_device *netdev, gfp_t gfp); |
117 | 76 | ||
118 | void | ||
119 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | ||
120 | struct net_device *netdev, const u8 *peer, | ||
121 | u32 num_packets, gfp_t gfp); | ||
122 | |||
123 | void | ||
124 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | ||
125 | struct net_device *netdev, const u8 *peer, | ||
126 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); | ||
127 | |||
128 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | ||
129 | struct net_device *netdev, const u8 *bssid, | ||
130 | const u8 *replay_ctr, gfp_t gfp); | ||
131 | |||
132 | void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | ||
133 | struct net_device *netdev, int index, | ||
134 | const u8 *bssid, bool preauth, gfp_t gfp); | ||
135 | |||
136 | void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | ||
137 | struct net_device *dev, | ||
138 | struct cfg80211_chan_def *chandef, gfp_t gfp); | ||
139 | |||
140 | bool nl80211_unexpected_frame(struct net_device *dev, | ||
141 | const u8 *addr, gfp_t gfp); | ||
142 | bool nl80211_unexpected_4addr_frame(struct net_device *dev, | ||
143 | const u8 *addr, gfp_t gfp); | ||
144 | |||
145 | #endif /* __NET_WIRELESS_NL80211_H */ | 77 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 422d38291d66..d77e1c1d3a0e 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -6,11 +6,12 @@ | |||
6 | #include "core.h" | 6 | #include "core.h" |
7 | #include "trace.h" | 7 | #include "trace.h" |
8 | 8 | ||
9 | static inline int rdev_suspend(struct cfg80211_registered_device *rdev) | 9 | static inline int rdev_suspend(struct cfg80211_registered_device *rdev, |
10 | struct cfg80211_wowlan *wowlan) | ||
10 | { | 11 | { |
11 | int ret; | 12 | int ret; |
12 | trace_rdev_suspend(&rdev->wiphy, rdev->wowlan); | 13 | trace_rdev_suspend(&rdev->wiphy, wowlan); |
13 | ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); | 14 | ret = rdev->ops->suspend(&rdev->wiphy, wowlan); |
14 | trace_rdev_return_int(&rdev->wiphy, ret); | 15 | trace_rdev_return_int(&rdev->wiphy, ret); |
15 | return ret; | 16 | return ret; |
16 | } | 17 | } |
@@ -887,4 +888,17 @@ static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, | |||
887 | trace_rdev_return_int(&rdev->wiphy, ret); | 888 | trace_rdev_return_int(&rdev->wiphy, ret); |
888 | return ret; | 889 | return ret; |
889 | } | 890 | } |
891 | |||
892 | static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev, | ||
893 | struct net_device *dev, | ||
894 | struct cfg80211_update_ft_ies_params *ftie) | ||
895 | { | ||
896 | int ret; | ||
897 | |||
898 | trace_rdev_update_ft_ies(&rdev->wiphy, dev, ftie); | ||
899 | ret = rdev->ops->update_ft_ies(&rdev->wiphy, dev, ftie); | ||
900 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
901 | return ret; | ||
902 | } | ||
903 | |||
890 | #endif /* __CFG80211_RDEV_OPS */ | 904 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 98532c00242d..e6df52dc8c69 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -184,14 +184,14 @@ static const struct ieee80211_regdomain world_regdom = { | |||
184 | NL80211_RRF_NO_IBSS | | 184 | NL80211_RRF_NO_IBSS | |
185 | NL80211_RRF_NO_OFDM), | 185 | NL80211_RRF_NO_OFDM), |
186 | /* IEEE 802.11a, channel 36..48 */ | 186 | /* IEEE 802.11a, channel 36..48 */ |
187 | REG_RULE(5180-10, 5240+10, 40, 6, 20, | 187 | REG_RULE(5180-10, 5240+10, 80, 6, 20, |
188 | NL80211_RRF_PASSIVE_SCAN | | 188 | NL80211_RRF_PASSIVE_SCAN | |
189 | NL80211_RRF_NO_IBSS), | 189 | NL80211_RRF_NO_IBSS), |
190 | 190 | ||
191 | /* NB: 5260 MHz - 5700 MHz requies DFS */ | 191 | /* NB: 5260 MHz - 5700 MHz requires DFS */ |
192 | 192 | ||
193 | /* IEEE 802.11a, channel 149..165 */ | 193 | /* IEEE 802.11a, channel 149..165 */ |
194 | REG_RULE(5745-10, 5825+10, 40, 6, 20, | 194 | REG_RULE(5745-10, 5825+10, 80, 6, 20, |
195 | NL80211_RRF_PASSIVE_SCAN | | 195 | NL80211_RRF_PASSIVE_SCAN | |
196 | NL80211_RRF_NO_IBSS), | 196 | NL80211_RRF_NO_IBSS), |
197 | 197 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f432bd3755b1..bad4c4b5e4eb 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -159,7 +159,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
159 | { | 159 | { |
160 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 160 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
161 | struct cfg80211_connect_params *params; | 161 | struct cfg80211_connect_params *params; |
162 | const u8 *prev_bssid = NULL; | 162 | struct cfg80211_assoc_request req = {}; |
163 | int err; | 163 | int err; |
164 | 164 | ||
165 | ASSERT_WDEV_LOCK(wdev); | 165 | ASSERT_WDEV_LOCK(wdev); |
@@ -186,16 +186,20 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
186 | BUG_ON(!rdev->ops->assoc); | 186 | BUG_ON(!rdev->ops->assoc); |
187 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 187 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
188 | if (wdev->conn->prev_bssid_valid) | 188 | if (wdev->conn->prev_bssid_valid) |
189 | prev_bssid = wdev->conn->prev_bssid; | 189 | req.prev_bssid = wdev->conn->prev_bssid; |
190 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, | 190 | req.ie = params->ie; |
191 | params->channel, params->bssid, | 191 | req.ie_len = params->ie_len; |
192 | prev_bssid, | 192 | req.use_mfp = params->mfp != NL80211_MFP_NO; |
193 | params->ssid, params->ssid_len, | 193 | req.crypto = params->crypto; |
194 | params->ie, params->ie_len, | 194 | req.flags = params->flags; |
195 | params->mfp != NL80211_MFP_NO, | 195 | req.ht_capa = params->ht_capa; |
196 | ¶ms->crypto, | 196 | req.ht_capa_mask = params->ht_capa_mask; |
197 | params->flags, ¶ms->ht_capa, | 197 | req.vht_capa = params->vht_capa; |
198 | ¶ms->ht_capa_mask); | 198 | req.vht_capa_mask = params->vht_capa_mask; |
199 | |||
200 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel, | ||
201 | params->bssid, params->ssid, | ||
202 | params->ssid_len, &req); | ||
199 | if (err) | 203 | if (err) |
200 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 204 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
201 | NULL, 0, | 205 | NULL, 0, |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 238ee49b3868..8f28b9f798d8 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -83,6 +83,14 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) | ||
87 | { | ||
88 | struct wireless_dev *wdev; | ||
89 | |||
90 | list_for_each_entry(wdev, &rdev->wdev_list, list) | ||
91 | cfg80211_leave(rdev, wdev); | ||
92 | } | ||
93 | |||
86 | static int wiphy_suspend(struct device *dev, pm_message_t state) | 94 | static int wiphy_suspend(struct device *dev, pm_message_t state) |
87 | { | 95 | { |
88 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | 96 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); |
@@ -90,12 +98,19 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) | |||
90 | 98 | ||
91 | rdev->suspend_at = get_seconds(); | 99 | rdev->suspend_at = get_seconds(); |
92 | 100 | ||
93 | if (rdev->ops->suspend) { | 101 | rtnl_lock(); |
94 | rtnl_lock(); | 102 | if (rdev->wiphy.registered) { |
95 | if (rdev->wiphy.registered) | 103 | if (!rdev->wowlan) |
96 | ret = rdev_suspend(rdev); | 104 | cfg80211_leave_all(rdev); |
97 | rtnl_unlock(); | 105 | if (rdev->ops->suspend) |
106 | ret = rdev_suspend(rdev, rdev->wowlan); | ||
107 | if (ret == 1) { | ||
108 | /* Driver refuse to configure wowlan */ | ||
109 | cfg80211_leave_all(rdev); | ||
110 | ret = rdev_suspend(rdev, NULL); | ||
111 | } | ||
98 | } | 112 | } |
113 | rtnl_unlock(); | ||
99 | 114 | ||
100 | return ret; | 115 | return ret; |
101 | } | 116 | } |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index b7a531380e19..ccadef2106ac 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1785,6 +1785,26 @@ TRACE_EVENT(rdev_set_mac_acl, | |||
1785 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy) | 1785 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy) |
1786 | ); | 1786 | ); |
1787 | 1787 | ||
1788 | TRACE_EVENT(rdev_update_ft_ies, | ||
1789 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
1790 | struct cfg80211_update_ft_ies_params *ftie), | ||
1791 | TP_ARGS(wiphy, netdev, ftie), | ||
1792 | TP_STRUCT__entry( | ||
1793 | WIPHY_ENTRY | ||
1794 | NETDEV_ENTRY | ||
1795 | __field(u16, md) | ||
1796 | __dynamic_array(u8, ie, ftie->ie_len) | ||
1797 | ), | ||
1798 | TP_fast_assign( | ||
1799 | WIPHY_ASSIGN; | ||
1800 | NETDEV_ASSIGN; | ||
1801 | __entry->md = ftie->md; | ||
1802 | memcpy(__get_dynamic_array(ie), ftie->ie, ftie->ie_len); | ||
1803 | ), | ||
1804 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", md: 0x%x", | ||
1805 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md) | ||
1806 | ); | ||
1807 | |||
1788 | /************************************************************* | 1808 | /************************************************************* |
1789 | * cfg80211 exported functions traces * | 1809 | * cfg80211 exported functions traces * |
1790 | *************************************************************/ | 1810 | *************************************************************/ |
@@ -2413,6 +2433,32 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup, | |||
2413 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) | 2433 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG) |
2414 | ); | 2434 | ); |
2415 | 2435 | ||
2436 | TRACE_EVENT(cfg80211_ft_event, | ||
2437 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
2438 | struct cfg80211_ft_event_params *ft_event), | ||
2439 | TP_ARGS(wiphy, netdev, ft_event), | ||
2440 | TP_STRUCT__entry( | ||
2441 | WIPHY_ENTRY | ||
2442 | NETDEV_ENTRY | ||
2443 | __dynamic_array(u8, ies, ft_event->ies_len) | ||
2444 | MAC_ENTRY(target_ap) | ||
2445 | __dynamic_array(u8, ric_ies, ft_event->ric_ies_len) | ||
2446 | ), | ||
2447 | TP_fast_assign( | ||
2448 | WIPHY_ASSIGN; | ||
2449 | NETDEV_ASSIGN; | ||
2450 | if (ft_event->ies) | ||
2451 | memcpy(__get_dynamic_array(ies), ft_event->ies, | ||
2452 | ft_event->ies_len); | ||
2453 | MAC_ASSIGN(target_ap, ft_event->target_ap); | ||
2454 | if (ft_event->ric_ies) | ||
2455 | memcpy(__get_dynamic_array(ric_ies), ft_event->ric_ies, | ||
2456 | ft_event->ric_ies_len); | ||
2457 | ), | ||
2458 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", target_ap: " MAC_PR_FMT, | ||
2459 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap)) | ||
2460 | ); | ||
2461 | |||
2416 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 2462 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
2417 | 2463 | ||
2418 | #undef TRACE_INCLUDE_PATH | 2464 | #undef TRACE_INCLUDE_PATH |