mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-20 01:24:39 +08:00
New features for the wifi stack:
* airtime fairness scheduling in mac80211, so we can share * more authentication offloads to userspace - this is for SAE which is part of WPA3 and is hard to do in firmware * documentation fixes * various mesh improvements * various other small improvements/cleanups This also contains the NLA_POLICY_NESTED{,_ARRAY} change we discussed, which affects everyone but there's no other user yet. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAlxUKdwACgkQB8qZga/f l8TVaA/+Mw4gwHqAb4oQPfimZi4Zvaefu1lA6xRFEpubMUuo9ntR+qbRQWEt4D5B XOyY0xoqqeewxelGdXZ/XvF9vFxK1m9SgP5A5RSswbWETDLV/AIL3x9OdhcBLYMn ONm79SgMC0pyP+UePvgtZqNSQpf/3T1jeTBZAADyE3jf42iYhvtpyRFKwJi1mvNT wGN6mWz4FD4m3uFQem6bVRFPPfv06f29fK7JcY9iTkP7H8Glt0NK9mrt2OVPqZM4 g7BDg/epOlKuvFgv5Z1uttNWfEWikZt6fWbyusA7T4UBO7jf7mQKotSczQ1D0awQ wWFfLcX8esVmiioMwyyJus1sxxxX3GIcbIfgfd3wM4kq4LfqICuT8NSssziPD5OH A1gJMQsVk/bT2uACDA2IoX1m4Sf1hvgdKiyihyMQdcAlJuRBh8Bbbthd2Jzlo+nM mHNT2lW2WR+0WslSl+uEk9NCtnOVZKdmSM5dJCmFgc/sycg7+AtksQNBT5p8C7SR TsqArDDRHXsySZYFVCDziaJsU/SIp3RQ/5K3owzs7TtCkVOlOJVRlG7/4twa4AdH qw3VPspXmPj6N+LDbBfmz5g2YAVQXktTTkrfYtwN5lAD9qfLpCRwO3T+BaVgVASZ 8GCd0uIuIo8DI61QFf8lLbB5K90FHoSNNfG0yDeB7oBYF+S5v94= =9ese -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2019-02-01' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== New features for the wifi stack: * airtime fairness scheduling in mac80211, so we can share * more authentication offloads to userspace - this is for SAE which is part of WPA3 and is hard to do in firmware * documentation fixes * various mesh improvements * various other small improvements/cleanups This also contains the NLA_POLICY_NESTED{,_ARRAY} change we discussed, which affects everyone but there's no other user yet. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
962c382d48
@ -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
|
||||
|
||||
|
@ -14,11 +14,6 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static struct wiphy *common_wiphy;
|
||||
|
||||
struct virt_wifi_wiphy_priv {
|
||||
@ -429,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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1003,6 +1016,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 +1046,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 +1315,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 +1367,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 +1377,8 @@ struct station_info {
|
||||
s8 ack_signal;
|
||||
s8 avg_ack_signal;
|
||||
|
||||
u16 airtime_weight;
|
||||
|
||||
u32 rx_mpdu_count;
|
||||
u32 fcs_err_count;
|
||||
};
|
||||
@ -1422,6 +1442,8 @@ 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
|
||||
* @MPATH_INFO_PATH_CHANGE: @path_change_count filled
|
||||
*/
|
||||
enum mpath_info_flags {
|
||||
MPATH_INFO_FRAME_QLEN = BIT(0),
|
||||
@ -1431,6 +1453,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_PATH_CHANGE = BIT(8),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1450,6 +1474,8 @@ 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
|
||||
* @path_change_count: total number of path changes to destination
|
||||
*/
|
||||
struct mpath_info {
|
||||
u32 filled;
|
||||
@ -1460,6 +1486,8 @@ struct mpath_info {
|
||||
u32 discovery_timeout;
|
||||
u8 discovery_retries;
|
||||
u8 flags;
|
||||
u8 hop_count;
|
||||
u32 path_change_count;
|
||||
|
||||
int generation;
|
||||
};
|
||||
@ -2391,6 +2419,8 @@ enum wiphy_params_flags {
|
||||
WIPHY_PARAM_TXQ_QUANTUM = 1 << 8,
|
||||
};
|
||||
|
||||
#define IEEE80211_DEFAULT_AIRTIME_WEIGHT 256
|
||||
|
||||
/**
|
||||
* struct cfg80211_pmksa - PMK Security Association
|
||||
*
|
||||
@ -2815,6 +2845,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;
|
||||
@ -2822,6 +2853,7 @@ struct cfg80211_external_auth_params {
|
||||
struct cfg80211_ssid ssid;
|
||||
unsigned int key_mgmt_suite;
|
||||
u16 status;
|
||||
const u8 *pmkid;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -4112,6 +4144,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);
|
||||
@ -4310,6 +4344,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;
|
||||
@ -4573,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
|
||||
@ -4672,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;
|
||||
@ -5568,7 +5617,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
|
||||
|
@ -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
|
||||
@ -936,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.
|
||||
@ -1157,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
|
||||
@ -1164,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)
|
||||
@ -1214,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
|
||||
@ -2184,6 +2216,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 {
|
||||
@ -2232,6 +2267,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
|
||||
@ -2323,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,
|
||||
@ -2354,6 +2392,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_multiplier: Driver specific airtime weight multiplier used while
|
||||
* refilling deficit of each TXQ.
|
||||
*/
|
||||
struct ieee80211_hw {
|
||||
struct ieee80211_conf conf;
|
||||
@ -2390,6 +2431,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,
|
||||
@ -5401,6 +5443,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()
|
||||
@ -6103,7 +6173,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 +6189,94 @@ 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_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
|
||||
*
|
||||
* 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
|
||||
*
|
||||
|
@ -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) \
|
||||
|
@ -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.
|
||||
@ -2260,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.
|
||||
@ -2299,6 +2305,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 +2757,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 +3136,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 +3182,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,
|
||||
@ -3277,8 +3293,10 @@ 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_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 {
|
||||
@ -3290,6 +3308,8 @@ enum nl80211_mpath_info {
|
||||
NL80211_MPATH_INFO_FLAGS,
|
||||
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,
|
||||
@ -5316,6 +5336,13 @@ 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@ -5355,6 +5382,8 @@ 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,
|
||||
NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
@ -5606,9 +5635,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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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:
|
||||
@ -1447,6 +1452,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)) {
|
||||
@ -1746,7 +1754,9 @@ 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 |
|
||||
MPATH_INFO_PATH_CHANGE;
|
||||
|
||||
pinfo->frame_qlen = mpath->frame_queue.qlen;
|
||||
pinfo->sn = mpath->sn;
|
||||
@ -1766,6 +1776,8 @@ 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;
|
||||
pinfo->path_change_count = mpath->path_change_count;
|
||||
}
|
||||
|
||||
static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
@ -383,6 +384,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! */
|
||||
|
@ -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<<IEEE80211_TXQ_STOP) ? "STOP" : "RUN",
|
||||
txqi->flags & (1<<IEEE80211_TXQ_AMPDU) ? " AMPDU" : "",
|
||||
txqi->flags & (1<<IEEE80211_TXQ_NO_AMSDU) ? " NO-AMSDU" : "");
|
||||
test_bit(IEEE80211_TXQ_STOP, &txqi->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,
|
||||
|
@ -1173,6 +1173,13 @@ 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)
|
||||
{
|
||||
ieee80211_schedule_txq(&local->hw, &txqi->txq);
|
||||
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)
|
||||
|
@ -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) {
|
||||
|
@ -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,13 @@ 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];
|
||||
|
||||
u16 airtime_flags;
|
||||
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/*
|
||||
|
@ -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 = {
|
||||
@ -663,6 +665,12 @@ 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]);
|
||||
}
|
||||
local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
|
||||
|
||||
INIT_LIST_HEAD(&local->chanctx_list);
|
||||
mutex_init(&local->chanctx_mtx);
|
||||
|
||||
@ -1148,6 +1156,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",
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
@ -386,6 +389,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 +408,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 +420,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();
|
||||
@ -441,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;
|
||||
}
|
||||
@ -476,12 +485,15 @@ 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;
|
||||
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);
|
||||
@ -506,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);
|
||||
@ -519,10 +533,13 @@ 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)
|
||||
? 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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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++)
|
||||
@ -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);
|
||||
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
@ -343,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
|
||||
@ -366,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;
|
||||
@ -394,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)
|
||||
@ -459,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
|
||||
@ -480,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 */
|
||||
@ -565,6 +600,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.
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
@ -1487,8 +1488,14 @@ 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]);
|
||||
}
|
||||
|
||||
void ieee80211_txq_set_params(struct ieee80211_local *local)
|
||||
@ -1605,7 +1612,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 +3637,151 @@ 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]);
|
||||
|
||||
begin:
|
||||
txqi = list_first_entry_or_null(&local->active_txqs[ac],
|
||||
struct txq_info,
|
||||
schedule_order);
|
||||
if (!txqi)
|
||||
return NULL;
|
||||
|
||||
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);
|
||||
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)) {
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -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,8 @@ 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),
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@ -2278,6 +2274,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;
|
||||
@ -4540,6 +4545,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) {
|
||||
@ -4851,6 +4859,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 +5483,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 +5620,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;
|
||||
@ -5803,7 +5834,13 @@ 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)) ||
|
||||
((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);
|
||||
@ -9857,7 +9894,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) {
|
||||
@ -13047,7 +13087,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])
|
||||
@ -13058,18 +13100,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);
|
||||
}
|
||||
|
||||
|
@ -2729,9 +2729,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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user