A few big new things:

* 802.11 frame encapsulation offload support
  * more HE (802.11ax) support, including some for 6 GHz band
  * powersave in hwsim, for better testing
 
 Of course as usual there are various cleanups and small fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAl5GggsACgkQB8qZga/f
 l8Qgdg//R42bSv94JYPcwZ5phgTgraCRZODWjBJq08n2T5m0EmEufgX79d9uEdgT
 u9npvn+ich5/VZhmuSbGrW9TT6/FPLAZyghV1fj79o971Qd7ky2Mp8G1fcTEbtDn
 IG2e9vauY9XDSb2O3wNj8dA8rAN/kLNmhsPqWxn2CgLPqjdbf+W15dvo4rnaL2gs
 ffGyE47dHuAFwCruyT8UPbw3iu4+tQhruN9eVg+UkU8rJGvEMqfrLK20zl1weIV9
 a7IuXdxacdsHO8Y+tl6GtvgOURQPpvf55+leLOUhcmHPJ3f/eAal6wmWRxDxs/qB
 IWSe8BC81cZZ5pYWk1A+0sXfJMlYjNsN0xw5SQRSrbgyb5saz8aLUIlHsOBM4iPH
 SwzCMN5A1GOPOUFsugzPwbiki9g6dh0/EC2NyXE4A26CAd967dVXTvTY5SMNgiB+
 bZaaUDaPQUm1jgDT5bLRhTipTHbekDkYzG/e+wNO+HKyStoEYM485MwY4MQCYzEh
 HKDmkAbFuCwEUeXXw1y8GybUknApCRru9FtY+oiN/+y/aESfB7HJfmDFFU/KYgPu
 HOuqJoNAxdMdycDCb24/cLjUiehzfM6sujwBxZOD5WHhAcXrBo5dGd6ibfurIrjj
 XI36/mwTiMtyyb0/5xM1AKvoic2j+a5YU3MB7KSc9TlaPa5j2NA=
 =CgmJ
 -----END PGP SIGNATURE-----

Merge tag 'mac80211-next-for-net-next-2020-02-14' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
A few big new things:
 * 802.11 frame encapsulation offload support
 * more HE (802.11ax) support, including some for 6 GHz band
 * powersave in hwsim, for better testing

Of course as usual there are various cleanups and small fixes.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-02-16 19:00:22 -08:00
commit ddb535a6a0
35 changed files with 1078 additions and 338 deletions

View File

@ -5103,7 +5103,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
if (arvif->txpower <= 0)
/* txpower not initialized yet? */
if (arvif->txpower == INT_MIN)
continue;
if (txpower == -1)

View File

@ -1196,6 +1196,9 @@ static void ath9k_tpc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
int *power = data;
if (vif->bss_conf.txpower == INT_MIN)
return;
if (*power < vif->bss_conf.txpower)
*power = vif->bss_conf.txpower;
}

View File

@ -2095,10 +2095,13 @@ static void setup_frame_info(struct ieee80211_hw *hw,
if (tx_info->control.vif) {
struct ieee80211_vif *vif = tx_info->control.vif;
if (vif->bss_conf.txpower == INT_MIN)
goto nonvifpower;
txpower = 2 * vif->bss_conf.txpower;
} else {
struct ath_softc *sc = hw->priv;
struct ath_softc *sc;
nonvifpower:
sc = hw->priv;
txpower = sc->cur_chan->cur_txpower;
}

View File

@ -2019,7 +2019,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
struct iwl_he_sta_context_cmd sta_ctxt_cmd = {
.sta_id = sta_id,
.tid_limit = IWL_MAX_TID_COUNT,
.bss_color = vif->bss_conf.bss_color,
.bss_color = vif->bss_conf.he_bss_color.color,
.htc_trig_based_pkt_ext = vif->bss_conf.htc_trig_based_pkt_ext,
.frame_time_rts_th =
cpu_to_le16(vif->bss_conf.frame_time_rts_th),

View File

@ -300,14 +300,12 @@ static struct net_device *hwsim_mon; /* global monitor netdev */
.band = NL80211_BAND_2GHZ, \
.center_freq = (_freq), \
.hw_value = (_freq), \
.max_power = 20, \
}
#define CHAN5G(_freq) { \
.band = NL80211_BAND_5GHZ, \
.center_freq = (_freq), \
.hw_value = (_freq), \
.max_power = 20, \
}
static const struct ieee80211_channel hwsim_channels_2ghz[] = {
@ -1595,6 +1593,11 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->def.chan);
while ((skb = ieee80211_get_buffered_bc(hw, vif)) != NULL) {
mac80211_hwsim_tx_frame(hw, skb,
rcu_dereference(vif->chanctx_conf)->def.chan);
}
if (vif->csa_active && ieee80211_csa_is_complete(vif))
ieee80211_csa_finish(vif);
}
@ -2925,11 +2928,15 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
ieee80211_hw_set(hw, MFP_CAPABLE);
ieee80211_hw_set(hw, SIGNAL_DBM);
ieee80211_hw_set(hw, SUPPORTS_PS);
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
ieee80211_hw_set(hw, TDLS_WIDER_BW);
if (rctbl)
ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_AP_UAPSD |

View File

@ -619,6 +619,15 @@ static inline bool ieee80211_is_qos_nullfunc(__le16 fc)
cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC);
}
/**
* ieee80211_is_any_nullfunc - check if frame is regular or QoS nullfunc frame
* @fc: frame control bytes in little-endian byteorder
*/
static inline bool ieee80211_is_any_nullfunc(__le16 fc)
{
return (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc));
}
/**
* ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
* @fc: frame control field in little-endian byteorder
@ -2047,13 +2056,13 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
#define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000
#define IEEE80211_HE_OPERATION_6GHZ_OP_INFO 0x00020000
#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000
#define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24
#define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24
#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000
#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000
/*
* 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
* @he_oper_ie: byte data of the He Operations IE, stating from the byte
* after the ext ID byte. It is assumed that he_oper_ie has at least
* sizeof(struct ieee80211_he_operation) bytes, the caller must have
* validated this.
@ -2091,7 +2100,7 @@ ieee80211_he_oper_size(const u8 *he_oper_ie)
/*
* ieee80211_he_spr_size - calculate 802.11ax HE Spatial Reuse IE size
* @he_spr_ie: byte data of the He Spatial Reuse IE, stating from the the byte
* @he_spr_ie: byte data of the He Spatial Reuse IE, stating from the byte
* after the ext ID byte. It is assumed that he_spr_ie has at least
* sizeof(struct ieee80211_he_spr) bytes, the caller must have validated
* this
@ -2523,6 +2532,7 @@ enum ieee80211_eid {
WLAN_EID_FILS_INDICATION = 240,
WLAN_EID_DILS = 241,
WLAN_EID_FRAGMENT = 242,
WLAN_EID_RSNX = 244,
WLAN_EID_EXTENSION = 255
};
@ -2734,7 +2744,7 @@ enum ieee80211_tdls_actioncode {
*/
#define WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT BIT(6)
/* TDLS capabilities in the the 4th byte of @WLAN_EID_EXT_CAPABILITY */
/* TDLS capabilities in the 4th byte of @WLAN_EID_EXT_CAPABILITY */
#define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4)
#define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5)
#define WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH BIT(6)
@ -3034,6 +3044,7 @@ struct ieee80211_multiple_bssid_configuration {
#define WLAN_AKM_SUITE_FILS_SHA384 SUITE(0x000FAC, 15)
#define WLAN_AKM_SUITE_FT_FILS_SHA256 SUITE(0x000FAC, 16)
#define WLAN_AKM_SUITE_FT_FILS_SHA384 SUITE(0x000FAC, 17)
#define WLAN_AKM_SUITE_OWE SUITE(0x000FAC, 18)
#define WLAN_MAX_KEY_LEN 32
@ -3412,4 +3423,11 @@ static inline bool for_each_element_completed(const struct element *element,
return (const u8 *)element == (const u8 *)data + datalen;
}
/**
* RSNX Capabilities:
* bits 0-3: Field length (n-1)
*/
#define WLAN_RSNX_CAPA_PROTECTED_TWT BIT(4)
#define WLAN_RSNX_CAPA_SAE_H2E BIT(5)
#endif /* LINUX_IEEE80211_H */

View File

@ -95,6 +95,7 @@ struct wiphy;
* on this channel.
* @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted
* on this channel.
* @IEEE80211_CHAN_NO_HE: HE operation is not permitted on this channel.
*
*/
enum ieee80211_channel_flags {
@ -111,6 +112,7 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_IR_CONCURRENT = 1<<10,
IEEE80211_CHAN_NO_20MHZ = 1<<11,
IEEE80211_CHAN_NO_10MHZ = 1<<12,
IEEE80211_CHAN_NO_HE = 1<<13,
};
#define IEEE80211_CHAN_NO_HT40 \
@ -259,6 +261,32 @@ struct ieee80211_he_obss_pd {
u8 max_offset;
};
/**
* struct cfg80211_he_bss_color - AP settings for BSS coloring
*
* @color: the current color.
* @disabled: is the feature disabled.
* @partial: define the AID equation.
*/
struct cfg80211_he_bss_color {
u8 color;
bool disabled;
bool partial;
};
/**
* struct ieee80211_he_bss_color - AP settings for BSS coloring
*
* @color: the current color.
* @disabled: is the feature disabled.
* @partial: define the AID equation.
*/
struct ieee80211_he_bss_color {
u8 color;
bool disabled;
bool partial;
};
/**
* struct ieee80211_sta_ht_cap - STA's HT capabilities
*
@ -990,6 +1018,7 @@ enum cfg80211_ap_settings_flags {
* @twt_responder: Enable Target Wait Time
* @flags: flags, as defined in enum cfg80211_ap_settings_flags
* @he_obss_pd: OBSS Packet Detection settings
* @he_bss_color: BSS Color settings
*/
struct cfg80211_ap_settings {
struct cfg80211_chan_def chandef;
@ -1018,6 +1047,7 @@ struct cfg80211_ap_settings {
bool twt_responder;
u32 flags;
struct ieee80211_he_obss_pd he_obss_pd;
struct cfg80211_he_bss_color he_bss_color;
};
/**
@ -3944,7 +3974,8 @@ struct cfg80211_ops {
int (*tx_control_port)(struct wiphy *wiphy,
struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, const __be16 proto,
const u8 *dest, const u8 *src,
const __be16 proto,
const bool noencrypt);
int (*get_ftm_responder_stats)(struct wiphy *wiphy,
@ -4375,6 +4406,21 @@ struct cfg80211_pmsr_capabilities {
} ftm;
};
/**
* struct wiphy_iftype_akm_suites - This structure encapsulates supported akm
* suites for interface types defined in @iftypes_mask. Each type in the
* @iftypes_mask must be unique across all instances of iftype_akm_suites.
*
* @iftypes_mask: bitmask of interfaces types
* @akm_suites: points to an array of supported akm suites
* @n_akm_suites: number of supported AKM suites
*/
struct wiphy_iftype_akm_suites {
u16 iftypes_mask;
const u32 *akm_suites;
int n_akm_suites;
};
/**
* struct wiphy - wireless hardware description
* @reg_notifier: the driver's regulatory notification callback,
@ -4387,8 +4433,16 @@ struct cfg80211_pmsr_capabilities {
* @signal_type: signal type reported in &struct cfg80211_bss.
* @cipher_suites: supported cipher suites
* @n_cipher_suites: number of supported cipher suites
* @akm_suites: supported AKM suites
* @akm_suites: supported AKM suites. These are the default AKMs supported if
* the supported AKMs not advertized for a specific interface type in
* iftype_akm_suites.
* @n_akm_suites: number of supported AKM suites
* @iftype_akm_suites: array of supported akm suites info per interface type.
* Note that the bits in @iftypes_mask inside this structure cannot
* overlap (i.e. only one occurrence of each type is allowed across all
* instances of iftype_akm_suites).
* @num_iftype_akm_suites: number of interface types for which supported akm
* suites are specified separately.
* @retry_short: Retry limit for short frames (dot11ShortRetryLimit)
* @retry_long: Retry limit for long frames (dot11LongRetryLimit)
* @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
@ -4595,6 +4649,9 @@ struct wiphy {
int n_akm_suites;
const u32 *akm_suites;
const struct wiphy_iftype_akm_suites *iftype_akm_suites;
unsigned int num_iftype_akm_suites;
u8 retry_short;
u8 retry_long;
u32 frag_threshold;
@ -4687,6 +4744,8 @@ struct wiphy {
u32 txq_memory_limit;
u32 txq_quantum;
unsigned long tx_queue_len;
u8 support_mbssid:1,
support_only_he_mbssid:1;

View File

@ -316,6 +316,7 @@ struct ieee80211_vif_chanctx_switch {
* functionality changed for this BSS (AP mode).
* @BSS_CHANGED_TWT: TWT status changed
* @BSS_CHANGED_HE_OBSS_PD: OBSS Packet Detection status changed.
* @BSS_CHANGED_HE_BSS_COLOR: BSS Color has changed
*
*/
enum ieee80211_bss_change {
@ -348,6 +349,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_FTM_RESPONDER = 1<<26,
BSS_CHANGED_TWT = 1<<27,
BSS_CHANGED_HE_OBSS_PD = 1<<28,
BSS_CHANGED_HE_BSS_COLOR = 1<<29,
/* when adding here, make sure to change ieee80211_reconfig */
};
@ -494,7 +496,6 @@ struct ieee80211_ftm_responder_params {
* 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
@ -573,7 +574,7 @@ struct ieee80211_ftm_responder_params {
* @ssid: The SSID of the current vif. Valid in AP and IBSS mode.
* @ssid_len: Length of SSID given in @ssid.
* @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode.
* @txpower: TX power in dBm
* @txpower: TX power in dBm. INT_MIN means not configured.
* @txpower_type: TX power adjustment used to control per packet Transmit
* Power Control (TPC) in lower driver for the current vif. In particular
* TPC is enabled if value passed in %txpower_type is
@ -604,10 +605,10 @@ struct ieee80211_ftm_responder_params {
* in order to discover all the nontransmitted BSSIDs in the set.
* @he_operation: HE operation information of the AP we are connected to
* @he_obss_pd: OBSS Packet Detection parameters.
* @he_bss_color: BSS coloring settings, if BSS supports HE
*/
struct ieee80211_bss_conf {
const u8 *bssid;
u8 bss_color;
u8 htc_trig_based_pkt_ext;
bool multi_sta_back_32bit;
bool uora_exists;
@ -667,6 +668,7 @@ struct ieee80211_bss_conf {
u8 profile_periodicity;
struct ieee80211_he_operation he_operation;
struct ieee80211_he_obss_pd he_obss_pd;
struct cfg80211_he_bss_color he_bss_color;
};
/**
@ -826,6 +828,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_AMSDU = BIT(3),
IEEE80211_TX_CTRL_FAST_XMIT = BIT(4),
IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP = BIT(5),
IEEE80211_TX_CTRL_HW_80211_ENCAP = BIT(6),
};
/*
@ -4659,6 +4662,26 @@ static inline void ieee80211_tx_status_ni(struct ieee80211_hw *hw,
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
struct sk_buff *skb);
/**
* ieee80211_tx_status_8023 - transmit status callback for 802.3 frame format
*
* Call this function for all transmitted data frames after their transmit
* completion. This callback should only be called for data frames which
* are are using driver's (or hardware's) offload capability of encap/decap
* 802.11 frames.
*
* This function may not be called in IRQ context. Calls to this function
* for a single hardware must be synchronized against each other and all
* calls in the same tx status family.
*
* @hw: the hardware the frame was transmitted by
* @vif: the interface for which the frame was transmitted
* @skb: the frame that was transmitted, owned by mac80211 after this call
*/
void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct sk_buff *skb);
/**
* ieee80211_report_low_ack - report non-responding station
*
@ -6479,5 +6502,16 @@ u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
int len);
/**
* ieee80211_set_hw_80211_encap - enable hardware encapsulation offloading.
*
* This function is used to notify mac80211 that a vif can be passed raw 802.3
* frames. The driver needs to then handle the 802.11 encapsulation inside the
* hardware or firmware.
*
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @enable: indicate if the feature should be turned on or off
*/
bool ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable);
#endif /* MAC80211_H */

View File

@ -1039,11 +1039,14 @@
* a control port frame and as a notification that a control port frame
* has been received. %NL80211_ATTR_FRAME is used to specify the
* frame contents. The frame is the raw EAPoL data, without ethernet or
* 802.11 headers.
* 802.11 headers. An optional %NL80211_ATTR_SRC_MAC can be used to send
* pre-auth frames to STAs on behalf of other APs.
* When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
* indicating the protocol type of the received frame; whether the frame
* was received unencrypted and the MAC address of the peer respectively.
* %NL80211_ATTR_DST_MAC can be used to forward pre-auth frames in
* userspace while using AP mode.
*
* @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
*
@ -2400,6 +2403,18 @@ enum nl80211_commands {
* @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key
* (u16).
*
* @NL80211_ATTR_HE_BSS_COLOR: nested attribute for BSS Color Settings.
*
* @NL80211_ATTR_IFTYPE_AKM_SUITES: nested array attribute, with each entry
* using attributes from &enum nl80211_iftype_akm_attributes. This
* attribute is sent in a response to %NL80211_CMD_GET_WIPHY indicating
* supported AKM suites capability per interface. AKMs advertised in
* %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not
* advertised for a specific interface type.
*
* @NL80211_ATTR_SRC_MAC: MAC address used in control port over nl80211 transmit
* @NL80211_ATTR_DST_MAC: MAC address used in control port over nl80211 receive
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -2864,6 +2879,13 @@ enum nl80211_attrs {
NL80211_ATTR_VLAN_ID,
NL80211_ATTR_HE_BSS_COLOR,
NL80211_ATTR_IFTYPE_AKM_SUITES,
NL80211_ATTR_SRC_MAC,
NL80211_ATTR_DST_MAC,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -3583,6 +3605,8 @@ enum nl80211_wmm_rule {
* @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations.
* This is a nested attribute that contains the wmm limitation per AC.
* (see &enum nl80211_wmm_rule)
* @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel
* in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@ -3612,6 +3636,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_20MHZ,
NL80211_FREQUENCY_ATTR_NO_10MHZ,
NL80211_FREQUENCY_ATTR_WMM,
NL80211_FREQUENCY_ATTR_NO_HE,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@ -3809,6 +3834,7 @@ enum nl80211_sched_scan_match_attr {
* @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
* @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
* @NL80211_RRF_NO_HE: HE operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@ -3826,6 +3852,7 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_NO_HT40PLUS = 1<<14,
NL80211_RRF_NO_80MHZ = 1<<15,
NL80211_RRF_NO_160MHZ = 1<<16,
NL80211_RRF_NO_HE = 1<<17,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
@ -5521,6 +5548,10 @@ enum nl80211_feature_flags {
* feature, which prevents bufferbloat by using the expected transmission
* time to limit the amount of data buffered in the hardware.
*
* @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_MAC_ADDRS: The driver
* can use src and dst MAC addresses with control port over nl80211 rx
* and tx operations.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@ -5568,6 +5599,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SAE_OFFLOAD,
NL80211_EXT_FEATURE_VLAN_OFFLOAD,
NL80211_EXT_FEATURE_AQL,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_MAC_ADDRS,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@ -6587,5 +6619,51 @@ enum nl80211_obss_pd_attributes {
NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1,
};
/**
* enum nl80211_bss_color_attributes - BSS Color attributes
* @__NL80211_HE_BSS_COLOR_ATTR_INVALID: Invalid
*
* @NL80211_HE_BSS_COLOR_ATTR_COLOR: the current BSS Color.
* @NL80211_HE_BSS_COLOR_ATTR_DISABLED: is BSS coloring disabled.
* @NL80211_HE_BSS_COLOR_ATTR_PARTIAL: the AID equation to be used..
*
* @__NL80211_HE_BSS_COLOR_ATTR_LAST: Internal
* @NL80211_HE_BSS_COLOR_ATTR_MAX: highest BSS Color attribute.
*/
enum nl80211_bss_color_attributes {
__NL80211_HE_BSS_COLOR_ATTR_INVALID,
NL80211_HE_BSS_COLOR_ATTR_COLOR,
NL80211_HE_BSS_COLOR_ATTR_DISABLED,
NL80211_HE_BSS_COLOR_ATTR_PARTIAL,
/* keep last */
__NL80211_HE_BSS_COLOR_ATTR_LAST,
NL80211_HE_BSS_COLOR_ATTR_MAX = __NL80211_HE_BSS_COLOR_ATTR_LAST - 1,
};
/**
* enum nl80211_iftype_akm_attributes - interface type AKM attributes
* @__NL80211_IFTYPE_AKM_ATTR_INVALID: Invalid
*
* @NL80211_IFTYPE_AKM_ATTR_IFTYPES: nested attribute containing a flag
* attribute for each interface type that supports AKM suites specified in
* %NL80211_IFTYPE_AKM_ATTR_SUITES
* @NL80211_IFTYPE_AKM_ATTR_SUITES: an array of u32. Used to indicate supported
* AKM suites for the specified interface types.
*
* @__NL80211_IFTYPE_AKM_ATTR_LAST: Internal
* @NL80211_IFTYPE_AKM_ATTR_MAX: highest interface type AKM attribute.
*/
enum nl80211_iftype_akm_attributes {
__NL80211_IFTYPE_AKM_ATTR_INVALID,
NL80211_IFTYPE_AKM_ATTR_IFTYPES,
NL80211_IFTYPE_AKM_ATTR_SUITES,
/* keep last */
__NL80211_IFTYPE_AKM_ATTR_LAST,
NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1,
};
#endif /* __LINUX_NL80211_H */

View File

@ -74,6 +74,8 @@
#include <linux/socket.h> /* for "struct sockaddr" et al */
#include <linux/if.h> /* for IFNAMSIZ and co... */
#include <stddef.h> /* for offsetof */
/***************************** VERSION *****************************/
/*
* This constant is used to know the availability of the wireless
@ -1090,8 +1092,7 @@ struct iw_event {
/* iw_point events are special. First, the payload (extra data) come at
* the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
* we omit the pointer, so start at an offset. */
#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
(char *) NULL)
#define IW_EV_POINT_OFF offsetof(struct iw_point, length)
#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
IW_EV_POINT_OFF)

View File

@ -981,7 +981,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
BSS_CHANGED_P2P_PS |
BSS_CHANGED_TXPOWER |
BSS_CHANGED_TWT |
BSS_CHANGED_HE_OBSS_PD;
BSS_CHANGED_HE_OBSS_PD |
BSS_CHANGED_HE_BSS_COLOR;
int err;
int prev_beacon_int;
@ -989,20 +990,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (old)
return -EALREADY;
switch (params->smps_mode) {
case NL80211_SMPS_OFF:
sdata->smps_mode = IEEE80211_SMPS_OFF;
break;
case NL80211_SMPS_STATIC:
sdata->smps_mode = IEEE80211_SMPS_STATIC;
break;
case NL80211_SMPS_DYNAMIC:
sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
break;
default:
return -EINVAL;
}
sdata->u.ap.req_smps = sdata->smps_mode;
if (params->smps_mode != NL80211_SMPS_OFF)
return -ENOTSUPP;
sdata->smps_mode = IEEE80211_SMPS_OFF;
sdata->needed_rx_chains = sdata->local->rx_chains;
@ -1054,6 +1045,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->vif.bss_conf.twt_responder = params->twt_responder;
memcpy(&sdata->vif.bss_conf.he_obss_pd, &params->he_obss_pd,
sizeof(struct ieee80211_he_obss_pd));
memcpy(&sdata->vif.bss_conf.he_bss_color, &params->he_bss_color,
sizeof(struct ieee80211_he_bss_color));
sdata->vif.bss_conf.ssid_len = params->ssid_len;
if (params->ssid_len)
@ -1166,7 +1159,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
kfree_rcu(old_beacon, rcu_head);
if (old_probe_resp)
kfree_rcu(old_probe_resp, rcu_head);
sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
kfree(sdata->vif.bss_conf.ftmr_params);
sdata->vif.bss_conf.ftmr_params = NULL;
@ -1691,20 +1683,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
mutex_unlock(&local->sta_mtx);
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
sta->known_smps_mode != sta->sdata->bss->req_smps &&
test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
sta_info_tx_streams(sta) != 1) {
ht_dbg(sta->sdata,
"%pM just authorized and MIMO capable - update SMPS\n",
sta->sta.addr);
ieee80211_send_smps_action(sta->sdata,
sta->sdata->bss->req_smps,
sta->sta.addr,
sta->sdata->vif.bss_conf.bssid);
}
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
ieee80211_recalc_ps(local);
@ -2636,74 +2614,6 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy,
}
#endif
int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode)
{
struct sta_info *sta;
enum ieee80211_smps_mode old_req;
if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP))
return -EINVAL;
if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
return 0;
old_req = sdata->u.ap.req_smps;
sdata->u.ap.req_smps = smps_mode;
/* AUTOMATIC doesn't mean much for AP - don't allow it */
if (old_req == smps_mode ||
smps_mode == IEEE80211_SMPS_AUTOMATIC)
return 0;
ht_dbg(sdata,
"SMPS %d requested in AP mode, sending Action frame to %d stations\n",
smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
mutex_lock(&sdata->local->sta_mtx);
list_for_each_entry(sta, &sdata->local->sta_list, list) {
/*
* Only stations associated to our AP and
* associated VLANs
*/
if (sta->sdata->bss != &sdata->u.ap)
continue;
/* This station doesn't support MIMO - skip it */
if (sta_info_tx_streams(sta) == 1)
continue;
/*
* Don't wake up a STA just to send the action frame
* unless we are getting more restrictive.
*/
if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
!ieee80211_smps_is_restrictive(sta->known_smps_mode,
smps_mode)) {
ht_dbg(sdata, "Won't send SMPS to sleeping STA %pM\n",
sta->sta.addr);
continue;
}
/*
* If the STA is not authorized, wait until it gets
* authorized and the action frame will be sent then.
*/
if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
continue;
ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
ieee80211_send_smps_action(sdata, smps_mode, sta->sta.addr,
sdata->vif.bss_conf.bssid);
}
mutex_unlock(&sdata->local->sta_mtx);
sdata->smps_mode = smps_mode;
ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
return 0;
}
int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode)
{

View File

@ -150,6 +150,59 @@ static const struct file_operations aqm_ops = {
.llseek = default_llseek,
};
static ssize_t airtime_flags_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
char buf[128] = {}, *pos, *end;
pos = buf;
end = pos + sizeof(buf) - 1;
if (local->airtime_flags & AIRTIME_USE_TX)
pos += scnprintf(pos, end - pos, "AIRTIME_TX\t(%lx)\n",
AIRTIME_USE_TX);
if (local->airtime_flags & AIRTIME_USE_RX)
pos += scnprintf(pos, end - pos, "AIRTIME_RX\t(%lx)\n",
AIRTIME_USE_RX);
return simple_read_from_buffer(user_buf, count, ppos, buf,
strlen(buf));
}
static ssize_t airtime_flags_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
char buf[16];
size_t len;
if (count > sizeof(buf))
return -EINVAL;
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
buf[sizeof(buf) - 1] = 0;
len = strlen(buf);
if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = 0;
if (kstrtou16(buf, 0, &local->airtime_flags))
return -EINVAL;
return count;
}
static const struct file_operations airtime_flags_ops = {
.write = airtime_flags_write,
.read = airtime_flags_read,
.open = simple_open,
.llseek = default_llseek,
};
static ssize_t aql_txq_limit_read(struct file *file,
char __user *user_buf,
size_t count,
@ -522,8 +575,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
if (local->ops->wake_tx_queue)
DEBUGFS_ADD_MODE(aqm, 0600);
debugfs_create_u16("airtime_flags", 0600,
phyd, &local->airtime_flags);
DEBUGFS_ADD_MODE(airtime_flags, 0600);
DEBUGFS_ADD(aql_txq_limit);
debugfs_create_u32("aql_threshold", 0600,

View File

@ -2,6 +2,7 @@
/*
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2020 Intel Corporation
*/
#include <linux/kernel.h>
@ -254,15 +255,11 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
smps_mode == IEEE80211_SMPS_AUTOMATIC))
return -EINVAL;
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_AP)
if (sdata->vif.type != NL80211_IFTYPE_STATION)
return -EOPNOTSUPP;
sdata_lock(sdata);
if (sdata->vif.type == NL80211_IFTYPE_STATION)
err = __ieee80211_request_smps_mgd(sdata, smps_mode);
else
err = __ieee80211_request_smps_ap(sdata, smps_mode);
err = __ieee80211_request_smps_mgd(sdata, smps_mode);
sdata_unlock(sdata);
return err;
@ -282,10 +279,6 @@ static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
return snprintf(buf, buflen, "request: %s\nused: %s\n",
smps_modes[sdata->u.mgd.req_smps],
smps_modes[sdata->smps_mode]);
if (sdata->vif.type == NL80211_IFTYPE_AP)
return snprintf(buf, buflen, "request: %s\nused: %s\n",
smps_modes[sdata->u.ap.req_smps],
smps_modes[sdata->smps_mode]);
return -EINVAL;
}

View File

@ -1025,12 +1025,10 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered);
if (local->ops->wake_tx_queue)
if (local->ops->wake_tx_queue) {
DEBUGFS_ADD(aqm);
if (wiphy_ext_feature_isset(local->hw.wiphy,
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
DEBUGFS_ADD(airtime);
}
if (wiphy_ext_feature_isset(local->hw.wiphy,
NL80211_EXT_FEATURE_AQL))

View File

@ -3,6 +3,7 @@
* HE handling
*
* Copyright(c) 2017 Intel Deutschland GmbH
* Copyright(c) 2019 - 2020 Intel Corporation
*/
#include "ieee80211_i.h"
@ -49,6 +50,9 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
he_ppe_size);
he_cap->has_he = true;
sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(sta);
sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
}
void

View File

@ -9,6 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation
* Copyright 2017 Intel Deutschland GmbH
* Copyright(c) 2020 Intel Corporation
*/
#include <linux/ieee80211.h>
@ -144,7 +145,6 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
int i, max_tx_streams;
bool changed;
enum ieee80211_sta_rx_bandwidth bw;
enum ieee80211_smps_mode smps_mode;
memset(&ht_cap, 0, sizeof(ht_cap));
@ -270,24 +270,30 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS)
>> IEEE80211_HT_CAP_SM_PS_SHIFT) {
case WLAN_HT_CAP_SM_PS_INVALID:
case WLAN_HT_CAP_SM_PS_STATIC:
smps_mode = IEEE80211_SMPS_STATIC;
break;
case WLAN_HT_CAP_SM_PS_DYNAMIC:
smps_mode = IEEE80211_SMPS_DYNAMIC;
break;
case WLAN_HT_CAP_SM_PS_DISABLED:
smps_mode = IEEE80211_SMPS_OFF;
break;
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
enum ieee80211_smps_mode smps_mode;
switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS)
>> IEEE80211_HT_CAP_SM_PS_SHIFT) {
case WLAN_HT_CAP_SM_PS_INVALID:
case WLAN_HT_CAP_SM_PS_STATIC:
smps_mode = IEEE80211_SMPS_STATIC;
break;
case WLAN_HT_CAP_SM_PS_DYNAMIC:
smps_mode = IEEE80211_SMPS_DYNAMIC;
break;
case WLAN_HT_CAP_SM_PS_DISABLED:
smps_mode = IEEE80211_SMPS_OFF;
break;
}
if (smps_mode != sta->sta.smps_mode)
changed = true;
sta->sta.smps_mode = smps_mode;
} else {
sta->sta.smps_mode = IEEE80211_SMPS_OFF;
}
if (smps_mode != sta->sta.smps_mode)
changed = true;
sta->sta.smps_mode = smps_mode;
return changed;
}
@ -544,19 +550,6 @@ void ieee80211_request_smps_mgd_work(struct work_struct *work)
sdata_unlock(sdata);
}
void ieee80211_request_smps_ap_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data,
u.ap.request_smps_work);
sdata_lock(sdata);
if (sdata_dereference(sdata->u.ap.beacon, sdata))
__ieee80211_request_smps_ap(sdata,
sdata->u.ap.driver_smps_mode);
sdata_unlock(sdata);
}
void ieee80211_request_smps(struct ieee80211_vif *vif,
enum ieee80211_smps_mode smps_mode)
{
@ -572,15 +565,6 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
sdata->u.mgd.driver_smps_mode = smps_mode;
ieee80211_queue_work(&sdata->local->hw,
&sdata->u.mgd.request_smps_work);
} else {
/* AUTOMATIC is meaningless in AP mode */
if (WARN_ON_ONCE(smps_mode == IEEE80211_SMPS_AUTOMATIC))
return;
if (sdata->u.ap.driver_smps_mode == smps_mode)
return;
sdata->u.ap.driver_smps_mode = smps_mode;
ieee80211_queue_work(&sdata->local->hw,
&sdata->u.ap.request_smps_work);
}
}
/* this might change ... don't want non-open drivers using it */

View File

@ -5,7 +5,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2018-2019 Intel Corporation
* Copyright (C) 2018-2020 Intel Corporation
*/
#ifndef IEEE80211_I_H
@ -292,10 +292,7 @@ struct ieee80211_if_ap {
struct ps_data ps;
atomic_t num_mcast_sta; /* number of stations receiving multicast */
enum ieee80211_smps_mode req_smps, /* requested smps mode */
driver_smps_mode; /* smps mode request */
struct work_struct request_smps_work;
bool multicast_to_unicast;
};
@ -984,6 +981,8 @@ struct ieee80211_sub_if_data {
} debugfs;
#endif
bool hw_80211_encap;
/* must be last, dynamically sized area in this! */
struct ieee80211_vif vif;
};
@ -1473,6 +1472,7 @@ struct ieee802_11_elems {
const struct ieee80211_tim_ie *tim;
const u8 *challenge;
const u8 *rsn;
const u8 *rsnx;
const u8 *erp_info;
const u8 *ext_supp_rates;
const u8 *wmm_info;
@ -1520,6 +1520,7 @@ struct ieee802_11_elems {
u8 tim_len;
u8 challenge_len;
u8 rsn_len;
u8 rsnx_len;
u8 ext_supp_rates_len;
u8 wmm_info_len;
u8 wmm_param_len;
@ -1727,6 +1728,13 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_csa_settings *params);
/* interface handling */
#define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
NETIF_F_HW_CSUM | NETIF_F_SG | \
NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE)
#define MAC80211_SUPPORTED_FEATURES_RX (NETIF_F_RXCSUM)
#define MAC80211_SUPPORTED_FEATURES (MAC80211_SUPPORTED_FEATURES_TX | \
MAC80211_SUPPORTED_FEATURES_RX)
int ieee80211_iface_init(void);
void ieee80211_iface_exit(void);
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
@ -1762,6 +1770,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev);
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);
netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
struct net_device *dev);
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
u32 info_flags,
@ -1782,7 +1792,8 @@ void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
void ieee80211_clear_fast_xmit(struct sta_info *sta);
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, __be16 proto, bool unencrypted);
const u8 *dest, const u8 *src, __be16 proto,
bool unencrypted);
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len);
@ -1948,6 +1959,11 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid,
enum nl80211_band band, u32 txdata_flags);
/* sta_out needs to be checked for ERR_PTR() before using */
int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct sta_info **sta_out);
static inline void
ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid,
@ -2132,8 +2148,6 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
enum nl80211_band band, u32 *basic_rates);
int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);

View File

@ -8,7 +8,7 @@
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 Intel Deutschland GmbH
* Copyright (C) 2018 Intel Corporation
* Copyright (C) 2018-2020 Intel Corporation
*/
#include <linux/slab.h>
#include <linux/kernel.h>
@ -824,9 +824,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_ADHOC:
ieee80211_ibss_stop(sdata);
break;
case NL80211_IFTYPE_AP:
cancel_work_sync(&sdata->u.ap.request_smps_work);
break;
case NL80211_IFTYPE_MONITOR:
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
break;
@ -1205,6 +1202,72 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
.ndo_get_stats64 = ieee80211_get_stats64,
};
static const struct net_device_ops ieee80211_dataif_8023_ops = {
.ndo_open = ieee80211_open,
.ndo_stop = ieee80211_stop,
.ndo_uninit = ieee80211_uninit,
.ndo_start_xmit = ieee80211_subif_start_xmit_8023,
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_netdev_select_queue,
.ndo_get_stats64 = ieee80211_get_stats64,
};
static void __ieee80211_set_hw_80211_encap(struct ieee80211_sub_if_data *sdata,
bool enable)
{
sdata->dev->netdev_ops = enable ? &ieee80211_dataif_8023_ops :
&ieee80211_dataif_ops;
sdata->hw_80211_encap = enable;
}
bool ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *iter;
struct ieee80211_key *key;
mutex_lock(&local->iflist_mtx);
list_for_each_entry(iter, &local->interfaces, list) {
struct ieee80211_sub_if_data *disable = NULL;
if (vif->type == NL80211_IFTYPE_MONITOR) {
disable = iter;
__ieee80211_set_hw_80211_encap(iter, false);
} else if (iter->vif.type == NL80211_IFTYPE_MONITOR) {
disable = sdata;
enable = false;
}
if (disable)
sdata_dbg(disable,
"disable hw 80211 encap due to mon co-exist\n");
}
mutex_unlock(&local->iflist_mtx);
if (enable == sdata->hw_80211_encap)
return enable;
if (!sdata->dev)
return false;
if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
(local->hw.wiphy->frag_threshold != (u32)-1))
enable = false;
mutex_lock(&sdata->local->key_mtx);
list_for_each_entry(key, &sdata->key_list, list) {
if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
enable = false;
}
mutex_unlock(&sdata->local->key_mtx);
__ieee80211_set_hw_80211_encap(sdata, enable);
return enable;
}
EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
static void ieee80211_if_free(struct net_device *dev)
{
free_percpu(dev->tstats);
@ -1402,8 +1465,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->control_port_no_encrypt = false;
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
sdata->vif.bss_conf.idle = true;
sdata->vif.bss_conf.txpower = INT_MIN; /* unset */
sdata->noack_map = 0;
sdata->hw_80211_encap = false;
/* only monitor/p2p-device differ */
if (sdata->dev) {
@ -1427,10 +1492,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP:
skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
INIT_LIST_HEAD(&sdata->u.ap.vlans);
INIT_WORK(&sdata->u.ap.request_smps_work,
ieee80211_request_smps_ap_work);
sdata->vif.bss_conf.bssid = sdata->vif.addr;
sdata->u.ap.req_smps = IEEE80211_SMPS_OFF;
break;
case NL80211_IFTYPE_P2P_CLIENT:
type = NL80211_IFTYPE_STATION;
@ -1772,6 +1834,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
if_setup, txqs, 1);
if (!ndev)
return -ENOMEM;
if (!local->ops->wake_tx_queue && local->hw.wiphy->tx_queue_len)
ndev->tx_queue_len = local->hw.wiphy->tx_queue_len;
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
ndev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
@ -1871,6 +1937,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sdata->u.mgd.use_4addr = params->use_4addr;
ndev->features |= local->hw.netdev_features;
ndev->hw_features |= ndev->features &
MAC80211_SUPPORTED_FEATURES_TX;
netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);

View File

@ -177,6 +177,13 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
}
}
/* TKIP countermeasures don't work in encap offload mode */
if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
sdata->hw_80211_encap) {
sdata_dbg(sdata, "TKIP is not allowed in hw 80211 encap mode\n");
return -EINVAL;
}
ret = drv_set_key(key->local, SET_KEY, sdata,
sta ? &sta->sta : NULL, &key->conf);
@ -210,12 +217,20 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
/* We cannot do software crypto of data frames with
* encapsulation offload enabled. However for 802.11w to
* function properly we need cmac/gmac keys.
*/
if (sdata->hw_80211_encap)
return -EINVAL;
/* Fall through */
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
/* all of these we can do in software - if driver can */
if (ret == 1)
return 0;

View File

@ -146,6 +146,8 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
continue;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
continue;
if (sdata->vif.bss_conf.txpower == INT_MIN)
continue;
power = min(power, sdata->vif.bss_conf.txpower);
}
rcu_read_unlock();
@ -416,7 +418,20 @@ ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
[NL80211_IFTYPE_STATION] = {
.tx = 0xffff,
/*
* To support Pre Association Security Negotiation (PASN) while
* already associated to one AP, allow user space to register to
* Rx authentication frames, so that the user space logic would
* be able to receive/handle authentication frames from a
* different AP as part of PASN.
* It is expected that user space would intelligently register
* for Rx authentication frames, i.e., only when PASN is used
* and configure a match filter only for PASN authentication
* algorithm, as otherwise the MLME functionality of mac80211
* would be broken.
*/
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
},
[NL80211_IFTYPE_AP] = {
@ -574,6 +589,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA);
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211);
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_MAC_ADDRS);
if (!ops->hw_scan) {
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
@ -872,7 +889,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
enum nl80211_band band;
int channels, max_bitrates;
bool supp_ht, supp_vht, supp_he;
netdev_features_t feature_whitelist;
struct cfg80211_chan_def dflt_chandef = {};
if (ieee80211_hw_check(hw, QUEUE_CONTROL) &&
@ -931,10 +947,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
/* Only HW csum features are currently compatible with mac80211 */
feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA |
NETIF_F_GSO_SOFTWARE | NETIF_F_RXCSUM;
if (WARN_ON(hw->netdev_features & ~feature_whitelist))
if (WARN_ON(hw->netdev_features & ~MAC80211_SUPPORTED_FEATURES))
return -EINVAL;
if (hw->max_report_rates == 0)
@ -981,6 +994,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (!supp_he)
supp_he = !!ieee80211_get_he_sta_cap(sband);
/* HT, VHT, HE require QoS, thus >= 4 queues */
if (WARN_ON(local->hw.queues < IEEE80211_NUM_ACS &&
(supp_ht || supp_vht || supp_he)))
return -EINVAL;
if (!sband->ht_cap.ht_supported)
continue;
@ -1184,10 +1202,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (!local->hw.weight_multiplier)
local->hw.weight_multiplier = 1;
result = ieee80211_wep_init(local);
if (result < 0)
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
result);
ieee80211_wep_init(local);
local->hw.conf.flags = IEEE80211_CONF_IDLE;

View File

@ -164,7 +164,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
chandef->center_freq1 = channel->center_freq;
if (!ht_oper || !sta_ht_cap.ht_supported) {
ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
ret = IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT |
IEEE80211_STA_DISABLE_HE;
goto out;
}
@ -185,7 +187,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
"Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
channel->center_freq, ht_cfreq,
ht_oper->primary_chan, channel->band);
ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
ret = IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT |
IEEE80211_STA_DISABLE_HE;
goto out;
}
@ -301,13 +305,18 @@ out:
IEEE80211_CHAN_DISABLED)) {
if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
ret = IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT;
IEEE80211_STA_DISABLE_VHT |
IEEE80211_STA_DISABLE_HE;
break;
}
ret |= ieee80211_chandef_downgrade(chandef);
}
if (!he_oper || !cfg80211_chandef_usable(sdata->wdev.wiphy, chandef,
IEEE80211_CHAN_NO_HE))
ret |= IEEE80211_STA_DISABLE_HE;
if (chandef->width != vht_chandef.width && !tracking)
sdata_info(sdata,
"capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
@ -393,6 +402,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT |
IEEE80211_STA_DISABLE_HE |
IEEE80211_STA_DISABLE_40MHZ |
IEEE80211_STA_DISABLE_80P80MHZ |
IEEE80211_STA_DISABLE_160MHZ)) ||
@ -616,10 +626,21 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
{
u8 *pos;
const struct ieee80211_sta_he_cap *he_cap = NULL;
struct ieee80211_chanctx_conf *chanctx_conf;
u8 he_cap_size;
bool reg_cap = false;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!WARN_ON_ONCE(!chanctx_conf))
reg_cap = cfg80211_chandef_usable(sdata->wdev.wiphy,
&chanctx_conf->def,
IEEE80211_CHAN_NO_HE);
rcu_read_unlock();
he_cap = ieee80211_get_he_sta_cap(sband);
if (!he_cap)
if (!he_cap || !reg_cap)
return;
/*
@ -650,6 +671,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
u32 rates = 0;
struct element *ext_capa = NULL;
/* we know it's writable, cast away the const */
if (assoc_data->ie_len)
ext_capa = (void *)cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
assoc_data->ie,
assoc_data->ie_len);
sdata_assert_lock(sdata);
@ -800,7 +828,15 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
*pos++ = ieee80211_chandef_max_power(&chanctx_conf->def);
}
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
/*
* Per spec, we shouldn't include the list of channels if we advertise
* support for extended channel switching, but we've always done that;
* (for now?) apply this restriction only on the (new) 6 GHz band.
*/
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT &&
(sband->band != NL80211_BAND_6GHZ ||
!ext_capa || ext_capa->datalen < 1 ||
!(ext_capa->data[0] & WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING))) {
/* TODO: get this in reg domain format */
pos = skb_put(skb, 2 * sband->n_channels + 2);
*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
@ -814,18 +850,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
/* Set MBSSID support for HE AP if needed */
if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len) {
struct element *elem;
/* we know it's writable, cast away the const */
elem = (void *)cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY,
assoc_data->ie,
assoc_data->ie_len);
/* We can probably assume both always true */
if (elem && elem->datalen >= 3)
elem->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
}
!(ifmgd->flags & IEEE80211_STA_DISABLE_HE) && assoc_data->ie_len &&
ext_capa && ext_capa->datalen >= 3)
ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
/* if present, add any custom IEs that go before HT */
if (assoc_data->ie_len) {
@ -2460,7 +2487,7 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
if (!ieee80211_is_data(hdr->frame_control))
return;
if (ieee80211_is_nullfunc(hdr->frame_control) &&
if (ieee80211_is_any_nullfunc(hdr->frame_control) &&
sdata->u.mgd.probe_send_count > 0) {
if (ack)
ieee80211_sta_reset_conn_monitor(sdata);
@ -3368,9 +3395,16 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
}
if (bss_conf->he_support) {
bss_conf->bss_color =
bss_conf->he_bss_color.color =
le32_get_bits(elems->he_operation->he_oper_params,
IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
bss_conf->he_bss_color.partial =
le32_get_bits(elems->he_operation->he_oper_params,
IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR);
bss_conf->he_bss_color.disabled =
le32_get_bits(elems->he_operation->he_oper_params,
IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED);
changed |= BSS_CHANGED_HE_BSS_COLOR;
bss_conf->htc_trig_based_pkt_ext =
le32_get_bits(elems->he_operation->he_oper_params,
@ -3649,13 +3683,28 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt = (void *)skb->data;
struct ieee80211_if_managed *ifmgd;
struct ieee80211_rx_status *rx_status = (void *) skb->cb;
struct ieee80211_channel *channel;
size_t baselen, len = skb->len;
ifmgd = &sdata->u.mgd;
sdata_assert_lock(sdata);
if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
/*
* According to Draft P802.11ax D6.0 clause 26.17.2.3.2:
* "If a 6 GHz AP receives a Probe Request frame and responds with
* a Probe Response frame [..], the Address 1 field of the Probe
* Response frame shall be set to the broadcast address [..]"
* So, on 6GHz band we should also accept broadcast responses.
*/
channel = ieee80211_get_channel(sdata->local->hw.wiphy,
rx_status->freq);
if (!channel)
return;
if (!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
(channel->band != NL80211_BAND_6GHZ ||
!is_broadcast_ether_addr(mgmt->da)))
return; /* ignore ProbeResp to foreign address */
baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
@ -4753,10 +4802,22 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
IEEE80211_STA_DISABLE_80P80MHZ |
IEEE80211_STA_DISABLE_160MHZ);
/* disable HT/VHT/HE if we don't support them */
if (!sband->ht_cap.ht_supported) {
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
}
if (!sband->vht_cap.vht_supported)
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
if (!ieee80211_get_he_sta_cap(sband))
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
rcu_read_lock();
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
sband->ht_cap.ht_supported) {
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
const u8 *ht_oper_ie, *ht_cap_ie;
ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
@ -4773,8 +4834,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
}
}
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
sband->vht_cap.vht_supported) {
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
const u8 *vht_oper_ie, *vht_cap;
vht_oper_ie = ieee80211_bss_get_ie(cbss,
@ -4784,9 +4844,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
if (vht_oper && !ht_oper) {
vht_oper = NULL;
sdata_info(sdata,
"AP advertised VHT without HT, disabling both\n");
"AP advertised VHT without HT, disabling HT/VHT/HE\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
}
vht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_VHT_CAPABILITY);
@ -4796,9 +4857,6 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
}
}
if (!ieee80211_get_he_sta_cap(sband))
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE)) {
const struct cfg80211_bss_ies *ies;
const u8 *he_oper_ie;
@ -5297,27 +5355,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
}
}
/* Also disable HT if we don't support it or the AP doesn't use WMM */
sband = local->hw.wiphy->bands[req->bss->channel->band];
if (!sband->ht_cap.ht_supported ||
local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
if (!bss->wmm_used &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
netdev_info(sdata->dev,
"disabling HT as WMM/QoS is not supported by the AP\n");
}
/* disable VHT if we don't support it or the AP doesn't use WMM */
if (!sband->vht_cap.vht_supported ||
local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used ||
ifmgd->flags & IEEE80211_STA_DISABLE_WMM) {
/* also disable HT/VHT/HE if the AP doesn't use WMM */
if (!bss->wmm_used) {
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
if (!bss->wmm_used &&
!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM))
netdev_info(sdata->dev,
"disabling VHT as WMM/QoS is not supported by the AP\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
netdev_info(sdata->dev,
"disabling HT/VHT/HE as WMM/QoS is not supported by the AP\n");
}
memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
@ -5449,6 +5495,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
if (req->flags & ASSOC_REQ_DISABLE_HT) {
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
}
if (req->flags & ASSOC_REQ_DISABLE_VHT)

View File

@ -6,7 +6,7 @@
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
* Copyright (C) 2018-2019 Intel Corporation
* Copyright (C) 2018-2020 Intel Corporation
*/
#include <linux/jiffies.h>
@ -1450,8 +1450,7 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
if (ieee80211_is_ctl(hdr->frame_control) ||
ieee80211_is_nullfunc(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control) ||
ieee80211_is_any_nullfunc(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1))
return RX_CONTINUE;
@ -1838,8 +1837,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
* Drop (qos-)data::nullfunc frames silently, since they
* are used only to control station power saving mode.
*/
if (ieee80211_is_nullfunc(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control)) {
if (ieee80211_is_any_nullfunc(hdr->frame_control)) {
I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
/*
@ -2319,7 +2317,7 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
/* Drop unencrypted frames if key is set. */
if (unlikely(!ieee80211_has_protected(fc) &&
!ieee80211_is_nullfunc(fc) &&
!ieee80211_is_any_nullfunc(fc) &&
ieee80211_is_data(fc) && rx->key))
return -EACCES;
@ -3084,6 +3082,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
enum ieee80211_smps_mode smps_mode;
struct sta_opmode_info sta_opmode = {};
if (sdata->vif.type != NL80211_IFTYPE_AP &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
goto handled;
/* convert to HT capability */
switch (mgmt->u.action.u.ht_smps.smps_control) {
case WLAN_HT_SMPS_CONTROL_DISABLED:

View File

@ -4,7 +4,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015 - 2017 Intel Deutschland GmbH
* Copyright (C) 2018-2019 Intel Corporation
* Copyright (C) 2018-2020 Intel Corporation
*/
#include <linux/module.h>
@ -1351,20 +1351,6 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
atomic_dec(&ps->num_sta_ps);
/* This station just woke up and isn't aware of our SMPS state */
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
!ieee80211_smps_is_restrictive(sta->known_smps_mode,
sdata->smps_mode) &&
sta->known_smps_mode != sdata->bss->req_smps &&
sta_info_tx_streams(sta) != 1) {
ht_dbg(sdata,
"%pM just woke up and MIMO capable - update SMPS\n",
sta->sta.addr);
ieee80211_send_smps_action(sdata, sdata->bss->req_smps,
sta->sta.addr,
sdata->vif.bss_conf.bssid);
}
local->total_ps_buffered -= buffered;
sta_info_recalc_tim(sta);

View File

@ -643,8 +643,7 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
rcu_read_lock();
sdata = ieee80211_sdata_from_skb(local, skb);
if (sdata) {
if (ieee80211_is_nullfunc(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control))
if (ieee80211_is_any_nullfunc(hdr->frame_control))
cfg80211_probe_status(sdata->dev, hdr->addr1,
cookie, acked,
info->status.ack_signal,
@ -888,6 +887,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
int rates_idx;
bool send_to_cooked;
bool acked;
bool noack_success;
struct ieee80211_bar *bar;
int shift = 0;
int tid = IEEE80211_NUM_TIDS;
@ -906,6 +906,8 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
clear_sta_flag(sta, WLAN_STA_SP);
acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
noack_success = !!(info->flags &
IEEE80211_TX_STAT_NOACK_TRANSMITTED);
/* mesh Peer Service Period support */
if (ieee80211_vif_is_mesh(&sta->sdata->vif) &&
@ -970,12 +972,12 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
ieee80211_handle_filtered_frame(local, sta, skb);
return;
} else {
if (!acked)
if (!acked && !noack_success)
sta->status_stats.retry_failed++;
sta->status_stats.retry_count += retry_count;
if (ieee80211_is_data_present(fc)) {
if (!acked)
if (!acked && !noack_success)
sta->status_stats.msdu_failed[tid]++;
sta->status_stats.msdu_retries[tid] +=
@ -1013,7 +1015,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
}
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
if (info->flags & IEEE80211_TX_STAT_ACK) {
if (acked) {
if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
@ -1021,6 +1023,8 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
sta->status_stats.last_tdls_pkt_time =
jiffies;
} else if (noack_success) {
/* nothing to do here, do not account as lost */
} else {
ieee80211_lost_packet(sta, info);
}
@ -1056,7 +1060,7 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
I802_DEBUG_INC(local->dot11FailedCount);
}
if ((ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
if (ieee80211_is_any_nullfunc(fc) &&
ieee80211_has_pm(fc) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS) &&
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
@ -1141,7 +1145,7 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
sta = container_of(pubsta, struct sta_info, sta);
if (!acked)
if (!acked && !noack_success)
sta->status_stats.retry_failed++;
sta->status_stats.retry_count += retry_count;
@ -1156,6 +1160,8 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
sta->status_stats.last_tdls_pkt_time = jiffies;
} else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
return;
} else if (noack_success) {
/* nothing to do here, do not account as lost */
} else {
ieee80211_lost_packet(sta, info);
}
@ -1198,6 +1204,77 @@ void ieee80211_tx_rate_update(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_tx_rate_update);
void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct sta_info *sta;
int retry_count;
int rates_idx;
bool acked;
sdata = vif_to_sdata(vif);
acked = info->flags & IEEE80211_TX_STAT_ACK;
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
rcu_read_lock();
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
goto counters_update;
if (IS_ERR(sta))
goto counters_update;
if (!acked)
sta->status_stats.retry_failed++;
if (rates_idx != -1)
sta->tx_stats.last_rate = info->status.rates[rates_idx];
sta->status_stats.retry_count += retry_count;
if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
if (acked && vif->type == NL80211_IFTYPE_STATION)
ieee80211_sta_reset_conn_monitor(sdata);
sta->status_stats.last_ack = jiffies;
if (info->flags & IEEE80211_TX_STAT_ACK) {
if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
sta->status_stats.last_tdls_pkt_time = jiffies;
} else {
ieee80211_lost_packet(sta, info);
}
}
counters_update:
rcu_read_unlock();
ieee80211_led_tx(local);
if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED))
goto skip_stats_update;
I802_DEBUG_INC(local->dot11TransmittedFrameCount);
if (is_multicast_ether_addr(skb->data))
I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
if (retry_count > 0)
I802_DEBUG_INC(local->dot11RetryCount);
if (retry_count > 1)
I802_DEBUG_INC(local->dot11MultipleRetryCount);
skip_stats_update:
ieee80211_report_used_skb(local, skb, false);
dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status_8023);
void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);

View File

@ -297,7 +297,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) &&
test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) &&
!ieee80211_is_probe_req(hdr->frame_control) &&
!ieee80211_is_nullfunc(hdr->frame_control))
!ieee80211_is_any_nullfunc(hdr->frame_control))
/*
* When software scanning only nullfunc frames (to notify
* the sleep state to the AP) and probe requests (for the
@ -1250,7 +1250,8 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
return NULL;
if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) &&
unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
if ((!ieee80211_is_mgmt(hdr->frame_control) ||
ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
vif->type == NL80211_IFTYPE_STATION) &&
@ -2360,9 +2361,9 @@ static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb)
skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
}
static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct sta_info **sta_out)
int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct sta_info **sta_out)
{
struct sta_info *sta;
@ -3616,6 +3617,9 @@ begin:
else
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
goto encap_out;
if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
struct sta_info *sta = container_of(txq->sta, struct sta_info,
sta);
@ -3675,6 +3679,7 @@ begin:
break;
}
encap_out:
IEEE80211_SKB_CB(skb)->control.vif = vif;
if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
@ -4103,6 +4108,153 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int led_len,
struct sta_info *sta,
bool txpending)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_control control = {};
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *pubsta = NULL;
unsigned long flags;
int q = info->hw_queue;
if (ieee80211_queue_skb(local, sdata, sta, skb))
return true;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
if (local->queue_stop_reasons[q] ||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
if (txpending)
skb_queue_head(&local->pending[q], skb);
else
skb_queue_tail(&local->pending[q], skb);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return false;
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
if (sta && sta->uploaded)
pubsta = &sta->sta;
control.sta = pubsta;
drv_tx(local, &control, skb);
return true;
}
static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
struct net_device *dev, struct sta_info *sta,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ethhdr *ehdr = (struct ethhdr *)skb->data;
struct ieee80211_local *local = sdata->local;
bool authorized = false;
bool multicast;
unsigned char *ra = ehdr->h_dest;
if (IS_ERR(sta) || (sta && !sta->uploaded))
sta = NULL;
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
(!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER)))
ra = sdata->u.mgd.bssid;
if (!is_valid_ether_addr(ra))
goto out_free;
multicast = is_multicast_ether_addr(ra);
if (sta)
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
if (!multicast && !authorized &&
(ehdr->h_proto != sdata->control_port_protocol ||
!ether_addr_equal(sdata->vif.addr, ehdr->h_source)))
goto out_free;
if (multicast && sdata->vif.type == NL80211_IFTYPE_AP &&
!atomic_read(&sdata->u.ap.num_mcast_sta))
goto out_free;
if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
goto out_free;
if (unlikely(!multicast && skb->sk &&
skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
ieee80211_store_ack_skb(local, skb, &info->flags);
memset(info, 0, sizeof(*info));
if (unlikely(sdata->control_port_protocol == ehdr->h_proto)) {
if (sdata->control_port_no_encrypt)
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
}
if (multicast)
info->flags |= IEEE80211_TX_CTL_NO_ACK;
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
ieee80211_tx_stats(dev, skb->len);
if (sta) {
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
}
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap);
info->control.flags |= IEEE80211_TX_CTRL_HW_80211_ENCAP;
info->control.vif = &sdata->vif;
ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
return;
out_free:
kfree_skb(skb);
}
netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
if (WARN_ON(!sdata->hw_80211_encap)) {
kfree_skb(skb);
return NETDEV_TX_OK;
}
if (unlikely(skb->len < ETH_HLEN)) {
kfree_skb(skb);
return NETDEV_TX_OK;
}
rcu_read_lock();
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
kfree_skb(skb);
else
ieee80211_8023_xmit(sdata, dev, sta, skb);
rcu_read_unlock();
return NETDEV_TX_OK;
}
struct sk_buff *
ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 info_flags)
@ -4181,6 +4333,16 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
}
info->band = chanctx_conf->def.chan->band;
result = ieee80211_tx(sdata, NULL, skb, true, 0);
} else if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
dev_kfree_skb(skb);
return true;
}
if (IS_ERR(sta) || (sta && !sta->uploaded))
sta = NULL;
result = ieee80211_tx_8023(sdata, skb, skb->len, sta, true);
} else {
struct sk_buff_head skbs;
@ -5120,7 +5282,8 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, __be16 proto, bool unencrypted)
const u8 *dest, const u8 *src, __be16 proto,
bool unencrypted)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
@ -5151,7 +5314,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
ehdr = skb_push(skb, sizeof(struct ethhdr));
memcpy(ehdr->h_dest, dest, ETH_ALEN);
memcpy(ehdr->h_source, sdata->vif.addr, ETH_ALEN);
memcpy(ehdr->h_source, src, ETH_ALEN);
ehdr->h_proto = proto;
skb->dev = dev;

View File

@ -6,7 +6,7 @@
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2019 Intel Corporation
* Copyright (C) 2018-2020 Intel Corporation
*
* utilities for mac80211
*/
@ -39,7 +39,6 @@ const void *const mac80211_wiphy_privid = &mac80211_wiphy_privid;
struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
{
struct ieee80211_local *local;
BUG_ON(!wiphy);
local = wiphy_priv(wiphy);
return &local->hw;
@ -891,6 +890,51 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
static void ieee80211_parse_extension_element(u32 *crc,
const struct element *elem,
struct ieee802_11_elems *elems)
{
const void *data = elem->data + 1;
u8 len = elem->datalen - 1;
switch (elem->data[0]) {
case WLAN_EID_EXT_HE_MU_EDCA:
if (len == sizeof(*elems->mu_edca_param_set)) {
elems->mu_edca_param_set = data;
if (crc)
*crc = crc32_be(*crc, (void *)elem,
elem->datalen + 2);
}
break;
case WLAN_EID_EXT_HE_CAPABILITY:
elems->he_cap = data;
elems->he_cap_len = len;
break;
case WLAN_EID_EXT_HE_OPERATION:
if (len >= sizeof(*elems->he_operation) &&
len == ieee80211_he_oper_size(data) - 1)
elems->he_operation = data;
break;
case WLAN_EID_EXT_UORA:
if (len == 1)
elems->uora_element = data;
break;
case WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME:
if (len == 3)
elems->max_channel_switch_time = data;
break;
case WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION:
if (len == sizeof(*elems->mbssid_config_ie))
elems->mbssid_config_ie = data;
break;
case WLAN_EID_EXT_HE_SPR:
if (len >= sizeof(*elems->he_spr) &&
len >= ieee80211_he_spr_size(data))
elems->he_spr = data;
break;
}
}
static u32
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems,
@ -950,6 +994,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
case WLAN_EID_CHAN_SWITCH_TIMING:
case WLAN_EID_LINK_ID:
case WLAN_EID_BSS_MAX_IDLE_PERIOD:
case WLAN_EID_RSNX:
/*
* not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
* that if the content gets bigger it might be needed more than once
@ -1226,34 +1271,14 @@ _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_RSNX:
elems->rsnx = pos;
elems->rsnx_len = elen;
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];
if (calc_crc)
crc = crc32_be(crc, pos - 2, elen + 2);
} 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];
} else if (pos[0] ==
WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME &&
elen == 4) {
elems->max_channel_switch_time = pos + 1;
} else if (pos[0] ==
WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION &&
elen == 3) {
elems->mbssid_config_ie = (void *)&pos[1];
} else if (pos[0] == WLAN_EID_EXT_HE_SPR &&
elen >= sizeof(*elems->he_spr) &&
elen >= ieee80211_he_spr_size(&pos[1])) {
elems->he_spr = (void *)&pos[1];
}
ieee80211_parse_extension_element(calc_crc ?
&crc : NULL,
elem, elems);
break;
default:
break;

View File

@ -333,11 +333,33 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
}
}
/* FIXME: move this to some better location - parses HE now */
enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta)
{
struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
struct ieee80211_sta_he_cap *he_cap = &sta->sta.he_cap;
u32 cap_width;
if (he_cap->has_he) {
u8 info = he_cap->he_cap_elem.phy_cap_info[0];
if (sta->sdata->vif.bss_conf.chandef.chan->band ==
NL80211_BAND_2GHZ) {
if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G)
return IEEE80211_STA_RX_BW_40;
else
return IEEE80211_STA_RX_BW_20;
}
if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G ||
info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
return IEEE80211_STA_RX_BW_160;
else if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)
return IEEE80211_STA_RX_BW_80;
return IEEE80211_STA_RX_BW_20;
}
if (!vht_cap->vht_supported)
return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
IEEE80211_STA_RX_BW_40 :
@ -433,6 +455,7 @@ ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
}
}
/* FIXME: rename/move - this deals with everything not just VHT */
enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
@ -458,12 +481,40 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
void ieee80211_sta_set_rx_nss(struct sta_info *sta)
{
u8 ht_rx_nss = 0, vht_rx_nss = 0;
u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, rx_nss;
/* if we received a notification already don't overwrite it */
if (sta->sta.rx_nss)
return;
if (sta->sta.he_cap.has_he) {
int i;
u8 rx_mcs_80 = 0, rx_mcs_160 = 0;
const struct ieee80211_sta_he_cap *he_cap = &sta->sta.he_cap;
u16 mcs_160_map =
le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
u16 mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
for (i = 7; i >= 0; i--) {
u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3;
if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
rx_mcs_160 = i + 1;
break;
}
}
for (i = 7; i >= 0; i--) {
u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3;
if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
rx_mcs_80 = i + 1;
break;
}
}
he_rx_nss = min(rx_mcs_80, rx_mcs_160);
}
if (sta->sta.ht_cap.ht_supported) {
if (sta->sta.ht_cap.mcs.rx_mask[0])
ht_rx_nss++;
@ -493,8 +544,9 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta)
/* FIXME: consider rx_highest? */
}
ht_rx_nss = max(ht_rx_nss, vht_rx_nss);
sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss);
rx_nss = max(vht_rx_nss, ht_rx_nss);
rx_nss = max(he_rx_nss, rx_nss);
sta->sta.rx_nss = max_t(u8, 1, rx_nss);
}
u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,

View File

@ -22,12 +22,10 @@
#include "wep.h"
int ieee80211_wep_init(struct ieee80211_local *local)
void ieee80211_wep_init(struct ieee80211_local *local)
{
/* start WEP IV from a random value */
get_random_bytes(&local->wep_iv, IEEE80211_WEP_IV_LEN);
return 0;
}
static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen)

View File

@ -13,7 +13,7 @@
#include "ieee80211_i.h"
#include "key.h"
int ieee80211_wep_init(struct ieee80211_local *local);
void ieee80211_wep_init(struct ieee80211_local *local);
int ieee80211_wep_encrypt_data(struct arc4_ctx *ctx, u8 *rc4key,
size_t klen, u8 *data, size_t data_len);
int ieee80211_wep_encrypt(struct ieee80211_local *local,

View File

@ -385,7 +385,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
struct net_device *dev);
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
u16 frame_type, const u8 *match_data,
int match_len);
int match_len, struct netlink_ext_ack *extack);
void cfg80211_mlme_unreg_wk(struct work_struct *wk);
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);

View File

@ -4,6 +4,7 @@
*
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2015 Intel Deutschland GmbH
* Copyright (C) 2019 Intel Corporation
*/
#include <linux/kernel.h>
@ -470,7 +471,7 @@ void cfg80211_mlme_unreg_wk(struct work_struct *wk)
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
u16 frame_type, const u8 *match_data,
int match_len)
int match_len, struct netlink_ext_ack *extack)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@ -481,15 +482,38 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
if (!wdev->wiphy->mgmt_stypes)
return -EOPNOTSUPP;
if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) {
NL_SET_ERR_MSG(extack, "frame type not management");
return -EINVAL;
}
if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) {
NL_SET_ERR_MSG(extack, "Invalid frame type");
return -EINVAL;
}
mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type)))
if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) {
NL_SET_ERR_MSG(extack,
"Registration to specific type not supported");
return -EINVAL;
}
/*
* To support Pre Association Security Negotiation (PASN), registration
* for authentication frames should be supported. However, as some
* versions of the user space daemons wrongly register to all types of
* authentication frames (which might result in unexpected behavior)
* allow such registration if the request is for a specific
* authentication algorithm number.
*/
if (wdev->iftype == NL80211_IFTYPE_STATION &&
(frame_type & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_AUTH &&
!(match_data && match_len >= 2)) {
NL_SET_ERR_MSG(extack,
"Authentication algorithm number required");
return -EINVAL;
}
nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
if (!nreg)
@ -504,6 +528,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
continue;
if (memcmp(reg->match, match_data, mlen) == 0) {
NL_SET_ERR_MSG(extack, "Match already configured");
err = -EALREADY;
break;
}

View File

@ -321,6 +321,13 @@ he_obss_pd_policy[NL80211_HE_OBSS_PD_ATTR_MAX + 1] = {
NLA_POLICY_RANGE(NLA_U8, 1, 20),
};
static const struct nla_policy
he_bss_color_policy[NL80211_HE_BSS_COLOR_ATTR_MAX + 1] = {
[NL80211_HE_BSS_COLOR_ATTR_COLOR] = NLA_POLICY_RANGE(NLA_U8, 1, 63),
[NL80211_HE_BSS_COLOR_ATTR_DISABLED] = { .type = NLA_FLAG },
[NL80211_HE_BSS_COLOR_ATTR_PARTIAL] = { .type = NLA_FLAG },
};
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@ -626,6 +633,9 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG },
[NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
[NL80211_ATTR_VLAN_ID] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2),
[NL80211_ATTR_HE_BSS_COLOR] = NLA_POLICY_NESTED(he_bss_color_policy),
[NL80211_ATTR_SRC_MAC] = NLA_POLICY_ETH_ADDR,
[NL80211_ATTR_DST_MAC] = NLA_POLICY_ETH_ADDR,
};
/* policy for the key attributes */
@ -965,6 +975,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
goto nla_put_failure;
if ((chan->flags & IEEE80211_CHAN_NO_HE) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HE))
goto nla_put_failure;
}
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
@ -1886,6 +1899,46 @@ static int nl80211_send_pmsr_capa(struct cfg80211_registered_device *rdev,
return 0;
}
static int
nl80211_put_iftype_akm_suites(struct cfg80211_registered_device *rdev,
struct sk_buff *msg)
{
int i;
struct nlattr *nested, *nested_akms;
const struct wiphy_iftype_akm_suites *iftype_akms;
if (!rdev->wiphy.num_iftype_akm_suites ||
!rdev->wiphy.iftype_akm_suites)
return 0;
nested = nla_nest_start(msg, NL80211_ATTR_IFTYPE_AKM_SUITES);
if (!nested)
return -ENOBUFS;
for (i = 0; i < rdev->wiphy.num_iftype_akm_suites; i++) {
nested_akms = nla_nest_start(msg, i + 1);
if (!nested_akms)
return -ENOBUFS;
iftype_akms = &rdev->wiphy.iftype_akm_suites[i];
if (nl80211_put_iftypes(msg, NL80211_IFTYPE_AKM_ATTR_IFTYPES,
iftype_akms->iftypes_mask))
return -ENOBUFS;
if (nla_put(msg, NL80211_IFTYPE_AKM_ATTR_SUITES,
sizeof(u32) * iftype_akms->n_akm_suites,
iftype_akms->akm_suites)) {
return -ENOBUFS;
}
nla_nest_end(msg, nested_akms);
}
nla_nest_end(msg, nested);
return 0;
}
struct nl80211_dump_wiphy_state {
s64 filter_wiphy;
long start;
@ -2444,6 +2497,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
rdev->wiphy.akm_suites))
goto nla_put_failure;
if (nl80211_put_iftype_akm_suites(rdev, msg))
goto nla_put_failure;
/* done */
state->split_start = 0;
break;
@ -4512,6 +4568,30 @@ static int nl80211_parse_he_obss_pd(struct nlattr *attrs,
return 0;
}
static int nl80211_parse_he_bss_color(struct nlattr *attrs,
struct cfg80211_he_bss_color *he_bss_color)
{
struct nlattr *tb[NL80211_HE_BSS_COLOR_ATTR_MAX + 1];
int err;
err = nla_parse_nested(tb, NL80211_HE_BSS_COLOR_ATTR_MAX, attrs,
he_bss_color_policy, NULL);
if (err)
return err;
if (!tb[NL80211_HE_BSS_COLOR_ATTR_COLOR])
return -EINVAL;
he_bss_color->color =
nla_get_u8(tb[NL80211_HE_BSS_COLOR_ATTR_COLOR]);
he_bss_color->disabled =
nla_get_flag(tb[NL80211_HE_BSS_COLOR_ATTR_DISABLED]);
he_bss_color->partial =
nla_get_flag(tb[NL80211_HE_BSS_COLOR_ATTR_PARTIAL]);
return 0;
}
static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
const u8 *rates)
{
@ -4804,6 +4884,14 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
return err;
}
if (info->attrs[NL80211_ATTR_HE_BSS_COLOR]) {
err = nl80211_parse_he_bss_color(
info->attrs[NL80211_ATTR_HE_BSS_COLOR],
&params.he_bss_color);
if (err)
return err;
}
nl80211_calculate_ap_params(&params);
if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
@ -10539,8 +10627,9 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
return -EOPNOTSUPP;
return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]),
info->extack);
}
static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
@ -13609,6 +13698,7 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
const u8 *buf;
size_t len;
u8 *dest;
u8 src[ETH_ALEN];
u16 proto;
bool noencrypt;
int err;
@ -13646,6 +13736,13 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
goto out;
}
/* copy src address under wdev_lock, as we may copy wdev_address */
if (info->attrs[NL80211_ATTR_SRC_MAC])
ether_addr_copy(src,
nla_data(info->attrs[NL80211_ATTR_SRC_MAC]));
else
ether_addr_copy(src, wdev_address(wdev));
wdev_unlock(wdev);
buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
@ -13656,7 +13753,7 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
return rdev_tx_control_port(rdev, dev, buf, len,
dest, cpu_to_be16(proto), noencrypt);
dest, src, cpu_to_be16(proto), noencrypt);
out:
wdev_unlock(wdev);
@ -15913,7 +16010,8 @@ static int __nl80211_rx_control_port(struct net_device *dev,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ethhdr *ehdr = eth_hdr(skb);
const u8 *addr = ehdr->h_source;
const u8 *daddr = ehdr->h_dest;
const u8 *saddr = ehdr->h_source;
u16 proto = be16_to_cpu(skb->protocol);
struct sk_buff *msg;
void *hdr;
@ -15938,7 +16036,8 @@ static int __nl80211_rx_control_port(struct net_device *dev,
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
NL80211_ATTR_PAD) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, saddr) ||
nla_put(msg, NL80211_ATTR_DST_MAC, ETH_ALEN, daddr) ||
nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
(unencrypted && nla_put_flag(msg,
NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))

View File

@ -734,14 +734,14 @@ static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
static inline int rdev_tx_control_port(struct cfg80211_registered_device *rdev,
struct net_device *dev,
const void *buf, size_t len,
const u8 *dest, __be16 proto,
const bool noencrypt)
const u8 *dest, const u8 *src,
__be16 proto, const bool noencrypt)
{
int ret;
trace_rdev_tx_control_port(&rdev->wiphy, dev, buf, len,
dest, proto, noencrypt);
dest, src, proto, noencrypt);
ret = rdev->ops->tx_control_port(&rdev->wiphy, dev, buf, len,
dest, proto, noencrypt);
dest, src, proto, noencrypt);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}

View File

@ -1569,6 +1569,8 @@ static u32 map_regdom_flags(u32 rd_flags)
channel_flags |= IEEE80211_CHAN_NO_80MHZ;
if (rd_flags & NL80211_RRF_NO_160MHZ)
channel_flags |= IEEE80211_CHAN_NO_160MHZ;
if (rd_flags & NL80211_RRF_NO_HE)
channel_flags |= IEEE80211_CHAN_NO_HE;
return channel_flags;
}

View File

@ -1928,27 +1928,31 @@ TRACE_EVENT(rdev_mgmt_tx,
TRACE_EVENT(rdev_tx_control_port,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
const u8 *buf, size_t len, const u8 *dest, __be16 proto,
const u8 *buf, size_t len,
const u8 *dest, const u8 *src, __be16 proto,
bool unencrypted),
TP_ARGS(wiphy, netdev, buf, len, dest, proto, unencrypted),
TP_ARGS(wiphy, netdev, buf, len, dest, src, proto, unencrypted),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(dest)
__field(__be16, proto)
MAC_ENTRY(src)
__field(u16, proto)
__field(bool, unencrypted)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(dest, dest);
__entry->proto = proto;
MAC_ASSIGN(src, src);
__entry->proto = be16_to_cpu(proto);
__entry->unencrypted = unencrypted;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ","
" proto: 0x%x, unencrypted: %s",
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest),
be16_to_cpu(__entry->proto),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", dest: " MAC_PR_FMT
", src: " MAC_PR_FMT ", proto: 0x%x, unencrypted: %s",
WIPHY_PR_ARG, NETDEV_PR_ARG,
MAC_PR_ARG(dest), MAC_PR_ARG(src),
__entry->proto,
BOOL_TO_STR(__entry->unencrypted))
);
@ -2840,6 +2844,7 @@ TRACE_EVENT(cfg80211_rx_control_port,
TP_STRUCT__entry(
NETDEV_ENTRY
__field(int, len)
MAC_ENTRY(to)
MAC_ENTRY(from)
__field(u16, proto)
__field(bool, unencrypted)
@ -2847,12 +2852,14 @@ TRACE_EVENT(cfg80211_rx_control_port,
TP_fast_assign(
NETDEV_ASSIGN;
__entry->len = skb->len;
MAC_ASSIGN(to, eth_hdr(skb)->h_dest);
MAC_ASSIGN(from, eth_hdr(skb)->h_source);
__entry->proto = be16_to_cpu(skb->protocol);
__entry->unencrypted = unencrypted;
),
TP_printk(NETDEV_PR_FMT ", len=%d, " MAC_PR_FMT ", proto: 0x%x, unencrypted: %s",
NETDEV_PR_ARG, __entry->len, MAC_PR_ARG(from),
TP_printk(NETDEV_PR_FMT ", len=%d, dest: " MAC_PR_FMT
", src: " MAC_PR_FMT ", proto: 0x%x, unencrypted: %s",
NETDEV_PR_ARG, __entry->len, MAC_PR_ARG(to), MAC_PR_ARG(from),
__entry->proto, BOOL_TO_STR(__entry->unencrypted))
);