From 1866760096bf40bcf6977a9076b3026598bc12ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Tue, 18 Dec 2018 17:02:06 -0800 Subject: [PATCH 01/23] mac80211: Add TXQ scheduling API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds an API to mac80211 to handle scheduling of TXQs. The interface between driver and mac80211 for TXQ handling is changed by adding two new functions: ieee80211_next_txq(), which will return the next TXQ to schedule in the current round-robin rotation, and ieee80211_return_txq(), which the driver uses to indicate that it has finished scheduling a TXQ (which will then be put back in the scheduling rotation if it isn't empty). The driver must call ieee80211_txq_schedule_start() at the start of each scheduling session, and ieee80211_txq_schedule_end() at the end. The API then guarantees that the same TXQ is not returned twice in the same session (so a driver can loop on ieee80211_next_txq() without worrying about breaking the loop. Usage of the new API is optional, so drivers can be ported one at a time. In this patch, the actual scheduling performed by mac80211 is simple round-robin, but a subsequent commit adds airtime fairness awareness to the scheduler. Signed-off-by: Toke Høiland-Jørgensen [minor kernel-doc fix, propagate sparse locking checks out] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 63 +++++++++++++++++++++++++++++++++++--- net/mac80211/agg-tx.c | 2 +- net/mac80211/driver-ops.h | 9 ++++++ net/mac80211/ieee80211_i.h | 9 ++++++ net/mac80211/main.c | 5 +++ net/mac80211/sta_info.c | 2 +- net/mac80211/tx.c | 60 +++++++++++++++++++++++++++++++++++- 7 files changed, 143 insertions(+), 7 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 88219cc137c3..e8a057f071c4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -108,9 +108,15 @@ * The driver is expected to initialize its private per-queue data for stations * and interfaces in the .add_interface and .sta_add ops. * - * The driver can't access the queue directly. To dequeue a frame, it calls - * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it - * calls the .wake_tx_queue driver op. + * The driver can't access the queue directly. To dequeue a frame from a + * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a + * queue, it calls the .wake_tx_queue driver op. + * + * Drivers can optionally delegate responsibility for scheduling queues to + * mac80211, to take advantage of airtime fairness accounting. In this case, to + * obtain the next queue to pull frames from, the driver calls + * ieee80211_next_txq(). The driver is then expected to return the txq using + * ieee80211_return_txq(). * * For AP powersave TIM handling, the driver only needs to indicate if it has * buffered packets in the driver specific data structures by calling @@ -6103,7 +6109,8 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); * ieee80211_tx_dequeue - dequeue a packet from a software tx queue * * @hw: pointer as obtained from ieee80211_alloc_hw() - * @txq: pointer obtained from station or virtual interface + * @txq: pointer obtained from station or virtual interface, or from + * ieee80211_next_txq() * * Returns the skb if successful, %NULL if no frame was available. * @@ -6118,6 +6125,54 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, struct ieee80211_txq *txq); +/** + * ieee80211_next_txq - get next tx queue to pull packets from + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @ac: AC number to return packets from. + * + * Should only be called between calls to ieee80211_txq_schedule_start() + * and ieee80211_txq_schedule_end(). + * Returns the next txq if successful, %NULL if no queue is eligible. If a txq + * is returned, it should be returned with ieee80211_return_txq() after the + * driver has finished scheduling it. + */ +struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac); + +/** + * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq() + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @txq: pointer obtained from station or virtual interface + * + * Should only be called between calls to ieee80211_txq_schedule_start() + * and ieee80211_txq_schedule_end(). + */ +void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); + +/** + * ieee80211_txq_schedule_start - acquire locks for safe scheduling of an AC + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @ac: AC number to acquire locks for + * + * Acquire locks needed to schedule TXQs from the given AC. Should be called + * before ieee80211_next_txq() or ieee80211_return_txq(). + */ +void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) + __acquires(txq_lock); + +/** + * ieee80211_txq_schedule_end - release locks for safe scheduling of an AC + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @ac: AC number to acquire locks for + * + * Release locks previously acquired by ieee80211_txq_schedule_end(). + */ +void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) + __releases(txq_lock); + /** * ieee80211_txq_get_depth - get pending frame/byte count of given txq * diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 69e831bc317b..e94b1a0407af 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -229,7 +229,7 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable) clear_bit(IEEE80211_TXQ_STOP, &txqi->flags); local_bh_disable(); rcu_read_lock(); - drv_wake_tx_queue(sta->sdata->local, txqi); + schedule_and_wake_txq(sta->sdata->local, txqi); rcu_read_unlock(); local_bh_enable(); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 3e0d5922a440..1aab1734b26f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1173,6 +1173,15 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local, local->ops->wake_tx_queue(&local->hw, &txq->txq); } +static inline void schedule_and_wake_txq(struct ieee80211_local *local, + struct txq_info *txqi) +{ + spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]); + ieee80211_return_txq(&local->hw, &txqi->txq); + spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]); + drv_wake_tx_queue(local, txqi); +} + static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local, struct sk_buff *head, struct sk_buff *skb) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7dfb4e2f98b2..d1db27b1e989 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -831,6 +831,8 @@ enum txq_info_flags { * a fq_flow which is already owned by a different tin * @def_cvars: codel vars for @def_flow * @frags: used to keep fragments created after dequeue + * @schedule_order: used with ieee80211_local->active_txqs + * @schedule_round: counter to prevent infinite loops on TXQ scheduling */ struct txq_info { struct fq_tin tin; @@ -838,6 +840,8 @@ struct txq_info { struct codel_vars def_cvars; struct codel_stats cstats; struct sk_buff_head frags; + struct list_head schedule_order; + u16 schedule_round; unsigned long flags; /* keep last! */ @@ -1129,6 +1133,11 @@ struct ieee80211_local { struct codel_vars *cvars; struct codel_params cparams; + /* protects active_txqs and txqi->schedule_order */ + spinlock_t active_txq_lock[IEEE80211_NUM_ACS]; + struct list_head active_txqs[IEEE80211_NUM_ACS]; + u16 schedule_round[IEEE80211_NUM_ACS]; + const struct ieee80211_ops *ops; /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 87a729926734..9b9d6cadf56e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -663,6 +663,11 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, spin_lock_init(&local->rx_path_lock); spin_lock_init(&local->queue_stop_reason_lock); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + INIT_LIST_HEAD(&local->active_txqs[i]); + spin_lock_init(&local->active_txq_lock[i]); + } + INIT_LIST_HEAD(&local->chanctx_list); mutex_init(&local->chanctx_mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c4a8f115ed33..83e1c316a29e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1249,7 +1249,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i])) continue; - drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i])); + schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i])); } skb_queue_head_init(&pending); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f170d6c6629a..544da6411620 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1449,6 +1449,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, codel_vars_init(&txqi->def_cvars); codel_stats_init(&txqi->cstats); __skb_queue_head_init(&txqi->frags); + INIT_LIST_HEAD(&txqi->schedule_order); txqi->txq.vif = &sdata->vif; @@ -1489,6 +1490,9 @@ void ieee80211_txq_purge(struct ieee80211_local *local, fq_tin_reset(fq, tin, fq_skb_free_func); ieee80211_purge_tx_queue(&local->hw, &txqi->frags); + spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]); + list_del_init(&txqi->schedule_order); + spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]); } void ieee80211_txq_set_params(struct ieee80211_local *local) @@ -1605,7 +1609,7 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local, ieee80211_txq_enqueue(local, txqi, skb); spin_unlock_bh(&fq->lock); - drv_wake_tx_queue(local, txqi); + schedule_and_wake_txq(local, txqi); return true; } @@ -3630,6 +3634,60 @@ out: } EXPORT_SYMBOL(ieee80211_tx_dequeue); +struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = NULL; + + lockdep_assert_held(&local->active_txq_lock[ac]); + + txqi = list_first_entry_or_null(&local->active_txqs[ac], + struct txq_info, + schedule_order); + + if (!txqi || txqi->schedule_round == local->schedule_round[ac]) + return NULL; + + list_del_init(&txqi->schedule_order); + txqi->schedule_round = local->schedule_round[ac]; + return &txqi->txq; +} +EXPORT_SYMBOL(ieee80211_next_txq); + +void ieee80211_return_txq(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = to_txq_info(txq); + + lockdep_assert_held(&local->active_txq_lock[txq->ac]); + + if (list_empty(&txqi->schedule_order) && + (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) + list_add_tail(&txqi->schedule_order, + &local->active_txqs[txq->ac]); +} +EXPORT_SYMBOL(ieee80211_return_txq); + +void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) + __acquires(txq_lock) +{ + struct ieee80211_local *local = hw_to_local(hw); + + spin_lock_bh(&local->active_txq_lock[ac]); + local->schedule_round[ac]++; +} +EXPORT_SYMBOL(ieee80211_txq_schedule_start); + +void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) + __releases(txq_lock) +{ + struct ieee80211_local *local = hw_to_local(hw); + + spin_unlock_bh(&local->active_txq_lock[ac]); +} +EXPORT_SYMBOL(ieee80211_txq_schedule_end); + void __ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev, u32 info_flags) From 36647055b37ec78e9068f470f14e7cd75c001c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Tue, 18 Dec 2018 17:02:07 -0800 Subject: [PATCH 02/23] cfg80211: Add airtime statistics and settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds TX airtime statistics to the cfg80211 station dump (to go along with the RX info already present), and adds a new parameter to set the airtime weight of each station. The latter allows userspace to implement policies for different stations by varying their weights. Signed-off-by: Toke Høiland-Jørgensen [rmanohar@codeaurora.org: fixed checkpatch warnings] Signed-off-by: Rajkumar Manoharan [move airtime weight != 0 check into policy] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 11 ++++++++++- include/uapi/linux/nl80211.h | 15 +++++++++++++++ net/wireless/nl80211.c | 24 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e0c41eb1c860..1691f52fcc80 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1003,6 +1003,7 @@ enum station_parameters_apply_mask { * @support_p2p_ps: information if station supports P2P PS mechanism * @he_capa: HE capabilities of station * @he_capa_len: the length of the HE capabilities + * @airtime_weight: airtime scheduler weight for this station */ struct station_parameters { const u8 *supported_rates; @@ -1032,6 +1033,7 @@ struct station_parameters { int support_p2p_ps; const struct ieee80211_he_cap_elem *he_capa; u8 he_capa_len; + u16 airtime_weight; }; /** @@ -1300,6 +1302,8 @@ struct cfg80211_tid_stats { * from this peer * @connected_to_gate: true if mesh STA has a path to mesh gate * @rx_duration: aggregate PPDU duration(usecs) for all the frames from a peer + * @tx_duration: aggregate PPDU duration(usecs) for all the frames to a peer + * @airtime_weight: current airtime scheduling weight * @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last * (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs. * Note that this doesn't use the @filled bit, but is used if non-NULL. @@ -1350,8 +1354,9 @@ struct station_info { u32 expected_throughput; - u64 rx_beacon; + u64 tx_duration; u64 rx_duration; + u64 rx_beacon; u8 rx_beacon_signal_avg; u8 connected_to_gate; @@ -1359,6 +1364,8 @@ struct station_info { s8 ack_signal; s8 avg_ack_signal; + u16 airtime_weight; + u32 rx_mpdu_count; u32 fcs_err_count; }; @@ -2391,6 +2398,8 @@ enum wiphy_params_flags { WIPHY_PARAM_TXQ_QUANTUM = 1 << 8, }; +#define IEEE80211_DEFAULT_AIRTIME_WEIGHT 256 + /** * struct cfg80211_pmksa - PMK Security Association * diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 31ae5c7f10e3..ebe79e12c82e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2299,6 +2299,9 @@ enum nl80211_commands { * This is also used for capability advertisement in the wiphy information, * with the appropriate sub-attributes. * + * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime + * scheduler. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2748,6 +2751,8 @@ enum nl80211_attrs { NL80211_ATTR_PEER_MEASUREMENTS, + NL80211_ATTR_AIRTIME_WEIGHT, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3125,6 +3130,9 @@ enum nl80211_sta_bss_param { * might not be fully accurate. * @NL80211_STA_INFO_CONNECTED_TO_GATE: set to true if STA has a path to a * mesh gate (u8, 0 or 1) + * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames + * sent to the station (u64, usec) + * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16) * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -3168,6 +3176,8 @@ enum nl80211_sta_info { NL80211_STA_INFO_RX_MPDUS, NL80211_STA_INFO_FCS_ERROR_COUNT, NL80211_STA_INFO_CONNECTED_TO_GATE, + NL80211_STA_INFO_TX_DURATION, + NL80211_STA_INFO_AIRTIME_WEIGHT, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -5316,6 +5326,10 @@ enum nl80211_feature_flags { * if this flag is not set. Ignoring this can leak clear text packets and/or * freeze the connection. * + * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime + * fairness for transmitted packets and has enabled airtime fairness + * scheduling. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -5355,6 +5369,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5e49492d5911..a89688929b16 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -557,6 +557,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_PEER_MEASUREMENTS] = NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX, nl80211_pmsr_attr_policy), + [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1), }; /* policy for the key attributes */ @@ -4851,6 +4852,11 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, PUT_SINFO(PLID, plid, u16); PUT_SINFO(PLINK_STATE, plink_state, u8); PUT_SINFO_U64(RX_DURATION, rx_duration); + PUT_SINFO_U64(TX_DURATION, tx_duration); + + if (wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + PUT_SINFO(AIRTIME_WEIGHT, airtime_weight, u16); switch (rdev->wiphy.signal_type) { case CFG80211_SIGNAL_TYPE_MBM: @@ -5470,6 +5476,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]); } + if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]) + params.airtime_weight = + nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]); + + if (params.airtime_weight && + !wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + return -EOPNOTSUPP; + /* Include parameters for TDLS peer (will check later) */ err = nl80211_set_station_tdls(info, ¶ms); if (err) @@ -5598,6 +5613,15 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.plink_action = nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); + if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]) + params.airtime_weight = + nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]); + + if (params.airtime_weight && + !wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + return -EOPNOTSUPP; + err = nl80211_parse_sta_channel_info(info, ¶ms); if (err) return err; From b4809e9484da147dc82a31b961df111eee72201a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Tue, 18 Dec 2018 17:02:08 -0800 Subject: [PATCH 03/23] mac80211: Add airtime accounting and scheduling to TXQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds airtime accounting and scheduling to the mac80211 TXQ scheduler. A new callback, ieee80211_sta_register_airtime(), is added that drivers can call to report airtime usage for stations. When airtime information is present, mac80211 will schedule TXQs (through ieee80211_next_txq()) in a way that enforces airtime fairness between active stations. This scheduling works the same way as the ath9k in-driver airtime fairness scheduling. If no airtime usage is reported by the driver, the scheduler will default to round-robin scheduling. For drivers that don't control TXQ scheduling in software, a new API function, ieee80211_txq_may_transmit(), is added which the driver can use to check if the TXQ is eligible for transmission, or should be throttled to enforce fairness. Calls to this function must also be enclosed in ieee80211_txq_schedule_{start,end}() calls to ensure proper locking. The API ieee80211_txq_may_transmit() also ensures that TXQ list will be aligned aginst driver's own round-robin scheduler list. i.e it rotates the TXQ list till it makes the requested node becomes the first entry in TXQ list. Thus both the TXQ list and driver's list are in sync. Co-developed-by: Rajkumar Manoharan Signed-off-by: Louie Lu [added debugfs write op to reset airtime counter] Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Rajkumar Manoharan Signed-off-by: Johannes Berg --- include/net/mac80211.h | 59 +++++++++++++++++++++++++ net/mac80211/cfg.c | 3 ++ net/mac80211/debugfs.c | 3 ++ net/mac80211/debugfs_sta.c | 68 ++++++++++++++++++++++++++-- net/mac80211/ieee80211_i.h | 2 + net/mac80211/main.c | 4 ++ net/mac80211/sta_info.c | 44 +++++++++++++++++-- net/mac80211/sta_info.h | 13 ++++++ net/mac80211/status.c | 6 +++ net/mac80211/tx.c | 90 ++++++++++++++++++++++++++++++++++++-- 10 files changed, 282 insertions(+), 10 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e8a057f071c4..5d36eacf401e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2360,6 +2360,9 @@ enum ieee80211_hw_flags { * @tx_sk_pacing_shift: Pacing shift to set on TCP sockets when frames from * them are encountered. The default should typically not be changed, * unless the driver has good reasons for needing more buffers. + * + * @weight_multipler: Driver specific airtime weight multiplier used while + * refilling deficit of each TXQ. */ struct ieee80211_hw { struct ieee80211_conf conf; @@ -2396,6 +2399,7 @@ struct ieee80211_hw { const struct ieee80211_cipher_scheme *cipher_schemes; u8 max_nan_de_entries; u8 tx_sk_pacing_shift; + u8 weight_multiplier; }; static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw, @@ -5407,6 +5411,34 @@ void ieee80211_sta_eosp(struct ieee80211_sta *pubsta); */ void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid); +/** + * ieee80211_sta_register_airtime - register airtime usage for a sta/tid + * + * Register airtime usage for a given sta on a given tid. The driver can call + * this function to notify mac80211 that a station used a certain amount of + * airtime. This information will be used by the TXQ scheduler to schedule + * stations in a way that ensures airtime fairness. + * + * The reported airtime should as a minimum include all time that is spent + * transmitting to the remote station, including overhead and padding, but not + * including time spent waiting for a TXOP. If the time is not reported by the + * hardware it can in some cases be calculated from the rate and known frame + * composition. When possible, the time should include any failed transmission + * attempts. + * + * The driver can either call this function synchronously for every packet or + * aggregate, or asynchronously as airtime usage information becomes available. + * TX and RX airtime can be reported together, or separately by setting one of + * them to 0. + * + * @pubsta: the station + * @tid: the TID to register airtime for + * @tx_airtime: airtime used during TX (in usec) + * @rx_airtime: airtime used during RX (in usec) + */ +void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, + u32 tx_airtime, u32 rx_airtime); + /** * ieee80211_iter_keys - iterate keys programmed into the device * @hw: pointer obtained from ieee80211_alloc_hw() @@ -6173,6 +6205,33 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) __releases(txq_lock); +/** + * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit + * + * This function is used to check whether given txq is allowed to transmit by + * the airtime scheduler, and can be used by drivers to access the airtime + * fairness accounting without going using the scheduling order enfored by + * next_txq(). + * + * Returns %true if the airtime scheduler thinks the TXQ should be allowed to + * transmit, and %false if it should be throttled. This function can also have + * the side effect of rotating the TXQ in the scheduler rotation, which will + * eventually bring the deficit to positive and allow the station to transmit + * again. + * + * The API ieee80211_txq_may_transmit() also ensures that TXQ list will be + * aligned aginst driver's own round-robin scheduler list. i.e it rotates + * the TXQ list till it makes the requested node becomes the first entry + * in TXQ list. Thus both the TXQ list and driver's list are in sync. If this + * function returns %true, the driver is expected to schedule packets + * for transmission, and then return the TXQ through ieee80211_return_txq(). + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @txq: pointer obtained from station or virtual interface + */ +bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, + struct ieee80211_txq *txq); + /** * ieee80211_txq_get_depth - get pending frame/byte count of given txq * diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index de65fe3ed9cc..83ee573b1804 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1447,6 +1447,9 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (ieee80211_vif_is_mesh(&sdata->vif)) sta_apply_mesh_params(local, sta, params); + if (params->airtime_weight) + sta->airtime_weight = params->airtime_weight; + /* set the STA state after all sta info from usermode has been set */ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) || set & BIT(NL80211_STA_FLAG_ASSOCIATED)) { diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 3fe541e358f3..81c5fec2eae7 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -383,6 +383,9 @@ void debugfs_hw_add(struct ieee80211_local *local) if (local->ops->wake_tx_queue) DEBUGFS_ADD_MODE(aqm, 0600); + debugfs_create_u16("airtime_flags", 0600, + phyd, &local->airtime_flags); + statsd = debugfs_create_dir("statistics", phyd); /* if the dir failed, don't put all the other things into the root! */ diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index b753194710ad..3aa618dcc58e 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -181,9 +181,9 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf, txqi->tin.tx_bytes, txqi->tin.tx_packets, txqi->flags, - txqi->flags & (1<flags & (1<flags & (1<flags) ? "STOP" : "RUN", + test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags) ? " AMPDU" : "", + test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : ""); } rcu_read_unlock(); @@ -195,6 +195,64 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf, } STA_OPS(aqm); +static ssize_t sta_airtime_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct ieee80211_local *local = sta->sdata->local; + size_t bufsz = 200; + char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; + u64 rx_airtime = 0, tx_airtime = 0; + s64 deficit[IEEE80211_NUM_ACS]; + ssize_t rv; + int ac; + + if (!buf) + return -ENOMEM; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + spin_lock_bh(&local->active_txq_lock[ac]); + rx_airtime += sta->airtime[ac].rx_airtime; + tx_airtime += sta->airtime[ac].tx_airtime; + deficit[ac] = sta->airtime[ac].deficit; + spin_unlock_bh(&local->active_txq_lock[ac]); + } + + p += scnprintf(p, bufsz + buf - p, + "RX: %llu us\nTX: %llu us\nWeight: %u\n" + "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", + rx_airtime, + tx_airtime, + sta->airtime_weight, + deficit[0], + deficit[1], + deficit[2], + deficit[3]); + + rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); + kfree(buf); + return rv; +} + +static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct ieee80211_local *local = sta->sdata->local; + int ac; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + spin_lock_bh(&local->active_txq_lock[ac]); + sta->airtime[ac].rx_airtime = 0; + sta->airtime[ac].tx_airtime = 0; + sta->airtime[ac].deficit = sta->airtime_weight; + spin_unlock_bh(&local->active_txq_lock[ac]); + } + + return count; +} +STA_OPS_RW(airtime); + static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -906,6 +964,10 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) if (local->ops->wake_tx_queue) DEBUGFS_ADD(aqm); + if (wiphy_ext_feature_isset(local->hw.wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + DEBUGFS_ADD(airtime); + if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) debugfs_create_x32("driver_buffered_tids", 0400, sta->debugfs_dir, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d1db27b1e989..056b16bce3b0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1138,6 +1138,8 @@ struct ieee80211_local { struct list_head active_txqs[IEEE80211_NUM_ACS]; u16 schedule_round[IEEE80211_NUM_ACS]; + u16 airtime_flags; + const struct ieee80211_ops *ops; /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9b9d6cadf56e..896f17d726d0 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -667,6 +667,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, INIT_LIST_HEAD(&local->active_txqs[i]); spin_lock_init(&local->active_txq_lock[i]); } + local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX; INIT_LIST_HEAD(&local->chanctx_list); mutex_init(&local->chanctx_mtx); @@ -1153,6 +1154,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (!local->hw.max_nan_de_entries) local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID; + if (!local->hw.weight_multiplier) + local->hw.weight_multiplier = 1; + result = ieee80211_wep_init(local); if (result < 0) wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 83e1c316a29e..11f058987a54 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -90,7 +90,6 @@ static void __cleanup_single_sta(struct sta_info *sta) struct tid_ampdu_tx *tid_tx; struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; - struct fq *fq = &local->fq; struct ps_data *ps; if (test_sta_flag(sta, WLAN_STA_PS_STA) || @@ -120,9 +119,7 @@ static void __cleanup_single_sta(struct sta_info *sta) txqi = to_txq_info(sta->sta.txq[i]); - spin_lock_bh(&fq->lock); ieee80211_txq_purge(local, txqi); - spin_unlock_bh(&fq->lock); } } @@ -387,9 +384,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, if (sta_prepare_rate_control(local, sta, gfp)) goto free_txq; + sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT; + for (i = 0; i < IEEE80211_NUM_ACS; i++) { skb_queue_head_init(&sta->ps_tx_buf[i]); skb_queue_head_init(&sta->tx_filtered[i]); + sta->airtime[i].deficit = sta->airtime_weight; } for (i = 0; i < IEEE80211_NUM_TIDS; i++) @@ -1826,6 +1826,27 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, } EXPORT_SYMBOL(ieee80211_sta_set_buffered); +void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, + u32 tx_airtime, u32 rx_airtime) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + struct ieee80211_local *local = sta->sdata->local; + u8 ac = ieee80211_ac_from_tid(tid); + u32 airtime = 0; + + if (sta->local->airtime_flags & AIRTIME_USE_TX) + airtime += tx_airtime; + if (sta->local->airtime_flags & AIRTIME_USE_RX) + airtime += rx_airtime; + + spin_lock_bh(&local->active_txq_lock[ac]); + sta->airtime[ac].tx_airtime += tx_airtime; + sta->airtime[ac].rx_airtime += rx_airtime; + sta->airtime[ac].deficit -= airtime; + spin_unlock_bh(&local->active_txq_lock[ac]); +} +EXPORT_SYMBOL(ieee80211_sta_register_airtime); + int sta_info_move_state(struct sta_info *sta, enum ieee80211_sta_state new_state) { @@ -2188,6 +2209,23 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); } + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) { + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + sinfo->rx_duration += sta->airtime[ac].rx_airtime; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); + } + + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) { + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + sinfo->tx_duration += sta->airtime[ac].tx_airtime; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION); + } + + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { + sinfo->airtime_weight = sta->airtime_weight; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); + } + sinfo->rx_dropped_misc = sta->rx_stats.dropped; if (sta->pcpu_rx_stats) { for_each_possible_cpu(cpu) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 8eb29041be54..9a380803e597 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -127,6 +127,16 @@ enum ieee80211_agg_stop_reason { AGG_STOP_DESTROY_STA, }; +/* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */ +#define AIRTIME_USE_TX BIT(0) +#define AIRTIME_USE_RX BIT(1) + +struct airtime_info { + u64 rx_airtime; + u64 tx_airtime; + s64 deficit; +}; + struct sta_info; /** @@ -565,6 +575,9 @@ struct sta_info { } tx_stats; u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; + struct airtime_info airtime[IEEE80211_NUM_ACS]; + u16 airtime_weight; + /* * Aggregation information, locked with lock. */ diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3f0b96e1e02f..5b9952b1caf3 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -823,6 +823,12 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked, info->status.tx_time); + if (info->status.tx_time && + wiphy_ext_feature_isset(local->hw.wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + ieee80211_sta_register_airtime(&sta->sta, tid, + info->status.tx_time, 0); + if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { if (info->flags & IEEE80211_TX_STAT_ACK) { if (sta->status_stats.lost_packets) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 544da6411620..f46d8d822f86 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1488,8 +1488,11 @@ void ieee80211_txq_purge(struct ieee80211_local *local, struct fq *fq = &local->fq; struct fq_tin *tin = &txqi->tin; + spin_lock_bh(&fq->lock); fq_tin_reset(fq, tin, fq_skb_free_func); ieee80211_purge_tx_queue(&local->hw, &txqi->frags); + spin_unlock_bh(&fq->lock); + spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]); list_del_init(&txqi->schedule_order); spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]); @@ -3641,11 +3644,28 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) lockdep_assert_held(&local->active_txq_lock[ac]); + begin: txqi = list_first_entry_or_null(&local->active_txqs[ac], struct txq_info, schedule_order); + if (!txqi) + return NULL; - if (!txqi || txqi->schedule_round == local->schedule_round[ac]) + if (txqi->txq.sta) { + struct sta_info *sta = container_of(txqi->txq.sta, + struct sta_info, sta); + + if (sta->airtime[txqi->txq.ac].deficit < 0) { + sta->airtime[txqi->txq.ac].deficit += + sta->airtime_weight; + list_move_tail(&txqi->schedule_order, + &local->active_txqs[txqi->txq.ac]); + goto begin; + } + } + + + if (txqi->schedule_round == local->schedule_round[ac]) return NULL; list_del_init(&txqi->schedule_order); @@ -3663,12 +3683,74 @@ void ieee80211_return_txq(struct ieee80211_hw *hw, lockdep_assert_held(&local->active_txq_lock[txq->ac]); if (list_empty(&txqi->schedule_order) && - (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) - list_add_tail(&txqi->schedule_order, - &local->active_txqs[txq->ac]); + (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) { + /* If airtime accounting is active, always enqueue STAs at the + * head of the list to ensure that they only get moved to the + * back by the airtime DRR scheduler once they have a negative + * deficit. A station that already has a negative deficit will + * get immediately moved to the back of the list on the next + * call to ieee80211_next_txq(). + */ + if (txqi->txq.sta && + wiphy_ext_feature_isset(local->hw.wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + list_add(&txqi->schedule_order, + &local->active_txqs[txq->ac]); + else + list_add_tail(&txqi->schedule_order, + &local->active_txqs[txq->ac]); + } } EXPORT_SYMBOL(ieee80211_return_txq); +bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *iter, *tmp, *txqi = to_txq_info(txq); + struct sta_info *sta; + u8 ac = txq->ac; + + lockdep_assert_held(&local->active_txq_lock[ac]); + + if (!txqi->txq.sta) + goto out; + + if (list_empty(&txqi->schedule_order)) + goto out; + + list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], + schedule_order) { + if (iter == txqi) + break; + + if (!iter->txq.sta) { + list_move_tail(&iter->schedule_order, + &local->active_txqs[ac]); + continue; + } + sta = container_of(iter->txq.sta, struct sta_info, sta); + if (sta->airtime[ac].deficit < 0) + sta->airtime[ac].deficit += sta->airtime_weight; + list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); + } + + sta = container_of(txqi->txq.sta, struct sta_info, sta); + if (sta->airtime[ac].deficit >= 0) + goto out; + + sta->airtime[ac].deficit += sta->airtime_weight; + list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]); + + return false; +out: + if (!list_empty(&txqi->schedule_order)) + list_del_init(&txqi->schedule_order); + + return true; +} +EXPORT_SYMBOL(ieee80211_txq_may_transmit); + void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) __acquires(txq_lock) { From d9bb410888ce1354ce29dcde671e1e21cc0c64cd Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Tue, 8 Jan 2019 23:31:49 +0300 Subject: [PATCH 04/23] mac80211: allow overriding HT STBC capabilities Allow user to override STBC configuration for Rx and Tx spatial streams. In practice RX/TX STBC settings can be modified using appropriate options in wpa_supplicant configuration file: tx_stbc=-1..1 rx_stbc=-1..3 This functionality has been added to wpa_supplicant in commit cdeea70f59d0. In FullMAC case these STBC options are passed to drivers by cfg80211 connect callback in fields of cfg80211_connect_params structure. However for mac80211 drivers, e.g. for mac80211_hwsim, overrides for STBC settings are ignored. The reason why RX/TX STBC capabilities are not modified for mac80211 drivers is as follows. All drivers need to specify supported HT/VHT overrides explicitly: see ht_capa_mod_mask and vht_capa_mod_mask fields of wiphy structure. Only supported overrides will be passed to drivers by cfg80211_connect and cfg80211_mlme_assoc operations: see bitwise 'AND' performed by cfg80211_oper_and_ht_capa and cfg80211_oper_and_vht_capa. This commit adds RX/TX STBC HT capabilities to mac80211_ht_capa_mod_mask, allowing their modifications, as well as applies requested STBC modifications in function ieee80211_apply_htcap_overrides. Signed-off-by: Sergey Matyukevich Signed-off-by: Johannes Berg --- net/mac80211/ht.c | 8 ++++++++ net/mac80211/main.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index f849ea814993..e03c46ac8e4d 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -107,6 +107,14 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap, IEEE80211_HT_CAP_40MHZ_INTOLERANT); + /* Allow user to enable TX STBC bit */ + __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap, + IEEE80211_HT_CAP_TX_STBC); + + /* Allow user to configure RX STBC bits */ + if (ht_capa_mask->cap_info & IEEE80211_HT_CAP_RX_STBC) + ht_cap->cap |= ht_capa->cap_info & IEEE80211_HT_CAP_RX_STBC; + /* Allow user to decrease AMPDU factor */ if (ht_capa_mask->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR) { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 896f17d726d0..71005b6dfcd1 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -478,6 +478,8 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = { IEEE80211_HT_CAP_MAX_AMSDU | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_TX_STBC | + IEEE80211_HT_CAP_RX_STBC | IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_40MHZ_INTOLERANT), .mcs = { From cc24163690997c685641d84e77ff6f1c592b06fe Mon Sep 17 00:00:00 2001 From: Julan Hsu Date: Tue, 15 Jan 2019 15:28:42 -0800 Subject: [PATCH 05/23] nl80211/mac80211: mesh: add hop count to mpath info Expose hop count to destination information in mpath info Signed-off-by: Julan Hsu Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 4 ++++ include/uapi/linux/nl80211.h | 2 ++ net/mac80211/cfg.c | 4 +++- net/mac80211/mesh_hwmp.c | 5 +++++ net/wireless/nl80211.c | 5 ++++- 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1691f52fcc80..37816786d3e1 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1429,6 +1429,7 @@ enum monitor_flags { * @MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled * @MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled * @MPATH_INFO_FLAGS: @flags filled + * @MPATH_INFO_HOP_COUNT: @hop_count filled */ enum mpath_info_flags { MPATH_INFO_FRAME_QLEN = BIT(0), @@ -1438,6 +1439,7 @@ enum mpath_info_flags { MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), MPATH_INFO_DISCOVERY_RETRIES = BIT(5), MPATH_INFO_FLAGS = BIT(6), + MPATH_INFO_HOP_COUNT = BIT(7) }; /** @@ -1457,6 +1459,7 @@ enum mpath_info_flags { * This number should increase every time the list of mesh paths * changes, i.e. when a station is added or removed, so that * userspace can tell whether it got a consistent snapshot. + * @hop_count: hops to destination */ struct mpath_info { u32 filled; @@ -1467,6 +1470,7 @@ struct mpath_info { u32 discovery_timeout; u8 discovery_retries; u8 flags; + u8 hop_count; int generation; }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index ebe79e12c82e..213a1d7c1063 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3287,6 +3287,7 @@ enum nl80211_mpath_flags { * &enum nl80211_mpath_flags; * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries + * @NL80211_MPATH_INFO_HOP_COUNT: hop count to destination * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number * currently defind * @__NL80211_MPATH_INFO_AFTER_LAST: internal use @@ -3300,6 +3301,7 @@ enum nl80211_mpath_info { NL80211_MPATH_INFO_FLAGS, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, NL80211_MPATH_INFO_DISCOVERY_RETRIES, + NL80211_MPATH_INFO_HOP_COUNT, /* keep last */ __NL80211_MPATH_INFO_AFTER_LAST, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 83ee573b1804..52cbaaf5caea 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1745,7 +1745,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, MPATH_INFO_EXPTIME | MPATH_INFO_DISCOVERY_TIMEOUT | MPATH_INFO_DISCOVERY_RETRIES | - MPATH_INFO_FLAGS; + MPATH_INFO_FLAGS | + MPATH_INFO_HOP_COUNT; pinfo->frame_qlen = mpath->frame_queue.qlen; pinfo->sn = mpath->sn; @@ -1765,6 +1766,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, pinfo->flags |= NL80211_MPATH_FLAG_FIXED; if (mpath->flags & MESH_PATH_RESOLVED) pinfo->flags |= NL80211_MPATH_FLAG_RESOLVED; + pinfo->hop_count = mpath->hop_count; } static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 6950cd0bf594..6d1190b3332f 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -386,6 +386,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, unsigned long orig_lifetime, exp_time; u32 last_hop_metric, new_metric; bool process = true; + u8 hopcount; rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); @@ -404,6 +405,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, orig_sn = PREQ_IE_ORIG_SN(hwmp_ie); orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); orig_metric = PREQ_IE_METRIC(hwmp_ie); + hopcount = PREQ_IE_HOPCOUNT(hwmp_ie) + 1; break; case MPATH_PREP: /* Originator here refers to the MP that was the target in the @@ -415,6 +417,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, orig_sn = PREP_IE_TARGET_SN(hwmp_ie); orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); orig_metric = PREP_IE_METRIC(hwmp_ie); + hopcount = PREP_IE_HOPCOUNT(hwmp_ie) + 1; break; default: rcu_read_unlock(); @@ -482,6 +485,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, mpath->sn = orig_sn; mpath->exp_time = time_after(mpath->exp_time, exp_time) ? mpath->exp_time : exp_time; + mpath->hop_count = hopcount; mesh_path_activate(mpath); spin_unlock_bh(&mpath->state_lock); ewma_mesh_fail_avg_init(&sta->mesh->fail_avg); @@ -523,6 +527,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, mpath->metric = last_hop_metric; mpath->exp_time = time_after(mpath->exp_time, exp_time) ? mpath->exp_time : exp_time; + mpath->hop_count = 1; mesh_path_activate(mpath); spin_unlock_bh(&mpath->state_lock); ewma_mesh_fail_avg_init(&sta->mesh->fail_avg); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a89688929b16..159125e16c79 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5827,7 +5827,10 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, pinfo->discovery_timeout)) || ((pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) && nla_put_u8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, - pinfo->discovery_retries))) + pinfo->discovery_retries)) || + ((pinfo->filled & MPATH_INFO_HOP_COUNT) && + nla_put_u8(msg, NL80211_MPATH_INFO_HOP_COUNT, + pinfo->hop_count))) goto nla_put_failure; nla_nest_end(msg, pinfoattr); From 540bbcb930ed2fc9d6a57e0babea00027a7ecc67 Mon Sep 17 00:00:00 2001 From: Julan Hsu Date: Tue, 15 Jan 2019 15:28:43 -0800 Subject: [PATCH 06/23] nl80211/mac80211: mesh: add mesh path change count to mpath info Expose path change count to destination in mpath info Signed-off-by: Julan Hsu Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 5 ++++- include/uapi/linux/nl80211.h | 4 +++- net/mac80211/cfg.c | 4 +++- net/mac80211/mesh.h | 2 ++ net/mac80211/mesh_hwmp.c | 4 ++++ net/wireless/nl80211.c | 5 ++++- 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 37816786d3e1..9c1d7979c200 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1439,7 +1439,8 @@ enum mpath_info_flags { MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), MPATH_INFO_DISCOVERY_RETRIES = BIT(5), MPATH_INFO_FLAGS = BIT(6), - MPATH_INFO_HOP_COUNT = BIT(7) + MPATH_INFO_HOP_COUNT = BIT(7), + MPATH_INFO_PATH_CHANGE = BIT(8), }; /** @@ -1460,6 +1461,7 @@ enum mpath_info_flags { * changes, i.e. when a station is added or removed, so that * userspace can tell whether it got a consistent snapshot. * @hop_count: hops to destination + * @path_change_count: total number of path changes to destination */ struct mpath_info { u32 filled; @@ -1471,6 +1473,7 @@ struct mpath_info { u8 discovery_retries; u8 flags; u8 hop_count; + u32 path_change_count; int generation; }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 213a1d7c1063..426db4d8f71c 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3288,8 +3288,9 @@ enum nl80211_mpath_flags { * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries * @NL80211_MPATH_INFO_HOP_COUNT: hop count to destination + * @NL80211_MPATH_INFO_PATH_CHANGE: total number of path changes to destination * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number - * currently defind + * currently defined * @__NL80211_MPATH_INFO_AFTER_LAST: internal use */ enum nl80211_mpath_info { @@ -3302,6 +3303,7 @@ enum nl80211_mpath_info { NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, NL80211_MPATH_INFO_DISCOVERY_RETRIES, NL80211_MPATH_INFO_HOP_COUNT, + NL80211_MPATH_INFO_PATH_CHANGE, /* keep last */ __NL80211_MPATH_INFO_AFTER_LAST, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 52cbaaf5caea..e5e0f100389c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1746,7 +1746,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, MPATH_INFO_DISCOVERY_TIMEOUT | MPATH_INFO_DISCOVERY_RETRIES | MPATH_INFO_FLAGS | - MPATH_INFO_HOP_COUNT; + MPATH_INFO_HOP_COUNT | + MPATH_INFO_PATH_CHANGE; pinfo->frame_qlen = mpath->frame_queue.qlen; pinfo->sn = mpath->sn; @@ -1767,6 +1768,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, if (mpath->flags & MESH_PATH_RESOLVED) pinfo->flags |= NL80211_MPATH_FLAG_RESOLVED; pinfo->hop_count = mpath->hop_count; + pinfo->path_change_count = mpath->path_change_count; } static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index cad6592c52a1..8b26858ab4d5 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -94,6 +94,7 @@ enum mesh_deferred_task_flags { * @last_preq_to_root: Timestamp of last PREQ sent to root * @is_root: the destination station of this path is a root node * @is_gate: the destination station of this path is a mesh gate + * @path_change_count: the number of path changes to destination * * * The dst address is unique in the mesh path table. Since the mesh_path is @@ -124,6 +125,7 @@ struct mesh_path { unsigned long last_preq_to_root; bool is_root; bool is_gate; + u32 path_change_count; }; /** diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 6d1190b3332f..a0aebf44493f 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -479,6 +479,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, } if (fresh_info) { + if (rcu_access_pointer(mpath->next_hop) != sta) + mpath->path_change_count++; mesh_path_assign_nexthop(mpath, sta); mpath->flags |= MESH_PATH_SN_VALID; mpath->metric = new_metric; @@ -523,6 +525,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, } if (fresh_info) { + if (rcu_access_pointer(mpath->next_hop) != sta) + mpath->path_change_count++; mesh_path_assign_nexthop(mpath, sta); mpath->metric = last_hop_metric; mpath->exp_time = time_after(mpath->exp_time, exp_time) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 159125e16c79..e5f9c9ceb6c9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5830,7 +5830,10 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, pinfo->discovery_retries)) || ((pinfo->filled & MPATH_INFO_HOP_COUNT) && nla_put_u8(msg, NL80211_MPATH_INFO_HOP_COUNT, - pinfo->hop_count))) + pinfo->hop_count)) || + ((pinfo->filled & MPATH_INFO_PATH_CHANGE) && + nla_put_u32(msg, NL80211_MPATH_INFO_PATH_CHANGE, + pinfo->path_change_count))) goto nla_put_failure; nla_nest_end(msg, pinfoattr); From 67fc05549cdb39f9e02ec4af5cc94509b1f89754 Mon Sep 17 00:00:00 2001 From: Julan Hsu Date: Tue, 15 Jan 2019 15:31:56 -0800 Subject: [PATCH 07/23] mac80211: mesh: use average bitrate for link metric calculation Use bitrate moving average to smooth out link metric and stablize path selection. Signed-off-by: Julan Hsu Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 5 +++++ net/mac80211/mesh_hwmp.c | 9 ++++++--- net/mac80211/sta_info.h | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e5e0f100389c..80d8ebc30ded 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1231,6 +1231,11 @@ static void sta_apply_mesh_params(struct ieee80211_local *local, ieee80211_mps_sta_status_update(sta); changed |= ieee80211_mps_set_sta_local_pm(sta, sdata->u.mesh.mshcfg.power_mode); + + ewma_mesh_tx_rate_avg_init(&sta->mesh->tx_rate_avg); + /* init at low value */ + ewma_mesh_tx_rate_avg_add(&sta->mesh->tx_rate_avg, 10); + break; case NL80211_PLINK_LISTEN: case NL80211_PLINK_BLOCKED: diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index a0aebf44493f..f50409635a16 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -300,6 +300,7 @@ void ieee80211s_update_metric(struct ieee80211_local *local, { struct ieee80211_tx_info *txinfo = st->info; int failed; + struct rate_info rinfo; failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); @@ -310,12 +311,15 @@ void ieee80211s_update_metric(struct ieee80211_local *local, if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) > LINK_FAIL_THRESH) mesh_plink_broken(sta); + + sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); + ewma_mesh_tx_rate_avg_add(&sta->mesh->tx_rate_avg, + cfg80211_calculate_bitrate(&rinfo)); } static u32 airtime_link_metric_get(struct ieee80211_local *local, struct sta_info *sta) { - struct rate_info rinfo; /* This should be adjusted for each device */ int device_constant = 1 << ARITH_SHIFT; int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT; @@ -339,8 +343,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, if (fail_avg > LINK_FAIL_THRESH) return MAX_METRIC; - sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); - rate = cfg80211_calculate_bitrate(&rinfo); + rate = ewma_mesh_tx_rate_avg_read(&sta->mesh->tx_rate_avg); if (WARN_ON(!rate)) return MAX_METRIC; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9a380803e597..90e03ebccd3f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -353,6 +353,7 @@ struct ieee80211_fast_rx { /* we use only values in the range 0-100, so pick a large precision */ DECLARE_EWMA(mesh_fail_avg, 20, 8) +DECLARE_EWMA(mesh_tx_rate_avg, 8, 16) /** * struct mesh_sta - mesh STA information @@ -376,6 +377,7 @@ DECLARE_EWMA(mesh_fail_avg, 20, 8) * processed * @connected_to_gate: true if mesh STA has a path to a mesh gate * @fail_avg: moving percentage of failed MSDUs + * @tx_rate_avg: moving average of tx bitrate */ struct mesh_sta { struct timer_list plink_timer; @@ -404,6 +406,8 @@ struct mesh_sta { /* moving percentage of failed MSDUs */ struct ewma_mesh_fail_avg fail_avg; + /* moving average of tx bitrate */ + struct ewma_mesh_tx_rate_avg tx_rate_avg; }; DECLARE_EWMA(signal, 10, 8) From a8d418d9ac25f85a9caf652a4b2d07ec790474ab Mon Sep 17 00:00:00 2001 From: Julan Hsu Date: Tue, 15 Jan 2019 15:33:03 -0800 Subject: [PATCH 08/23] mac80211: mesh: only switch path when new metric is at least 10% better This helps to reduce frequent path switches when multiple path candidates have the same or very similar path metrics. Signed-off-by: Julan Hsu Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f50409635a16..e00284afdda5 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -447,7 +447,10 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, (mpath->flags & MESH_PATH_SN_VALID)) { if (SN_GT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && - new_metric >= mpath->metric)) { + (rcu_access_pointer(mpath->next_hop) != + sta ? + mult_frac(new_metric, 10, 9) : + new_metric) >= mpath->metric)) { process = false; fresh_info = false; } @@ -515,8 +518,10 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, if (mpath) { spin_lock_bh(&mpath->state_lock); if ((mpath->flags & MESH_PATH_FIXED) || - ((mpath->flags & MESH_PATH_ACTIVE) && - (last_hop_metric > mpath->metric))) + ((mpath->flags & MESH_PATH_ACTIVE) && + ((rcu_access_pointer(mpath->next_hop) != sta ? + mult_frac(last_hop_metric, 10, 9) : + last_hop_metric) > mpath->metric))) fresh_info = false; } else { mpath = mesh_path_add(sdata, ta); From 77f7ffdc335de8541a2a40618781ed0b76cee9f7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 16 Jan 2019 22:32:12 +0100 Subject: [PATCH 09/23] mac80211: minstrel_ht: add flag to indicate missing/inaccurate tx A-MPDU length Some hardware (e.g. MediaTek MT7603) cannot report A-MPDU length in tx status information. Add support for a flag to indicate that, to allow minstrel_ht to use a fixed value in its internal calculation (which gives better results than just defaulting to 1). Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ++++ net/mac80211/debugfs.c | 1 + net/mac80211/rc80211_minstrel_ht.c | 25 +++++++++++++++++----- net/mac80211/rc80211_minstrel_ht_debugfs.c | 7 +++--- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5d36eacf401e..a285c2bfd14e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2190,6 +2190,9 @@ struct ieee80211_txq { * MMPDUs on station interfaces. This of course requires the driver to use * TXQs to start with. * + * @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU + * length in tx status information + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -2238,6 +2241,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_BUFF_MMPDU_TXQ, IEEE80211_HW_SUPPORTS_VHT_EXT_NSS_BW, IEEE80211_HW_STA_MMPDU_TXQ, + IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 81c5fec2eae7..343ad0a915e4 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -218,6 +218,7 @@ static const char *hw_flag_names[] = { FLAG(BUFF_MMPDU_TXQ), FLAG(SUPPORTS_VHT_EXT_NSS_BW), FLAG(STA_MMPDU_TXQ), + FLAG(TX_STATUS_NO_AMPDU_LEN), #undef FLAG }; diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index f466ec37d161..ccaf951e4e31 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -294,6 +294,15 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; } +static unsigned int +minstrel_ht_avg_ampdu_len(struct minstrel_ht_sta *mi) +{ + if (!mi->avg_ampdu_len) + return AVG_AMPDU_SIZE; + + return MINSTREL_TRUNC(mi->avg_ampdu_len); +} + /* * Return current throughput based on the average A-MPDU length, taking into * account the expected number of retransmissions and their expected length @@ -309,7 +318,7 @@ minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, return 0; if (group != MINSTREL_CCK_GROUP) - nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); + nsecs = 1000 * mi->overhead / minstrel_ht_avg_ampdu_len(mi); nsecs += minstrel_mcs_groups[group].duration[rate] << minstrel_mcs_groups[group].shift; @@ -503,8 +512,12 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) u16 tmp_cck_tp_rate[MAX_THR_RATES], index; if (mi->ampdu_packets > 0) { - mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, - MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL); + if (!ieee80211_hw_check(mp->hw, TX_STATUS_NO_AMPDU_LEN)) + mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, + MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), + EWMA_LEVEL); + else + mi->avg_ampdu_len = 0; mi->ampdu_len = 0; mi->ampdu_packets = 0; } @@ -709,7 +722,9 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, mi->ampdu_len += info->status.ampdu_len; if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { - mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len); + int avg_ampdu_len = minstrel_ht_avg_ampdu_len(mi); + + mi->sample_wait = 16 + 2 * avg_ampdu_len; mi->sample_tries = 1; mi->sample_count--; } @@ -777,7 +792,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, unsigned int cw = mp->cw_min; unsigned int ctime = 0; unsigned int t_slot = 9; /* FIXME */ - unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); + unsigned int ampdu_len = minstrel_ht_avg_ampdu_len(mi); unsigned int overhead = 0, overhead_rtscts = 0; mrs = minstrel_get_ratestats(mi, index); diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index 57820a5f2c16..31641d0b0f5c 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c @@ -160,9 +160,10 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) "lookaround %d\n", max(0, (int) mi->total_packets - (int) mi->sample_packets), mi->sample_packets); - p += sprintf(p, "Average # of aggregated frames per A-MPDU: %d.%d\n", - MINSTREL_TRUNC(mi->avg_ampdu_len), - MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); + if (mi->avg_ampdu_len) + p += sprintf(p, "Average # of aggregated frames per A-MPDU: %d.%d\n", + MINSTREL_TRUNC(mi->avg_ampdu_len), + MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); ms->len = p - ms->buf; WARN_ON(ms->len + sizeof(*ms) > 32768); From 0c4335de196c23a28d9de8f5eb8b973673051ad9 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 17 Jan 2019 03:13:12 +0000 Subject: [PATCH 10/23] virt_wifi: remove duplicated include from virt_wifi.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: Johannes Berg --- drivers/net/wireless/virt_wifi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c index 64b218699656..245d4d0af89b 100644 --- a/drivers/net/wireless/virt_wifi.c +++ b/drivers/net/wireless/virt_wifi.c @@ -14,11 +14,6 @@ #include #include -#include -#include -#include -#include - static struct wiphy *common_wiphy; struct virt_wifi_wiphy_priv { From e073f7caa26cc7f5423779b1a47f1689dd20bf17 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 17 Jan 2019 03:17:03 +0000 Subject: [PATCH 11/23] virt_wifi: remove set but not used variable 'w_priv' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/virt_wifi.c: In function 'virt_wifi_net_device_stop': drivers/net/wireless/virt_wifi.c:432:31: warning: variable 'w_priv' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Signed-off-by: Johannes Berg --- drivers/net/wireless/virt_wifi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c index 245d4d0af89b..9479b26b2d02 100644 --- a/drivers/net/wireless/virt_wifi.c +++ b/drivers/net/wireless/virt_wifi.c @@ -424,13 +424,11 @@ static int virt_wifi_net_device_open(struct net_device *dev) static int virt_wifi_net_device_stop(struct net_device *dev) { struct virt_wifi_netdev_priv *n_priv = netdev_priv(dev); - struct virt_wifi_wiphy_priv *w_priv; n_priv->is_up = false; if (!dev->ieee80211_ptr) return 0; - w_priv = wiphy_priv(dev->ieee80211_ptr->wiphy); virt_wifi_cancel_scan(dev->ieee80211_ptr->wiphy); virt_wifi_cancel_connect(dev); From 390298e86f8a2e8b428ffb259a323667229ff822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Tue, 22 Jan 2019 15:20:16 +0100 Subject: [PATCH 12/23] mac80211: Expose ieee80211_schedule_txq() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we reworked ieee80211_return_txq() so it assumes that the caller takes care of logging, we need another function that can be called without holding any locks. Introduce ieee80211_schedule_txq() which serves this purpose. Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Johannes Berg --- include/net/mac80211.h | 13 +++++++++++++ net/mac80211/driver-ops.h | 4 +--- net/mac80211/tx.c | 13 +++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a285c2bfd14e..294a8a36012a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -6209,6 +6209,19 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) __releases(txq_lock); +/** + * ieee80211_schedule_txq - schedule a TXQ for transmission + * + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @txq: pointer obtained from station or virtual interface + * + * Schedules a TXQ for transmission if it is not already scheduled. Takes a + * lock, which means it must *not* be called between + * ieee80211_txq_schedule_start() and ieee80211_txq_schedule_end() + */ +void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq) + __acquires(txq_lock) __releases(txq_lock); + /** * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit * diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 1aab1734b26f..ba3c07b10cd0 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1176,9 +1176,7 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local, static inline void schedule_and_wake_txq(struct ieee80211_local *local, struct txq_info *txqi) { - spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]); - ieee80211_return_txq(&local->hw, &txqi->txq); - spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]); + ieee80211_schedule_txq(&local->hw, &txqi->txq); drv_wake_tx_queue(local, txqi); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f46d8d822f86..037f95e39a45 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3703,6 +3703,19 @@ void ieee80211_return_txq(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_return_txq); +void ieee80211_schedule_txq(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + __acquires(txq_lock) __releases(txq_lock) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = to_txq_info(txq); + + spin_lock_bh(&local->active_txq_lock[txq->ac]); + ieee80211_return_txq(hw, txq); + spin_unlock_bh(&local->active_txq_lock[txq->ac]); +} +EXPORT_SYMBOL(ieee80211_schedule_txq); + bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { From 4af217500e7fc7cf87528488db5bc6494f4890a9 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 23 Jan 2019 01:03:32 -0600 Subject: [PATCH 13/23] cfg80211: mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warnings: net/wireless/wext-compat.c:1327:6: warning: this statement may fall through [-Wimplicit-fallthrough=] net/wireless/wext-compat.c:1341:6: warning: this statement may fall through [-Wimplicit-fallthrough=] Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enabling -Wimplicit-fallthrough Signed-off-by: Gustavo A. R. Silva Signed-off-by: Johannes Berg --- net/wireless/wext-compat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 06943d9c9835..d522787c7354 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1337,6 +1337,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) wstats.qual.qual = sig + 110; break; } + /* fall through */ case CFG80211_SIGNAL_TYPE_UNSPEC: if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_SIGNAL)) { wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; @@ -1345,6 +1346,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev) wstats.qual.qual = sinfo.signal; break; } + /* fall through */ default: wstats.qual.updated |= IW_QUAL_LEVEL_INVALID; wstats.qual.updated |= IW_QUAL_QUAL_INVALID; From c82c06ce43d372e0127982414539d1601d5f9ce3 Mon Sep 17 00:00:00 2001 From: Sriram R Date: Thu, 6 Dec 2018 15:34:57 +0530 Subject: [PATCH 14/23] cfg80211: Notify all User Hints To self managed wiphys Currently Self Managed WIPHY's are not notified on any hints other than user cell base station hints. Self Managed wiphy's basically rely on hints from firmware and its local regdb for regulatory management, so hints from wireless core can be ignored. But all user hints needs to be notified to them to provide flexibility to these drivers to honour or ignore these user hints. Currently none of the drivers supporting self managed wiphy register a notifier with cfg80211. Hence this change does not affect any other driver behavior. Signed-off-by: Sriram R Signed-off-by: Johannes Berg --- net/wireless/reg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ecfb1a06dbb2..7def1ece22b2 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2724,9 +2724,7 @@ static void notify_self_managed_wiphys(struct regulatory_request *request) list_for_each_entry(rdev, &cfg80211_rdev_list, list) { wiphy = &rdev->wiphy; if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && - request->initiator == NL80211_REGDOM_SET_BY_USER && - request->user_reg_hint_type == - NL80211_USER_REG_HINT_CELL_BASE) + request->initiator == NL80211_REGDOM_SET_BY_USER) reg_call_notifier(wiphy, request); } } From ab4dfa20534e32e48de6b761b42d943518fb26f7 Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Wed, 19 Dec 2018 22:52:25 +0530 Subject: [PATCH 15/23] cfg80211: Allow drivers to advertise supported AKM suites There was no such capability advertisement from the driver and thus the current user space has to assume the driver to support all the AKMs. While that may be the case with some drivers (e.g., mac80211-based ones), there are cfg80211-based drivers that implement SME and have constraints on which AKMs can be supported (e.g., such drivers may need an update to support SAE AKM using NL80211_CMD_EXTERNAL_AUTH). Allow such drivers to advertise the exact set of supported AKMs so that user space tools can determine what network profile options should be allowed to be configured. Signed-off-by: Veerendranath Jakkam [pmsr data might be big, start a new netlink message section] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 5 +++++ include/uapi/linux/nl80211.h | 6 ++++++ net/wireless/nl80211.c | 9 +++++++++ 3 files changed, 20 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9c1d7979c200..b61ac6e9de08 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4128,6 +4128,8 @@ struct cfg80211_pmsr_capabilities { * @signal_type: signal type reported in &struct cfg80211_bss. * @cipher_suites: supported cipher suites * @n_cipher_suites: number of supported cipher suites + * @akm_suites: supported AKM suites + * @n_akm_suites: number of supported AKM suites * @retry_short: Retry limit for short frames (dot11ShortRetryLimit) * @retry_long: Retry limit for long frames (dot11LongRetryLimit) * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); @@ -4326,6 +4328,9 @@ struct wiphy { int n_cipher_suites; const u32 *cipher_suites; + int n_akm_suites; + const u32 *akm_suites; + u8 retry_short; u8 retry_long; u32 frag_threshold; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 426db4d8f71c..5f9d5cd458a1 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1565,6 +1565,12 @@ enum nl80211_commands { * (a u32 with flags from &enum nl80211_wpa_versions). * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to * indicate which key management algorithm(s) to use (an array of u32). + * This attribute is also sent in response to @NL80211_CMD_GET_WIPHY, + * indicating the supported AKM suites, intended for specific drivers which + * implement SME and have constraints on which AKMs are supported and also + * the cases where an AKM support is offloaded to the driver/firmware. + * If there is no such notification from the driver, user space should + * assume the driver supports all the AKM suites. * * @NL80211_ATTR_REQ_IE: (Re)association request information elements as * sent out by the card, for ROAM and successful CONNECT events. diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e5f9c9ceb6c9..eb4437fa0539 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2279,6 +2279,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, if (nl80211_send_pmsr_capa(rdev, msg)) goto nla_put_failure; + state->split_start++; + break; + case 15: + if (rdev->wiphy.akm_suites && + nla_put(msg, NL80211_ATTR_AKM_SUITES, + sizeof(u32) * rdev->wiphy.n_akm_suites, + rdev->wiphy.akm_suites)) + goto nla_put_failure; + /* done */ state->split_start = 0; break; From fe4943702c850fa07f963eaa6f1530d9d4c2da78 Mon Sep 17 00:00:00 2001 From: Srinivas Dasari Date: Wed, 23 Jan 2019 18:06:56 +0530 Subject: [PATCH 16/23] cfg80211: Authentication offload to user space in AP mode commit 40cbfa90218b ("cfg80211/nl80211: Optional authentication offload to userspace")' introduced authentication offload to user space by the host drivers in station mode. This commit extends the same for the AP mode too. Extend NL80211_ATTR_EXTERNAL_AUTH_SUPPORT to also claim the support of external authentication from the user space in AP mode. A new flag parameter is introduced in cfg80211_ap_settings to intend the same while "start ap". Host driver to use NL80211_CMD_FRAME interface to transmit and receive the authentication frames to / from the user space. Host driver to indicate the flag NL80211_RXMGMT_FLAG_EXTERNAL_AUTH while sending the authentication frame to the user space. This intends to the user space that the driver wishes it to process the authentication frame for certain protocols, though it had initially advertised the support for SME functionality. User space shall accordingly do the authentication and indicate its final status through the command NL80211_CMD_EXTERNAL_AUTH. Allow the command even if userspace doesn't include the attribute NL80211_ATTR_SSID for AP interface. Host driver shall continue with the association sequence and indicate the STA connection status through cfg80211_new_sta. To facilitate the host drivers in AP mode for matching the pmkid by the stations during the association, NL80211_CMD_EXTERNAL_AUTH is also enhanced to include the pmkid to drivers after the authentication. This pmkid can also be used in the STA mode to include in the association request. Also modify nl80211_external_auth to not mandate SSID in AP mode. Signed-off-by: Srinivas Dasari [remove useless nla_get_flag() usage] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 15 +++++++++++++++ include/uapi/linux/nl80211.h | 13 +++++++++---- net/wireless/nl80211.c | 25 ++++++++++++++++++------- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b61ac6e9de08..7033c90850b0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -835,6 +835,17 @@ struct cfg80211_bitrate_mask { } control[NUM_NL80211_BANDS]; }; +/** + * enum cfg80211_ap_settings_flags - AP settings flags + * + * Used by cfg80211_ap_settings + * + * @AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external authentication + */ +enum cfg80211_ap_settings_flags { + AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = BIT(0), +}; + /** * struct cfg80211_ap_settings - AP configuration * @@ -865,6 +876,7 @@ struct cfg80211_bitrate_mask { * @he_cap: HE capabilities (or %NULL if HE isn't enabled) * @ht_required: stations must support HT * @vht_required: stations must support VHT + * @flags: flags, as defined in enum cfg80211_ap_settings_flags */ struct cfg80211_ap_settings { struct cfg80211_chan_def chandef; @@ -890,6 +902,7 @@ struct cfg80211_ap_settings { const struct ieee80211_vht_cap *vht_cap; const struct ieee80211_he_cap_elem *he_cap; bool ht_required, vht_required; + u32 flags; }; /** @@ -2831,6 +2844,7 @@ struct cfg80211_pmk_conf { * use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space cannot give you * the real status code for failures. Used only for the authentication * response command interface (user space to driver). + * @pmkid: The identifier to refer a PMKSA. */ struct cfg80211_external_auth_params { enum nl80211_external_auth_action action; @@ -2838,6 +2852,7 @@ struct cfg80211_external_auth_params { struct cfg80211_ssid ssid; unsigned int key_mgmt_suite; u16 status; + const u8 *pmkid; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 5f9d5cd458a1..8b0fdb9e133b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2266,10 +2266,10 @@ enum nl80211_commands { * &enum nl80211_external_auth_action value). This is used with the * %NL80211_CMD_EXTERNAL_AUTH request event. * @NL80211_ATTR_EXTERNAL_AUTH_SUPPORT: Flag attribute indicating that the user - * space supports external authentication. This attribute shall be used - * only with %NL80211_CMD_CONNECT request. The driver may offload - * authentication processing to user space if this capability is indicated - * in NL80211_CMD_CONNECT requests from the user space. + * space supports external authentication. This attribute shall be used + * with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver + * may offload authentication processing to user space if this capability + * is indicated in the respective requests from the user space. * * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED. @@ -5631,9 +5631,14 @@ enum nl80211_crit_proto_id { * Used by cfg80211_rx_mgmt() * * @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver. + * @NL80211_RXMGMT_FLAG_EXTERNAL_AUTH: Host driver intends to offload + * the authentication. Exclusively defined for host drivers that + * advertises the SME functionality but would like the userspace + * to handle certain authentication algorithms (e.g. SAE). */ enum nl80211_rxmgmt_flags { NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, + NL80211_RXMGMT_FLAG_EXTERNAL_AUTH = 1 << 1, }; /* diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index eb4437fa0539..dc96077afe5e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4550,6 +4550,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) nl80211_calculate_ap_params(¶ms); + if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) + params.flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT; + wdev_lock(wdev); err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { @@ -13086,7 +13089,9 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->external_auth) return -EOPNOTSUPP; - if (!info->attrs[NL80211_ATTR_SSID]) + if (!info->attrs[NL80211_ATTR_SSID] && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) return -EINVAL; if (!info->attrs[NL80211_ATTR_BSSID]) @@ -13097,18 +13102,24 @@ static int nl80211_external_auth(struct sk_buff *skb, struct genl_info *info) memset(¶ms, 0, sizeof(params)); - params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); - if (params.ssid.ssid_len == 0 || - params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - memcpy(params.ssid.ssid, nla_data(info->attrs[NL80211_ATTR_SSID]), - params.ssid.ssid_len); + if (info->attrs[NL80211_ATTR_SSID]) { + params.ssid.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); + if (params.ssid.ssid_len == 0 || + params.ssid.ssid_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + memcpy(params.ssid.ssid, + nla_data(info->attrs[NL80211_ATTR_SSID]), + params.ssid.ssid_len); + } memcpy(params.bssid, nla_data(info->attrs[NL80211_ATTR_BSSID]), ETH_ALEN); params.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); + if (info->attrs[NL80211_ATTR_PMKID]) + params.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); + return rdev_external_auth(rdev, dev, ¶ms); } From 6c900360e7c0df6a4846ac97d7b548d72cd801b0 Mon Sep 17 00:00:00 2001 From: Liangwei Dong Date: Fri, 18 Jan 2019 16:54:38 +0530 Subject: [PATCH 17/23] nl80211: Allow set/del pmksa operations for AP Host drivers may offload authentication to the user space through the commit ("cfg80211: Authentication offload to user space in AP mode"). This interface can be used to implement SAE by having the userspace do authentication/PMKID key derivation and driver handle the association. A step ahead, this interface can get further optimized if the PMKID is passed to the host driver and also have it respond to the association request by the STA on a valid PMKID. This commit enables the userspace to pass the PMKID to the host drivers through the set/del pmksa operations in AP mode. Set/Del pmksa is now restricted to STA/P2P client mode only and thus the drivers might not expect them in any other(AP) mode. This commit also introduces a feature flag NL80211_EXT_FEATURE_AP_PMKSA_CACHING (johannes: renamed) to maintain the backward compatibility of such an expectation by the host drivers. These operations are allowed in AP mode only when the drivers advertize the capability through this flag. Signed-off-by: Liangwei Dong Signed-off-by: Srinivas Dasari [rename flag to NL80211_EXT_FEATURE_AP_PMKSA_CACHING] Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 4 ++++ net/wireless/nl80211.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 8b0fdb9e133b..dd4f86ee286e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -5340,6 +5340,9 @@ enum nl80211_feature_flags { * fairness for transmitted packets and has enabled airtime fairness * scheduling. * + * @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching + * (set/del PMKSA operations) in AP mode. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -5380,6 +5383,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_CAN_REPLACE_PTK0, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS, + NL80211_EXT_FEATURE_AP_PMKSA_CACHING, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index dc96077afe5e..af89e5c9fd0a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -9899,7 +9899,10 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) } if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && + !(dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP && + wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_AP_PMKSA_CACHING))) return -EOPNOTSUPP; switch (info->genlhdr->cmd) { From 2ec56f9180091a7ff5e178bdca7672c912d74326 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 28 Jan 2019 11:47:47 +0100 Subject: [PATCH 18/23] mac80211: remove unused variable Clearly, I missed this when trying out the previously merged patches. Remove the spurious variable now. Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 037f95e39a45..61c7ea9de2cc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3708,7 +3708,6 @@ void ieee80211_schedule_txq(struct ieee80211_hw *hw, __acquires(txq_lock) __releases(txq_lock) { struct ieee80211_local *local = hw_to_local(hw); - struct txq_info *txqi = to_txq_info(txq); spin_lock_bh(&local->active_txq_lock[txq->ac]); ieee80211_return_txq(hw, txq); From cb86880ee493ea41e95476be054a605b3e434035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Tue, 29 Jan 2019 11:31:26 +0100 Subject: [PATCH 19/23] mac80211: Fix documentation strings for airtime-related variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a typo in the documentation for weight_multiplier in mac80211.h, and the doc was missing entirely for airtime and airtime_weight in sta_info.h. Reported-by: kbuild test robot Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 +- net/mac80211/sta_info.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 294a8a36012a..396b0c079c3b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2365,7 +2365,7 @@ enum ieee80211_hw_flags { * them are encountered. The default should typically not be changed, * unless the driver has good reasons for needing more buffers. * - * @weight_multipler: Driver specific airtime weight multiplier used while + * @weight_multiplier: Driver specific airtime weight multiplier used while * refilling deficit of each TXQ. */ struct ieee80211_hw { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 90e03ebccd3f..05647d835894 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -473,6 +473,9 @@ struct ieee80211_sta_rx_stats { * @last_seq_ctrl: last received seq/frag number from this STA (per TID * plus one for non-QoS frames) * @tid_seq: per-TID sequence numbers for sending to this STA + * @airtime: per-AC struct airtime_info describing airtime statistics for this + * station + * @airtime_weight: station weight for airtime fairness calculation purposes * @ampdu_mlme: A-MPDU state machine state * @mesh: mesh STA information * @debugfs_dir: debug filesystem directory dentry From 5ac4a12df58121f0cf874b518406ec2a8e2d4ac4 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Tue, 29 Jan 2019 19:25:53 +0100 Subject: [PATCH 20/23] cfg80211: fix typo Fix spelling mistake in cfg80211.h: "lenght" -> "length". The typo is also in the special comment block which translates to documentation. Signed-off-by: Matteo Croce Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7033c90850b0..5862f1efb52c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5604,7 +5604,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, * @dev: network device * @macaddr: the MAC address of the new candidate * @ie: information elements advertised by the peer candidate - * @ie_len: lenght of the information elements buffer + * @ie_len: length of the information elements buffer * @gfp: allocation flags * * This function notifies cfg80211 that the mesh peer candidate has been From 23323289b1543b445d1f10aeab1bcfd84f2ca50a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Jan 2019 10:08:28 +0100 Subject: [PATCH 21/23] netlink: reduce NLA_POLICY_NESTED{,_ARRAY} arguments In typical cases, there's no need to pass both the maxattr and the policy array pointer, as the maxattr should just be ARRAY_SIZE(policy) - 1. Therefore, to be less error prone, just remove the maxattr argument from the default macros and deduce the size accordingly. Leave the original macros with a leading underscore to use here and in case somebody needs to pass a policy pointer where the policy isn't declared in the same place and thus ARRAY_SIZE() cannot be used. Signed-off-by: Johannes Berg --- include/net/netlink.h | 8 ++++++-- net/wireless/nl80211.c | 15 +++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 4c1e99303b5a..23f27b0b3cef 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -306,10 +306,14 @@ struct nla_policy { #define NLA_POLICY_ETH_ADDR NLA_POLICY_EXACT_LEN(ETH_ALEN) #define NLA_POLICY_ETH_ADDR_COMPAT NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN) -#define NLA_POLICY_NESTED(maxattr, policy) \ +#define _NLA_POLICY_NESTED(maxattr, policy) \ { .type = NLA_NESTED, .validation_data = policy, .len = maxattr } -#define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \ +#define _NLA_POLICY_NESTED_ARRAY(maxattr, policy) \ { .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr } +#define NLA_POLICY_NESTED(policy) \ + _NLA_POLICY_NESTED(ARRAY_SIZE(policy) - 1, policy) +#define NLA_POLICY_NESTED_ARRAY(policy) \ + _NLA_POLICY_NESTED_ARRAY(ARRAY_SIZE(policy) - 1, policy) #define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition)) #define NLA_ENSURE_INT_TYPE(tp) \ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ed53f8332ec8..a3cc039b9f55 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -259,15 +259,13 @@ nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = { static const struct nla_policy nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = { [NL80211_PMSR_TYPE_FTM] = - NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX, - nl80211_pmsr_ftm_req_attr_policy), + NLA_POLICY_NESTED(nl80211_pmsr_ftm_req_attr_policy), }; static const struct nla_policy nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = { [NL80211_PMSR_REQ_ATTR_DATA] = - NLA_POLICY_NESTED(NL80211_PMSR_TYPE_MAX, - nl80211_pmsr_req_data_policy), + NLA_POLICY_NESTED(nl80211_pmsr_req_data_policy), [NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG }, }; @@ -280,8 +278,7 @@ nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = { */ [NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED }, [NL80211_PMSR_PEER_ATTR_REQ] = - NLA_POLICY_NESTED(NL80211_PMSR_REQ_ATTR_MAX, - nl80211_pmsr_req_attr_policy), + NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy), [NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT }, }; @@ -292,8 +289,7 @@ nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = { [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT }, [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT }, [NL80211_PMSR_ATTR_PEERS] = - NLA_POLICY_NESTED_ARRAY(NL80211_PMSR_PEER_ATTR_MAX, - nl80211_psmr_peer_attr_policy), + NLA_POLICY_NESTED_ARRAY(nl80211_psmr_peer_attr_policy), }; const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { @@ -555,8 +551,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { }, [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1), [NL80211_ATTR_PEER_MEASUREMENTS] = - NLA_POLICY_NESTED(NL80211_PMSR_ATTR_MAX, - nl80211_pmsr_attr_policy), + NLA_POLICY_NESTED(nl80211_pmsr_attr_policy), [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1), }; From 9874b71fa19c3ae4d13e02081326975ab2734061 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Feb 2019 11:52:44 +0100 Subject: [PATCH 22/23] cfg80211: add missing documentation that kernel-doc warns about Add the missing documentation that kernel-doc continually warns about, to get rid of all that noise. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5862f1efb52c..7f2739a90bdb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1443,6 +1443,7 @@ enum monitor_flags { * @MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled * @MPATH_INFO_FLAGS: @flags filled * @MPATH_INFO_HOP_COUNT: @hop_count filled + * @MPATH_INFO_PATH_CHANGE: @path_change_count filled */ enum mpath_info_flags { MPATH_INFO_FRAME_QLEN = BIT(0), @@ -4609,6 +4610,17 @@ struct cfg80211_cqm_config; * @mesh_id_len: (private) Used by the internal configuration code * @mesh_id_up_len: (private) Used by the internal configuration code * @wext: (private) Used by the internal wireless extensions compat code + * @wext.ibss: (private) IBSS data part of wext handling + * @wext.connect: (private) connection handling data + * @wext.keys: (private) (WEP) key data + * @wext.ie: (private) extra elements for association + * @wext.ie_len: (private) length of extra elements + * @wext.bssid: (private) selected network BSSID + * @wext.ssid: (private) selected network SSID + * @wext.default_key: (private) selected default key index + * @wext.default_mgmt_key: (private) selected default management key index + * @wext.prev_bssid: (private) previous BSSID for reassociation + * @wext.prev_bssid_valid: (private) previous BSSID validity * @use_4addr: indicates 4addr mode is used on this interface, must be * set by driver (if supported) on add_interface BEFORE registering the * netdev and may otherwise be used by driver read-only, will be update @@ -4708,7 +4720,8 @@ struct wireless_dev { struct cfg80211_cached_keys *keys; const u8 *ie; size_t ie_len; - u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u8 prev_bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; s8 default_key, default_mgmt_key; bool prev_bssid_valid; From 7d4194633b29342d93501b53accebf638da134ad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Feb 2019 11:53:32 +0100 Subject: [PATCH 23/23] mac80211: fix missing/malformed documentation Fix the missing and malformed documentation that kernel-doc and sphinx warn about. While at it, also add some things to the docs to fix missing links. Sadly, the only way I could find to fix this was to add some trailing whitespace. Signed-off-by: Johannes Berg --- Documentation/driver-api/80211/mac80211.rst | 3 ++ include/net/mac80211.h | 44 +++++++++++++++++---- net/mac80211/sta_info.h | 18 +++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/Documentation/driver-api/80211/mac80211.rst b/Documentation/driver-api/80211/mac80211.rst index 85a8335e80b6..eab40bcf3987 100644 --- a/Documentation/driver-api/80211/mac80211.rst +++ b/Documentation/driver-api/80211/mac80211.rst @@ -125,6 +125,9 @@ functions/definitions .. kernel-doc:: include/net/mac80211.h :functions: ieee80211_rx_status +.. kernel-doc:: include/net/mac80211.h + :functions: mac80211_rx_encoding_flags + .. kernel-doc:: include/net/mac80211.h :functions: mac80211_rx_flags diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 396b0c079c3b..de866a7253c9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -942,8 +942,32 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate) * @band: the band to transmit on (use for checking for races) * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC * @ack_frame_id: internal frame ID for TX status, used internally - * @control: union for control data - * @status: union for status data + * @control: union part for control data + * @control.rates: TX rates array to try + * @control.rts_cts_rate_idx: rate for RTS or CTS + * @control.use_rts: use RTS + * @control.use_cts_prot: use RTS/CTS + * @control.short_preamble: use short preamble (CCK only) + * @control.skip_table: skip externally configured rate table + * @control.jiffies: timestamp for expiry on powersave clients + * @control.vif: virtual interface (may be NULL) + * @control.hw_key: key to encrypt with (may be NULL) + * @control.flags: control flags, see &enum mac80211_tx_control_flags + * @control.enqueue_time: enqueue time (for iTXQs) + * @driver_rates: alias to @control.rates to reserve space + * @pad: padding + * @rate_driver_data: driver use area if driver needs @control.rates + * @status: union part for status data + * @status.rates: attempted rates + * @status.ack_signal: ACK signal + * @status.ampdu_ack_len: AMPDU ack length + * @status.ampdu_len: AMPDU length + * @status.antenna: (legacy, kept only for iwlegacy) + * @status.tx_time: airtime consumed for transmission + * @status.is_valid_ack_signal: ACK signal is valid + * @status.status_driver_data: driver use area + * @ack: union part for pure ACK data + * @ack.cookie: cookie for the ACK * @driver_data: array of driver_data pointers * @ampdu_ack_len: number of acked aggregated frames. * relevant only if IEEE80211_TX_STAT_AMPDU was set. @@ -1163,6 +1187,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_AMPDU_EOF_BIT_KNOWN: The EOF value is known * @RX_FLAG_RADIOTAP_HE: HE radiotap data is present * (&struct ieee80211_radiotap_he, mac80211 will fill in + * * - DATA3_DATA_MCS * - DATA3_DATA_DCM * - DATA3_CODING @@ -1170,6 +1195,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * - DATA5_DATA_BW_RU_ALLOC * - DATA6_NSTS * - DATA3_STBC + * * from the RX info data, so leave those zeroed when building this data) * @RX_FLAG_RADIOTAP_HE_MU: HE MU radiotap data is present * (&struct ieee80211_radiotap_he_mu) @@ -1220,7 +1246,7 @@ enum mac80211_rx_flags { * @RX_ENC_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, * if the driver fills this value it should add * %IEEE80211_RADIOTAP_MCS_HAVE_FMT - * to hw.radiotap_mcs_details to advertise that fact + * to @hw.radiotap_mcs_details to advertise that fact. * @RX_ENC_FLAG_LDPC: LDPC was used * @RX_ENC_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3 * @RX_ENC_FLAG_BF: packet was beamformed @@ -2333,12 +2359,14 @@ enum ieee80211_hw_flags { * @radiotap_he: HE radiotap validity flags * * @radiotap_timestamp: Information for the radiotap timestamp field; if the - * 'units_pos' member is set to a non-negative value it must be set to - * a combination of a IEEE80211_RADIOTAP_TIMESTAMP_UNIT_* and a - * IEEE80211_RADIOTAP_TIMESTAMP_SPOS_* value, and then the timestamp + * @units_pos member is set to a non-negative value then the timestamp * field will be added and populated from the &struct ieee80211_rx_status - * device_timestamp. If the 'accuracy' member is non-negative, it's put - * into the accuracy radiotap field and the accuracy known flag is set. + * device_timestamp. + * @radiotap_timestamp.units_pos: Must be set to a combination of a + * IEEE80211_RADIOTAP_TIMESTAMP_UNIT_* and a + * IEEE80211_RADIOTAP_TIMESTAMP_SPOS_* value. + * @radiotap_timestamp.accuracy: If non-negative, fills the accuracy in the + * radiotap field and the accuracy known flag will be set. * * @netdev_features: netdev features to be set in each netdev created * from this HW. Note that not all features are usable with mac80211, diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 05647d835894..71f7e4973329 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -497,10 +497,28 @@ struct ieee80211_sta_rx_stats { * @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to * the BSS one. * @tx_stats: TX statistics + * @tx_stats.packets: # of packets transmitted + * @tx_stats.bytes: # of bytes in all packets transmitted + * @tx_stats.last_rate: last TX rate + * @tx_stats.msdu: # of transmitted MSDUs per TID * @rx_stats: RX statistics + * @rx_stats_avg: averaged RX statistics + * @rx_stats_avg.signal: averaged signal + * @rx_stats_avg.chain_signal: averaged per-chain signal * @pcpu_rx_stats: per-CPU RX statistics, assigned only if the driver needs * this (by advertising the USES_RSS hw flag) * @status_stats: TX status statistics + * @status_stats.filtered: # of filtered frames + * @status_stats.retry_failed: # of frames that failed after retry + * @status_stats.retry_count: # of retries attempted + * @status_stats.lost_packets: # of lost packets + * @status_stats.last_tdls_pkt_time: timestamp of last TDLS packet + * @status_stats.msdu_retries: # of MSDU retries + * @status_stats.msdu_failed: # of failed MSDUs + * @status_stats.last_ack: last ack timestamp (jiffies) + * @status_stats.last_ack_signal: last ACK signal + * @status_stats.ack_signal_filled: last ACK signal validity + * @status_stats.avg_ack_signal: average ACK signal */ struct sta_info { /* General information, mostly static */