mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-25 10:59:05 +00:00
This round's updates:
* finally some of the promised HE code, but it turns out to be small - but everything kept changing, so one part I did in the driver was >30 patches for what was ultimately <200 lines of code ... similar here for this code. * improved scan privacy support - can now specify scan flags for randomizing the sequence number as well as reducing the probe request element content * rfkill cleanups * a timekeeping cleanup from Arnd * various other cleanups -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAls2HpsACgkQB8qZga/f l8RPuQ//aZbTXc/GkYh0/GAmF4ORHePOHTXTZbMEzPeHQSlUE0nTSieyVtamsyy+ P+0Ik/lck15Oq/8qabUqDfDY37Fm/OD88jxmoVhjDdgTUcTbIm71n1yS9vDLytuL n0Awq2d8xuR2bRkwGgt3Bg0RsCbvqUTa/irrighPiKGqwdVGf7kqGi76hsLrMkx9 MQsVh1tRJCEvqEfs3yojhPna4AFjl9OoKFh0JjKJmKv5MWY5x4ojYG3kvvnAq2uF TIqko4l+R6AR+IzgBsPfzjj8YSJT67Z9IGe8YzId3OcMubpaJqKwrIq0+sYD/9AO /FGlK7V/NNge4E7sRPwu+dFzf9tOQAtKE06Icxy7aFknhdv5yGnuT2XaIUt2fv6b 1jMWMPxY8azBL3H2siDJ17ouRoIJbkw+3o41m3ZCneLebMWjIX/s2Azqiz2lUiU2 RjZ9Zr0qXdSghK5yD6/iInUBdmNBNq5ubQ8OIAy7fL7linvBAO23iP/G4E7zBikw 9DtHvrpRx2yA4oYTZiaP0FIEmN/nhVuY7VLdjfLlLBtU9cs9kxOydOVSVB9MeJfE c+HiIApuykDxUj5mrd2mo7AkINjUVXKrVZLOH8hqlNvbjJRmcfyR/TOUJzdfeLX+ 0jmji7TMZaaooUEm+KllCnIyUxSmlS25/Ekfm2gdx/rMXXzi/Oo= =sNaA -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2018-06-29' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Small merge conflict in net/mac80211/scan.c, I preserved the kcalloc() conversion. -DaveM Johannes Berg says: ==================== This round's updates: * finally some of the promised HE code, but it turns out to be small - but everything kept changing, so one part I did in the driver was >30 patches for what was ultimately <200 lines of code ... similar here for this code. * improved scan privacy support - can now specify scan flags for randomizing the sequence number as well as reducing the probe request element content * rfkill cleanups * a timekeeping cleanup from Arnd * various other cleanups ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
8365da2c05
@ -11,7 +11,7 @@ KernelVersion: v2.6.22
|
||||
Contact: linux-wireless@vger.kernel.org,
|
||||
Description: The rfkill class subsystem folder.
|
||||
Each registered rfkill driver is represented by an rfkillX
|
||||
subfolder (X being an integer > 0).
|
||||
subfolder (X being an integer >= 0).
|
||||
|
||||
|
||||
What: /sys/class/rfkill/rfkill[0-9]+/name
|
||||
@ -48,8 +48,8 @@ Contact: linux-wireless@vger.kernel.org
|
||||
Description: Current state of the transmitter.
|
||||
This file was scheduled to be removed in 2014, but due to its
|
||||
large number of users it will be sticking around for a bit
|
||||
longer. Despite it being marked as stabe, the newer "hard" and
|
||||
"soft" interfaces should be preffered, since it is not possible
|
||||
longer. Despite it being marked as stable, the newer "hard" and
|
||||
"soft" interfaces should be preferred, since it is not possible
|
||||
to express the 'soft and hard block' state of the rfkill driver
|
||||
through this interface. There will likely be another attempt to
|
||||
remove it in the future.
|
||||
|
@ -9,7 +9,7 @@ rfkill - RF kill switch support
|
||||
Introduction
|
||||
============
|
||||
|
||||
The rfkill subsystem provides a generic interface to disabling any radio
|
||||
The rfkill subsystem provides a generic interface for disabling any radio
|
||||
transmitter in the system. When a transmitter is blocked, it shall not
|
||||
radiate any power.
|
||||
|
||||
@ -45,7 +45,7 @@ The rfkill subsystem is composed of three main components:
|
||||
* the rfkill drivers.
|
||||
|
||||
The rfkill core provides API for kernel drivers to register their radio
|
||||
transmitter with the kernel, methods for turning it on and off and, letting
|
||||
transmitter with the kernel, methods for turning it on and off, and letting
|
||||
the system know about hardware-disabled states that may be implemented on
|
||||
the device.
|
||||
|
||||
@ -54,7 +54,7 @@ ways for userspace to query the current states. See the "Userspace support"
|
||||
section below.
|
||||
|
||||
When the device is hard-blocked (either by a call to rfkill_set_hw_state()
|
||||
or from query_hw_block) set_block() will be invoked for additional software
|
||||
or from query_hw_block), set_block() will be invoked for additional software
|
||||
block, but drivers can ignore the method call since they can use the return
|
||||
value of the function rfkill_set_hw_state() to sync the software state
|
||||
instead of keeping track of calls to set_block(). In fact, drivers should
|
||||
@ -65,7 +65,6 @@ keeps track of soft and hard block separately.
|
||||
Kernel API
|
||||
==========
|
||||
|
||||
|
||||
Drivers for radio transmitters normally implement an rfkill driver.
|
||||
|
||||
Platform drivers might implement input devices if the rfkill button is just
|
||||
@ -75,14 +74,14 @@ a way to turn on/off the transmitter(s).
|
||||
|
||||
For some platforms, it is possible that the hardware state changes during
|
||||
suspend/hibernation, in which case it will be necessary to update the rfkill
|
||||
core with the current state is at resume time.
|
||||
core with the current state at resume time.
|
||||
|
||||
To create an rfkill driver, driver's Kconfig needs to have::
|
||||
|
||||
depends on RFKILL || !RFKILL
|
||||
|
||||
to ensure the driver cannot be built-in when rfkill is modular. The !RFKILL
|
||||
case allows the driver to be built when rfkill is not configured, which
|
||||
case allows the driver to be built when rfkill is not configured, in which
|
||||
case all rfkill API can still be used but will be provided by static inlines
|
||||
which compile to almost nothing.
|
||||
|
||||
@ -91,7 +90,7 @@ rfkill drivers that control devices that can be hard-blocked unless they also
|
||||
assign the poll_hw_block() callback (then the rfkill core will poll the
|
||||
device). Don't do this unless you cannot get the event in any other way.
|
||||
|
||||
RFKill provides per-switch LED triggers, which can be used to drive LEDs
|
||||
rfkill provides per-switch LED triggers, which can be used to drive LEDs
|
||||
according to the switch state (LED_FULL when blocked, LED_OFF otherwise).
|
||||
|
||||
|
||||
@ -114,7 +113,7 @@ a specified type) into a state which also updates the default state for
|
||||
hotplugged devices.
|
||||
|
||||
After an application opens /dev/rfkill, it can read the current state of all
|
||||
devices. Changes can be either obtained by either polling the descriptor for
|
||||
devices. Changes can be obtained by either polling the descriptor for
|
||||
hotplug or state change events or by listening for uevents emitted by the
|
||||
rfkill core framework.
|
||||
|
||||
@ -127,8 +126,7 @@ environment variables set::
|
||||
RFKILL_STATE
|
||||
RFKILL_TYPE
|
||||
|
||||
The contents of these variables corresponds to the "name", "state" and
|
||||
The content of these variables corresponds to the "name", "state" and
|
||||
"type" sysfs files explained above.
|
||||
|
||||
|
||||
For further details consult Documentation/ABI/stable/sysfs-class-rfkill.
|
||||
|
@ -12156,6 +12156,8 @@ S: Maintained
|
||||
F: Documentation/rfkill.txt
|
||||
F: Documentation/ABI/stable/sysfs-class-rfkill
|
||||
F: net/rfkill/
|
||||
F: include/linux/rfkill.h
|
||||
F: include/uapi/linux/rfkill.h
|
||||
|
||||
RHASHTABLE
|
||||
M: Thomas Graf <tgraf@suug.ch>
|
||||
|
@ -1904,7 +1904,7 @@ void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv)
|
||||
reject_agg, ctrl_agg_size, agg_size);
|
||||
|
||||
rtlpriv->hw->max_rx_aggregation_subframes =
|
||||
(ctrl_agg_size ? agg_size : IEEE80211_MAX_AMPDU_BUF);
|
||||
(ctrl_agg_size ? agg_size : IEEE80211_MAX_AMPDU_BUF_HT);
|
||||
}
|
||||
EXPORT_SYMBOL(rtl_rx_ampdu_apply);
|
||||
|
||||
|
@ -575,7 +575,6 @@ enum ht_cap_ampdu_factor {
|
||||
* According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
|
||||
*/
|
||||
#define IEEE80211_MIN_AMPDU_BUF 0x8
|
||||
#define IEEE80211_MAX_AMPDU_BUF 0x40
|
||||
|
||||
|
||||
#define OP_MODE_PURE 0
|
||||
|
@ -574,7 +574,6 @@ struct ieee80211_ht_addt_info {
|
||||
* According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
|
||||
*/
|
||||
#define IEEE80211_MIN_AMPDU_BUF 0x8
|
||||
#define IEEE80211_MAX_AMPDU_BUF 0x40
|
||||
|
||||
|
||||
/* Spatial Multiplexing Power Save Modes */
|
||||
|
@ -799,7 +799,6 @@ enum HT_CAP_AMPDU_FACTOR {
|
||||
* According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
|
||||
*/
|
||||
#define IEEE80211_MIN_AMPDU_BUF 0x8
|
||||
#define IEEE80211_MAX_AMPDU_BUF 0x40
|
||||
|
||||
|
||||
/* Spatial Multiplexing Power Save Modes */
|
||||
|
@ -1838,7 +1838,7 @@ void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv)
|
||||
reject_agg, ctrl_agg_size, agg_size);
|
||||
|
||||
rtlpriv->hw->max_rx_aggregation_subframes =
|
||||
(ctrl_agg_size ? agg_size : IEEE80211_MAX_AMPDU_BUF);
|
||||
(ctrl_agg_size ? agg_size : IEEE80211_MAX_AMPDU_BUF_HT);
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
|
@ -1433,11 +1433,13 @@ struct ieee80211_ht_operation {
|
||||
#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
|
||||
|
||||
/*
|
||||
* A-PMDU buffer sizes
|
||||
* According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
|
||||
* A-MPDU buffer sizes
|
||||
* According to HT size varies from 8 to 64 frames
|
||||
* HE adds the ability to have up to 256 frames.
|
||||
*/
|
||||
#define IEEE80211_MIN_AMPDU_BUF 0x8
|
||||
#define IEEE80211_MAX_AMPDU_BUF 0x40
|
||||
#define IEEE80211_MIN_AMPDU_BUF 0x8
|
||||
#define IEEE80211_MAX_AMPDU_BUF_HT 0x40
|
||||
#define IEEE80211_MAX_AMPDU_BUF 0x100
|
||||
|
||||
|
||||
/* Spatial Multiplexing Power Save Modes (for capability) */
|
||||
@ -1539,6 +1541,106 @@ struct ieee80211_vht_operation {
|
||||
__le16 basic_mcs_set;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ieee80211_he_cap_elem - HE capabilities element
|
||||
*
|
||||
* This structure is the "HE capabilities element" fixed fields as
|
||||
* described in P802.11ax_D2.0 section 9.4.2.237.2 and 9.4.2.237.3
|
||||
*/
|
||||
struct ieee80211_he_cap_elem {
|
||||
u8 mac_cap_info[5];
|
||||
u8 phy_cap_info[9];
|
||||
} __packed;
|
||||
|
||||
#define IEEE80211_TX_RX_MCS_NSS_DESC_MAX_LEN 5
|
||||
|
||||
/**
|
||||
* enum ieee80211_he_mcs_support - HE MCS support definitions
|
||||
* @IEEE80211_HE_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the
|
||||
* number of streams
|
||||
* @IEEE80211_HE_MCS_SUPPORT_0_9: MCSes 0-9 are supported
|
||||
* @IEEE80211_HE_MCS_SUPPORT_0_11: MCSes 0-11 are supported
|
||||
* @IEEE80211_HE_MCS_NOT_SUPPORTED: This number of streams isn't supported
|
||||
*
|
||||
* These definitions are used in each 2-bit subfield of the rx_mcs_*
|
||||
* and tx_mcs_* fields of &struct ieee80211_he_mcs_nss_supp, which are
|
||||
* both split into 8 subfields by number of streams. These values indicate
|
||||
* which MCSes are supported for the number of streams the value appears
|
||||
* for.
|
||||
*/
|
||||
enum ieee80211_he_mcs_support {
|
||||
IEEE80211_HE_MCS_SUPPORT_0_7 = 0,
|
||||
IEEE80211_HE_MCS_SUPPORT_0_9 = 1,
|
||||
IEEE80211_HE_MCS_SUPPORT_0_11 = 2,
|
||||
IEEE80211_HE_MCS_NOT_SUPPORTED = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_he_mcs_nss_supp - HE Tx/Rx HE MCS NSS Support Field
|
||||
*
|
||||
* This structure holds the data required for the Tx/Rx HE MCS NSS Support Field
|
||||
* described in P802.11ax_D2.0 section 9.4.2.237.4
|
||||
*
|
||||
* @rx_mcs_80: Rx MCS map 2 bits for each stream, total 8 streams, for channel
|
||||
* widths less than 80MHz.
|
||||
* @tx_mcs_80: Tx MCS map 2 bits for each stream, total 8 streams, for channel
|
||||
* widths less than 80MHz.
|
||||
* @rx_mcs_160: Rx MCS map 2 bits for each stream, total 8 streams, for channel
|
||||
* width 160MHz.
|
||||
* @tx_mcs_160: Tx MCS map 2 bits for each stream, total 8 streams, for channel
|
||||
* width 160MHz.
|
||||
* @rx_mcs_80p80: Rx MCS map 2 bits for each stream, total 8 streams, for
|
||||
* channel width 80p80MHz.
|
||||
* @tx_mcs_80p80: Tx MCS map 2 bits for each stream, total 8 streams, for
|
||||
* channel width 80p80MHz.
|
||||
*/
|
||||
struct ieee80211_he_mcs_nss_supp {
|
||||
__le16 rx_mcs_80;
|
||||
__le16 tx_mcs_80;
|
||||
__le16 rx_mcs_160;
|
||||
__le16 tx_mcs_160;
|
||||
__le16 rx_mcs_80p80;
|
||||
__le16 tx_mcs_80p80;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ieee80211_he_operation - HE capabilities element
|
||||
*
|
||||
* This structure is the "HE operation element" fields as
|
||||
* described in P802.11ax_D2.0 section 9.4.2.238
|
||||
*/
|
||||
struct ieee80211_he_operation {
|
||||
__le32 he_oper_params;
|
||||
__le16 he_mcs_nss_set;
|
||||
/* Optional 0,1,3 or 4 bytes: depends on @he_oper_params */
|
||||
u8 optional[0];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field
|
||||
*
|
||||
* This structure is the "MU AC Parameter Record" fields as
|
||||
* described in P802.11ax_D2.0 section 9.4.2.240
|
||||
*/
|
||||
struct ieee80211_he_mu_edca_param_ac_rec {
|
||||
u8 aifsn;
|
||||
u8 ecw_min_max;
|
||||
u8 mu_edca_timer;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element
|
||||
*
|
||||
* This structure is the "MU EDCA Parameter Set element" fields as
|
||||
* described in P802.11ax_D2.0 section 9.4.2.240
|
||||
*/
|
||||
struct ieee80211_mu_edca_param_set {
|
||||
u8 mu_qos_info;
|
||||
struct ieee80211_he_mu_edca_param_ac_rec ac_be;
|
||||
struct ieee80211_he_mu_edca_param_ac_rec ac_bk;
|
||||
struct ieee80211_he_mu_edca_param_ac_rec ac_vi;
|
||||
struct ieee80211_he_mu_edca_param_ac_rec ac_vo;
|
||||
} __packed;
|
||||
|
||||
/* 802.11ac VHT Capabilities */
|
||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
|
||||
@ -1577,6 +1679,328 @@ struct ieee80211_vht_operation {
|
||||
#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000
|
||||
#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000
|
||||
|
||||
/* 802.11ax HE MAC capabilities */
|
||||
#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01
|
||||
#define IEEE80211_HE_MAC_CAP0_TWT_REQ 0x02
|
||||
#define IEEE80211_HE_MAC_CAP0_TWT_RES 0x04
|
||||
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_NOT_SUPP 0x00
|
||||
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_1 0x08
|
||||
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_2 0x10
|
||||
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_LEVEL_3 0x18
|
||||
#define IEEE80211_HE_MAC_CAP0_DYNAMIC_FRAG_MASK 0x18
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_1 0x00
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_2 0x20
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_4 0x40
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_8 0x60
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_16 0x80
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_32 0xa0
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_64 0xc0
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_UNLIMITED 0xe0
|
||||
#define IEEE80211_HE_MAC_CAP0_MAX_NUM_FRAG_MSDU_MASK 0xe0
|
||||
|
||||
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_UNLIMITED 0x00
|
||||
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_128 0x01
|
||||
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_256 0x02
|
||||
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_512 0x03
|
||||
#define IEEE80211_HE_MAC_CAP1_MIN_FRAG_SIZE_MASK 0x03
|
||||
#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US 0x00
|
||||
#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_8US 0x04
|
||||
#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US 0x08
|
||||
#define IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK 0x0c
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_1 0x00
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_2 0x10
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_3 0x20
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_4 0x30
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_5 0x40
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_6 0x50
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_7 0x60
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8 0x70
|
||||
#define IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_MASK 0x70
|
||||
|
||||
/* Link adaptation is split between byte HE_MAC_CAP1 and
|
||||
* HE_MAC_CAP2. It should be set only if IEEE80211_HE_MAC_CAP0_HTC_HE
|
||||
* in which case the following values apply:
|
||||
* 0 = No feedback.
|
||||
* 1 = reserved.
|
||||
* 2 = Unsolicited feedback.
|
||||
* 3 = both
|
||||
*/
|
||||
#define IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION 0x80
|
||||
|
||||
#define IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION 0x01
|
||||
#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02
|
||||
#define IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED 0x04
|
||||
#define IEEE80211_HE_MAC_CAP2_BSR 0x08
|
||||
#define IEEE80211_HE_MAC_CAP2_BCAST_TWT 0x10
|
||||
#define IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP 0x20
|
||||
#define IEEE80211_HE_MAC_CAP2_MU_CASCADING 0x40
|
||||
#define IEEE80211_HE_MAC_CAP2_ACK_EN 0x80
|
||||
|
||||
#define IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU 0x01
|
||||
#define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x02
|
||||
#define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x04
|
||||
|
||||
/* The maximum length of an A-MDPU is defined by the combination of the Maximum
|
||||
* A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and the
|
||||
* same field in the HE capabilities.
|
||||
*/
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_USE_VHT 0x00
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_1 0x08
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2 0x10
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_RESERVED 0x18
|
||||
#define IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK 0x18
|
||||
#define IEEE80211_HE_MAC_CAP3_A_AMSDU_FRAG 0x20
|
||||
#define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40
|
||||
#define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80
|
||||
|
||||
#define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01
|
||||
#define IEEE80211_HE_MAC_CAP4_QTP 0x02
|
||||
#define IEEE80211_HE_MAC_CAP4_BQR 0x04
|
||||
#define IEEE80211_HE_MAC_CAP4_SR_RESP 0x08
|
||||
#define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10
|
||||
#define IEEE80211_HE_MAC_CAP4_OPS 0x20
|
||||
#define IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU 0x40
|
||||
|
||||
/* 802.11ax HE PHY capabilities */
|
||||
#define IEEE80211_HE_PHY_CAP0_DUAL_BAND 0x01
|
||||
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02
|
||||
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04
|
||||
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 0x08
|
||||
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G 0x10
|
||||
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G 0x20
|
||||
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G 0x40
|
||||
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK 0xfe
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_20MHZ 0x01
|
||||
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_80MHZ_ONLY_SECOND_40MHZ 0x02
|
||||
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_20MHZ 0x04
|
||||
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_160MHZ_ONLY_SECOND_40MHZ 0x08
|
||||
#define IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK 0x0f
|
||||
#define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A 0x10
|
||||
#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20
|
||||
#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40
|
||||
/* Midamble RX Max NSTS is split between byte #2 and byte #3 */
|
||||
#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS 0x80
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS 0x01
|
||||
#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02
|
||||
#define IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ 0x04
|
||||
#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08
|
||||
#define IEEE80211_HE_PHY_CAP2_DOPPLER_TX 0x10
|
||||
#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20
|
||||
|
||||
/* Note that the meaning of UL MU below is different between an AP and a non-AP
|
||||
* sta, where in the AP case it indicates support for Rx and in the non-AP sta
|
||||
* case it indicates support for Tx.
|
||||
*/
|
||||
#define IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO 0x40
|
||||
#define IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO 0x80
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM 0x00
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK 0x01
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK 0x02
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM 0x03
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK 0x03
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 0x00
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2 0x04
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM 0x00
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK 0x08
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK 0x10
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK 0x18
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00
|
||||
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2 0x20
|
||||
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40
|
||||
#define IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER 0x80
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01
|
||||
#define IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER 0x02
|
||||
|
||||
/* Minimal allowed value of Max STS under 80MHz is 3 */
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 0x10
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_6 0x14
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_7 0x18
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8 0x1c
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK 0x1c
|
||||
|
||||
/* Minimal allowed value of Max STS above 80MHz is 3 */
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 0x60
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5 0x80
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_6 0xa0
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_7 0xc0
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 0xe0
|
||||
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK 0xe0
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_1 0x00
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 0x01
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_3 0x02
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_4 0x03
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_5 0x04
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_6 0x05
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_7 0x06
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_8 0x07
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK 0x07
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_1 0x00
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 0x08
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_3 0x10
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_4 0x18
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_5 0x20
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_6 0x28
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_7 0x30
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_8 0x38
|
||||
#define IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK 0x38
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40
|
||||
#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01
|
||||
#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02
|
||||
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04
|
||||
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08
|
||||
#define IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB 0x10
|
||||
#define IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE 0x20
|
||||
#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40
|
||||
#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP7_SRP_BASED_SR 0x01
|
||||
#define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR 0x02
|
||||
#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04
|
||||
#define IEEE80211_HE_PHY_CAP7_MAX_NC_1 0x08
|
||||
#define IEEE80211_HE_PHY_CAP7_MAX_NC_2 0x10
|
||||
#define IEEE80211_HE_PHY_CAP7_MAX_NC_3 0x18
|
||||
#define IEEE80211_HE_PHY_CAP7_MAX_NC_4 0x20
|
||||
#define IEEE80211_HE_PHY_CAP7_MAX_NC_5 0x28
|
||||
#define IEEE80211_HE_PHY_CAP7_MAX_NC_6 0x30
|
||||
#define IEEE80211_HE_PHY_CAP7_MAX_NC_7 0x38
|
||||
#define IEEE80211_HE_PHY_CAP7_MAX_NC_MASK 0x38
|
||||
#define IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ 0x40
|
||||
#define IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ 0x80
|
||||
|
||||
#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI 0x01
|
||||
#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02
|
||||
#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU 0x04
|
||||
#define IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU 0x08
|
||||
#define IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI 0x10
|
||||
#define IEEE80211_HE_PHY_CAP8_MIDAMBLE_RX_2X_AND_1XLTF 0x20
|
||||
|
||||
/* 802.11ax HE TX/RX MCS NSS Support */
|
||||
#define IEEE80211_TX_RX_MCS_NSS_SUPP_HIGHEST_MCS_POS (3)
|
||||
#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_POS (6)
|
||||
#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_POS (11)
|
||||
#define IEEE80211_TX_RX_MCS_NSS_SUPP_TX_BITMAP_MASK 0x07c0
|
||||
#define IEEE80211_TX_RX_MCS_NSS_SUPP_RX_BITMAP_MASK 0xf800
|
||||
|
||||
/* TX/RX HE MCS Support field Highest MCS subfield encoding */
|
||||
enum ieee80211_he_highest_mcs_supported_subfield_enc {
|
||||
HIGHEST_MCS_SUPPORTED_MCS7 = 0,
|
||||
HIGHEST_MCS_SUPPORTED_MCS8,
|
||||
HIGHEST_MCS_SUPPORTED_MCS9,
|
||||
HIGHEST_MCS_SUPPORTED_MCS10,
|
||||
HIGHEST_MCS_SUPPORTED_MCS11,
|
||||
};
|
||||
|
||||
/* Calculate 802.11ax HE capabilities IE Tx/Rx HE MCS NSS Support Field size */
|
||||
static inline u8
|
||||
ieee80211_he_mcs_nss_size(const struct ieee80211_he_cap_elem *he_cap)
|
||||
{
|
||||
u8 count = 4;
|
||||
|
||||
if (he_cap->phy_cap_info[0] &
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
|
||||
count += 4;
|
||||
|
||||
if (he_cap->phy_cap_info[0] &
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
|
||||
count += 4;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* 802.11ax HE PPE Thresholds */
|
||||
#define IEEE80211_PPE_THRES_NSS_SUPPORT_2NSS (1)
|
||||
#define IEEE80211_PPE_THRES_NSS_POS (0)
|
||||
#define IEEE80211_PPE_THRES_NSS_MASK (7)
|
||||
#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_2x966_AND_966_RU \
|
||||
(BIT(5) | BIT(6))
|
||||
#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK 0x78
|
||||
#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS (3)
|
||||
#define IEEE80211_PPE_THRES_INFO_PPET_SIZE (3)
|
||||
|
||||
/*
|
||||
* Calculate 802.11ax HE capabilities IE PPE field size
|
||||
* Input: Header byte of ppe_thres (first byte), and HE capa IE's PHY cap u8*
|
||||
*/
|
||||
static inline u8
|
||||
ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
|
||||
{
|
||||
u8 n;
|
||||
|
||||
if ((phy_cap_info[6] &
|
||||
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0)
|
||||
return 0;
|
||||
|
||||
n = hweight8(ppe_thres_hdr &
|
||||
IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
|
||||
n *= (1 + ((ppe_thres_hdr & IEEE80211_PPE_THRES_NSS_MASK) >>
|
||||
IEEE80211_PPE_THRES_NSS_POS));
|
||||
|
||||
/*
|
||||
* Each pair is 6 bits, and we need to add the 7 "header" bits to the
|
||||
* total size.
|
||||
*/
|
||||
n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7;
|
||||
n = DIV_ROUND_UP(n, 8);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* HE Operation defines */
|
||||
#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x0000003f
|
||||
#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK 0x000001c0
|
||||
#define IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET 6
|
||||
#define IEEE80211_HE_OPERATION_TWT_REQUIRED 0x00000200
|
||||
#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK 0x000ffc00
|
||||
#define IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET 10
|
||||
#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x000100000
|
||||
#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x000200000
|
||||
#define IEEE80211_HE_OPERATION_MULTI_BSSID_AP 0x10000000
|
||||
#define IEEE80211_HE_OPERATION_TX_BSSID_INDICATOR 0x20000000
|
||||
#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x40000000
|
||||
|
||||
/*
|
||||
* ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size
|
||||
* @he_oper_ie: byte data of the He Operations IE, stating from the the byte
|
||||
* after the ext ID byte. It is assumed that he_oper_ie has at least
|
||||
* sizeof(struct ieee80211_he_operation) bytes, checked already in
|
||||
* ieee802_11_parse_elems_crc()
|
||||
* @return the actual size of the IE data (not including header), or 0 on error
|
||||
*/
|
||||
static inline u8
|
||||
ieee80211_he_oper_size(const u8 *he_oper_ie)
|
||||
{
|
||||
struct ieee80211_he_operation *he_oper = (void *)he_oper_ie;
|
||||
u8 oper_len = sizeof(struct ieee80211_he_operation);
|
||||
u32 he_oper_params;
|
||||
|
||||
/* Make sure the input is not NULL */
|
||||
if (!he_oper_ie)
|
||||
return 0;
|
||||
|
||||
/* Calc required length */
|
||||
he_oper_params = le32_to_cpu(he_oper->he_oper_params);
|
||||
if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO)
|
||||
oper_len += 3;
|
||||
if (he_oper_params & IEEE80211_HE_OPERATION_MULTI_BSSID_AP)
|
||||
oper_len++;
|
||||
|
||||
/* Add the first byte (extension ID) to the total length */
|
||||
oper_len++;
|
||||
|
||||
return oper_len;
|
||||
}
|
||||
|
||||
/* Authentication algorithms */
|
||||
#define WLAN_AUTH_OPEN 0
|
||||
#define WLAN_AUTH_SHARED_KEY 1
|
||||
@ -1992,6 +2416,11 @@ enum ieee80211_eid_ext {
|
||||
WLAN_EID_EXT_FILS_WRAPPED_DATA = 8,
|
||||
WLAN_EID_EXT_FILS_PUBLIC_KEY = 12,
|
||||
WLAN_EID_EXT_FILS_NONCE = 13,
|
||||
WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14,
|
||||
WLAN_EID_EXT_HE_CAPABILITY = 35,
|
||||
WLAN_EID_EXT_HE_OPERATION = 36,
|
||||
WLAN_EID_EXT_UORA = 37,
|
||||
WLAN_EID_EXT_HE_MU_EDCA = 38,
|
||||
};
|
||||
|
||||
/* Action category code */
|
||||
|
@ -66,7 +66,7 @@ struct rfkill_ops {
|
||||
|
||||
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
||||
/**
|
||||
* rfkill_alloc - allocate rfkill structure
|
||||
* rfkill_alloc - Allocate rfkill structure
|
||||
* @name: name of the struct -- the string is not copied internally
|
||||
* @parent: device that has rf switch on it
|
||||
* @type: type of the switch (RFKILL_TYPE_*)
|
||||
@ -112,7 +112,7 @@ void rfkill_pause_polling(struct rfkill *rfkill);
|
||||
/**
|
||||
* rfkill_resume_polling(struct rfkill *rfkill)
|
||||
*
|
||||
* Pause polling -- say transmitter is off for other reasons.
|
||||
* Resume polling
|
||||
* NOTE: not necessary for suspend/resume -- in that case the
|
||||
* core stops polling anyway
|
||||
*/
|
||||
@ -130,7 +130,7 @@ void rfkill_resume_polling(struct rfkill *rfkill);
|
||||
void rfkill_unregister(struct rfkill *rfkill);
|
||||
|
||||
/**
|
||||
* rfkill_destroy - free rfkill structure
|
||||
* rfkill_destroy - Free rfkill structure
|
||||
* @rfkill: rfkill structure to be destroyed
|
||||
*
|
||||
* Destroys the rfkill structure.
|
||||
@ -140,7 +140,7 @@ void rfkill_destroy(struct rfkill *rfkill);
|
||||
/**
|
||||
* rfkill_set_hw_state - Set the internal rfkill hardware block state
|
||||
* @rfkill: pointer to the rfkill class to modify.
|
||||
* @state: the current hardware block state to set
|
||||
* @blocked: the current hardware block state to set
|
||||
*
|
||||
* rfkill drivers that get events when the hard-blocked state changes
|
||||
* use this function to notify the rfkill core (and through that also
|
||||
@ -161,7 +161,7 @@ bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
|
||||
/**
|
||||
* rfkill_set_sw_state - Set the internal rfkill software block state
|
||||
* @rfkill: pointer to the rfkill class to modify.
|
||||
* @state: the current software block state to set
|
||||
* @blocked: the current software block state to set
|
||||
*
|
||||
* rfkill drivers that get events when the soft-blocked state changes
|
||||
* (yes, some platforms directly act on input but allow changing again)
|
||||
@ -183,7 +183,7 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked);
|
||||
/**
|
||||
* rfkill_init_sw_state - Initialize persistent software block state
|
||||
* @rfkill: pointer to the rfkill class to modify.
|
||||
* @state: the current software block state to set
|
||||
* @blocked: the current software block state to set
|
||||
*
|
||||
* rfkill drivers that preserve their software block state over power off
|
||||
* use this function to notify the rfkill core (and through that also
|
||||
@ -208,17 +208,17 @@ void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked);
|
||||
void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw);
|
||||
|
||||
/**
|
||||
* rfkill_blocked - query rfkill block
|
||||
* rfkill_blocked - Query rfkill block state
|
||||
*
|
||||
* @rfkill: rfkill struct to query
|
||||
*/
|
||||
bool rfkill_blocked(struct rfkill *rfkill);
|
||||
|
||||
/**
|
||||
* rfkill_find_type - Helpper for finding rfkill type by name
|
||||
* rfkill_find_type - Helper for finding rfkill type by name
|
||||
* @name: the name of the type
|
||||
*
|
||||
* Returns enum rfkill_type that conrresponds the name.
|
||||
* Returns enum rfkill_type that corresponds to the name.
|
||||
*/
|
||||
enum rfkill_type rfkill_find_type(const char *name);
|
||||
|
||||
@ -296,7 +296,7 @@ static inline enum rfkill_type rfkill_find_type(const char *name)
|
||||
const char *rfkill_get_led_trigger_name(struct rfkill *rfkill);
|
||||
|
||||
/**
|
||||
* rfkill_set_led_trigger_name -- set the LED trigger name
|
||||
* rfkill_set_led_trigger_name - Set the LED trigger name
|
||||
* @rfkill: rfkill struct
|
||||
* @name: LED trigger name
|
||||
*
|
||||
|
@ -285,6 +285,41 @@ struct ieee80211_sta_vht_cap {
|
||||
struct ieee80211_vht_mcs_info vht_mcs;
|
||||
};
|
||||
|
||||
#define IEEE80211_HE_PPE_THRES_MAX_LEN 25
|
||||
|
||||
/**
|
||||
* struct ieee80211_sta_he_cap - STA's HE capabilities
|
||||
*
|
||||
* This structure describes most essential parameters needed
|
||||
* to describe 802.11ax HE capabilities for a STA.
|
||||
*
|
||||
* @has_he: true iff HE data is valid.
|
||||
* @he_cap_elem: Fixed portion of the HE capabilities element.
|
||||
* @he_mcs_nss_supp: The supported NSS/MCS combinations.
|
||||
* @ppe_thres: Holds the PPE Thresholds data.
|
||||
*/
|
||||
struct ieee80211_sta_he_cap {
|
||||
bool has_he;
|
||||
struct ieee80211_he_cap_elem he_cap_elem;
|
||||
struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp;
|
||||
u8 ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_sband_iftype_data
|
||||
*
|
||||
* This structure encapsulates sband data that is relevant for the
|
||||
* interface types defined in @types_mask. Each type in the
|
||||
* @types_mask must be unique across all instances of iftype_data.
|
||||
*
|
||||
* @types_mask: interface types mask
|
||||
* @he_cap: holds the HE capabilities
|
||||
*/
|
||||
struct ieee80211_sband_iftype_data {
|
||||
u16 types_mask;
|
||||
struct ieee80211_sta_he_cap he_cap;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_supported_band - frequency band definition
|
||||
*
|
||||
@ -301,6 +336,11 @@ struct ieee80211_sta_vht_cap {
|
||||
* @n_bitrates: Number of bitrates in @bitrates
|
||||
* @ht_cap: HT capabilities in this band
|
||||
* @vht_cap: VHT capabilities in this band
|
||||
* @n_iftype_data: number of iftype data entries
|
||||
* @iftype_data: interface type data entries. Note that the bits in
|
||||
* @types_mask inside this structure cannot overlap (i.e. only
|
||||
* one occurrence of each type is allowed across all instances of
|
||||
* iftype_data).
|
||||
*/
|
||||
struct ieee80211_supported_band {
|
||||
struct ieee80211_channel *channels;
|
||||
@ -310,8 +350,55 @@ struct ieee80211_supported_band {
|
||||
int n_bitrates;
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
struct ieee80211_sta_vht_cap vht_cap;
|
||||
u16 n_iftype_data;
|
||||
const struct ieee80211_sband_iftype_data *iftype_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* ieee80211_get_sband_iftype_data - return sband data for a given iftype
|
||||
* @sband: the sband to search for the STA on
|
||||
* @iftype: enum nl80211_iftype
|
||||
*
|
||||
* Return: pointer to struct ieee80211_sband_iftype_data, or NULL is none found
|
||||
*/
|
||||
static inline const struct ieee80211_sband_iftype_data *
|
||||
ieee80211_get_sband_iftype_data(const struct ieee80211_supported_band *sband,
|
||||
u8 iftype)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (WARN_ON(iftype >= NL80211_IFTYPE_MAX))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < sband->n_iftype_data; i++) {
|
||||
const struct ieee80211_sband_iftype_data *data =
|
||||
&sband->iftype_data[i];
|
||||
|
||||
if (data->types_mask & BIT(iftype))
|
||||
return data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_get_he_sta_cap - return HE capabilities for an sband's STA
|
||||
* @sband: the sband to search for the STA on
|
||||
*
|
||||
* Return: pointer to the struct ieee80211_sta_he_cap, or NULL is none found
|
||||
*/
|
||||
static inline const struct ieee80211_sta_he_cap *
|
||||
ieee80211_get_he_sta_cap(const struct ieee80211_supported_band *sband)
|
||||
{
|
||||
const struct ieee80211_sband_iftype_data *data =
|
||||
ieee80211_get_sband_iftype_data(sband, NL80211_IFTYPE_STATION);
|
||||
|
||||
if (data && data->he_cap.has_he)
|
||||
return &data->he_cap;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* wiphy_read_of_freq_limits - read frequency limits from device tree
|
||||
*
|
||||
@ -899,6 +986,8 @@ enum station_parameters_apply_mask {
|
||||
* @opmode_notif: operating mode field from Operating Mode Notification
|
||||
* @opmode_notif_used: information if operating mode field is used
|
||||
* @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
|
||||
*/
|
||||
struct station_parameters {
|
||||
const u8 *supported_rates;
|
||||
@ -926,6 +1015,8 @@ struct station_parameters {
|
||||
u8 opmode_notif;
|
||||
bool opmode_notif_used;
|
||||
int support_p2p_ps;
|
||||
const struct ieee80211_he_cap_elem *he_capa;
|
||||
u8 he_capa_len;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1000,12 +1091,14 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
|
||||
* @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
|
||||
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
|
||||
* @RATE_INFO_FLAGS_60G: 60GHz MCS
|
||||
* @RATE_INFO_FLAGS_HE_MCS: HE MCS information
|
||||
*/
|
||||
enum rate_info_flags {
|
||||
RATE_INFO_FLAGS_MCS = BIT(0),
|
||||
RATE_INFO_FLAGS_VHT_MCS = BIT(1),
|
||||
RATE_INFO_FLAGS_SHORT_GI = BIT(2),
|
||||
RATE_INFO_FLAGS_60G = BIT(3),
|
||||
RATE_INFO_FLAGS_HE_MCS = BIT(4),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1019,6 +1112,7 @@ enum rate_info_flags {
|
||||
* @RATE_INFO_BW_40: 40 MHz bandwidth
|
||||
* @RATE_INFO_BW_80: 80 MHz bandwidth
|
||||
* @RATE_INFO_BW_160: 160 MHz bandwidth
|
||||
* @RATE_INFO_BW_HE_RU: bandwidth determined by HE RU allocation
|
||||
*/
|
||||
enum rate_info_bw {
|
||||
RATE_INFO_BW_20 = 0,
|
||||
@ -1027,6 +1121,7 @@ enum rate_info_bw {
|
||||
RATE_INFO_BW_40,
|
||||
RATE_INFO_BW_80,
|
||||
RATE_INFO_BW_160,
|
||||
RATE_INFO_BW_HE_RU,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1035,10 +1130,14 @@ enum rate_info_bw {
|
||||
* Information about a receiving or transmitting bitrate
|
||||
*
|
||||
* @flags: bitflag of flags from &enum rate_info_flags
|
||||
* @mcs: mcs index if struct describes a 802.11n bitrate
|
||||
* @mcs: mcs index if struct describes an HT/VHT/HE rate
|
||||
* @legacy: bitrate in 100kbit/s for 802.11abg
|
||||
* @nss: number of streams (VHT only)
|
||||
* @nss: number of streams (VHT & HE only)
|
||||
* @bw: bandwidth (from &enum rate_info_bw)
|
||||
* @he_gi: HE guard interval (from &enum nl80211_he_gi)
|
||||
* @he_dcm: HE DCM value
|
||||
* @he_ru_alloc: HE RU allocation (from &enum nl80211_he_ru_alloc,
|
||||
* only valid if bw is %RATE_INFO_BW_HE_RU)
|
||||
*/
|
||||
struct rate_info {
|
||||
u8 flags;
|
||||
@ -1046,6 +1145,9 @@ struct rate_info {
|
||||
u16 legacy;
|
||||
u8 nss;
|
||||
u8 bw;
|
||||
u8 he_gi;
|
||||
u8 he_dcm;
|
||||
u8 he_ru_alloc;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Deutschland GmbH
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -72,6 +73,8 @@ enum ieee80211_radiotap_presence {
|
||||
IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
|
||||
IEEE80211_RADIOTAP_VHT = 21,
|
||||
IEEE80211_RADIOTAP_TIMESTAMP = 22,
|
||||
IEEE80211_RADIOTAP_HE = 23,
|
||||
IEEE80211_RADIOTAP_HE_MU = 24,
|
||||
|
||||
/* valid in every it_present bitmap, even vendor namespaces */
|
||||
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
|
||||
@ -202,6 +205,126 @@ enum ieee80211_radiotap_timestamp_flags {
|
||||
IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY = 0x02,
|
||||
};
|
||||
|
||||
struct ieee80211_radiotap_he {
|
||||
__le16 data1, data2, data3, data4, data5, data6;
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_he_bits {
|
||||
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MASK = 3,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_SU = 0,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_EXT_SU = 1,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MU = 2,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_TRIG = 3,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN = 0x0004,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN = 0x0008,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN = 0x0010,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN = 0x0020,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN = 0x0040,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN = 0x0080,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN = 0x0100,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN = 0x0200,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN = 0x0400,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN = 0x0800,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN = 0x1000,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN = 0x2000,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN = 0x4000,
|
||||
IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN = 0x8000,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN = 0x0001,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN = 0x0002,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN = 0x0004,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN = 0x0008,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN = 0x0010,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN = 0x0020,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN = 0x0040,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_MIDAMBLE_KNOWN = 0x0080,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET = 0x3f00,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN = 0x4000,
|
||||
IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC = 0x8000,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR = 0x003f,
|
||||
IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE = 0x0040,
|
||||
IEEE80211_RADIOTAP_HE_DATA3_UL_DL = 0x0080,
|
||||
IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS = 0x0f00,
|
||||
IEEE80211_RADIOTAP_HE_DATA3_DATA_DCM = 0x1000,
|
||||
IEEE80211_RADIOTAP_HE_DATA3_CODING = 0x2000,
|
||||
IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG = 0x4000,
|
||||
IEEE80211_RADIOTAP_HE_DATA3_STBC = 0x8000,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE = 0x000f,
|
||||
IEEE80211_RADIOTAP_HE_DATA4_MU_STA_ID = 0x7ff0,
|
||||
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1 = 0x000f,
|
||||
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2 = 0x00f0,
|
||||
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3 = 0x0f00,
|
||||
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4 = 0xf000,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC = 0x000f,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ = 0,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ = 1,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ = 2,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ = 3,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_26T = 4,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_52T = 5,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_106T = 6,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_242T = 7,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_484T = 8,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_996T = 9,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_2x996T = 10,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_DATA5_GI = 0x0030,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_GI_0_8 = 0,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_GI_1_6 = 1,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_GI_3_2 = 2,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE = 0x00c0,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN = 0,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X = 1,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X = 2,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X = 3,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS = 0x0700,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD = 0x3000,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_TXBF = 0x4000,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG = 0x8000,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_DATA6_NSTS = 0x000f,
|
||||
IEEE80211_RADIOTAP_HE_DATA6_DOPPLER = 0x0010,
|
||||
IEEE80211_RADIOTAP_HE_DATA6_TXOP = 0x7f00,
|
||||
IEEE80211_RADIOTAP_HE_DATA6_MIDAMBLE_PDCTY = 0x8000,
|
||||
};
|
||||
|
||||
struct ieee80211_radiotap_he_mu {
|
||||
__le16 flags1, flags2;
|
||||
u8 ru_ch1[4];
|
||||
u8 ru_ch2[4];
|
||||
};
|
||||
|
||||
enum ieee80211_radiotap_he_mu_bits {
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS = 0x000f,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN = 0x0010,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM = 0x0020,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN = 0x0040,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN = 0x0080,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN = 0x0100,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN = 0x0200,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN = 0x1000,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU = 0x2000,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN = 0x4000,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN = 0x8000,
|
||||
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW = 0x0003,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_20MHZ = 0x0000,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_40MHZ = 0x0001,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_80MHZ = 0x0002,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_160MHZ = 0x0003,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN = 0x0004,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP = 0x0008,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS = 0x00f0,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW = 0x0300,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN= 0x0400,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU = 0x0800,
|
||||
};
|
||||
|
||||
/**
|
||||
* ieee80211_get_radiotap_len - get radiotap header length
|
||||
*/
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/codel.h>
|
||||
#include <net/ieee80211_radiotap.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/**
|
||||
@ -162,6 +163,8 @@ enum ieee80211_ac_numbers {
|
||||
* @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
|
||||
* @acm: is mandatory admission control required for the access category
|
||||
* @uapsd: is U-APSD mode enabled for the queue
|
||||
* @mu_edca: is the MU EDCA configured
|
||||
* @mu_edca_param_rec: MU EDCA Parameter Record for HE
|
||||
*/
|
||||
struct ieee80211_tx_queue_params {
|
||||
u16 txop;
|
||||
@ -170,6 +173,8 @@ struct ieee80211_tx_queue_params {
|
||||
u8 aifs;
|
||||
bool acm;
|
||||
bool uapsd;
|
||||
bool mu_edca;
|
||||
struct ieee80211_he_mu_edca_param_ac_rec mu_edca_param_rec;
|
||||
};
|
||||
|
||||
struct ieee80211_low_level_stats {
|
||||
@ -463,6 +468,15 @@ struct ieee80211_mu_group_data {
|
||||
* This structure keeps information about a BSS (and an association
|
||||
* to that BSS) that can change during the lifetime of the BSS.
|
||||
*
|
||||
* @bss_color: 6-bit value to mark inter-BSS frame, if BSS supports HE
|
||||
* @htc_trig_based_pkt_ext: default PE in 4us units, if BSS supports HE
|
||||
* @multi_sta_back_32bit: supports BA bitmap of 32-bits in Multi-STA BACK
|
||||
* @uora_exists: is the UORA element advertised by AP
|
||||
* @ack_enabled: indicates support to receive a multi-TID that solicits either
|
||||
* ACK, BACK or both
|
||||
* @uora_ocw_range: UORA element's OCW Range field
|
||||
* @frame_time_rts_th: HE duration RTS threshold, in units of 32us
|
||||
* @he_support: does this BSS support HE
|
||||
* @assoc: association status
|
||||
* @ibss_joined: indicates whether this station is part of an IBSS
|
||||
* or not
|
||||
@ -550,6 +564,14 @@ struct ieee80211_mu_group_data {
|
||||
*/
|
||||
struct ieee80211_bss_conf {
|
||||
const u8 *bssid;
|
||||
u8 bss_color;
|
||||
u8 htc_trig_based_pkt_ext;
|
||||
bool multi_sta_back_32bit;
|
||||
bool uora_exists;
|
||||
bool ack_enabled;
|
||||
u8 uora_ocw_range;
|
||||
u16 frame_time_rts_th;
|
||||
bool he_support;
|
||||
/* association related data */
|
||||
bool assoc, ibss_joined;
|
||||
bool ibss_creator;
|
||||
@ -1106,6 +1128,18 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
||||
* @RX_FLAG_AMPDU_EOF_BIT: Value of the EOF bit in the A-MPDU delimiter for this
|
||||
* frame
|
||||
* @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
|
||||
* - DATA5_GI
|
||||
* - 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)
|
||||
*/
|
||||
enum mac80211_rx_flags {
|
||||
RX_FLAG_MMIC_ERROR = BIT(0),
|
||||
@ -1134,6 +1168,8 @@ enum mac80211_rx_flags {
|
||||
RX_FLAG_ICV_STRIPPED = BIT(23),
|
||||
RX_FLAG_AMPDU_EOF_BIT = BIT(24),
|
||||
RX_FLAG_AMPDU_EOF_BIT_KNOWN = BIT(25),
|
||||
RX_FLAG_RADIOTAP_HE = BIT(26),
|
||||
RX_FLAG_RADIOTAP_HE_MU = BIT(27),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1164,6 +1200,7 @@ enum mac80211_rx_encoding {
|
||||
RX_ENC_LEGACY = 0,
|
||||
RX_ENC_HT,
|
||||
RX_ENC_VHT,
|
||||
RX_ENC_HE,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1198,6 +1235,9 @@ enum mac80211_rx_encoding {
|
||||
* @encoding: &enum mac80211_rx_encoding
|
||||
* @bw: &enum rate_info_bw
|
||||
* @enc_flags: uses bits from &enum mac80211_rx_encoding_flags
|
||||
* @he_ru: HE RU, from &enum nl80211_he_ru_alloc
|
||||
* @he_gi: HE GI, from &enum nl80211_he_gi
|
||||
* @he_dcm: HE DCM value
|
||||
* @rx_flags: internal RX flags for mac80211
|
||||
* @ampdu_reference: A-MPDU reference number, must be a different value for
|
||||
* each A-MPDU but the same for each subframe within one A-MPDU
|
||||
@ -1211,7 +1251,8 @@ struct ieee80211_rx_status {
|
||||
u32 flag;
|
||||
u16 freq;
|
||||
u8 enc_flags;
|
||||
u8 encoding:2, bw:3;
|
||||
u8 encoding:2, bw:3, he_ru:3;
|
||||
u8 he_gi:2, he_dcm:1;
|
||||
u8 rate_idx;
|
||||
u8 nss;
|
||||
u8 rx_flags;
|
||||
@ -1770,6 +1811,7 @@ struct ieee80211_sta_rates {
|
||||
* @supp_rates: Bitmap of supported rates (per band)
|
||||
* @ht_cap: HT capabilities of this STA; restricted to our own capabilities
|
||||
* @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
|
||||
* @he_cap: HE capabilities of this STA
|
||||
* @max_rx_aggregation_subframes: maximal amount of frames in a single AMPDU
|
||||
* that this station is allowed to transmit to us.
|
||||
* Can be modified by driver.
|
||||
@ -1805,7 +1847,8 @@ struct ieee80211_sta {
|
||||
u16 aid;
|
||||
struct ieee80211_sta_ht_cap ht_cap;
|
||||
struct ieee80211_sta_vht_cap vht_cap;
|
||||
u8 max_rx_aggregation_subframes;
|
||||
struct ieee80211_sta_he_cap he_cap;
|
||||
u16 max_rx_aggregation_subframes;
|
||||
bool wme;
|
||||
u8 uapsd_queues;
|
||||
u8 max_sp;
|
||||
@ -2196,10 +2239,11 @@ enum ieee80211_hw_flags {
|
||||
* it shouldn't be set.
|
||||
*
|
||||
* @max_tx_aggregation_subframes: maximum number of subframes in an
|
||||
* aggregate an HT driver will transmit. Though ADDBA will advertise
|
||||
* a constant value of 64 as some older APs can crash if the window
|
||||
* size is smaller (an example is LinkSys WRT120N with FW v1.0.07
|
||||
* build 002 Jun 18 2012).
|
||||
* aggregate an HT/HE device will transmit. In HT AddBA we'll
|
||||
* advertise a constant value of 64 as some older APs crash if
|
||||
* the window size is smaller (an example is LinkSys WRT120N
|
||||
* with FW v1.0.07 build 002 Jun 18 2012).
|
||||
* For AddBA to HE capable peers this value will be used.
|
||||
*
|
||||
* @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum
|
||||
* of 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list.
|
||||
@ -2216,6 +2260,8 @@ enum ieee80211_hw_flags {
|
||||
* the default is _GI | _BANDWIDTH.
|
||||
* Use the %IEEE80211_RADIOTAP_VHT_KNOWN_\* values.
|
||||
*
|
||||
* @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
|
||||
@ -2263,8 +2309,8 @@ struct ieee80211_hw {
|
||||
u8 max_rates;
|
||||
u8 max_report_rates;
|
||||
u8 max_rate_tries;
|
||||
u8 max_rx_aggregation_subframes;
|
||||
u8 max_tx_aggregation_subframes;
|
||||
u16 max_rx_aggregation_subframes;
|
||||
u16 max_tx_aggregation_subframes;
|
||||
u8 max_tx_fragments;
|
||||
u8 offchannel_tx_hw_queue;
|
||||
u8 radiotap_mcs_details;
|
||||
@ -2904,7 +2950,7 @@ struct ieee80211_ampdu_params {
|
||||
struct ieee80211_sta *sta;
|
||||
u16 tid;
|
||||
u16 ssn;
|
||||
u8 buf_size;
|
||||
u16 buf_size;
|
||||
bool amsdu;
|
||||
u16 timeout;
|
||||
};
|
||||
|
@ -2237,6 +2237,9 @@ enum nl80211_commands {
|
||||
* enforced.
|
||||
* @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes
|
||||
* a flow is assigned on each round of the DRR scheduler.
|
||||
* @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from
|
||||
* association request when used with NL80211_CMD_NEW_STATION). Can be set
|
||||
* only if %NL80211_STA_FLAG_WME is set.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
@ -2677,6 +2680,8 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_TXQ_MEMORY_LIMIT,
|
||||
NL80211_ATTR_TXQ_QUANTUM,
|
||||
|
||||
NL80211_ATTR_HE_CAPABILITY,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@ -2726,7 +2731,8 @@ enum nl80211_attrs {
|
||||
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
|
||||
#define NL80211_HT_CAPABILITY_LEN 26
|
||||
#define NL80211_VHT_CAPABILITY_LEN 12
|
||||
|
||||
#define NL80211_HE_MIN_CAPABILITY_LEN 16
|
||||
#define NL80211_HE_MAX_CAPABILITY_LEN 51
|
||||
#define NL80211_MAX_NR_CIPHER_SUITES 5
|
||||
#define NL80211_MAX_NR_AKM_SUITES 2
|
||||
|
||||
@ -2853,6 +2859,38 @@ struct nl80211_sta_flag_update {
|
||||
__u32 set;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* enum nl80211_he_gi - HE guard interval
|
||||
* @NL80211_RATE_INFO_HE_GI_0_8: 0.8 usec
|
||||
* @NL80211_RATE_INFO_HE_GI_1_6: 1.6 usec
|
||||
* @NL80211_RATE_INFO_HE_GI_3_2: 3.2 usec
|
||||
*/
|
||||
enum nl80211_he_gi {
|
||||
NL80211_RATE_INFO_HE_GI_0_8,
|
||||
NL80211_RATE_INFO_HE_GI_1_6,
|
||||
NL80211_RATE_INFO_HE_GI_3_2,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_he_ru_alloc - HE RU allocation values
|
||||
* @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation
|
||||
* @NL80211_RATE_INFO_HE_RU_ALLOC_52: 52-tone RU allocation
|
||||
* @NL80211_RATE_INFO_HE_RU_ALLOC_106: 106-tone RU allocation
|
||||
* @NL80211_RATE_INFO_HE_RU_ALLOC_242: 242-tone RU allocation
|
||||
* @NL80211_RATE_INFO_HE_RU_ALLOC_484: 484-tone RU allocation
|
||||
* @NL80211_RATE_INFO_HE_RU_ALLOC_996: 996-tone RU allocation
|
||||
* @NL80211_RATE_INFO_HE_RU_ALLOC_2x996: 2x996-tone RU allocation
|
||||
*/
|
||||
enum nl80211_he_ru_alloc {
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_26,
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_52,
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_106,
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_242,
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_484,
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_996,
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_2x996,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_rate_info - bitrate information
|
||||
*
|
||||
@ -2885,6 +2923,13 @@ struct nl80211_sta_flag_update {
|
||||
* @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
|
||||
* a legacy rate and will be reported as the actual bitrate, i.e.
|
||||
* a quarter of the base (20 MHz) rate
|
||||
* @NL80211_RATE_INFO_HE_MCS: HE MCS index (u8, 0-11)
|
||||
* @NL80211_RATE_INFO_HE_NSS: HE NSS value (u8, 1-8)
|
||||
* @NL80211_RATE_INFO_HE_GI: HE guard interval identifier
|
||||
* (u8, see &enum nl80211_he_gi)
|
||||
* @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
|
||||
* @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
|
||||
* non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc)
|
||||
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
|
||||
*/
|
||||
enum nl80211_rate_info {
|
||||
@ -2901,6 +2946,11 @@ enum nl80211_rate_info {
|
||||
NL80211_RATE_INFO_160_MHZ_WIDTH,
|
||||
NL80211_RATE_INFO_10_MHZ_WIDTH,
|
||||
NL80211_RATE_INFO_5_MHZ_WIDTH,
|
||||
NL80211_RATE_INFO_HE_MCS,
|
||||
NL80211_RATE_INFO_HE_NSS,
|
||||
NL80211_RATE_INFO_HE_GI,
|
||||
NL80211_RATE_INFO_HE_DCM,
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_RATE_INFO_AFTER_LAST,
|
||||
@ -3166,6 +3216,38 @@ enum nl80211_mpath_info {
|
||||
NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_band_iftype_attr - Interface type data attributes
|
||||
*
|
||||
* @__NL80211_BAND_IFTYPE_ATTR_INVALID: attribute number 0 is reserved
|
||||
* @NL80211_BAND_IFTYPE_ATTR_IFTYPES: nested attribute containing a flag attribute
|
||||
* for each interface type that supports the band data
|
||||
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC: HE MAC capabilities as in HE
|
||||
* capabilities IE
|
||||
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: HE PHY capabilities as in HE
|
||||
* capabilities IE
|
||||
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: HE supported NSS/MCS as in HE
|
||||
* capabilities IE
|
||||
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as
|
||||
* defined in HE capabilities IE
|
||||
* @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
|
||||
* defined
|
||||
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
enum nl80211_band_iftype_attr {
|
||||
__NL80211_BAND_IFTYPE_ATTR_INVALID,
|
||||
|
||||
NL80211_BAND_IFTYPE_ATTR_IFTYPES,
|
||||
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
|
||||
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
|
||||
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
|
||||
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
|
||||
NL80211_BAND_IFTYPE_ATTR_MAX = __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_band_attr - band attributes
|
||||
* @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
|
||||
@ -3181,6 +3263,8 @@ enum nl80211_mpath_info {
|
||||
* @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as
|
||||
* defined in 802.11ac
|
||||
* @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
|
||||
* @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
|
||||
* attributes from &enum nl80211_band_iftype_attr
|
||||
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
|
||||
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -3196,6 +3280,7 @@ enum nl80211_band_attr {
|
||||
|
||||
NL80211_BAND_ATTR_VHT_MCS_SET,
|
||||
NL80211_BAND_ATTR_VHT_CAPA,
|
||||
NL80211_BAND_ATTR_IFTYPE_DATA,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_BAND_ATTR_AFTER_LAST,
|
||||
@ -5133,6 +5218,11 @@ enum nl80211_feature_flags {
|
||||
* support to nl80211.
|
||||
* @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate
|
||||
* TXQs.
|
||||
* @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the
|
||||
* SN in probe request frames if requested by %NL80211_SCAN_FLAG_RANDOM_SN.
|
||||
* @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data
|
||||
* except for supported rates from the probe request content if requested
|
||||
* by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
@ -5167,6 +5257,8 @@ enum nl80211_ext_feature_index {
|
||||
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
|
||||
NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT,
|
||||
NL80211_EXT_FEATURE_TXQS,
|
||||
NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
|
||||
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
@ -5272,6 +5364,12 @@ enum nl80211_timeout_reason {
|
||||
* possible scan results. This flag hints the driver to use the best
|
||||
* possible scan configuration to improve the accuracy in scanning.
|
||||
* Latency and power use may get impacted with this flag.
|
||||
* @NL80211_SCAN_FLAG_RANDOM_SN: randomize the sequence number in probe
|
||||
* request frames from this scan to avoid correlation/tracking being
|
||||
* possible.
|
||||
* @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to
|
||||
* only have supported rates and no additional capabilities (unless
|
||||
* added by userspace explicitly.)
|
||||
*/
|
||||
enum nl80211_scan_flags {
|
||||
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
|
||||
@ -5285,6 +5383,8 @@ enum nl80211_scan_flags {
|
||||
NL80211_SCAN_FLAG_LOW_SPAN = 1<<8,
|
||||
NL80211_SCAN_FLAG_LOW_POWER = 1<<9,
|
||||
NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10,
|
||||
NL80211_SCAN_FLAG_RANDOM_SN = 1<<11,
|
||||
NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -12,6 +12,7 @@ mac80211-y := \
|
||||
scan.o offchannel.o \
|
||||
ht.o agg-tx.o agg-rx.o \
|
||||
vht.o \
|
||||
he.o \
|
||||
ibss.o \
|
||||
iface.o \
|
||||
rate.o \
|
||||
|
@ -245,6 +245,7 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
};
|
||||
int i, ret = -EOPNOTSUPP;
|
||||
u16 status = WLAN_STATUS_REQUEST_DECLINED;
|
||||
u16 max_buf_size;
|
||||
|
||||
if (tid >= IEEE80211_FIRST_TSPEC_TSID) {
|
||||
ht_dbg(sta->sdata,
|
||||
@ -268,13 +269,18 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (sta->sta.he_cap.has_he)
|
||||
max_buf_size = IEEE80211_MAX_AMPDU_BUF;
|
||||
else
|
||||
max_buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
|
||||
|
||||
/* sanity check for incoming parameters:
|
||||
* check if configuration can support the BA policy
|
||||
* and if buffer size does not exceeds max value */
|
||||
/* XXX: check own ht delayed BA capability?? */
|
||||
if (((ba_policy != 1) &&
|
||||
(!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) ||
|
||||
(buf_size > IEEE80211_MAX_AMPDU_BUF)) {
|
||||
(buf_size > max_buf_size)) {
|
||||
status = WLAN_STATUS_INVALID_QOS_PARAM;
|
||||
ht_dbg_ratelimited(sta->sdata,
|
||||
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
|
||||
@ -283,7 +289,7 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
}
|
||||
/* determine default buffer size */
|
||||
if (buf_size == 0)
|
||||
buf_size = IEEE80211_MAX_AMPDU_BUF;
|
||||
buf_size = max_buf_size;
|
||||
|
||||
/* make sure the size doesn't exceed the maximum supported by the hw */
|
||||
if (buf_size > sta->sta.max_rx_aggregation_subframes)
|
||||
|
@ -463,6 +463,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||
.timeout = 0,
|
||||
};
|
||||
int ret;
|
||||
u16 buf_size;
|
||||
|
||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
|
||||
@ -511,11 +512,22 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||
sta->ampdu_mlme.addba_req_num[tid]++;
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
if (sta->sta.he_cap.has_he) {
|
||||
buf_size = local->hw.max_tx_aggregation_subframes;
|
||||
} else {
|
||||
/*
|
||||
* We really should use what the driver told us it will
|
||||
* transmit as the maximum, but certain APs (e.g. the
|
||||
* LinkSys WRT120N with FW v1.0.07 build 002 Jun 18 2012)
|
||||
* will crash when we use a lower number.
|
||||
*/
|
||||
buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
|
||||
}
|
||||
|
||||
/* send AddBA request */
|
||||
ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
|
||||
tid_tx->dialog_token, params.ssn,
|
||||
IEEE80211_MAX_AMPDU_BUF,
|
||||
tid_tx->timeout);
|
||||
buf_size, tid_tx->timeout);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -905,8 +917,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
||||
{
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
struct ieee80211_txq *txq;
|
||||
u16 capab, tid;
|
||||
u8 buf_size;
|
||||
u16 capab, tid, buf_size;
|
||||
bool amsdu;
|
||||
|
||||
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
|
||||
|
@ -1412,6 +1412,11 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
params->vht_capa, sta);
|
||||
|
||||
if (params->he_capa)
|
||||
ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
|
||||
(void *)params->he_capa,
|
||||
params->he_capa_len, sta);
|
||||
|
||||
if (params->opmode_notif_used) {
|
||||
/* returned value is only needed for rc update, but the
|
||||
* rc isn't initialized here yet, so ignore it
|
||||
@ -3486,7 +3491,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
|
||||
}
|
||||
|
||||
local_bh_disable();
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
ieee80211_xmit(sdata, sta, skb, 0);
|
||||
local_bh_enable();
|
||||
|
||||
ret = 0;
|
||||
|
@ -116,16 +116,16 @@ static void ieee80211_get_stats(struct net_device *dev,
|
||||
data[i++] = sta->sta_state;
|
||||
|
||||
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))
|
||||
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE))
|
||||
data[i] = 100000ULL *
|
||||
cfg80211_calculate_bitrate(&sinfo.txrate);
|
||||
i++;
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE))
|
||||
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE))
|
||||
data[i] = 100000ULL *
|
||||
cfg80211_calculate_bitrate(&sinfo.rxrate);
|
||||
i++;
|
||||
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))
|
||||
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG))
|
||||
data[i] = (u8)sinfo.signal_avg;
|
||||
i++;
|
||||
} else {
|
||||
|
55
net/mac80211/he.c
Normal file
55
net/mac80211/he.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* HE handling
|
||||
*
|
||||
* Copyright(c) 2017 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
|
||||
void
|
||||
ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_supported_band *sband,
|
||||
const u8 *he_cap_ie, u8 he_cap_len,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_sta_he_cap *he_cap = &sta->sta.he_cap;
|
||||
struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
|
||||
u8 he_ppe_size;
|
||||
u8 mcs_nss_size;
|
||||
u8 he_total_size;
|
||||
|
||||
memset(he_cap, 0, sizeof(*he_cap));
|
||||
|
||||
if (!he_cap_ie || !ieee80211_get_he_sta_cap(sband))
|
||||
return;
|
||||
|
||||
/* Make sure size is OK */
|
||||
mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap_ie_elem);
|
||||
he_ppe_size =
|
||||
ieee80211_he_ppe_size(he_cap_ie[sizeof(he_cap->he_cap_elem) +
|
||||
mcs_nss_size],
|
||||
he_cap_ie_elem->phy_cap_info);
|
||||
he_total_size = sizeof(he_cap->he_cap_elem) + mcs_nss_size +
|
||||
he_ppe_size;
|
||||
if (he_cap_len < he_total_size)
|
||||
return;
|
||||
|
||||
memcpy(&he_cap->he_cap_elem, he_cap_ie, sizeof(he_cap->he_cap_elem));
|
||||
|
||||
/* HE Tx/Rx HE MCS NSS Support Field */
|
||||
memcpy(&he_cap->he_mcs_nss_supp,
|
||||
&he_cap_ie[sizeof(he_cap->he_cap_elem)], mcs_nss_size);
|
||||
|
||||
/* Check if there are (optional) PPE Thresholds */
|
||||
if (he_cap->he_cap_elem.phy_cap_info[6] &
|
||||
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
|
||||
memcpy(he_cap->ppe_thres,
|
||||
&he_cap_ie[sizeof(he_cap->he_cap_elem) + mcs_nss_size],
|
||||
he_ppe_size);
|
||||
|
||||
he_cap->has_he = true;
|
||||
}
|
@ -352,7 +352,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
|
||||
test_and_clear_bit(tid,
|
||||
sta->ampdu_mlme.tid_rx_manage_offl))
|
||||
___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
|
||||
IEEE80211_MAX_AMPDU_BUF,
|
||||
IEEE80211_MAX_AMPDU_BUF_HT,
|
||||
false, true);
|
||||
|
||||
if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
|
||||
|
@ -165,6 +165,7 @@ typedef unsigned __bitwise ieee80211_tx_result;
|
||||
#define TX_DROP ((__force ieee80211_tx_result) 1u)
|
||||
#define TX_QUEUED ((__force ieee80211_tx_result) 2u)
|
||||
|
||||
#define IEEE80211_TX_NO_SEQNO BIT(0)
|
||||
#define IEEE80211_TX_UNICAST BIT(1)
|
||||
#define IEEE80211_TX_PS_BUFFERED BIT(2)
|
||||
|
||||
@ -364,6 +365,7 @@ enum ieee80211_sta_flags {
|
||||
IEEE80211_STA_DISABLE_160MHZ = BIT(13),
|
||||
IEEE80211_STA_DISABLE_WMM = BIT(14),
|
||||
IEEE80211_STA_ENABLE_RRM = BIT(15),
|
||||
IEEE80211_STA_DISABLE_HE = BIT(16),
|
||||
};
|
||||
|
||||
struct ieee80211_mgd_auth_data {
|
||||
@ -1453,6 +1455,10 @@ struct ieee802_11_elems {
|
||||
const struct ieee80211_vht_cap *vht_cap_elem;
|
||||
const struct ieee80211_vht_operation *vht_operation;
|
||||
const struct ieee80211_meshconf_ie *mesh_config;
|
||||
const u8 *he_cap;
|
||||
const struct ieee80211_he_operation *he_operation;
|
||||
const struct ieee80211_mu_edca_param_set *mu_edca_param_set;
|
||||
const u8 *uora_element;
|
||||
const u8 *mesh_id;
|
||||
const u8 *peering;
|
||||
const __le16 *awake_window;
|
||||
@ -1482,6 +1488,7 @@ struct ieee802_11_elems {
|
||||
u8 ext_supp_rates_len;
|
||||
u8 wmm_info_len;
|
||||
u8 wmm_param_len;
|
||||
u8 he_cap_len;
|
||||
u8 mesh_id_len;
|
||||
u8 peering_len;
|
||||
u8 preq_len;
|
||||
@ -1824,6 +1831,13 @@ void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
|
||||
enum nl80211_chan_width
|
||||
ieee80211_sta_rx_bw_to_chan_width(struct sta_info *sta);
|
||||
|
||||
/* HE */
|
||||
void
|
||||
ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_supported_band *sband,
|
||||
const u8 *he_cap_ie, u8 he_cap_len,
|
||||
struct sta_info *sta);
|
||||
|
||||
/* Spectrum management */
|
||||
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
@ -1880,19 +1894,20 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
|
||||
bool bss_notify, bool enable_qos);
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb);
|
||||
struct sta_info *sta, struct sk_buff *skb,
|
||||
u32 txdata_flags);
|
||||
|
||||
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid,
|
||||
enum nl80211_band band);
|
||||
enum nl80211_band band, u32 txdata_flags);
|
||||
|
||||
static inline void
|
||||
ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid,
|
||||
enum nl80211_band band)
|
||||
enum nl80211_band band, u32 txdata_flags)
|
||||
{
|
||||
rcu_read_lock();
|
||||
__ieee80211_tx_skb_tid_band(sdata, skb, tid, band);
|
||||
__ieee80211_tx_skb_tid_band(sdata, skb, tid, band, txdata_flags);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@ -1910,7 +1925,7 @@ static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
__ieee80211_tx_skb_tid_band(sdata, skb, tid,
|
||||
chanctx_conf->def.chan->band);
|
||||
chanctx_conf->def.chan->band, 0);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@ -2031,26 +2046,27 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
||||
void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *bssid, u16 stype, u16 reason,
|
||||
bool send_frame, u8 *frame_buf);
|
||||
|
||||
enum {
|
||||
IEEE80211_PROBE_FLAG_DIRECTED = BIT(0),
|
||||
IEEE80211_PROBE_FLAG_MIN_CONTENT = BIT(1),
|
||||
IEEE80211_PROBE_FLAG_RANDOM_SN = BIT(2),
|
||||
};
|
||||
|
||||
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
size_t buffer_len,
|
||||
struct ieee80211_scan_ies *ie_desc,
|
||||
const u8 *ie, size_t ie_len,
|
||||
u8 bands_used, u32 *rate_masks,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
struct cfg80211_chan_def *chandef,
|
||||
u32 flags);
|
||||
struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *src, const u8 *dst,
|
||||
u32 ratemask,
|
||||
struct ieee80211_channel *chan,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len,
|
||||
bool directed);
|
||||
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *src, const u8 *dst,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len,
|
||||
u32 ratemask, bool directed, u32 tx_flags,
|
||||
struct ieee80211_channel *channel, bool scan);
|
||||
|
||||
u32 flags);
|
||||
u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee802_11_elems *elems,
|
||||
enum nl80211_band band, u32 *basic_rates);
|
||||
@ -2073,6 +2089,9 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
u32 cap);
|
||||
u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
const struct cfg80211_chan_def *chandef);
|
||||
u8 *ieee80211_ie_build_he_cap(u8 *pos,
|
||||
const struct ieee80211_sta_he_cap *he_cap,
|
||||
u8 *end);
|
||||
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
|
||||
const struct ieee80211_supported_band *sband,
|
||||
const u8 *srates, int srates_len, u32 *rates);
|
||||
|
@ -3,6 +3,7 @@
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -557,10 +558,19 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
|
||||
wiphy_ext_feature_set(wiphy,
|
||||
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211);
|
||||
|
||||
if (!ops->hw_scan)
|
||||
if (!ops->hw_scan) {
|
||||
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
|
||||
NL80211_FEATURE_AP_SCAN;
|
||||
|
||||
/*
|
||||
* if the driver behaves correctly using the probe request
|
||||
* (template) from mac80211, then both of these should be
|
||||
* supported even with hw scan - but let drivers opt in.
|
||||
*/
|
||||
wiphy_ext_feature_set(wiphy,
|
||||
NL80211_EXT_FEATURE_SCAN_RANDOM_SN);
|
||||
wiphy_ext_feature_set(wiphy,
|
||||
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT);
|
||||
}
|
||||
|
||||
if (!ops->set_key)
|
||||
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
||||
@ -588,8 +598,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
|
||||
local->hw.queues = 1;
|
||||
local->hw.max_rates = 1;
|
||||
local->hw.max_report_rates = 0;
|
||||
local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
|
||||
local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
|
||||
local->hw.max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HT;
|
||||
local->hw.max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HT;
|
||||
local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE;
|
||||
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
|
||||
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
|
||||
@ -816,7 +826,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
int result, i;
|
||||
enum nl80211_band band;
|
||||
int channels, max_bitrates;
|
||||
bool supp_ht, supp_vht;
|
||||
bool supp_ht, supp_vht, supp_he;
|
||||
netdev_features_t feature_whitelist;
|
||||
struct cfg80211_chan_def dflt_chandef = {};
|
||||
|
||||
@ -896,6 +906,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
max_bitrates = 0;
|
||||
supp_ht = false;
|
||||
supp_vht = false;
|
||||
supp_he = false;
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
@ -922,6 +933,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
supp_ht = supp_ht || sband->ht_cap.ht_supported;
|
||||
supp_vht = supp_vht || sband->vht_cap.vht_supported;
|
||||
|
||||
if (!supp_he)
|
||||
supp_he = !!ieee80211_get_he_sta_cap(sband);
|
||||
|
||||
if (!sband->ht_cap.ht_supported)
|
||||
continue;
|
||||
|
||||
@ -1011,6 +1025,18 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
local->scan_ies_len +=
|
||||
2 + sizeof(struct ieee80211_vht_cap);
|
||||
|
||||
/* HE cap element is variable in size - set len to allow max size */
|
||||
/*
|
||||
* TODO: 1 is added at the end of the calculation to accommodate for
|
||||
* the temporary placing of the HE capabilities IE under EXT.
|
||||
* Remove it once it is placed in the final place.
|
||||
*/
|
||||
if (supp_he)
|
||||
local->scan_ies_len +=
|
||||
2 + sizeof(struct ieee80211_he_cap_elem) +
|
||||
sizeof(struct ieee80211_he_mcs_nss_supp) +
|
||||
IEEE80211_HE_PPE_THRES_MAX_LEN + 1;
|
||||
|
||||
if (!local->ops->hw_scan) {
|
||||
/* For hw_scan, driver needs to set these up. */
|
||||
local->hw.wiphy->max_scan_ssids = 4;
|
||||
|
@ -149,6 +149,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel *channel,
|
||||
const struct ieee80211_ht_operation *ht_oper,
|
||||
const struct ieee80211_vht_operation *vht_oper,
|
||||
const struct ieee80211_he_operation *he_oper,
|
||||
struct cfg80211_chan_def *chandef, bool tracking)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
@ -207,7 +208,27 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
vht_chandef = *chandef;
|
||||
if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && he_oper &&
|
||||
(le32_to_cpu(he_oper->he_oper_params) &
|
||||
IEEE80211_HE_OPERATION_VHT_OPER_INFO)) {
|
||||
struct ieee80211_vht_operation he_oper_vht_cap;
|
||||
|
||||
/*
|
||||
* Set only first 3 bytes (other 2 aren't used in
|
||||
* ieee80211_chandef_vht_oper() anyway)
|
||||
*/
|
||||
memcpy(&he_oper_vht_cap, he_oper->optional, 3);
|
||||
he_oper_vht_cap.basic_mcs_set = cpu_to_le16(0);
|
||||
|
||||
if (!ieee80211_chandef_vht_oper(&he_oper_vht_cap,
|
||||
&vht_chandef)) {
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
|
||||
sdata_info(sdata,
|
||||
"HE AP VHT information is invalid, disable HE\n");
|
||||
ret = IEEE80211_STA_DISABLE_HE;
|
||||
goto out;
|
||||
}
|
||||
} else if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
|
||||
sdata_info(sdata,
|
||||
"AP VHT information is invalid, disable VHT\n");
|
||||
@ -300,12 +321,14 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
|
||||
const struct ieee80211_ht_cap *ht_cap,
|
||||
const struct ieee80211_ht_operation *ht_oper,
|
||||
const struct ieee80211_vht_operation *vht_oper,
|
||||
const struct ieee80211_he_operation *he_oper,
|
||||
const u8 *bssid, u32 *changed)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *chan;
|
||||
struct ieee80211_channel *chan = sdata->vif.bss_conf.chandef.chan;
|
||||
struct ieee80211_supported_band *sband =
|
||||
local->hw.wiphy->bands[chan->band];
|
||||
struct cfg80211_chan_def chandef;
|
||||
u16 ht_opmode;
|
||||
u32 flags;
|
||||
@ -320,6 +343,11 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
|
||||
if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
|
||||
vht_oper = NULL;
|
||||
|
||||
/* don't check HE if we associated as non-HE station */
|
||||
if (ifmgd->flags & IEEE80211_STA_DISABLE_HE ||
|
||||
!ieee80211_get_he_sta_cap(sband))
|
||||
he_oper = NULL;
|
||||
|
||||
if (WARN_ON_ONCE(!sta))
|
||||
return -EINVAL;
|
||||
|
||||
@ -333,12 +361,9 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
|
||||
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
|
||||
}
|
||||
|
||||
chan = sdata->vif.bss_conf.chandef.chan;
|
||||
sband = local->hw.wiphy->bands[chan->band];
|
||||
|
||||
/* calculate new channel (type) based on HT/VHT operation IEs */
|
||||
/* calculate new channel (type) based on HT/VHT/HE operation IEs */
|
||||
flags = ieee80211_determine_chantype(sdata, sband, chan,
|
||||
ht_oper, vht_oper,
|
||||
ht_oper, vht_oper, he_oper,
|
||||
&chandef, true);
|
||||
|
||||
/*
|
||||
@ -582,6 +607,34 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
|
||||
}
|
||||
|
||||
/* This function determines HE capability flags for the association
|
||||
* and builds the IE.
|
||||
*/
|
||||
static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_supported_band *sband)
|
||||
{
|
||||
u8 *pos;
|
||||
const struct ieee80211_sta_he_cap *he_cap = NULL;
|
||||
u8 he_cap_size;
|
||||
|
||||
he_cap = ieee80211_get_he_sta_cap(sband);
|
||||
if (!he_cap)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: the 1 added is because this temporarily is under the EXTENSION
|
||||
* IE. Get rid of it when it moves.
|
||||
*/
|
||||
he_cap_size =
|
||||
2 + 1 + sizeof(he_cap->he_cap_elem) +
|
||||
ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) +
|
||||
ieee80211_he_ppe_size(he_cap->ppe_thres[0],
|
||||
he_cap->he_cap_elem.phy_cap_info);
|
||||
pos = skb_put(skb, he_cap_size);
|
||||
ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size);
|
||||
}
|
||||
|
||||
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
@ -643,6 +696,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
||||
2 + 2 * sband->n_channels + /* supported channels */
|
||||
2 + sizeof(struct ieee80211_ht_cap) + /* HT */
|
||||
2 + sizeof(struct ieee80211_vht_cap) + /* VHT */
|
||||
2 + 1 + sizeof(struct ieee80211_he_cap_elem) + /* HE */
|
||||
sizeof(struct ieee80211_he_mcs_nss_supp) +
|
||||
IEEE80211_HE_PPE_THRES_MAX_LEN +
|
||||
assoc_data->ie_len + /* extra IEs */
|
||||
(assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
|
||||
9, /* WMM */
|
||||
@ -827,11 +883,41 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
|
||||
offset = noffset;
|
||||
}
|
||||
|
||||
/* if present, add any custom IEs that go before HE */
|
||||
if (assoc_data->ie_len) {
|
||||
static const u8 before_he[] = {
|
||||
/*
|
||||
* no need to list the ones split off before VHT
|
||||
* or generated here
|
||||
*/
|
||||
WLAN_EID_OPMODE_NOTIF,
|
||||
WLAN_EID_EXTENSION, WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE,
|
||||
/* 11ai elements */
|
||||
WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_SESSION,
|
||||
WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_PUBLIC_KEY,
|
||||
WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_KEY_CONFIRM,
|
||||
WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_HLP_CONTAINER,
|
||||
WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN,
|
||||
/* TODO: add 11ah/11aj/11ak elements */
|
||||
};
|
||||
|
||||
/* RIC already taken above, so no need to handle here anymore */
|
||||
noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
|
||||
before_he, ARRAY_SIZE(before_he),
|
||||
offset);
|
||||
pos = skb_put(skb, noffset - offset);
|
||||
memcpy(pos, assoc_data->ie + offset, noffset - offset);
|
||||
offset = noffset;
|
||||
}
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
|
||||
ieee80211_add_vht_ie(sdata, skb, sband,
|
||||
&assoc_data->ap_vht_cap);
|
||||
|
||||
/* if present, add any custom non-vendor IEs that go after HT */
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
|
||||
ieee80211_add_he_ie(sdata, skb, sband);
|
||||
|
||||
/* if present, add any custom non-vendor IEs that go after HE */
|
||||
if (assoc_data->ie_len) {
|
||||
noffset = ieee80211_ie_split_vendor(assoc_data->ie,
|
||||
assoc_data->ie_len,
|
||||
@ -898,6 +984,11 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
|
||||
struct ieee80211_hdr_3addr *nullfunc;
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
/* Don't send NDPs when STA is connected HE */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
|
||||
return;
|
||||
|
||||
skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif,
|
||||
!ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP));
|
||||
if (!skb)
|
||||
@ -929,6 +1020,10 @@ static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
|
||||
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
|
||||
return;
|
||||
|
||||
/* Don't send NDPs when connected HE */
|
||||
if (!(sdata->u.mgd.flags & IEEE80211_STA_DISABLE_HE))
|
||||
return;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30);
|
||||
if (!skb)
|
||||
return;
|
||||
@ -1700,9 +1795,11 @@ static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
|
||||
}
|
||||
|
||||
/* MLME */
|
||||
static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *wmm_param, size_t wmm_param_len)
|
||||
static bool
|
||||
ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *wmm_param, size_t wmm_param_len,
|
||||
const struct ieee80211_mu_edca_param_set *mu_edca)
|
||||
{
|
||||
struct ieee80211_tx_queue_params params[IEEE80211_NUM_ACS];
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
@ -1749,6 +1846,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
|
||||
uapsd = true;
|
||||
params[ac].mu_edca = !!mu_edca;
|
||||
if (mu_edca)
|
||||
params[ac].mu_edca_param_rec = mu_edca->ac_bk;
|
||||
break;
|
||||
case 2: /* AC_VI */
|
||||
ac = IEEE80211_AC_VI;
|
||||
@ -1756,6 +1856,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
|
||||
uapsd = true;
|
||||
params[ac].mu_edca = !!mu_edca;
|
||||
if (mu_edca)
|
||||
params[ac].mu_edca_param_rec = mu_edca->ac_vi;
|
||||
break;
|
||||
case 3: /* AC_VO */
|
||||
ac = IEEE80211_AC_VO;
|
||||
@ -1763,6 +1866,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
||||
uapsd = true;
|
||||
params[ac].mu_edca = !!mu_edca;
|
||||
if (mu_edca)
|
||||
params[ac].mu_edca_param_rec = mu_edca->ac_vo;
|
||||
break;
|
||||
case 0: /* AC_BE */
|
||||
default:
|
||||
@ -1771,6 +1877,9 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
|
||||
if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
|
||||
uapsd = true;
|
||||
params[ac].mu_edca = !!mu_edca;
|
||||
if (mu_edca)
|
||||
params[ac].mu_edca_param_rec = mu_edca->ac_be;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2219,6 +2328,20 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_sta_reset_conn_monitor(sdata);
|
||||
}
|
||||
|
||||
static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *src, const u8 *dst,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
struct ieee80211_channel *channel)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = ieee80211_build_probe_req(sdata, src, dst, (u32)-1, channel,
|
||||
ssid, ssid_len, NULL, 0,
|
||||
IEEE80211_PROBE_FLAG_DIRECTED);
|
||||
if (skb)
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
@ -2265,10 +2388,9 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
|
||||
else
|
||||
ssid_len = ssid[1];
|
||||
|
||||
ieee80211_send_probe_req(sdata, sdata->vif.addr, dst,
|
||||
ssid + 2, ssid_len, NULL,
|
||||
0, (u32) -1, true, 0,
|
||||
ifmgd->associated->channel, false);
|
||||
ieee80211_mlme_send_probe_req(sdata, sdata->vif.addr, dst,
|
||||
ssid + 2, ssid_len,
|
||||
ifmgd->associated->channel);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@ -2370,7 +2492,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
|
||||
skb = ieee80211_build_probe_req(sdata, sdata->vif.addr, cbss->bssid,
|
||||
(u32) -1, cbss->channel,
|
||||
ssid + 2, ssid_len,
|
||||
NULL, 0, true);
|
||||
NULL, 0, IEEE80211_PROBE_FLAG_DIRECTED);
|
||||
rcu_read_unlock();
|
||||
|
||||
return skb;
|
||||
@ -3008,6 +3130,25 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If AP doesn't support HT, or it doesn't have HE mandatory IEs, mark
|
||||
* HE as disabled. If on the 5GHz band, make sure it supports VHT.
|
||||
*/
|
||||
if (ifmgd->flags & IEEE80211_STA_DISABLE_HT ||
|
||||
(sband->band == NL80211_BAND_5GHZ &&
|
||||
ifmgd->flags & IEEE80211_STA_DISABLE_VHT) ||
|
||||
(!elems.he_cap && !elems.he_operation))
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
|
||||
(!elems.he_cap || !elems.he_operation)) {
|
||||
mutex_unlock(&sdata->local->sta_mtx);
|
||||
sdata_info(sdata,
|
||||
"HE AP is missing HE capability/operation\n");
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set up internal HT/VHT capabilities */
|
||||
if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
|
||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||
@ -3017,6 +3158,48 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
elems.vht_cap_elem, sta);
|
||||
|
||||
if (elems.he_operation && !(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
|
||||
elems.he_cap) {
|
||||
ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
|
||||
elems.he_cap,
|
||||
elems.he_cap_len,
|
||||
sta);
|
||||
|
||||
bss_conf->he_support = sta->sta.he_cap.has_he;
|
||||
} else {
|
||||
bss_conf->he_support = false;
|
||||
}
|
||||
|
||||
if (bss_conf->he_support) {
|
||||
u32 he_oper_params =
|
||||
le32_to_cpu(elems.he_operation->he_oper_params);
|
||||
|
||||
bss_conf->bss_color = he_oper_params &
|
||||
IEEE80211_HE_OPERATION_BSS_COLOR_MASK;
|
||||
bss_conf->htc_trig_based_pkt_ext =
|
||||
(he_oper_params &
|
||||
IEEE80211_HE_OPERATION_DFLT_PE_DURATION_MASK) <<
|
||||
IEEE80211_HE_OPERATION_DFLT_PE_DURATION_OFFSET;
|
||||
bss_conf->frame_time_rts_th =
|
||||
(he_oper_params &
|
||||
IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK) <<
|
||||
IEEE80211_HE_OPERATION_RTS_THRESHOLD_OFFSET;
|
||||
|
||||
bss_conf->multi_sta_back_32bit =
|
||||
sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
|
||||
IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP;
|
||||
|
||||
bss_conf->ack_enabled =
|
||||
sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
|
||||
IEEE80211_HE_MAC_CAP2_ACK_EN;
|
||||
|
||||
bss_conf->uora_exists = !!elems.uora_element;
|
||||
if (elems.uora_element)
|
||||
bss_conf->uora_ocw_range = elems.uora_element[0];
|
||||
|
||||
/* TODO: OPEN: what happens if BSS color disable is set? */
|
||||
}
|
||||
|
||||
/*
|
||||
* Some APs, e.g. Netgear WNDR3700, report invalid HT operation data
|
||||
* in their association response, so ignore that data for our own
|
||||
@ -3076,7 +3259,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
||||
if (ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
|
||||
ieee80211_set_wmm_default(sdata, false, false);
|
||||
} else if (!ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
|
||||
elems.wmm_param_len)) {
|
||||
elems.wmm_param_len,
|
||||
elems.mu_edca_param_set)) {
|
||||
/* still enable QoS since we might have HT/VHT */
|
||||
ieee80211_set_wmm_default(sdata, false, true);
|
||||
/* set the disable-WMM flag in this case to disable
|
||||
@ -3590,7 +3774,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
|
||||
ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
|
||||
elems.wmm_param_len))
|
||||
elems.wmm_param_len,
|
||||
elems.mu_edca_param_set))
|
||||
changed |= BSS_CHANGED_QOS;
|
||||
|
||||
/*
|
||||
@ -3629,7 +3814,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (ieee80211_config_bw(sdata, sta,
|
||||
elems.ht_cap_elem, elems.ht_operation,
|
||||
elems.vht_operation, bssid, &changed)) {
|
||||
elems.vht_operation, elems.he_operation,
|
||||
bssid, &changed)) {
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
sdata_info(sdata,
|
||||
"failed to follow AP %pM bandwidth change, disconnect\n",
|
||||
@ -4266,6 +4452,68 @@ static u8 ieee80211_ht_vht_rx_chains(struct ieee80211_sub_if_data *sdata,
|
||||
return chains;
|
||||
}
|
||||
|
||||
static bool
|
||||
ieee80211_verify_sta_he_mcs_support(struct ieee80211_supported_band *sband,
|
||||
const struct ieee80211_he_operation *he_op)
|
||||
{
|
||||
const struct ieee80211_sta_he_cap *sta_he_cap =
|
||||
ieee80211_get_he_sta_cap(sband);
|
||||
u16 ap_min_req_set;
|
||||
int i;
|
||||
|
||||
if (!sta_he_cap || !he_op)
|
||||
return false;
|
||||
|
||||
ap_min_req_set = le16_to_cpu(he_op->he_mcs_nss_set);
|
||||
|
||||
/* Need to go over for 80MHz, 160MHz and for 80+80 */
|
||||
for (i = 0; i < 3; i++) {
|
||||
const struct ieee80211_he_mcs_nss_supp *sta_mcs_nss_supp =
|
||||
&sta_he_cap->he_mcs_nss_supp;
|
||||
u16 sta_mcs_map_rx =
|
||||
le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i]);
|
||||
u16 sta_mcs_map_tx =
|
||||
le16_to_cpu(((__le16 *)sta_mcs_nss_supp)[2 * i + 1]);
|
||||
u8 nss;
|
||||
bool verified = true;
|
||||
|
||||
/*
|
||||
* For each band there is a maximum of 8 spatial streams
|
||||
* possible. Each of the sta_mcs_map_* is a 16-bit struct built
|
||||
* of 2 bits per NSS (1-8), with the values defined in enum
|
||||
* ieee80211_he_mcs_support. Need to make sure STA TX and RX
|
||||
* capabilities aren't less than the AP's minimum requirements
|
||||
* for this HE BSS per SS.
|
||||
* It is enough to find one such band that meets the reqs.
|
||||
*/
|
||||
for (nss = 8; nss > 0; nss--) {
|
||||
u8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3;
|
||||
u8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3;
|
||||
u8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
|
||||
|
||||
if (ap_val == IEEE80211_HE_MCS_NOT_SUPPORTED)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Make sure the HE AP doesn't require MCSs that aren't
|
||||
* supported by the client
|
||||
*/
|
||||
if (sta_rx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
|
||||
sta_tx_val == IEEE80211_HE_MCS_NOT_SUPPORTED ||
|
||||
(ap_val > sta_rx_val) || (ap_val > sta_tx_val)) {
|
||||
verified = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (verified)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If here, STA doesn't meet AP's HE min requirements */
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_bss *cbss)
|
||||
{
|
||||
@ -4274,6 +4522,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
||||
const struct ieee80211_ht_cap *ht_cap = NULL;
|
||||
const struct ieee80211_ht_operation *ht_oper = NULL;
|
||||
const struct ieee80211_vht_operation *vht_oper = NULL;
|
||||
const struct ieee80211_he_operation *he_oper = NULL;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct cfg80211_chan_def chandef;
|
||||
int ret;
|
||||
@ -4329,6 +4578,24 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) &&
|
||||
ieee80211_get_he_sta_cap(sband)) {
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
const u8 *he_oper_ie;
|
||||
|
||||
ies = rcu_dereference(cbss->ies);
|
||||
he_oper_ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_OPERATION,
|
||||
ies->data, ies->len);
|
||||
if (he_oper_ie &&
|
||||
he_oper_ie[1] == ieee80211_he_oper_size(&he_oper_ie[3]))
|
||||
he_oper = (void *)(he_oper_ie + 3);
|
||||
else
|
||||
he_oper = NULL;
|
||||
|
||||
if (!ieee80211_verify_sta_he_mcs_support(sband, he_oper))
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
|
||||
}
|
||||
|
||||
/* Allow VHT if at least one channel on the sband supports 80 MHz */
|
||||
have_80mhz = false;
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
@ -4345,7 +4612,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
|
||||
cbss->channel,
|
||||
ht_oper, vht_oper,
|
||||
ht_oper, vht_oper, he_oper,
|
||||
&chandef, false);
|
||||
|
||||
sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
|
||||
@ -4751,8 +5018,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
|
||||
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
|
||||
netdev_info(sdata->dev,
|
||||
"disabling HT/VHT due to WEP/TKIP use\n");
|
||||
"disabling HE/HT/VHT due to WEP/TKIP use\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ static void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc,
|
||||
if (roc->mgmt_tx_cookie) {
|
||||
if (!WARN_ON(!roc->frame)) {
|
||||
ieee80211_tx_skb_tid_band(roc->sdata, roc->frame, 7,
|
||||
roc->chan->band);
|
||||
roc->chan->band, 0);
|
||||
roc->frame = NULL;
|
||||
}
|
||||
} else {
|
||||
|
@ -175,6 +175,20 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
|
||||
len += 12;
|
||||
}
|
||||
|
||||
if (status->encoding == RX_ENC_HE &&
|
||||
status->flag & RX_FLAG_RADIOTAP_HE) {
|
||||
len = ALIGN(len, 2);
|
||||
len += 12;
|
||||
BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) != 12);
|
||||
}
|
||||
|
||||
if (status->encoding == RX_ENC_HE &&
|
||||
status->flag & RX_FLAG_RADIOTAP_HE_MU) {
|
||||
len = ALIGN(len, 2);
|
||||
len += 12;
|
||||
BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) != 12);
|
||||
}
|
||||
|
||||
if (status->chains) {
|
||||
/* antenna and antenna signal fields */
|
||||
len += 2 * hweight8(status->chains);
|
||||
@ -263,6 +277,19 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
||||
int mpdulen, chain;
|
||||
unsigned long chains = status->chains;
|
||||
struct ieee80211_vendor_radiotap rtap = {};
|
||||
struct ieee80211_radiotap_he he = {};
|
||||
struct ieee80211_radiotap_he_mu he_mu = {};
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_HE) {
|
||||
he = *(struct ieee80211_radiotap_he *)skb->data;
|
||||
skb_pull(skb, sizeof(he));
|
||||
WARN_ON_ONCE(status->encoding != RX_ENC_HE);
|
||||
}
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_HE_MU) {
|
||||
he_mu = *(struct ieee80211_radiotap_he_mu *)skb->data;
|
||||
skb_pull(skb, sizeof(he_mu));
|
||||
}
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
|
||||
rtap = *(struct ieee80211_vendor_radiotap *)skb->data;
|
||||
@ -520,6 +547,89 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
||||
*pos++ = flags;
|
||||
}
|
||||
|
||||
if (status->encoding == RX_ENC_HE &&
|
||||
status->flag & RX_FLAG_RADIOTAP_HE) {
|
||||
#define HE_PREP(f, val) cpu_to_le16(FIELD_PREP(IEEE80211_RADIOTAP_HE_##f, val))
|
||||
|
||||
if (status->enc_flags & RX_ENC_FLAG_STBC_MASK) {
|
||||
he.data6 |= HE_PREP(DATA6_NSTS,
|
||||
FIELD_GET(RX_ENC_FLAG_STBC_MASK,
|
||||
status->enc_flags));
|
||||
he.data3 |= HE_PREP(DATA3_STBC, 1);
|
||||
} else {
|
||||
he.data6 |= HE_PREP(DATA6_NSTS, status->nss);
|
||||
}
|
||||
|
||||
#define CHECK_GI(s) \
|
||||
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \
|
||||
(int)NL80211_RATE_INFO_HE_GI_##s)
|
||||
|
||||
CHECK_GI(0_8);
|
||||
CHECK_GI(1_6);
|
||||
CHECK_GI(3_2);
|
||||
|
||||
he.data3 |= HE_PREP(DATA3_DATA_MCS, status->rate_idx);
|
||||
he.data3 |= HE_PREP(DATA3_DATA_DCM, status->he_dcm);
|
||||
he.data3 |= HE_PREP(DATA3_CODING,
|
||||
!!(status->enc_flags & RX_ENC_FLAG_LDPC));
|
||||
|
||||
he.data5 |= HE_PREP(DATA5_GI, status->he_gi);
|
||||
|
||||
switch (status->bw) {
|
||||
case RATE_INFO_BW_20:
|
||||
he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ);
|
||||
break;
|
||||
case RATE_INFO_BW_40:
|
||||
he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ);
|
||||
break;
|
||||
case RATE_INFO_BW_80:
|
||||
he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ);
|
||||
break;
|
||||
case RATE_INFO_BW_160:
|
||||
he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
|
||||
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ);
|
||||
break;
|
||||
case RATE_INFO_BW_HE_RU:
|
||||
#define CHECK_RU_ALLOC(s) \
|
||||
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4)
|
||||
|
||||
CHECK_RU_ALLOC(26);
|
||||
CHECK_RU_ALLOC(52);
|
||||
CHECK_RU_ALLOC(106);
|
||||
CHECK_RU_ALLOC(242);
|
||||
CHECK_RU_ALLOC(484);
|
||||
CHECK_RU_ALLOC(996);
|
||||
CHECK_RU_ALLOC(2x996);
|
||||
|
||||
he.data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
|
||||
status->he_ru + 4);
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Invalid SU BW %d\n", status->bw);
|
||||
}
|
||||
|
||||
/* ensure 2 byte alignment */
|
||||
while ((pos - (u8 *)rthdr) & 1)
|
||||
pos++;
|
||||
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE);
|
||||
memcpy(pos, &he, sizeof(he));
|
||||
pos += sizeof(he);
|
||||
}
|
||||
|
||||
if (status->encoding == RX_ENC_HE &&
|
||||
status->flag & RX_FLAG_RADIOTAP_HE_MU) {
|
||||
/* ensure 2 byte alignment */
|
||||
while ((pos - (u8 *)rthdr) & 1)
|
||||
pos++;
|
||||
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE_MU);
|
||||
memcpy(pos, &he_mu, sizeof(he_mu));
|
||||
pos += sizeof(he_mu);
|
||||
}
|
||||
|
||||
for_each_set_bit(chain, &chains, IEEE80211_MAX_CHAINS) {
|
||||
*pos++ = status->chain_signal[chain];
|
||||
*pos++ = chain;
|
||||
@ -613,6 +723,12 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
||||
rcu_dereference(local->monitor_sdata);
|
||||
bool only_monitor = false;
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_HE)
|
||||
rtap_space += sizeof(struct ieee80211_radiotap_he);
|
||||
|
||||
if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
|
||||
rtap_space += sizeof(struct ieee80211_radiotap_he_mu);
|
||||
|
||||
if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) {
|
||||
struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data;
|
||||
|
||||
@ -3241,7 +3357,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
|
||||
}
|
||||
|
||||
__ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7,
|
||||
status->band);
|
||||
status->band, 0);
|
||||
}
|
||||
dev_kfree_skb(rx->skb);
|
||||
return RX_QUEUED;
|
||||
@ -3386,8 +3502,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
|
||||
status = IEEE80211_SKB_RXCB((rx->skb));
|
||||
|
||||
sband = rx->local->hw.wiphy->bands[status->band];
|
||||
if (!(status->encoding == RX_ENC_HT) &&
|
||||
!(status->encoding == RX_ENC_VHT))
|
||||
if (status->encoding == RX_ENC_LEGACY)
|
||||
rate = &sband->bitrates[status->rate_idx];
|
||||
|
||||
ieee80211_rx_cooked_monitor(rx, rate);
|
||||
@ -4386,6 +4501,14 @@ void ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
|
||||
status->rate_idx, status->nss))
|
||||
goto drop;
|
||||
break;
|
||||
case RX_ENC_HE:
|
||||
if (WARN_ONCE(status->rate_idx > 11 ||
|
||||
!status->nss ||
|
||||
status->nss > 8,
|
||||
"Rate marked as an HE rate but data is invalid: MCS: %d, NSS: %d\n",
|
||||
status->rate_idx, status->nss))
|
||||
goto drop;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
/* fall through */
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <net/sch_generic.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
@ -293,6 +294,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
|
||||
struct cfg80211_chan_def chandef;
|
||||
u8 bands_used = 0;
|
||||
int i, ielen, n_chans;
|
||||
u32 flags = 0;
|
||||
|
||||
req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
@ -331,12 +333,16 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
|
||||
local->hw_scan_req->req.n_channels = n_chans;
|
||||
ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
|
||||
|
||||
if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
|
||||
flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
|
||||
|
||||
ielen = ieee80211_build_preq_ies(local,
|
||||
(u8 *)local->hw_scan_req->req.ie,
|
||||
local->hw_scan_ies_bufsize,
|
||||
&local->hw_scan_req->ies,
|
||||
req->ie, req->ie_len,
|
||||
bands_used, req->rates, &chandef);
|
||||
bands_used, req->rates, &chandef,
|
||||
flags);
|
||||
local->hw_scan_req->req.ie_len = ielen;
|
||||
local->hw_scan_req->req.no_cck = req->no_cck;
|
||||
ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr);
|
||||
@ -528,6 +534,35 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local)
|
||||
round_jiffies_relative(0));
|
||||
}
|
||||
|
||||
static void ieee80211_send_scan_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *src, const u8 *dst,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len,
|
||||
u32 ratemask, u32 flags, u32 tx_flags,
|
||||
struct ieee80211_channel *channel)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u32 txdata_flags = 0;
|
||||
|
||||
skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel,
|
||||
ssid, ssid_len,
|
||||
ie, ie_len, flags);
|
||||
|
||||
if (skb) {
|
||||
if (flags & IEEE80211_PROBE_FLAG_RANDOM_SN) {
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
u16 sn = get_random_u32();
|
||||
|
||||
txdata_flags |= IEEE80211_TX_NO_SEQNO;
|
||||
hdr->seq_ctrl =
|
||||
cpu_to_le16(IEEE80211_SN_TO_SEQ(sn));
|
||||
}
|
||||
IEEE80211_SKB_CB(skb)->flags |= tx_flags;
|
||||
ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band,
|
||||
txdata_flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
|
||||
unsigned long *next_delay)
|
||||
{
|
||||
@ -535,7 +570,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
enum nl80211_band band = local->hw.conf.chandef.chan->band;
|
||||
u32 tx_flags;
|
||||
u32 flags = 0, tx_flags;
|
||||
|
||||
scan_req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
@ -543,17 +578,21 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
|
||||
tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
|
||||
if (scan_req->no_cck)
|
||||
tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
|
||||
if (scan_req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
|
||||
flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
|
||||
if (scan_req->flags & NL80211_SCAN_FLAG_RANDOM_SN)
|
||||
flags |= IEEE80211_PROBE_FLAG_RANDOM_SN;
|
||||
|
||||
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
for (i = 0; i < scan_req->n_ssids; i++)
|
||||
ieee80211_send_probe_req(
|
||||
ieee80211_send_scan_probe_req(
|
||||
sdata, local->scan_addr, scan_req->bssid,
|
||||
scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len,
|
||||
scan_req->ie, scan_req->ie_len,
|
||||
scan_req->rates[band], false,
|
||||
tx_flags, local->hw.conf.chandef.chan, true);
|
||||
scan_req->rates[band], flags,
|
||||
tx_flags, local->hw.conf.chandef.chan);
|
||||
|
||||
/*
|
||||
* After sending probe requests, wait for probe responses
|
||||
@ -1141,6 +1180,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||
u32 rate_masks[NUM_NL80211_BANDS] = {};
|
||||
u8 bands_used = 0;
|
||||
u8 *ie;
|
||||
u32 flags = 0;
|
||||
|
||||
iebufsz = local->scan_ies_len + req->ie_len;
|
||||
|
||||
@ -1157,6 +1197,9 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
|
||||
if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
|
||||
flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
|
||||
|
||||
ie = kcalloc(iebufsz, num_bands, GFP_KERNEL);
|
||||
if (!ie) {
|
||||
ret = -ENOMEM;
|
||||
@ -1167,7 +1210,8 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
ieee80211_build_preq_ies(local, ie, num_bands * iebufsz,
|
||||
&sched_scan_ies, req->ie,
|
||||
req->ie_len, bands_used, rate_masks, &chandef);
|
||||
req->ie_len, bands_used, rate_masks, &chandef,
|
||||
flags);
|
||||
|
||||
ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
|
||||
if (ret == 0) {
|
||||
|
@ -1323,6 +1323,11 @@ static void ieee80211_send_null_response(struct sta_info *sta, int tid,
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
|
||||
/* Don't send NDPs when STA is connected HE */
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!(sdata->u.mgd.flags & IEEE80211_STA_DISABLE_HE))
|
||||
return;
|
||||
|
||||
if (qos) {
|
||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
|
||||
IEEE80211_STYPE_QOS_NULLFUNC |
|
||||
@ -1391,7 +1396,7 @@ static void ieee80211_send_null_response(struct sta_info *sta, int tid,
|
||||
}
|
||||
|
||||
info->band = chanctx_conf->def.chan->band;
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
ieee80211_xmit(sdata, sta, skb, 0);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@ -1968,7 +1973,7 @@ sta_get_last_rx_stats(struct sta_info *sta)
|
||||
return stats;
|
||||
}
|
||||
|
||||
static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
|
||||
static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate,
|
||||
struct rate_info *rinfo)
|
||||
{
|
||||
rinfo->bw = STA_STATS_GET(BW, rate);
|
||||
@ -2005,6 +2010,14 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
|
||||
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
|
||||
break;
|
||||
}
|
||||
case STA_STATS_RATE_TYPE_HE:
|
||||
rinfo->flags = RATE_INFO_FLAGS_HE_MCS;
|
||||
rinfo->mcs = STA_STATS_GET(HE_MCS, rate);
|
||||
rinfo->nss = STA_STATS_GET(HE_NSS, rate);
|
||||
rinfo->he_gi = STA_STATS_GET(HE_GI, rate);
|
||||
rinfo->he_ru_alloc = STA_STATS_GET(HE_RU, rate);
|
||||
rinfo->he_dcm = STA_STATS_GET(HE_DCM, rate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2101,38 +2114,38 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
|
||||
drv_sta_statistics(local, sdata, &sta->sta, sinfo);
|
||||
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME) |
|
||||
BIT(NL80211_STA_INFO_STA_FLAGS) |
|
||||
BIT(NL80211_STA_INFO_BSS_PARAM) |
|
||||
BIT(NL80211_STA_INFO_CONNECTED_TIME) |
|
||||
BIT(NL80211_STA_INFO_RX_DROP_MISC);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) |
|
||||
BIT_ULL(NL80211_STA_INFO_STA_FLAGS) |
|
||||
BIT_ULL(NL80211_STA_INFO_BSS_PARAM) |
|
||||
BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME) |
|
||||
BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
sinfo->beacon_loss_count = sdata->u.mgd.beacon_loss_count;
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_LOSS);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_LOSS);
|
||||
}
|
||||
|
||||
sinfo->connected_time = ktime_get_seconds() - sta->last_connected;
|
||||
sinfo->inactive_time =
|
||||
jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta));
|
||||
|
||||
if (!(sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES64) |
|
||||
BIT(NL80211_STA_INFO_TX_BYTES)))) {
|
||||
if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES64) |
|
||||
BIT_ULL(NL80211_STA_INFO_TX_BYTES)))) {
|
||||
sinfo->tx_bytes = 0;
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
sinfo->tx_bytes += sta->tx_stats.bytes[ac];
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_PACKETS))) {
|
||||
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_PACKETS))) {
|
||||
sinfo->tx_packets = 0;
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
sinfo->tx_packets += sta->tx_stats.packets[ac];
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
|
||||
BIT(NL80211_STA_INFO_RX_BYTES)))) {
|
||||
if (!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES64) |
|
||||
BIT_ULL(NL80211_STA_INFO_RX_BYTES)))) {
|
||||
sinfo->rx_bytes += sta_get_stats_bytes(&sta->rx_stats);
|
||||
|
||||
if (sta->pcpu_rx_stats) {
|
||||
@ -2144,10 +2157,10 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
}
|
||||
}
|
||||
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_PACKETS))) {
|
||||
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_PACKETS))) {
|
||||
sinfo->rx_packets = sta->rx_stats.packets;
|
||||
if (sta->pcpu_rx_stats) {
|
||||
for_each_possible_cpu(cpu) {
|
||||
@ -2157,17 +2170,17 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
sinfo->rx_packets += cpurxs->packets;
|
||||
}
|
||||
}
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_RETRIES))) {
|
||||
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_RETRIES))) {
|
||||
sinfo->tx_retries = sta->status_stats.retry_count;
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_TX_RETRIES);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_FAILED))) {
|
||||
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED))) {
|
||||
sinfo->tx_failed = sta->status_stats.retry_failed;
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
|
||||
}
|
||||
|
||||
sinfo->rx_dropped_misc = sta->rx_stats.dropped;
|
||||
@ -2182,23 +2195,23 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
|
||||
!(sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)) {
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_RX) |
|
||||
BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX) |
|
||||
BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
|
||||
sinfo->rx_beacon_signal_avg = ieee80211_ave_rssi(&sdata->vif);
|
||||
}
|
||||
|
||||
if (ieee80211_hw_check(&sta->local->hw, SIGNAL_DBM) ||
|
||||
ieee80211_hw_check(&sta->local->hw, SIGNAL_UNSPEC)) {
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL))) {
|
||||
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL))) {
|
||||
sinfo->signal = (s8)last_rxstats->last_signal;
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
|
||||
}
|
||||
|
||||
if (!sta->pcpu_rx_stats &&
|
||||
!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) {
|
||||
!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG))) {
|
||||
sinfo->signal_avg =
|
||||
-ewma_signal_read(&sta->rx_stats_avg.signal);
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2207,11 +2220,11 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
* pcpu statistics
|
||||
*/
|
||||
if (last_rxstats->chains &&
|
||||
!(sinfo->filled & (BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
|
||||
BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL);
|
||||
!(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL) |
|
||||
BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
|
||||
if (!sta->pcpu_rx_stats)
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
|
||||
|
||||
sinfo->chains = last_rxstats->chains;
|
||||
|
||||
@ -2223,15 +2236,15 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))) {
|
||||
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE))) {
|
||||
sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate,
|
||||
&sinfo->txrate);
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
|
||||
}
|
||||
|
||||
if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE))) {
|
||||
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE))) {
|
||||
if (sta_set_rate_info_rx(sta, &sinfo->rxrate) == 0)
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
|
||||
}
|
||||
|
||||
if (tidstats && !cfg80211_sinfo_alloc_tid_stats(sinfo, GFP_KERNEL)) {
|
||||
@ -2244,18 +2257,18 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_LLID) |
|
||||
BIT(NL80211_STA_INFO_PLID) |
|
||||
BIT(NL80211_STA_INFO_PLINK_STATE) |
|
||||
BIT(NL80211_STA_INFO_LOCAL_PM) |
|
||||
BIT(NL80211_STA_INFO_PEER_PM) |
|
||||
BIT(NL80211_STA_INFO_NONPEER_PM);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_LLID) |
|
||||
BIT_ULL(NL80211_STA_INFO_PLID) |
|
||||
BIT_ULL(NL80211_STA_INFO_PLINK_STATE) |
|
||||
BIT_ULL(NL80211_STA_INFO_LOCAL_PM) |
|
||||
BIT_ULL(NL80211_STA_INFO_PEER_PM) |
|
||||
BIT_ULL(NL80211_STA_INFO_NONPEER_PM);
|
||||
|
||||
sinfo->llid = sta->mesh->llid;
|
||||
sinfo->plid = sta->mesh->plid;
|
||||
sinfo->plink_state = sta->mesh->plink_state;
|
||||
if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_T_OFFSET);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_T_OFFSET);
|
||||
sinfo->t_offset = sta->mesh->t_offset;
|
||||
}
|
||||
sinfo->local_pm = sta->mesh->local_pm;
|
||||
@ -2300,7 +2313,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
|
||||
thr = sta_get_expected_throughput(sta);
|
||||
|
||||
if (thr != 0) {
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
|
||||
sinfo->expected_throughput = thr;
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ struct tid_ampdu_tx {
|
||||
u8 dialog_token;
|
||||
u8 stop_initiator;
|
||||
bool tx_stop;
|
||||
u8 buf_size;
|
||||
u16 buf_size;
|
||||
|
||||
u16 failed_bar_ssn;
|
||||
bool bar_pending;
|
||||
@ -405,7 +405,7 @@ struct ieee80211_sta_rx_stats {
|
||||
int last_signal;
|
||||
u8 chains;
|
||||
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
|
||||
u16 last_rate;
|
||||
u32 last_rate;
|
||||
struct u64_stats_sync syncp;
|
||||
u64 bytes;
|
||||
u64 msdu[IEEE80211_NUM_TIDS + 1];
|
||||
@ -764,6 +764,7 @@ enum sta_stats_type {
|
||||
STA_STATS_RATE_TYPE_LEGACY,
|
||||
STA_STATS_RATE_TYPE_HT,
|
||||
STA_STATS_RATE_TYPE_VHT,
|
||||
STA_STATS_RATE_TYPE_HE,
|
||||
};
|
||||
|
||||
#define STA_STATS_FIELD_HT_MCS GENMASK( 7, 0)
|
||||
@ -771,9 +772,14 @@ enum sta_stats_type {
|
||||
#define STA_STATS_FIELD_LEGACY_BAND GENMASK( 7, 4)
|
||||
#define STA_STATS_FIELD_VHT_MCS GENMASK( 3, 0)
|
||||
#define STA_STATS_FIELD_VHT_NSS GENMASK( 7, 4)
|
||||
#define STA_STATS_FIELD_HE_MCS GENMASK( 3, 0)
|
||||
#define STA_STATS_FIELD_HE_NSS GENMASK( 7, 4)
|
||||
#define STA_STATS_FIELD_BW GENMASK(11, 8)
|
||||
#define STA_STATS_FIELD_SGI GENMASK(12, 12)
|
||||
#define STA_STATS_FIELD_TYPE GENMASK(15, 13)
|
||||
#define STA_STATS_FIELD_HE_RU GENMASK(18, 16)
|
||||
#define STA_STATS_FIELD_HE_GI GENMASK(20, 19)
|
||||
#define STA_STATS_FIELD_HE_DCM GENMASK(21, 21)
|
||||
|
||||
#define STA_STATS_FIELD(_n, _v) FIELD_PREP(STA_STATS_FIELD_ ## _n, _v)
|
||||
#define STA_STATS_GET(_n, _v) FIELD_GET(STA_STATS_FIELD_ ## _n, _v)
|
||||
@ -782,7 +788,7 @@ enum sta_stats_type {
|
||||
|
||||
static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
|
||||
{
|
||||
u16 r;
|
||||
u32 r;
|
||||
|
||||
r = STA_STATS_FIELD(BW, s->bw);
|
||||
|
||||
@ -804,6 +810,14 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
|
||||
r |= STA_STATS_FIELD(LEGACY_BAND, s->band);
|
||||
r |= STA_STATS_FIELD(LEGACY_IDX, s->rate_idx);
|
||||
break;
|
||||
case RX_ENC_HE:
|
||||
r |= STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_HE);
|
||||
r |= STA_STATS_FIELD(HE_NSS, s->nss);
|
||||
r |= STA_STATS_FIELD(HE_MCS, s->rate_idx);
|
||||
r |= STA_STATS_FIELD(HE_GI, s->he_gi);
|
||||
r |= STA_STATS_FIELD(HE_RU, s->he_ru);
|
||||
r |= STA_STATS_FIELD(HE_DCM, s->he_dcm);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return STA_STATS_RATE_INVALID;
|
||||
|
@ -92,7 +92,7 @@
|
||||
STA_ENTRY \
|
||||
__field(u16, tid) \
|
||||
__field(u16, ssn) \
|
||||
__field(u8, buf_size) \
|
||||
__field(u16, buf_size) \
|
||||
__field(bool, amsdu) \
|
||||
__field(u16, timeout) \
|
||||
__field(u16, action)
|
||||
|
@ -825,6 +825,8 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
|
||||
*/
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
is_multicast_ether_addr(hdr->addr1)) {
|
||||
if (tx->flags & IEEE80211_TX_NO_SEQNO)
|
||||
return TX_CONTINUE;
|
||||
/* driver should assign sequence number */
|
||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||
/* for pure STA mode without beacons, we can do it */
|
||||
@ -1854,7 +1856,7 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
|
||||
*/
|
||||
static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb,
|
||||
bool txpending)
|
||||
bool txpending, u32 txdata_flags)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_data tx;
|
||||
@ -1872,6 +1874,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
||||
led_len = skb->len;
|
||||
res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
|
||||
|
||||
tx.flags |= txdata_flags;
|
||||
|
||||
if (unlikely(res_prepare == TX_DROP)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
return true;
|
||||
@ -1933,7 +1937,8 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb)
|
||||
struct sta_info *sta, struct sk_buff *skb,
|
||||
u32 txdata_flags)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
@ -1968,7 +1973,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
ieee80211_set_qos_hdr(sdata, skb);
|
||||
ieee80211_tx(sdata, sta, skb, false);
|
||||
ieee80211_tx(sdata, sta, skb, false, txdata_flags);
|
||||
}
|
||||
|
||||
static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local,
|
||||
@ -2289,7 +2294,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
||||
if (!ieee80211_parse_tx_radiotap(local, skb))
|
||||
goto fail_rcu;
|
||||
|
||||
ieee80211_xmit(sdata, NULL, skb);
|
||||
ieee80211_xmit(sdata, NULL, skb, 0);
|
||||
rcu_read_unlock();
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
@ -3648,7 +3653,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
|
||||
ieee80211_tx_stats(dev, skb->len);
|
||||
|
||||
ieee80211_xmit(sdata, sta, skb);
|
||||
ieee80211_xmit(sdata, sta, skb, 0);
|
||||
}
|
||||
goto out;
|
||||
out_free:
|
||||
@ -3867,7 +3872,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
|
||||
return true;
|
||||
}
|
||||
info->band = chanctx_conf->def.chan->band;
|
||||
result = ieee80211_tx(sdata, NULL, skb, true);
|
||||
result = ieee80211_tx(sdata, NULL, skb, true, 0);
|
||||
} else {
|
||||
struct sk_buff_head skbs;
|
||||
|
||||
@ -4783,7 +4788,7 @@ EXPORT_SYMBOL(ieee80211_unreserve_tid);
|
||||
|
||||
void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, int tid,
|
||||
enum nl80211_band band)
|
||||
enum nl80211_band band, u32 txdata_flags)
|
||||
{
|
||||
int ac = ieee80211_ac_from_tid(tid);
|
||||
|
||||
@ -4800,7 +4805,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
local_bh_disable();
|
||||
IEEE80211_SKB_CB(skb)->band = band;
|
||||
ieee80211_xmit(sdata, NULL, skb);
|
||||
ieee80211_xmit(sdata, NULL, skb, txdata_flags);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
|
@ -1095,6 +1095,21 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
if (elen >= sizeof(*elems->max_idle_period_ie))
|
||||
elems->max_idle_period_ie = (void *)pos;
|
||||
break;
|
||||
case WLAN_EID_EXTENSION:
|
||||
if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
|
||||
elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
|
||||
elems->mu_edca_param_set = (void *)&pos[1];
|
||||
} else if (pos[0] == WLAN_EID_EXT_HE_CAPABILITY) {
|
||||
elems->he_cap = (void *)&pos[1];
|
||||
elems->he_cap_len = elen - 1;
|
||||
} else if (pos[0] == WLAN_EID_EXT_HE_OPERATION &&
|
||||
elen >= sizeof(*elems->he_operation) &&
|
||||
elen >= ieee80211_he_oper_size(&pos[1])) {
|
||||
elems->he_operation = (void *)&pos[1];
|
||||
} else if (pos[0] == WLAN_EID_EXT_UORA && elen >= 1) {
|
||||
elems->uora_element = (void *)&pos[1];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1353,9 +1368,10 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||
enum nl80211_band band,
|
||||
u32 rate_mask,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
size_t *offset)
|
||||
size_t *offset, u32 flags)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
const struct ieee80211_sta_he_cap *he_cap;
|
||||
u8 *pos = buffer, *end = buffer + buffer_len;
|
||||
size_t noffset;
|
||||
int supp_rates_len, i;
|
||||
@ -1433,6 +1449,9 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||
chandef->chan->center_freq);
|
||||
}
|
||||
|
||||
if (flags & IEEE80211_PROBE_FLAG_MIN_CONTENT)
|
||||
goto done;
|
||||
|
||||
/* insert custom IEs that go before HT */
|
||||
if (ie && ie_len) {
|
||||
static const u8 before_ht[] = {
|
||||
@ -1460,11 +1479,6 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||
sband->ht_cap.cap);
|
||||
}
|
||||
|
||||
/*
|
||||
* If adding more here, adjust code in main.c
|
||||
* that calculates local->scan_ies_len.
|
||||
*/
|
||||
|
||||
/* insert custom IEs that go before VHT */
|
||||
if (ie && ie_len) {
|
||||
static const u8 before_vht[] = {
|
||||
@ -1507,9 +1521,43 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
|
||||
sband->vht_cap.cap);
|
||||
}
|
||||
|
||||
/* insert custom IEs that go before HE */
|
||||
if (ie && ie_len) {
|
||||
static const u8 before_he[] = {
|
||||
/*
|
||||
* no need to list the ones split off before VHT
|
||||
* or generated here
|
||||
*/
|
||||
WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_REQ_PARAMS,
|
||||
WLAN_EID_AP_CSN,
|
||||
/* TODO: add 11ah/11aj/11ak elements */
|
||||
};
|
||||
noffset = ieee80211_ie_split(ie, ie_len,
|
||||
before_he, ARRAY_SIZE(before_he),
|
||||
*offset);
|
||||
if (end - pos < noffset - *offset)
|
||||
goto out_err;
|
||||
memcpy(pos, ie + *offset, noffset - *offset);
|
||||
pos += noffset - *offset;
|
||||
*offset = noffset;
|
||||
}
|
||||
|
||||
he_cap = ieee80211_get_he_sta_cap(sband);
|
||||
if (he_cap) {
|
||||
pos = ieee80211_ie_build_he_cap(pos, he_cap, end);
|
||||
if (!pos)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* If adding more here, adjust code in main.c
|
||||
* that calculates local->scan_ies_len.
|
||||
*/
|
||||
|
||||
return pos - buffer;
|
||||
out_err:
|
||||
WARN_ONCE(1, "not enough space for preq IEs\n");
|
||||
done:
|
||||
return pos - buffer;
|
||||
}
|
||||
|
||||
@ -1518,7 +1566,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
struct ieee80211_scan_ies *ie_desc,
|
||||
const u8 *ie, size_t ie_len,
|
||||
u8 bands_used, u32 *rate_masks,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
struct cfg80211_chan_def *chandef,
|
||||
u32 flags)
|
||||
{
|
||||
size_t pos = 0, old_pos = 0, custom_ie_offset = 0;
|
||||
int i;
|
||||
@ -1533,7 +1582,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
|
||||
ie, ie_len, i,
|
||||
rate_masks[i],
|
||||
chandef,
|
||||
&custom_ie_offset);
|
||||
&custom_ie_offset,
|
||||
flags);
|
||||
ie_desc->ies[i] = buffer + old_pos;
|
||||
ie_desc->len[i] = pos - old_pos;
|
||||
old_pos = pos;
|
||||
@ -1561,7 +1611,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_channel *chan,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len,
|
||||
bool directed)
|
||||
u32 flags)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct cfg80211_chan_def chandef;
|
||||
@ -1577,7 +1627,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
* badly-behaved APs don't respond when this parameter is included.
|
||||
*/
|
||||
chandef.width = sdata->vif.bss_conf.chandef.width;
|
||||
if (directed)
|
||||
if (flags & IEEE80211_PROBE_FLAG_DIRECTED)
|
||||
chandef.chan = NULL;
|
||||
else
|
||||
chandef.chan = chan;
|
||||
@ -1591,7 +1641,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb),
|
||||
skb_tailroom(skb), &dummy_ie_desc,
|
||||
ie, ie_len, BIT(chan->band),
|
||||
rate_masks, &chandef);
|
||||
rate_masks, &chandef, flags);
|
||||
skb_put(skb, ies_len);
|
||||
|
||||
if (dst) {
|
||||
@ -1605,27 +1655,6 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
return skb;
|
||||
}
|
||||
|
||||
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *src, const u8 *dst,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const u8 *ie, size_t ie_len,
|
||||
u32 ratemask, bool directed, u32 tx_flags,
|
||||
struct ieee80211_channel *channel, bool scan)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel,
|
||||
ssid, ssid_len,
|
||||
ie, ie_len, directed);
|
||||
if (skb) {
|
||||
IEEE80211_SKB_CB(skb)->flags |= tx_flags;
|
||||
if (scan)
|
||||
ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band);
|
||||
else
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
}
|
||||
|
||||
u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee802_11_elems *elems,
|
||||
enum nl80211_band band, u32 *basic_rates)
|
||||
@ -2412,6 +2441,72 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||
return pos;
|
||||
}
|
||||
|
||||
u8 *ieee80211_ie_build_he_cap(u8 *pos,
|
||||
const struct ieee80211_sta_he_cap *he_cap,
|
||||
u8 *end)
|
||||
{
|
||||
u8 n;
|
||||
u8 ie_len;
|
||||
u8 *orig_pos = pos;
|
||||
|
||||
/* Make sure we have place for the IE */
|
||||
/*
|
||||
* TODO: the 1 added is because this temporarily is under the EXTENSION
|
||||
* IE. Get rid of it when it moves.
|
||||
*/
|
||||
if (!he_cap)
|
||||
return orig_pos;
|
||||
|
||||
n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem);
|
||||
ie_len = 2 + 1 +
|
||||
sizeof(he_cap->he_cap_elem) + n +
|
||||
ieee80211_he_ppe_size(he_cap->ppe_thres[0],
|
||||
he_cap->he_cap_elem.phy_cap_info);
|
||||
|
||||
if ((end - pos) < ie_len)
|
||||
return orig_pos;
|
||||
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
pos++; /* We'll set the size later below */
|
||||
*pos++ = WLAN_EID_EXT_HE_CAPABILITY;
|
||||
|
||||
/* Fixed data */
|
||||
memcpy(pos, &he_cap->he_cap_elem, sizeof(he_cap->he_cap_elem));
|
||||
pos += sizeof(he_cap->he_cap_elem);
|
||||
|
||||
memcpy(pos, &he_cap->he_mcs_nss_supp, n);
|
||||
pos += n;
|
||||
|
||||
/* Check if PPE Threshold should be present */
|
||||
if ((he_cap->he_cap_elem.phy_cap_info[6] &
|
||||
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0)
|
||||
goto end;
|
||||
|
||||
/*
|
||||
* Calculate how many PPET16/PPET8 pairs are to come. Algorithm:
|
||||
* (NSS_M1 + 1) x (num of 1 bits in RU_INDEX_BITMASK)
|
||||
*/
|
||||
n = hweight8(he_cap->ppe_thres[0] &
|
||||
IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK);
|
||||
n *= (1 + ((he_cap->ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) >>
|
||||
IEEE80211_PPE_THRES_NSS_POS));
|
||||
|
||||
/*
|
||||
* Each pair is 6 bits, and we need to add the 7 "header" bits to the
|
||||
* total size.
|
||||
*/
|
||||
n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7;
|
||||
n = DIV_ROUND_UP(n, 8);
|
||||
|
||||
/* Copy PPE Thresholds */
|
||||
memcpy(pos, &he_cap->ppe_thres, n);
|
||||
pos += n;
|
||||
|
||||
end:
|
||||
orig_pos[1] = (pos - orig_pos) - 2;
|
||||
return pos;
|
||||
}
|
||||
|
||||
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||
const struct cfg80211_chan_def *chandef,
|
||||
u16 prot_mode, bool rifs_mode)
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 Intel Deutschland GmbH
|
||||
* Copyright 2015-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -744,6 +744,8 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
|
||||
/* sanity check supported bands/channels */
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
u16 types = 0;
|
||||
|
||||
sband = wiphy->bands[band];
|
||||
if (!sband)
|
||||
continue;
|
||||
@ -788,6 +790,23 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
sband->channels[i].band = band;
|
||||
}
|
||||
|
||||
for (i = 0; i < sband->n_iftype_data; i++) {
|
||||
const struct ieee80211_sband_iftype_data *iftd;
|
||||
|
||||
iftd = &sband->iftype_data[i];
|
||||
|
||||
if (WARN_ON(!iftd->types_mask))
|
||||
return -EINVAL;
|
||||
if (WARN_ON(types & iftd->types_mask))
|
||||
return -EINVAL;
|
||||
|
||||
/* at least one piece of information must be present */
|
||||
if (WARN_ON(!iftd->he_cap.has_he))
|
||||
return -EINVAL;
|
||||
|
||||
types |= iftd->types_mask;
|
||||
}
|
||||
|
||||
have_band = true;
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ struct cfg80211_registered_device {
|
||||
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
|
||||
struct sk_buff *scan_msg;
|
||||
struct list_head sched_scan_req_list;
|
||||
unsigned long suspend_at;
|
||||
time64_t suspend_at;
|
||||
struct work_struct scan_done_wk;
|
||||
|
||||
struct genl_info *cur_cmd_info;
|
||||
|
@ -428,6 +428,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
|
||||
.len = NL80211_HE_MAX_CAPABILITY_LEN },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@ -1324,6 +1326,34 @@ static int nl80211_send_coalesce(struct sk_buff *msg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nl80211_send_iftype_data(struct sk_buff *msg,
|
||||
const struct ieee80211_sband_iftype_data *iftdata)
|
||||
{
|
||||
const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
|
||||
|
||||
if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES,
|
||||
iftdata->types_mask))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (he_cap->has_he) {
|
||||
if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
|
||||
sizeof(he_cap->he_cap_elem.mac_cap_info),
|
||||
he_cap->he_cap_elem.mac_cap_info) ||
|
||||
nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
|
||||
sizeof(he_cap->he_cap_elem.phy_cap_info),
|
||||
he_cap->he_cap_elem.phy_cap_info) ||
|
||||
nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
|
||||
sizeof(he_cap->he_mcs_nss_supp),
|
||||
&he_cap->he_mcs_nss_supp) ||
|
||||
nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
|
||||
sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_send_band_rateinfo(struct sk_buff *msg,
|
||||
struct ieee80211_supported_band *sband)
|
||||
{
|
||||
@ -1353,6 +1383,32 @@ static int nl80211_send_band_rateinfo(struct sk_buff *msg,
|
||||
sband->vht_cap.cap)))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (sband->n_iftype_data) {
|
||||
struct nlattr *nl_iftype_data =
|
||||
nla_nest_start(msg, NL80211_BAND_ATTR_IFTYPE_DATA);
|
||||
int err;
|
||||
|
||||
if (!nl_iftype_data)
|
||||
return -ENOBUFS;
|
||||
|
||||
for (i = 0; i < sband->n_iftype_data; i++) {
|
||||
struct nlattr *iftdata;
|
||||
|
||||
iftdata = nla_nest_start(msg, i + 1);
|
||||
if (!iftdata)
|
||||
return -ENOBUFS;
|
||||
|
||||
err = nl80211_send_iftype_data(msg,
|
||||
&sband->iftype_data[i]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
nla_nest_end(msg, iftdata);
|
||||
}
|
||||
|
||||
nla_nest_end(msg, nl_iftype_data);
|
||||
}
|
||||
|
||||
/* add bitrates */
|
||||
nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
|
||||
if (!nl_rates)
|
||||
@ -2757,7 +2813,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, wdev_address(wdev)) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_GENERATION,
|
||||
rdev->devlist_generation ^
|
||||
(cfg80211_rdev_list_generation << 2)))
|
||||
(cfg80211_rdev_list_generation << 2)) ||
|
||||
nla_put_u8(msg, NL80211_ATTR_4ADDR, wdev->use_4addr))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (rdev->ops->get_channel) {
|
||||
@ -4471,6 +4528,9 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
case RATE_INFO_BW_160:
|
||||
rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
|
||||
break;
|
||||
case RATE_INFO_BW_HE_RU:
|
||||
rate_flg = 0;
|
||||
WARN_ON(!(info->flags & RATE_INFO_FLAGS_HE_MCS));
|
||||
}
|
||||
|
||||
if (rate_flg && nla_put_flag(msg, rate_flg))
|
||||
@ -4490,6 +4550,19 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
|
||||
nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
|
||||
return false;
|
||||
} else if (info->flags & RATE_INFO_FLAGS_HE_MCS) {
|
||||
if (nla_put_u8(msg, NL80211_RATE_INFO_HE_MCS, info->mcs))
|
||||
return false;
|
||||
if (nla_put_u8(msg, NL80211_RATE_INFO_HE_NSS, info->nss))
|
||||
return false;
|
||||
if (nla_put_u8(msg, NL80211_RATE_INFO_HE_GI, info->he_gi))
|
||||
return false;
|
||||
if (nla_put_u8(msg, NL80211_RATE_INFO_HE_DCM, info->he_dcm))
|
||||
return false;
|
||||
if (info->bw == RATE_INFO_BW_HE_RU &&
|
||||
nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC,
|
||||
info->he_ru_alloc))
|
||||
return false;
|
||||
}
|
||||
|
||||
nla_nest_end(msg, rate);
|
||||
@ -4546,13 +4619,13 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
|
||||
#define PUT_SINFO(attr, memb, type) do { \
|
||||
BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
|
||||
if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
|
||||
if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
|
||||
nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
|
||||
sinfo->memb)) \
|
||||
goto nla_put_failure; \
|
||||
} while (0)
|
||||
#define PUT_SINFO_U64(attr, memb) do { \
|
||||
if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
|
||||
if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_ ## attr) && \
|
||||
nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
|
||||
sinfo->memb, NL80211_STA_INFO_PAD)) \
|
||||
goto nla_put_failure; \
|
||||
@ -4561,14 +4634,14 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
PUT_SINFO(CONNECTED_TIME, connected_time, u32);
|
||||
PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
|
||||
|
||||
if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
|
||||
BIT(NL80211_STA_INFO_RX_BYTES64)) &&
|
||||
if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_RX_BYTES) |
|
||||
BIT_ULL(NL80211_STA_INFO_RX_BYTES64)) &&
|
||||
nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
|
||||
(u32)sinfo->rx_bytes))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
|
||||
BIT(NL80211_STA_INFO_TX_BYTES64)) &&
|
||||
if (sinfo->filled & (BIT_ULL(NL80211_STA_INFO_TX_BYTES) |
|
||||
BIT_ULL(NL80211_STA_INFO_TX_BYTES64)) &&
|
||||
nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
|
||||
(u32)sinfo->tx_bytes))
|
||||
goto nla_put_failure;
|
||||
@ -4588,24 +4661,24 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
|
||||
if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) {
|
||||
if (!nl80211_put_signal(msg, sinfo->chains,
|
||||
sinfo->chain_signal,
|
||||
NL80211_STA_INFO_CHAIN_SIGNAL))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
|
||||
if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
|
||||
if (!nl80211_put_signal(msg, sinfo->chains,
|
||||
sinfo->chain_signal_avg,
|
||||
NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
|
||||
if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) {
|
||||
if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
|
||||
NL80211_STA_INFO_TX_BITRATE))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
|
||||
if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_BITRATE)) {
|
||||
if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
|
||||
NL80211_STA_INFO_RX_BITRATE))
|
||||
goto nla_put_failure;
|
||||
@ -4621,7 +4694,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
PUT_SINFO(PEER_PM, peer_pm, u32);
|
||||
PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
|
||||
|
||||
if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
|
||||
if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) {
|
||||
bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
|
||||
if (!bss_param)
|
||||
goto nla_put_failure;
|
||||
@ -4640,7 +4713,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
|
||||
nla_nest_end(msg, bss_param);
|
||||
}
|
||||
if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
|
||||
if ((sinfo->filled & BIT_ULL(NL80211_STA_INFO_STA_FLAGS)) &&
|
||||
nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
|
||||
sizeof(struct nl80211_sta_flag_update),
|
||||
&sinfo->sta_flags))
|
||||
@ -4886,7 +4959,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
|
||||
return -EINVAL;
|
||||
if (params->supported_rates)
|
||||
return -EINVAL;
|
||||
if (params->ext_capab || params->ht_capa || params->vht_capa)
|
||||
if (params->ext_capab || params->ht_capa || params->vht_capa ||
|
||||
params->he_capa)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -5092,6 +5166,15 @@ static int nl80211_set_station_tdls(struct genl_info *info,
|
||||
if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
|
||||
params->vht_capa =
|
||||
nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
|
||||
if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
|
||||
params->he_capa =
|
||||
nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
|
||||
params->he_capa_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
|
||||
|
||||
if (params->he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = nl80211_parse_sta_channel_info(info, params);
|
||||
if (err)
|
||||
@ -5319,6 +5402,17 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||
params.vht_capa =
|
||||
nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_HE_CAPABILITY]) {
|
||||
params.he_capa =
|
||||
nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
|
||||
params.he_capa_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
|
||||
|
||||
/* max len is validated in nla policy */
|
||||
if (params.he_capa_len < NL80211_HE_MIN_CAPABILITY_LEN)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
|
||||
params.opmode_notif_used = true;
|
||||
params.opmode_notif =
|
||||
@ -5351,6 +5445,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
|
||||
params.ht_capa = NULL;
|
||||
params.vht_capa = NULL;
|
||||
|
||||
/* HE requires WME */
|
||||
if (params.he_capa_len)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* When you run into this, adjust the code below for the new flag */
|
||||
@ -6861,6 +6959,16 @@ static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
|
||||
return regulatory_pre_cac_allowed(wdev->wiphy);
|
||||
}
|
||||
|
||||
static bool nl80211_check_scan_feat(struct wiphy *wiphy, u32 flags, u32 flag,
|
||||
enum nl80211_ext_feature_index feat)
|
||||
{
|
||||
if (!(flags & flag))
|
||||
return true;
|
||||
if (wiphy_ext_feature_isset(wiphy, feat))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
void *request, struct nlattr **attrs,
|
||||
@ -6895,15 +7003,33 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
|
||||
if (((*flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
|
||||
!(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
|
||||
((*flags & NL80211_SCAN_FLAG_LOW_SPAN) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_LOW_SPAN_SCAN)) ||
|
||||
((*flags & NL80211_SCAN_FLAG_LOW_POWER) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_LOW_POWER_SCAN)) ||
|
||||
((*flags & NL80211_SCAN_FLAG_HIGH_ACCURACY) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN)))
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_LOW_SPAN,
|
||||
NL80211_EXT_FEATURE_LOW_SPAN_SCAN) ||
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_LOW_POWER,
|
||||
NL80211_EXT_FEATURE_LOW_POWER_SCAN) ||
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_HIGH_ACCURACY,
|
||||
NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN) ||
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME,
|
||||
NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME) ||
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP,
|
||||
NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP) ||
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) ||
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE) ||
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_RANDOM_SN,
|
||||
NL80211_EXT_FEATURE_SCAN_RANDOM_SN) ||
|
||||
!nl80211_check_scan_feat(wiphy, *flags,
|
||||
NL80211_SCAN_FLAG_MIN_PREQ_CONTENT,
|
||||
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (*flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
|
||||
@ -6918,26 +7044,6 @@ nl80211_check_scan_flags(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((*flags & NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE) &&
|
||||
!wiphy_ext_feature_isset(wiphy,
|
||||
NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -10160,7 +10266,7 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
|
||||
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
|
||||
wdev->cqm_config->last_rssi_event_value =
|
||||
(s8) sinfo.rx_beacon_signal_avg;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ static int wiphy_suspend(struct device *dev)
|
||||
struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
|
||||
int ret = 0;
|
||||
|
||||
rdev->suspend_at = get_seconds();
|
||||
rdev->suspend_at = ktime_get_boottime_seconds();
|
||||
|
||||
rtnl_lock();
|
||||
if (rdev->wiphy.registered) {
|
||||
@ -130,7 +130,7 @@ static int wiphy_resume(struct device *dev)
|
||||
int ret = 0;
|
||||
|
||||
/* Age scan results with time spent in suspend */
|
||||
cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at);
|
||||
cfg80211_bss_age(rdev, ktime_get_boottime_seconds() - rdev->suspend_at);
|
||||
|
||||
rtnl_lock();
|
||||
if (rdev->wiphy.registered && rdev->ops->resume)
|
||||
|
@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2017 Intel Deutschland GmbH
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/bitops.h>
|
||||
@ -1142,6 +1143,85 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
|
||||
{
|
||||
#define SCALE 2048
|
||||
u16 mcs_divisors[12] = {
|
||||
34133, /* 16.666666... */
|
||||
17067, /* 8.333333... */
|
||||
11378, /* 5.555555... */
|
||||
8533, /* 4.166666... */
|
||||
5689, /* 2.777777... */
|
||||
4267, /* 2.083333... */
|
||||
3923, /* 1.851851... */
|
||||
3413, /* 1.666666... */
|
||||
2844, /* 1.388888... */
|
||||
2560, /* 1.250000... */
|
||||
2276, /* 1.111111... */
|
||||
2048, /* 1.000000... */
|
||||
};
|
||||
u32 rates_160M[3] = { 960777777, 907400000, 816666666 };
|
||||
u32 rates_969[3] = { 480388888, 453700000, 408333333 };
|
||||
u32 rates_484[3] = { 229411111, 216666666, 195000000 };
|
||||
u32 rates_242[3] = { 114711111, 108333333, 97500000 };
|
||||
u32 rates_106[3] = { 40000000, 37777777, 34000000 };
|
||||
u32 rates_52[3] = { 18820000, 17777777, 16000000 };
|
||||
u32 rates_26[3] = { 9411111, 8888888, 8000000 };
|
||||
u64 tmp;
|
||||
u32 result;
|
||||
|
||||
if (WARN_ON_ONCE(rate->mcs > 11))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2))
|
||||
return 0;
|
||||
if (WARN_ON_ONCE(rate->he_ru_alloc >
|
||||
NL80211_RATE_INFO_HE_RU_ALLOC_2x996))
|
||||
return 0;
|
||||
if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8))
|
||||
return 0;
|
||||
|
||||
if (rate->bw == RATE_INFO_BW_160)
|
||||
result = rates_160M[rate->he_gi];
|
||||
else if (rate->bw == RATE_INFO_BW_80 ||
|
||||
(rate->bw == RATE_INFO_BW_HE_RU &&
|
||||
rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996))
|
||||
result = rates_969[rate->he_gi];
|
||||
else if (rate->bw == RATE_INFO_BW_40 ||
|
||||
(rate->bw == RATE_INFO_BW_HE_RU &&
|
||||
rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484))
|
||||
result = rates_484[rate->he_gi];
|
||||
else if (rate->bw == RATE_INFO_BW_20 ||
|
||||
(rate->bw == RATE_INFO_BW_HE_RU &&
|
||||
rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242))
|
||||
result = rates_242[rate->he_gi];
|
||||
else if (rate->bw == RATE_INFO_BW_HE_RU &&
|
||||
rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106)
|
||||
result = rates_106[rate->he_gi];
|
||||
else if (rate->bw == RATE_INFO_BW_HE_RU &&
|
||||
rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52)
|
||||
result = rates_52[rate->he_gi];
|
||||
else if (rate->bw == RATE_INFO_BW_HE_RU &&
|
||||
rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26)
|
||||
result = rates_26[rate->he_gi];
|
||||
else if (WARN(1, "invalid HE MCS: bw:%d, ru:%d\n",
|
||||
rate->bw, rate->he_ru_alloc))
|
||||
return 0;
|
||||
|
||||
/* now scale to the appropriate MCS */
|
||||
tmp = result;
|
||||
tmp *= SCALE;
|
||||
do_div(tmp, mcs_divisors[rate->mcs]);
|
||||
result = tmp;
|
||||
|
||||
/* and take NSS, DCM into account */
|
||||
result = (result * rate->nss) / 8;
|
||||
if (rate->he_dcm)
|
||||
result /= 2;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
|
||||
{
|
||||
if (rate->flags & RATE_INFO_FLAGS_MCS)
|
||||
@ -1150,6 +1230,8 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
|
||||
return cfg80211_calculate_bitrate_60g(rate);
|
||||
if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
|
||||
return cfg80211_calculate_bitrate_vht(rate);
|
||||
if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
|
||||
return cfg80211_calculate_bitrate_he(rate);
|
||||
|
||||
return rate->legacy;
|
||||
}
|
||||
@ -1791,8 +1873,9 @@ bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,
|
||||
|
||||
int cfg80211_sinfo_alloc_tid_stats(struct station_info *sinfo, gfp_t gfp)
|
||||
{
|
||||
sinfo->pertid = kcalloc(sizeof(*(sinfo->pertid)),
|
||||
IEEE80211_NUM_TIDS + 1, gfp);
|
||||
sinfo->pertid = kcalloc(IEEE80211_NUM_TIDS + 1,
|
||||
sizeof(*(sinfo->pertid)),
|
||||
gfp);
|
||||
if (!sinfo->pertid)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1278,7 +1278,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!(sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)))
|
||||
if (!(sinfo.filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate);
|
||||
@ -1320,7 +1320,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
|
||||
|
||||
switch (rdev->wiphy.signal_type) {
|
||||
case CFG80211_SIGNAL_TYPE_MBM:
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) {
|
||||
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_SIGNAL)) {
|
||||
int sig = sinfo.signal;
|
||||
wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
|
||||
wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
|
||||
@ -1334,7 +1334,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
|
||||
break;
|
||||
}
|
||||
case CFG80211_SIGNAL_TYPE_UNSPEC:
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) {
|
||||
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_SIGNAL)) {
|
||||
wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
|
||||
wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
|
||||
wstats.qual.level = sinfo.signal;
|
||||
@ -1347,9 +1347,9 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
|
||||
}
|
||||
|
||||
wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_RX_DROP_MISC))
|
||||
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC))
|
||||
wstats.discard.misc = sinfo.rx_dropped_misc;
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_TX_FAILED))
|
||||
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED))
|
||||
wstats.discard.retries = sinfo.tx_failed;
|
||||
|
||||
return &wstats;
|
||||
|
Loading…
Reference in New Issue
Block a user