This time we have:

* ndo_fill_forward_path support in mac80211, to let
    drivers use it
  * association comeback notification for userspace,
    to be able to react more sensibly to long delays
  * support for background radar detection hardware
    in some chipsets
  * SA Query Procedures offload on the AP side
  * more logging if we find problems with HT/VHT/HE
  * various cleanups and minor fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAmHBuIoACgkQB8qZga/f
 l8SDNQ//bWl1fnVTzXcva16NGXNtQc8ufOdDfEHsusTA0qP1EfCDfhiMmRZ+jUQH
 Xdg7F3Yube0fgij1sEgpcoVOFm5wr7p861nljR8m71t9FI832gfd+qdCJicNxGGI
 B3zEhHCkcZ4yBhT35+cKG/H3WBysI8RO65dC6NVlzCyY1iM9TVkHBtbEKrdNljcM
 cKKWRp/fk7lCRVqLtunUd5kJauwJxjwHOm4GTH5BajbT/06m91GLoj/tZEjr9rQL
 aSsBa1nR0/LcMyYbbQYIxLikTZnkzILIJGLakb7k5ZJ2W4/hUv0Zn6LUCyMDM1mK
 7+Bt6qvB3Wz/TwjKYDm2qOniaD4IDVOtEpVPaXGau8c5Cj6rjnJ/cgF3ydBk4+xB
 5xngZBCk6Y4+epg9V7EWfqmV0vVqlWqfUfARwPulLWA1X15mVVBmcrafGEaLvGrC
 mvkq0n0XZzf+ObrILK7yjafOdLC4ATCj8j6RW85mH4yU+PqKrx3gOCrWn3Zm+6BN
 n6y7vs5x6zEitqjap4zsiVxqJf3jtAVcdVy7k52VF2BBpF8xoyrIMYZw5CNUG2Jv
 aTmW5aE8X9mQ2VT88JewZst0IX4jjfK/B8wOj24tokC2mXRdM5uKTOWK7uTFQJfM
 lLFcRYzo6n6epHrA5oBN4SnQ3/QpZNJOEsRxyROXemDxnQ9de+w=
 =u1jf
 -----END PGP SIGNATURE-----

Merge tag 'mac80211-next-for-net-next-2021-12-21' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
This time we have:
 * ndo_fill_forward_path support in mac80211, to let drivers use it
 * association comeback notification for userspace, to be able
   to react more sensibly to long delays
 * support for background radar detection hardware in some chipsets
 * SA Query Procedures offload on the AP side
 * more logging if we find problems with HT/VHT/HE
 * various cleanups and minor fixes

Conflicts:

net/wireless/reg.c:
  e08ebd6d7b ("cfg80211: Acquire wiphy mutex on regulatory work")
  701fdfe348 ("cfg80211: Enable regulatory enforcement checks for drivers supporting mesh iface")
  https://lore.kernel.org/r/20211221111950.57ecc6a7@canb.auug.org.au

drivers/net/wireless/ath/ath10k/wmi.c:
  7f599aeccb ("cfg80211: Use the HE operation IE to determine a 6GHz BSS channel")
  3bf2537ec2 ("ath10k: drop beacon and probe response which leak from other channel")
  https://lore.kernel.org/r/20211221115004.1cd6b262@canb.auug.org.au

* tag 'mac80211-next-for-net-next-2021-12-21' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next: (32 commits)
  cfg80211: Enable regulatory enforcement checks for drivers supporting mesh iface
  rfkill: allow to get the software rfkill state
  cfg80211: refactor cfg80211_get_ies_channel_number()
  nl82011: clarify interface combinations wrt. channels
  nl80211: Add support to offload SA Query procedures for AP SME device
  nl80211: Add support to set AP settings flags with single attribute
  mac80211: add more HT/VHT/HE state logging
  cfg80211: Use the HE operation IE to determine a 6GHz BSS channel
  cfg80211: rename offchannel_chain structs to background_chain to avoid confusion with ETSI standard
  mac80211: Notify cfg80211 about association comeback
  cfg80211: Add support for notifying association comeback
  mac80211: introduce channel switch disconnect function
  cfg80211: Fix order of enum nl80211_band_iftype_attr documentation
  cfg80211: simplify cfg80211_chandef_valid()
  mac80211: Remove a couple of obsolete TODO
  mac80211: fix FEC flag in radio tap header
  mac80211: use coarse boottime for airtime fairness code
  ieee80211: change HE nominal packet padding value defines
  cfg80211: use ieee80211_bss_get_elem() instead of _get_ie()
  mac80211: Use memset_after() to clear tx status
  ...
====================

Link: https://lore.kernel.org/r/20211221112532.28708-1-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2021-12-21 07:41:47 -08:00
commit 294e70c952
39 changed files with 873 additions and 240 deletions

View File

@ -2613,6 +2613,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
if (ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control)) {
struct ieee80211_mgmt *mgmt = (void *)skb->data;
enum cfg80211_bss_frame_type ftype;
u8 *ies;
int ies_ch;
@ -2623,9 +2624,14 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
ies = mgmt->u.beacon.variable;
if (ieee80211_is_beacon(mgmt->frame_control))
ftype = CFG80211_BSS_FTYPE_BEACON;
else
ftype = CFG80211_BSS_FTYPE_PRESP;
ies_ch = cfg80211_get_ies_channel_number(mgmt->u.beacon.variable,
skb_tail_pointer(skb) - ies,
sband->band);
sband->band, ftype);
if (ies_ch > 0 && ies_ch != channel) {
ath10k_dbg(ar, ATH10K_DBG_MGMT,

View File

@ -275,12 +275,12 @@ static void carl9170_tx_release(struct kref *ref)
if (WARN_ON_ONCE(!ar))
return;
BUILD_BUG_ON(
offsetof(struct ieee80211_tx_info, status.ack_signal) != 20);
memset(&txinfo->status.ack_signal, 0,
sizeof(struct ieee80211_tx_info) -
offsetof(struct ieee80211_tx_info, status.ack_signal));
/*
* This does not call ieee80211_tx_info_clear_status() because
* carl9170_tx_fill_rateinfo() has filled the rate information
* before we get to this point.
*/
memset_after(&txinfo->status, 0, rates);
if (atomic_read(&ar->tx_total_queued))
ar->tx_schedule = true;

View File

@ -608,7 +608,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {
.phy_cap_info[9] =
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED,
(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED <<
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS),
.phy_cap_info[10] =
IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF,
},
@ -665,7 +666,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {
IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242,
.phy_cap_info[9] =
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED,
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED
<< IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS,
},
/*
* Set default Tx/Rx HE MCS NSS Support field.

View File

@ -2209,24 +2209,24 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
}
flags |= STA_CTXT_HE_PACKET_EXT;
} else if ((sta->he_cap.he_cap_elem.phy_cap_info[9] &
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) !=
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED) {
} else if (u8_get_bits(sta->he_cap.he_cap_elem.phy_cap_info[9],
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK)
!= IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED) {
int low_th = -1;
int high_th = -1;
/* Take the PPE thresholds from the nominal padding info */
switch (sta->he_cap.he_cap_elem.phy_cap_info[9] &
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) {
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US:
switch (u8_get_bits(sta->he_cap.he_cap_elem.phy_cap_info[9],
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK)) {
case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_0US:
low_th = IWL_HE_PKT_EXT_NONE;
high_th = IWL_HE_PKT_EXT_NONE;
break;
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US:
case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_8US:
low_th = IWL_HE_PKT_EXT_BPSK;
high_th = IWL_HE_PKT_EXT_NONE;
break;
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US:
case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US:
low_th = IWL_HE_PKT_EXT_NONE;
high_th = IWL_HE_PKT_EXT_BPSK;
break;

View File

@ -431,11 +431,7 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
* Clear manually, ieee80211_tx_info_clear_status would
* clear the counts too and we need them.
*/
memset(&info->status.ack_signal, 0,
sizeof(struct ieee80211_tx_info) -
offsetof(struct ieee80211_tx_info, status.ack_signal));
BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
status.ack_signal) != 20);
memset_after(&info->status, 0, rates);
if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
pad = entry_data->align[0];

View File

@ -1276,7 +1276,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
/* If the queue contains MAX_QUEUE skb's drop some */
if (skb_queue_len(&data->pending) >= MAX_QUEUE) {
/* Droping until WARN_QUEUE level */
/* Dropping until WARN_QUEUE level */
while (skb_queue_len(&data->pending) >= WARN_QUEUE) {
ieee80211_free_txskb(hw, skb_dequeue(&data->pending));
data->tx_dropped++;

View File

@ -853,7 +853,8 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
mt7915_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
}
idx++;
}

View File

@ -140,7 +140,8 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
mt7921_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
}
if (band == NL80211_BAND_6GHZ) {

View File

@ -2119,7 +2119,8 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev,
IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
if (i == NL80211_IFTYPE_STATION)
phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map);

View File

@ -781,7 +781,7 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
if (!ppe_th) {
u8 pad;
pad = FIELD_GET(IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK,
pad = FIELD_GET(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK,
sta->he_cap.he_cap_elem.phy_cap_info[9]);
for (i = 0; i < RTW89_PPE_BW_NUM; i++)

View File

@ -2258,11 +2258,12 @@ enum ieee80211_client_reg_power {
#define IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU 0x08
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US 0x00
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US 0x40
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US 0x80
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED 0xc0
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK 0xc0
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_0US 0x0
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_8US 0x1
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US 0x2
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED 0x3
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS 6
#define IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK 0xc0
#define IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF 0x01

View File

@ -229,6 +229,13 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw);
*/
bool rfkill_blocked(struct rfkill *rfkill);
/**
* rfkill_soft_blocked - Query soft rfkill block state
*
* @rfkill: rfkill struct to query
*/
bool rfkill_soft_blocked(struct rfkill *rfkill);
/**
* rfkill_find_type - Helper for finding rfkill type by name
* @name: the name of the type

View File

@ -1187,17 +1187,6 @@ struct cfg80211_unsol_bcast_probe_resp {
const u8 *tmpl;
};
/**
* enum cfg80211_ap_settings_flags - AP settings flags
*
* Used by cfg80211_ap_settings
*
* @AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external authentication
*/
enum cfg80211_ap_settings_flags {
AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = BIT(0),
};
/**
* struct cfg80211_ap_settings - AP configuration
*
@ -4072,6 +4061,15 @@ struct mgmt_frame_regs {
* @set_fils_aad: Set FILS AAD data to the AP driver so that the driver can use
* those to decrypt (Re)Association Request and encrypt (Re)Association
* Response frame.
*
* @set_radar_background: Configure dedicated offchannel chain available for
* radar/CAC detection on some hw. This chain can't be used to transmit
* or receive frames and it is bounded to a running wdev.
* Background radar/CAC detection allows to avoid the CAC downtime
* switching to a different channel during CAC detection on the selected
* radar channel.
* The caller is expected to set chandef pointer to NULL in order to
* disable background CAC/radar detection.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@ -4404,6 +4402,8 @@ struct cfg80211_ops {
struct cfg80211_color_change_settings *params);
int (*set_fils_aad)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_fils_aad *fils_aad);
int (*set_radar_background)(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef);
};
/*
@ -6374,17 +6374,6 @@ static inline void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid,
u64_to_ether_addr(new_bssid_u64, new_bssid);
}
/**
* cfg80211_get_ies_channel_number - returns the channel number from ies
* @ie: IEs
* @ielen: length of IEs
* @band: enum nl80211_band of the channel
*
* Returns the channel number, or -1 if none could be determined.
*/
int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
enum nl80211_band band);
/**
* cfg80211_is_element_inherited - returns if element ID should be inherited
* @element: element to check
@ -6420,6 +6409,19 @@ enum cfg80211_bss_frame_type {
CFG80211_BSS_FTYPE_PRESP,
};
/**
* cfg80211_get_ies_channel_number - returns the channel number from ies
* @ie: IEs
* @ielen: length of IEs
* @band: enum nl80211_band of the channel
* @ftype: frame type
*
* Returns the channel number, or -1 if none could be determined.
*/
int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
enum nl80211_band band,
enum cfg80211_bss_frame_type ftype);
/**
* cfg80211_inform_bss_data - inform cfg80211 of a new BSS
*
@ -7594,15 +7596,33 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer,
void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp);
/**
* cfg80211_radar_event - radar detection event
* __cfg80211_radar_event - radar detection event
* @wiphy: the wiphy
* @chandef: chandef for the current channel
* @offchan: the radar has been detected on the offchannel chain
* @gfp: context flags
*
* This function is called when a radar is detected on the current chanenl.
*/
void cfg80211_radar_event(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef, gfp_t gfp);
void __cfg80211_radar_event(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
bool offchan, gfp_t gfp);
static inline void
cfg80211_radar_event(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
gfp_t gfp)
{
__cfg80211_radar_event(wiphy, chandef, false, gfp);
}
static inline void
cfg80211_background_radar_event(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
gfp_t gfp)
{
__cfg80211_radar_event(wiphy, chandef, true, gfp);
}
/**
* cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event
@ -7633,6 +7653,14 @@ void cfg80211_cac_event(struct net_device *netdev,
const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event, gfp_t gfp);
/**
* cfg80211_background_cac_abort - Channel Availability Check offchan abort event
* @wiphy: the wiphy
*
* This function is called by the driver when a Channel Availability Check
* (CAC) is aborted by a offchannel dedicated chain.
*/
void cfg80211_background_cac_abort(struct wiphy *wiphy);
/**
* cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
@ -8250,6 +8278,18 @@ bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
bool is_4addr, u8 check_swif);
/**
* cfg80211_assoc_comeback - notification of association that was
* temporarly rejected with a comeback
* @netdev: network device
* @bss: the bss entry with which association is in progress.
* @timeout: timeout interval value TUs.
*
* this function may sleep. the caller must hold the corresponding wdev's mutex.
*/
void cfg80211_assoc_comeback(struct net_device *netdev,
struct cfg80211_bss *bss, u32 timeout);
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */

View File

@ -1205,12 +1205,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
/* clear the rate counts */
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++)
info->status.rates[i].count = 0;
BUILD_BUG_ON(
offsetof(struct ieee80211_tx_info, status.ack_signal) != 20);
memset(&info->status.ampdu_ack_len, 0,
sizeof(struct ieee80211_tx_info) -
offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
memset_after(&info->status, 0, rates);
}
@ -3944,6 +3939,16 @@ struct ieee80211_prep_tx_info {
* twt structure.
* @twt_teardown_request: Update the hw with TWT teardown request received
* from the peer.
* @set_radar_background: Configure dedicated offchannel chain available for
* radar/CAC detection on some hw. This chain can't be used to transmit
* or receive frames and it is bounded to a running wdev.
* Background radar/CAC detection allows to avoid the CAC downtime
* switching to a different channel during CAC detection on the selected
* radar channel.
* The caller is expected to set chandef pointer to NULL in order to
* disable background CAC/radar detection.
* @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
* resolve a path for hardware flow offloading
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@ -4272,6 +4277,13 @@ struct ieee80211_ops {
struct ieee80211_twt_setup *twt);
void (*twt_teardown_request)(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u8 flowid);
int (*set_radar_background)(struct ieee80211_hw *hw,
struct cfg80211_chan_def *chandef);
int (*net_fill_forward_path)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct net_device_path_ctx *ctx,
struct net_device_path *path);
};
/**
@ -6063,6 +6075,18 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw);
*/
void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
/**
* ieee80211_channel_switch_disconnect - disconnect due to channel switch error
* @vif &struct ieee80211_vif pointer from the add_interface callback.
* @block_tx: if %true, do not send deauth frame.
*
* Instruct mac80211 to disconnect due to a channel switch error. The channel
* switch can request to block the tx and so, we need to make sure we do not send
* a deauth frame in this case.
*/
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif,
bool block_tx);
/**
* ieee80211_request_smps - request SM PS transition
* @vif: &struct ieee80211_vif pointer from the add_interface callback.

View File

@ -1232,6 +1232,11 @@
* &NL80211_ATTR_FILS_NONCES - for FILS Nonces
* (STA Nonce 16 bytes followed by AP Nonce 16 bytes)
*
* @NL80211_CMD_ASSOC_COMEBACK: notification about an association
* temporal rejection with comeback. The event includes %NL80211_ATTR_MAC
* to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to
* specify the timeout value.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@ -1474,6 +1479,8 @@ enum nl80211_commands {
NL80211_CMD_SET_FILS_AAD,
NL80211_CMD_ASSOC_COMEBACK,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -2470,7 +2477,9 @@ enum nl80211_commands {
* space supports external authentication. This attribute shall be used
* with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver
* may offload authentication processing to user space if this capability
* is indicated in the respective requests from the user space.
* is indicated in the respective requests from the user space. (This flag
* attribute deprecated for %NL80211_CMD_START_AP, use
* %NL80211_ATTR_AP_SETTINGS_FLAGS)
*
* @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this
* u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
@ -2639,6 +2648,17 @@ enum nl80211_commands {
* Mandatory parameter for the transmitting interface to enable MBSSID.
* Optional for the non-transmitting interfaces.
*
* @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain
* available for radar/CAC detection on some hw. This chain can't be used
* to transmit or receive frames and it is bounded to a running wdev.
* Background radar/CAC detection allows to avoid the CAC downtime
* switching on a different channel during CAC detection on the selected
* radar channel.
*
* @NL80211_ATTR_AP_SETTINGS_FLAGS: u32 attribute contains ap settings flags,
* enumerated in &enum nl80211_ap_settings_flags. This attribute shall be
* used with %NL80211_CMD_START_AP request.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -3145,6 +3165,10 @@ enum nl80211_attrs {
NL80211_ATTR_MBSSID_CONFIG,
NL80211_ATTR_MBSSID_ELEMS,
NL80211_ATTR_RADAR_BACKGROUND,
NL80211_ATTR_AP_SETTINGS_FLAGS,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -3738,13 +3762,12 @@ enum nl80211_mpath_info {
* 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_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
* given for all 6 GHz band channels
* @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are
* advertised on this band/for this iftype (binary)
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
* @NL80211_BAND_IFTYPE_ATTR_MAX: highest band attribute currently defined
*/
enum nl80211_band_iftype_attr {
__NL80211_BAND_IFTYPE_ATTR_INVALID,
@ -5555,7 +5578,7 @@ enum nl80211_iface_limit_attrs {
* => allows 8 of AP/GO that can have BI gcd >= min gcd
*
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2
* => allows two STAs on different channels
* => allows two STAs on the same or on different channels
*
* numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
* => allows a STA plus three P2P interfaces
@ -5737,13 +5760,15 @@ enum nl80211_tdls_operation {
NL80211_TDLS_DISABLE_LINK,
};
/*
/**
* enum nl80211_ap_sme_features - device-integrated AP features
* Reserved for future use, no bits are defined in
* NL80211_ATTR_DEVICE_AP_SME yet.
enum nl80211_ap_sme_features {
};
* @NL80211_AP_SME_SA_QUERY_OFFLOAD: SA Query procedures offloaded to driver
* when user space indicates support for SA Query procedures offload during
* "start ap" with %NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT.
*/
enum nl80211_ap_sme_features {
NL80211_AP_SME_SA_QUERY_OFFLOAD = 1 << 0,
};
/**
* enum nl80211_feature_flags - device/driver features
@ -6051,6 +6076,9 @@ enum nl80211_feature_flags {
* frames. Userspace has to share FILS AAD details to the driver by using
* @NL80211_CMD_SET_FILS_AAD.
*
* @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC
* detection.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@ -6117,6 +6145,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
NL80211_EXT_FEATURE_BSS_COLOR,
NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,
NL80211_EXT_FEATURE_RADAR_BACKGROUND,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@ -7462,4 +7491,20 @@ enum nl80211_mbssid_config_attributes {
NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1,
};
/**
* enum nl80211_ap_settings_flags - AP settings flags
*
* @NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external
* authentication.
* @NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT: Userspace supports SA Query
* procedures offload to driver. If driver advertises
* %NL80211_AP_SME_SA_QUERY_OFFLOAD in AP SME features, userspace shall
* ignore SA Query procedures and validations when this flag is set by
* userspace.
*/
enum nl80211_ap_settings_flags {
NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = 1 << 0,
NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1,
};
#endif /* __LINUX_NL80211_H */

View File

@ -5,7 +5,7 @@
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2020 Intel Corporation
* Copyright (C) 2018-2021 Intel Corporation
*/
#include <linux/ieee80211.h>
@ -3198,6 +3198,18 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif)
}
EXPORT_SYMBOL(ieee80211_csa_finish);
void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_tx)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
sdata->csa_block_tx = block_tx;
sdata_info(sdata, "channel switch failed, disconnecting\n");
ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work);
}
EXPORT_SYMBOL(ieee80211_channel_switch_disconnect);
static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
u32 *changed)
{
@ -4268,6 +4280,21 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_HE_BSS_COLOR;
ieee80211_bss_info_change_notify(sdata, changed);
if (!sdata->vif.bss_conf.nontransmitted && sdata->vif.mbssid_tx_vif) {
struct ieee80211_sub_if_data *child;
mutex_lock(&sdata->local->iflist_mtx);
list_for_each_entry(child, &sdata->local->interfaces, list) {
if (child != sdata && child->vif.mbssid_tx_vif == &sdata->vif) {
child->vif.bss_conf.he_bss_color.color = color;
child->vif.bss_conf.he_bss_color.enabled = enable;
ieee80211_bss_info_change_notify(child,
BSS_CHANGED_HE_BSS_COLOR);
}
}
mutex_unlock(&sdata->local->iflist_mtx);
}
}
static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata)
@ -4352,6 +4379,9 @@ ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev,
sdata_assert_lock(sdata);
if (sdata->vif.bss_conf.nontransmitted)
return -EINVAL;
mutex_lock(&local->mtx);
/* don't allow another color change if one is already active or if csa
@ -4383,6 +4413,18 @@ out:
return err;
}
static int
ieee80211_set_radar_background(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
if (!local->ops->set_radar_background)
return -EOPNOTSUPP;
return local->ops->set_radar_background(&local->hw, chandef);
}
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@ -4487,4 +4529,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.reset_tid_config = ieee80211_reset_tid_config,
.set_sar_specs = ieee80211_set_sar_specs,
.color_change = ieee80211_color_change,
.set_radar_background = ieee80211_set_radar_background,
};

View File

@ -936,14 +936,15 @@ static ssize_t sta_he_capa_read(struct file *file, char __user *userbuf,
PFLAG(PHY, 9, RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB,
"RX-FULL-BW-SU-USING-MU-WITH-NON-COMP-SIGB");
switch (cap[9] & IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) {
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US:
switch (u8_get_bits(cap[9],
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK)) {
case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_0US:
PRINT("NOMINAL-PACKET-PADDING-0US");
break;
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US:
case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_8US:
PRINT("NOMINAL-PACKET-PADDING-8US");
break;
case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US:
case IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US:
PRINT("NOMINAL-PACKET-PADDING-16US");
break;
}

View File

@ -1486,4 +1486,26 @@ static inline void drv_twt_teardown_request(struct ieee80211_local *local,
trace_drv_return_void(local);
}
static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta,
struct net_device_path_ctx *ctx,
struct net_device_path *path)
{
int ret = -EOPNOTSUPP;
sdata = get_bss_sdata(sdata);
if (!check_sdata_in_driver(sdata))
return -EIO;
trace_drv_net_fill_forward_path(local, sdata, sta);
if (local->ops->net_fill_forward_path)
ret = local->ops->net_fill_forward_path(&local->hw,
&sdata->vif, sta,
ctx, path);
trace_drv_return_int(local, ret);
return ret;
}
#endif /* __MAC80211_DRIVER_OPS */

View File

@ -1463,7 +1463,7 @@ struct ieee80211_local {
};
static inline struct ieee80211_sub_if_data *
IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
IEEE80211_DEV_TO_SUB_IF(const struct net_device *dev)
{
return netdev_priv(dev);
}

View File

@ -789,6 +789,64 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
.ndo_get_stats64 = ieee80211_get_stats64,
};
static int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx,
struct net_device_path *path)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_local *local;
struct sta_info *sta;
int ret = -ENOENT;
sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev);
local = sdata->local;
if (!local->ops->net_fill_forward_path)
return -EOPNOTSUPP;
rcu_read_lock();
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
sta = rcu_dereference(sdata->u.vlan.sta);
if (sta)
break;
if (sdata->wdev.use_4addr)
goto out;
if (is_multicast_ether_addr(ctx->daddr))
goto out;
sta = sta_info_get_bss(sdata, ctx->daddr);
break;
case NL80211_IFTYPE_AP:
if (is_multicast_ether_addr(ctx->daddr))
goto out;
sta = sta_info_get(sdata, ctx->daddr);
break;
case NL80211_IFTYPE_STATION:
if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
sta = sta_info_get(sdata, ctx->daddr);
if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
goto out;
break;
}
}
sta = sta_info_get(sdata, sdata->u.mgd.bssid);
break;
default:
goto out;
}
if (!sta)
goto out;
ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path);
out:
rcu_read_unlock();
return ret;
}
static const struct net_device_ops ieee80211_dataif_8023_ops = {
.ndo_open = ieee80211_open,
.ndo_stop = ieee80211_stop,
@ -798,6 +856,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = {
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_netdev_select_queue,
.ndo_get_stats64 = ieee80211_get_stats64,
.ndo_fill_forward_path = ieee80211_netdev_fill_forward_path,
};
static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)

View File

@ -1131,17 +1131,14 @@ 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)
* HE cap element is variable in size - set len to allow max size */
if (supp_he) {
local->scan_ies_len +=
2 + sizeof(struct ieee80211_he_cap_elem) +
3 + sizeof(struct ieee80211_he_cap_elem) +
sizeof(struct ieee80211_he_mcs_nss_supp) +
IEEE80211_HE_PPE_THRES_MAX_LEN + 1;
IEEE80211_HE_PPE_THRES_MAX_LEN;
}
if (!local->ops->hw_scan) {
/* For hw_scan, driver needs to set these up. */

View File

@ -164,12 +164,15 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
chandef->freq1_offset = channel->freq_offset;
if (channel->band == NL80211_BAND_6GHZ) {
if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, chandef))
if (!ieee80211_chandef_he_6ghz_oper(sdata, he_oper, chandef)) {
mlme_dbg(sdata,
"bad 6 GHz operation, disabling HT/VHT/HE\n");
ret = IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT |
IEEE80211_STA_DISABLE_HE;
else
} else {
ret = 0;
}
vht_chandef = *chandef;
goto out;
} else if (sband->band == NL80211_BAND_S1GHZ) {
@ -190,6 +193,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
if (!ht_oper || !sta_ht_cap.ht_supported) {
mlme_dbg(sdata, "HT operation missing / HT not supported\n");
ret = IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT |
IEEE80211_STA_DISABLE_HE;
@ -223,6 +227,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
ieee80211_chandef_ht_oper(ht_oper, chandef);
} else {
mlme_dbg(sdata, "40 MHz not supported\n");
/* 40 MHz (and 80 MHz) must be supported for VHT */
ret = IEEE80211_STA_DISABLE_VHT;
/* also mark 40 MHz disabled */
@ -231,6 +236,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
}
if (!vht_oper || !sband->vht_cap.vht_supported) {
mlme_dbg(sdata, "VHT operation missing / VHT not supported\n");
ret = IEEE80211_STA_DISABLE_VHT;
goto out;
}
@ -253,7 +259,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
&vht_chandef)) {
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HE))
sdata_info(sdata,
"HE AP VHT information is invalid, disable HE\n");
"HE AP VHT information is invalid, disabling HE\n");
ret = IEEE80211_STA_DISABLE_HE;
goto out;
}
@ -263,7 +269,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
&vht_chandef)) {
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information is invalid, disable VHT\n");
"AP VHT information is invalid, disabling VHT\n");
ret = IEEE80211_STA_DISABLE_VHT;
goto out;
}
@ -271,7 +277,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
if (!cfg80211_chandef_valid(&vht_chandef)) {
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information is invalid, disable VHT\n");
"AP VHT information is invalid, disabling VHT\n");
ret = IEEE80211_STA_DISABLE_VHT;
goto out;
}
@ -284,7 +290,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
sdata_info(sdata,
"AP VHT information doesn't match HT, disable VHT\n");
"AP VHT information doesn't match HT, disabling VHT\n");
ret = IEEE80211_STA_DISABLE_VHT;
goto out;
}
@ -649,10 +655,6 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
if (!he_cap || !reg_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) +
@ -3741,6 +3743,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
elems->timeout_int &&
elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
u32 tu, ms;
cfg80211_assoc_comeback(sdata->dev, assoc_data->bss,
le32_to_cpu(elems->timeout_int->value));
tu = le32_to_cpu(elems->timeout_int->value);
ms = tu * 1024 / 1000;
sdata_info(sdata,
@ -5043,19 +5049,23 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
/* disable HT/VHT/HE if we don't support them */
if (!sband->ht_cap.ht_supported && !is_6ghz) {
mlme_dbg(sdata, "HT not supported, disabling HT/VHT/HE\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
}
if (!sband->vht_cap.vht_supported && is_5ghz) {
mlme_dbg(sdata, "VHT not supported, disabling VHT/HE\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
}
if (!ieee80211_get_he_iftype_cap(sband,
ieee80211_vif_type_p2p(&sdata->vif)))
ieee80211_vif_type_p2p(&sdata->vif))) {
mlme_dbg(sdata, "HE not supported, disabling it\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
}
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && !is_6ghz) {
ht_oper = elems->ht_operation;
@ -5079,6 +5089,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
}
if (!elems->vht_cap_elem) {
sdata_info(sdata,
"bad VHT capabilities, disabling VHT\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
vht_oper = NULL;
}
@ -5126,8 +5138,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
break;
}
if (!have_80mhz)
if (!have_80mhz) {
sdata_info(sdata, "80 MHz not supported, disabling VHT\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
}
if (sband->band == NL80211_BAND_S1GHZ) {
s1g_oper = elems->s1g_oper;
@ -5691,12 +5705,14 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
else if (!is_6ghz)
ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
vht_elem = ieee80211_bss_get_elem(req->bss, WLAN_EID_VHT_CAPABILITY);
if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap))
if (vht_elem && vht_elem->datalen >= sizeof(struct ieee80211_vht_cap)) {
memcpy(&assoc_data->ap_vht_cap, vht_elem->data,
sizeof(struct ieee80211_vht_cap));
else if (is_5ghz)
} else if (is_5ghz) {
sdata_info(sdata, "VHT capa missing/short, disabling VHT/HE\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT |
IEEE80211_STA_DISABLE_HE;
}
rcu_read_unlock();
if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) &&
@ -5770,16 +5786,21 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
}
if (req->flags & ASSOC_REQ_DISABLE_HT) {
mlme_dbg(sdata, "HT disabled by flag, disabling HT/VHT/HE\n");
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)
if (req->flags & ASSOC_REQ_DISABLE_VHT) {
mlme_dbg(sdata, "VHT disabled by flag, disabling VHT\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
}
if (req->flags & ASSOC_REQ_DISABLE_HE)
if (req->flags & ASSOC_REQ_DISABLE_HE) {
mlme_dbg(sdata, "HE disabled by flag, disabling VHT\n");
ifmgd->flags |= IEEE80211_STA_DISABLE_HE;
}
err = ieee80211_prep_connection(sdata, req->bss, true, override);
if (err)

View File

@ -18,8 +18,6 @@
#define AVG_AMPDU_SIZE 16
#define AVG_PKT_SIZE 1200
#define SAMPLE_SWITCH_THR 100
/* Number of bits for an average sized packet */
#define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3)

View File

@ -465,7 +465,12 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
unsigned int stbc;
rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_MCS));
*pos++ = local->hw.radiotap_mcs_details;
*pos = local->hw.radiotap_mcs_details;
if (status->enc_flags & RX_ENC_FLAG_HT_GF)
*pos |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
if (status->enc_flags & RX_ENC_FLAG_LDPC)
*pos |= IEEE80211_RADIOTAP_MCS_HAVE_FEC;
pos++;
*pos = 0;
if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
*pos |= IEEE80211_RADIOTAP_MCS_SGI;

View File

@ -2892,6 +2892,13 @@ TRACE_EVENT(drv_twt_teardown_request,
)
);
DEFINE_EVENT(sta_event, drv_net_fill_forward_path,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta),
TP_ARGS(local, sdata, sta)
);
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH

View File

@ -3821,7 +3821,7 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
{
struct ieee80211_local *local = hw_to_local(hw);
struct airtime_sched_info *air_sched;
u64 now = ktime_get_boottime_ns();
u64 now = ktime_get_coarse_boottime_ns();
struct ieee80211_txq *ret = NULL;
struct airtime_info *air_info;
struct txq_info *txqi = NULL;
@ -3948,7 +3948,7 @@ void ieee80211_update_airtime_weight(struct ieee80211_local *local,
u64 weight_sum = 0;
if (unlikely(!now))
now = ktime_get_boottime_ns();
now = ktime_get_coarse_boottime_ns();
lockdep_assert_held(&air_sched->lock);
@ -3974,7 +3974,7 @@ void ieee80211_schedule_txq(struct ieee80211_hw *hw,
struct ieee80211_local *local = hw_to_local(hw);
struct txq_info *txqi = to_txq_info(txq);
struct airtime_sched_info *air_sched;
u64 now = ktime_get_boottime_ns();
u64 now = ktime_get_coarse_boottime_ns();
struct airtime_info *air_info;
u8 ac = txq->ac;
bool was_active;
@ -4032,7 +4032,7 @@ static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw,
if (!purge)
airtime_set_active(air_sched, air_info,
ktime_get_boottime_ns());
ktime_get_coarse_boottime_ns());
rb_erase_cached(&txqi->schedule_order,
&air_sched->active_txqs);
@ -4120,7 +4120,7 @@ bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
if (RB_EMPTY_NODE(&txqi->schedule_order))
goto out;
now = ktime_get_boottime_ns();
now = ktime_get_coarse_boottime_ns();
/* Like in ieee80211_next_txq(), make sure the first station in the
* scheduling order is eligible for transmission to avoid starvation.

View File

@ -449,7 +449,6 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
return 0;
hdr = (struct ieee80211_hdr *) pos;
pos += hdrlen;
pn64 = atomic64_inc_return(&key->conf.tx_pn);
@ -686,7 +685,6 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
return 0;
hdr = (struct ieee80211_hdr *)pos;
pos += hdrlen;
pn64 = atomic64_inc_return(&key->conf.tx_pn);
@ -881,8 +879,6 @@ ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx)
if (skb_linearize(rx->skb))
return RX_DROP_UNUSABLE;
hdr = (struct ieee80211_hdr *)rx->skb->data;
rx_pn = key->u.gen.rx_pn[qos_tid];
skb_pn = rx->skb->data + hdrlen + cs->pn_off;

View File

@ -946,6 +946,18 @@ bool rfkill_blocked(struct rfkill *rfkill)
}
EXPORT_SYMBOL(rfkill_blocked);
bool rfkill_soft_blocked(struct rfkill *rfkill)
{
unsigned long flags;
u32 state;
spin_lock_irqsave(&rfkill->lock, flags);
state = rfkill->state;
spin_unlock_irqrestore(&rfkill->lock, flags);
return !!(state & RFKILL_BLOCK_SW);
}
EXPORT_SYMBOL(rfkill_soft_blocked);
struct rfkill * __must_check rfkill_alloc(const char *name,
struct device *parent,

View File

@ -245,19 +245,7 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
oper_freq - MHZ_TO_KHZ(oper_width) / 2)
return false;
break;
case NL80211_CHAN_WIDTH_40:
if (chandef->center_freq1 != control_freq + 10 &&
chandef->center_freq1 != control_freq - 10)
return false;
if (chandef->center_freq2)
return false;
break;
case NL80211_CHAN_WIDTH_80P80:
if (chandef->center_freq1 != control_freq + 30 &&
chandef->center_freq1 != control_freq + 10 &&
chandef->center_freq1 != control_freq - 10 &&
chandef->center_freq1 != control_freq - 30)
return false;
if (!chandef->center_freq2)
return false;
/* adjacent is not allowed -- that's a 160 MHz channel */
@ -265,28 +253,42 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
chandef->center_freq2 - chandef->center_freq1 == 80)
return false;
break;
case NL80211_CHAN_WIDTH_80:
if (chandef->center_freq1 != control_freq + 30 &&
chandef->center_freq1 != control_freq + 10 &&
chandef->center_freq1 != control_freq - 10 &&
chandef->center_freq1 != control_freq - 30)
return false;
default:
if (chandef->center_freq2)
return false;
break;
}
switch (chandef->width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_1:
case NL80211_CHAN_WIDTH_2:
case NL80211_CHAN_WIDTH_4:
case NL80211_CHAN_WIDTH_8:
case NL80211_CHAN_WIDTH_16:
/* all checked above */
break;
case NL80211_CHAN_WIDTH_160:
if (chandef->center_freq1 != control_freq + 70 &&
chandef->center_freq1 != control_freq + 50 &&
chandef->center_freq1 != control_freq + 30 &&
chandef->center_freq1 != control_freq + 10 &&
chandef->center_freq1 != control_freq - 10 &&
chandef->center_freq1 != control_freq - 30 &&
chandef->center_freq1 != control_freq - 50 &&
chandef->center_freq1 != control_freq - 70)
return false;
if (chandef->center_freq2)
return false;
break;
if (chandef->center_freq1 == control_freq + 70 ||
chandef->center_freq1 == control_freq + 50 ||
chandef->center_freq1 == control_freq - 50 ||
chandef->center_freq1 == control_freq - 70)
break;
fallthrough;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_80:
if (chandef->center_freq1 == control_freq + 30 ||
chandef->center_freq1 == control_freq - 30)
break;
fallthrough;
case NL80211_CHAN_WIDTH_40:
if (chandef->center_freq1 == control_freq + 10 ||
chandef->center_freq1 == control_freq - 10)
break;
fallthrough;
default:
return false;
}
@ -712,6 +714,19 @@ static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
return false;
}
static bool
cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *channel)
{
if (!rdev->background_radar_wdev)
return false;
if (!cfg80211_chandef_valid(&rdev->background_radar_chandef))
return false;
return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel);
}
bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
struct ieee80211_channel *chan)
{
@ -728,6 +743,9 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
return true;
if (cfg80211_offchan_chain_is_active(rdev, chan))
return true;
}
return false;

View File

@ -545,6 +545,10 @@ use_default_name:
INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work);
INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
INIT_WORK(&rdev->event_work, cfg80211_event_work);
INIT_WORK(&rdev->background_cac_abort_wk,
cfg80211_background_cac_abort_wk);
INIT_DELAYED_WORK(&rdev->background_cac_done_wk,
cfg80211_background_cac_done_wk);
init_waitqueue_head(&rdev->dev_wait);
@ -733,6 +737,7 @@ int wiphy_register(struct wiphy *wiphy)
if (wiphy->interface_modes & ~(BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_P2P_DEVICE) |
@ -1054,11 +1059,13 @@ void wiphy_unregister(struct wiphy *wiphy)
cancel_work_sync(&rdev->conn_work);
flush_work(&rdev->event_work);
cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
cancel_delayed_work_sync(&rdev->background_cac_done_wk);
flush_work(&rdev->destroy_work);
flush_work(&rdev->sched_scan_stop_wk);
flush_work(&rdev->propagate_radar_detect_wk);
flush_work(&rdev->propagate_cac_done_wk);
flush_work(&rdev->mgmt_registrations_update_wk);
flush_work(&rdev->background_cac_abort_wk);
#ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
@ -1207,6 +1214,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
cfg80211_pmsr_wdev_down(wdev);
cfg80211_stop_background_radar_detection(wdev);
switch (wdev->iftype) {
case NL80211_IFTYPE_ADHOC:
__cfg80211_leave_ibss(rdev, dev, true);

View File

@ -84,6 +84,11 @@ struct cfg80211_registered_device {
struct delayed_work dfs_update_channels_wk;
struct wireless_dev *background_radar_wdev;
struct cfg80211_chan_def background_radar_chandef;
struct delayed_work background_cac_done_wk;
struct work_struct background_cac_abort_wk;
/* netlink port which started critical protocol (0 means not started) */
u32 crit_proto_nlportid;
@ -491,6 +496,17 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
int
cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct cfg80211_chan_def *chandef);
void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev);
void cfg80211_background_cac_done_wk(struct work_struct *work);
void cfg80211_background_cac_abort_wk(struct work_struct *work);
bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
struct ieee80211_channel *chan);

View File

@ -905,13 +905,13 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
}
void cfg80211_radar_event(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
gfp_t gfp)
void __cfg80211_radar_event(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
bool offchan, gfp_t gfp)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
trace_cfg80211_radar_event(wiphy, chandef);
trace_cfg80211_radar_event(wiphy, chandef, offchan);
/* only set the chandef supplied channel to unavailable, in
* case the radar is detected on only one of multiple channels
@ -919,6 +919,9 @@ void cfg80211_radar_event(struct wiphy *wiphy,
*/
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
if (offchan)
queue_work(cfg80211_wq, &rdev->background_cac_abort_wk);
cfg80211_sched_dfs_chan_update(rdev);
nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
@ -926,7 +929,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def));
queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
}
EXPORT_SYMBOL(cfg80211_radar_event);
EXPORT_SYMBOL(__cfg80211_radar_event);
void cfg80211_cac_event(struct net_device *netdev,
const struct cfg80211_chan_def *chandef,
@ -970,3 +973,143 @@ void cfg80211_cac_event(struct net_device *netdev,
nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
}
EXPORT_SYMBOL(cfg80211_cac_event);
static void
__cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event)
{
struct wiphy *wiphy = &rdev->wiphy;
struct net_device *netdev;
lockdep_assert_wiphy(&rdev->wiphy);
if (!cfg80211_chandef_valid(chandef))
return;
if (!rdev->background_radar_wdev)
return;
switch (event) {
case NL80211_RADAR_CAC_FINISHED:
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef));
queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
cfg80211_sched_dfs_chan_update(rdev);
wdev = rdev->background_radar_wdev;
break;
case NL80211_RADAR_CAC_ABORTED:
if (!cancel_delayed_work(&rdev->background_cac_done_wk))
return;
wdev = rdev->background_radar_wdev;
break;
case NL80211_RADAR_CAC_STARTED:
break;
default:
return;
}
netdev = wdev ? wdev->netdev : NULL;
nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL);
}
static void
cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event)
{
wiphy_lock(&rdev->wiphy);
__cfg80211_background_cac_event(rdev, rdev->background_radar_wdev,
chandef, event);
wiphy_unlock(&rdev->wiphy);
}
void cfg80211_background_cac_done_wk(struct work_struct *work)
{
struct delayed_work *delayed_work = to_delayed_work(work);
struct cfg80211_registered_device *rdev;
rdev = container_of(delayed_work, struct cfg80211_registered_device,
background_cac_done_wk);
cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef,
NL80211_RADAR_CAC_FINISHED);
}
void cfg80211_background_cac_abort_wk(struct work_struct *work)
{
struct cfg80211_registered_device *rdev;
rdev = container_of(work, struct cfg80211_registered_device,
background_cac_abort_wk);
cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef,
NL80211_RADAR_CAC_ABORTED);
}
void cfg80211_background_cac_abort(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
queue_work(cfg80211_wq, &rdev->background_cac_abort_wk);
}
EXPORT_SYMBOL(cfg80211_background_cac_abort);
int
cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct cfg80211_chan_def *chandef)
{
unsigned int cac_time_ms;
int err;
lockdep_assert_wiphy(&rdev->wiphy);
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_RADAR_BACKGROUND))
return -EOPNOTSUPP;
/* Offchannel chain already locked by another wdev */
if (rdev->background_radar_wdev && rdev->background_radar_wdev != wdev)
return -EBUSY;
/* CAC already in progress on the offchannel chain */
if (rdev->background_radar_wdev == wdev &&
delayed_work_pending(&rdev->background_cac_done_wk))
return -EBUSY;
err = rdev_set_radar_background(rdev, chandef);
if (err)
return err;
cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, chandef);
if (!cac_time_ms)
cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
rdev->background_radar_chandef = *chandef;
rdev->background_radar_wdev = wdev; /* Get offchain ownership */
__cfg80211_background_cac_event(rdev, wdev, chandef,
NL80211_RADAR_CAC_STARTED);
queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk,
msecs_to_jiffies(cac_time_ms));
return 0;
}
void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev)
{
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
lockdep_assert_wiphy(wiphy);
if (wdev != rdev->background_radar_wdev)
return;
rdev_set_radar_background(rdev, NULL);
rdev->background_radar_wdev = NULL; /* Release offchain ownership */
__cfg80211_background_cac_event(rdev, wdev,
&rdev->background_radar_chandef,
NL80211_RADAR_CAC_ABORTED);
}

View File

@ -776,6 +776,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_MBSSID_CONFIG] =
NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
[NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
[NL80211_ATTR_AP_SETTINGS_FLAGS] = { .type = NLA_U32 },
};
/* policy for the key attributes */
@ -3669,14 +3671,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_ADHOC: {
const u8 *ssid_ie;
const struct element *ssid_elem;
if (!wdev->current_bss)
break;
rcu_read_lock();
ssid_ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
WLAN_EID_SSID);
if (ssid_ie &&
nla_put(msg, NL80211_ATTR_SSID, ssid_ie[1], ssid_ie + 2))
ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub,
WLAN_EID_SSID);
if (ssid_elem &&
nla_put(msg, NL80211_ATTR_SSID, ssid_elem->datalen,
ssid_elem->data))
goto nla_put_failure_rcu_locked;
rcu_read_unlock();
break;
@ -5711,8 +5715,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
nl80211_calculate_ap_params(params);
if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
params->flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
if (info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS])
params->flags = nla_get_u32(
info->attrs[NL80211_ATTR_AP_SETTINGS_FLAGS]);
else if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
params->flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
wdev_lock(wdev);
err = rdev_start_ap(rdev, dev, params);
@ -9274,38 +9281,60 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
struct cfg80211_chan_def chandef;
enum nl80211_dfs_regions dfs_region;
unsigned int cac_time_ms;
int err;
int err = -EINVAL;
flush_delayed_work(&rdev->dfs_update_channels_wk);
wiphy_lock(wiphy);
dfs_region = reg_get_dfs_region(wiphy);
if (dfs_region == NL80211_DFS_UNSET)
return -EINVAL;
goto unlock;
err = nl80211_parse_chandef(rdev, info, &chandef);
if (err)
return err;
if (netif_carrier_ok(dev))
return -EBUSY;
if (wdev->cac_started)
return -EBUSY;
goto unlock;
err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
if (err < 0)
return err;
goto unlock;
if (err == 0)
return -EINVAL;
if (err == 0) {
err = -EINVAL;
goto unlock;
}
if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
return -EINVAL;
if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) {
err = -EINVAL;
goto unlock;
}
if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_BACKGROUND])) {
err = cfg80211_start_background_radar_detection(rdev, wdev,
&chandef);
goto unlock;
}
if (netif_carrier_ok(dev)) {
err = -EBUSY;
goto unlock;
}
if (wdev->cac_started) {
err = -EBUSY;
goto unlock;
}
/* CAC start is offloaded to HW and can't be started manually */
if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
return -EOPNOTSUPP;
if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) {
err = -EOPNOTSUPP;
goto unlock;
}
if (!rdev->ops->start_radar_detection)
return -EOPNOTSUPP;
if (!rdev->ops->start_radar_detection) {
err = -EOPNOTSUPP;
goto unlock;
}
cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
if (WARN_ON(!cac_time_ms))
@ -9318,6 +9347,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
wdev->cac_start_time = jiffies;
wdev->cac_time_ms = cac_time_ms;
}
unlock:
wiphy_unlock(wiphy);
return err;
}
@ -15954,7 +15986,8 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_start_radar_detection,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NO_WIPHY_MTX,
},
{
.cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
@ -17035,6 +17068,44 @@ static void nl80211_send_remain_on_chan_event(
nlmsg_free(msg);
}
void cfg80211_assoc_comeback(struct net_device *netdev,
struct cfg80211_bss *bss, u32 timeout)
{
struct wireless_dev *wdev = netdev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct sk_buff *msg;
void *hdr;
trace_cfg80211_assoc_comeback(wdev, bss->bssid, timeout);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ASSOC_COMEBACK);
if (!hdr) {
nlmsg_free(msg);
return;
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bss->bssid) ||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT, timeout))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_MLME, GFP_KERNEL);
return;
nla_put_failure:
nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_assoc_comeback);
void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
unsigned int duration, gfp_t gfp)

View File

@ -1395,4 +1395,21 @@ rdev_set_fils_aad(struct cfg80211_registered_device *rdev,
return ret;
}
static inline int
rdev_set_radar_background(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef)
{
struct wiphy *wiphy = &rdev->wiphy;
int ret;
if (!rdev->ops->set_radar_background)
return -EOPNOTSUPP;
trace_rdev_set_radar_background(wiphy, chandef);
ret = rdev->ops->set_radar_background(wiphy, chandef);
trace_rdev_return_int(wiphy, ret);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */

View File

@ -2371,6 +2371,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
switch (iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_MESH_POINT:
if (!wdev->beacon_interval)
goto wdev_inactive_unlock;
chandef = wdev->chandef;
@ -2409,6 +2410,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
wiphy_lock(wiphy);
ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
wiphy_unlock(wiphy);

View File

@ -406,22 +406,20 @@ static int
cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,
struct cfg80211_bss *nontrans_bss)
{
const u8 *ssid;
size_t ssid_len;
const struct element *ssid_elem;
struct cfg80211_bss *bss = NULL;
rcu_read_lock();
ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
if (!ssid) {
ssid_elem = ieee80211_bss_get_elem(nontrans_bss, WLAN_EID_SSID);
if (!ssid_elem) {
rcu_read_unlock();
return -EINVAL;
}
ssid_len = ssid[1];
ssid = ssid + 2;
/* check if nontrans_bss is in the list */
list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) {
if (is_bss(bss, nontrans_bss->bssid, ssid, ssid_len)) {
if (is_bss(bss, nontrans_bss->bssid, ssid_elem->data,
ssid_elem->datalen)) {
rcu_read_unlock();
return 0;
}
@ -1795,33 +1793,52 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
}
int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen,
enum nl80211_band band)
enum nl80211_band band,
enum cfg80211_bss_frame_type ftype)
{
const u8 *tmp;
int channel_number = -1;
const struct element *tmp;
if (band == NL80211_BAND_S1GHZ) {
tmp = cfg80211_find_ie(WLAN_EID_S1G_OPERATION, ie, ielen);
if (tmp && tmp[1] >= sizeof(struct ieee80211_s1g_oper_ie)) {
struct ieee80211_s1g_oper_ie *s1gop = (void *)(tmp + 2);
if (band == NL80211_BAND_6GHZ) {
struct ieee80211_he_operation *he_oper;
channel_number = s1gop->primary_ch;
tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie,
ielen);
if (tmp && tmp->datalen >= sizeof(*he_oper) &&
tmp->datalen >= ieee80211_he_oper_size(&tmp->data[1])) {
const struct ieee80211_he_6ghz_oper *he_6ghz_oper;
he_oper = (void *)&tmp->data[1];
he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper);
if (!he_6ghz_oper)
return -1;
if (ftype != CFG80211_BSS_FTYPE_BEACON ||
he_6ghz_oper->control & IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON)
return he_6ghz_oper->primary;
}
} else if (band == NL80211_BAND_S1GHZ) {
tmp = cfg80211_find_elem(WLAN_EID_S1G_OPERATION, ie, ielen);
if (tmp && tmp->datalen >= sizeof(struct ieee80211_s1g_oper_ie)) {
struct ieee80211_s1g_oper_ie *s1gop = (void *)tmp->data;
return s1gop->primary_ch;
}
} else {
tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
if (tmp && tmp[1] == 1) {
channel_number = tmp[2];
} else {
tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
tmp = cfg80211_find_elem(WLAN_EID_DS_PARAMS, ie, ielen);
if (tmp && tmp->datalen == 1)
return tmp->data[0];
channel_number = htop->primary_chan;
}
tmp = cfg80211_find_elem(WLAN_EID_HT_OPERATION, ie, ielen);
if (tmp &&
tmp->datalen >= sizeof(struct ieee80211_ht_operation)) {
struct ieee80211_ht_operation *htop = (void *)tmp->data;
return htop->primary_chan;
}
}
return channel_number;
return -1;
}
EXPORT_SYMBOL(cfg80211_get_ies_channel_number);
@ -1831,18 +1848,20 @@ EXPORT_SYMBOL(cfg80211_get_ies_channel_number);
* from neighboring channels and the Beacon frames use the DSSS Parameter Set
* element to indicate the current (transmitting) channel, but this might also
* be needed on other bands if RX frequency does not match with the actual
* operating channel of a BSS.
* operating channel of a BSS, or if the AP reports a different primary channel.
*/
static struct ieee80211_channel *
cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
struct ieee80211_channel *channel,
enum nl80211_bss_scan_width scan_width)
enum nl80211_bss_scan_width scan_width,
enum cfg80211_bss_frame_type ftype)
{
u32 freq;
int channel_number;
struct ieee80211_channel *alt_channel;
channel_number = cfg80211_get_ies_channel_number(ie, ielen, channel->band);
channel_number = cfg80211_get_ies_channel_number(ie, ielen,
channel->band, ftype);
if (channel_number < 0) {
/* No channel information in frame payload */
@ -1850,6 +1869,16 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
}
freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
/*
* In 6GHz, duplicated beacon indication is relevant for
* beacons only.
*/
if (channel->band == NL80211_BAND_6GHZ &&
(freq == channel->center_freq ||
abs(freq - channel->center_freq) > 80))
return channel;
alt_channel = ieee80211_get_channel_khz(wiphy, freq);
if (!alt_channel) {
if (channel->band == NL80211_BAND_2GHZ) {
@ -1911,7 +1940,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
return NULL;
channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan,
data->scan_width);
data->scan_width, ftype);
if (!channel)
return NULL;
@ -2234,7 +2263,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
struct ieee80211_mgmt *mgmt, size_t len)
{
u8 *ie, *new_ie, *pos;
const u8 *nontrans_ssid, *trans_ssid, *mbssid;
const struct element *nontrans_ssid;
const u8 *trans_ssid, *mbssid;
size_t ielen = len - offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
size_t new_ie_len;
@ -2261,11 +2291,11 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
return;
new_ie_len -= mbssid[1];
nontrans_ssid = ieee80211_bss_get_ie(nontrans_bss, WLAN_EID_SSID);
nontrans_ssid = ieee80211_bss_get_elem(nontrans_bss, WLAN_EID_SSID);
if (!nontrans_ssid)
return;
new_ie_len += nontrans_ssid[1];
new_ie_len += nontrans_ssid->datalen;
/* generate new ie for nontrans BSS
* 1. replace SSID with nontrans BSS' SSID
@ -2282,7 +2312,7 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
pos = new_ie;
/* copy the nontransmitted SSID */
cpy_len = nontrans_ssid[1] + 2;
cpy_len = nontrans_ssid->datalen + 2;
memcpy(pos, nontrans_ssid, cpy_len);
pos += cpy_len;
/* copy the IEs between SSID and MBSSID */
@ -2333,6 +2363,7 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
int bss_type;
enum cfg80211_bss_frame_type ftype;
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
offsetof(struct ieee80211_mgmt, u.beacon.variable));
@ -2369,8 +2400,16 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
variable = ext->u.s1g_beacon.variable;
}
if (ieee80211_is_beacon(mgmt->frame_control))
ftype = CFG80211_BSS_FTYPE_BEACON;
else if (ieee80211_is_probe_resp(mgmt->frame_control))
ftype = CFG80211_BSS_FTYPE_PRESP;
else
ftype = CFG80211_BSS_FTYPE_UNKNOWN;
channel = cfg80211_get_bss_channel(wiphy, variable,
ielen, data->chan, data->scan_width);
ielen, data->chan, data->scan_width,
ftype);
if (!channel)
return NULL;
@ -2687,7 +2726,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
struct cfg80211_registered_device *rdev;
struct wiphy *wiphy;
struct iw_scan_req *wreq = NULL;
struct cfg80211_scan_request *creq = NULL;
struct cfg80211_scan_request *creq;
int i, err, n_channels = 0;
enum nl80211_band band;
@ -2702,10 +2741,8 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (IS_ERR(rdev))
return PTR_ERR(rdev);
if (rdev->scan_req || rdev->scan_msg) {
err = -EBUSY;
goto out;
}
if (rdev->scan_req || rdev->scan_msg)
return -EBUSY;
wiphy = &rdev->wiphy;
@ -2718,10 +2755,8 @@ int cfg80211_wext_siwscan(struct net_device *dev,
creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
n_channels * sizeof(void *),
GFP_ATOMIC);
if (!creq) {
err = -ENOMEM;
goto out;
}
if (!creq)
return -ENOMEM;
creq->wiphy = wiphy;
creq->wdev = dev->ieee80211_ptr;

View File

@ -680,7 +680,9 @@ void __cfg80211_connect_result(struct net_device *dev,
bool wextev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
const u8 *country_ie;
const struct element *country_elem;
const u8 *country_data;
u8 country_datalen;
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@ -762,26 +764,22 @@ void __cfg80211_connect_result(struct net_device *dev,
cfg80211_upload_connect_keys(wdev);
rcu_read_lock();
country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY);
if (!country_ie) {
country_elem = ieee80211_bss_get_elem(cr->bss, WLAN_EID_COUNTRY);
if (!country_elem) {
rcu_read_unlock();
return;
}
country_ie = kmemdup(country_ie, 2 + country_ie[1], GFP_ATOMIC);
country_datalen = country_elem->datalen;
country_data = kmemdup(country_elem->data, country_datalen, GFP_ATOMIC);
rcu_read_unlock();
if (!country_ie)
if (!country_data)
return;
/*
* ieee80211_bss_get_ie() ensures we can access:
* - country_ie + 2, the start of the country ie data, and
* - and country_ie[1] which is the IE length
*/
regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band,
country_ie + 2, country_ie[1]);
kfree(country_ie);
country_data, country_datalen);
kfree(country_data);
}
/* Consumes bss object one way or another */

View File

@ -3053,18 +3053,21 @@ TRACE_EVENT(cfg80211_ch_switch_started_notify,
);
TRACE_EVENT(cfg80211_radar_event,
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
TP_ARGS(wiphy, chandef),
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
bool offchan),
TP_ARGS(wiphy, chandef, offchan),
TP_STRUCT__entry(
WIPHY_ENTRY
CHAN_DEF_ENTRY
__field(bool, offchan)
),
TP_fast_assign(
WIPHY_ASSIGN;
CHAN_DEF_ASSIGN(chandef);
__entry->offchan = offchan;
),
TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", offchan %d",
WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->offchan)
);
TRACE_EVENT(cfg80211_cac_event,
@ -3674,6 +3677,42 @@ TRACE_EVENT(cfg80211_bss_color_notify,
__entry->color_bitmap)
);
TRACE_EVENT(rdev_set_radar_background,
TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
TP_ARGS(wiphy, chandef),
TP_STRUCT__entry(
WIPHY_ENTRY
CHAN_DEF_ENTRY
),
TP_fast_assign(
WIPHY_ASSIGN;
CHAN_DEF_ASSIGN(chandef)
),
TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
);
TRACE_EVENT(cfg80211_assoc_comeback,
TP_PROTO(struct wireless_dev *wdev, const u8 *bssid, u32 timeout),
TP_ARGS(wdev, bssid, timeout),
TP_STRUCT__entry(
WDEV_ENTRY
MAC_ENTRY(bssid)
__field(u32, timeout)
),
TP_fast_assign(
WDEV_ASSIGN;
MAC_ASSIGN(bssid, bssid);
__entry->timeout = timeout;
),
TP_printk(WDEV_PR_FMT ", " MAC_PR_FMT ", timeout: %u TUs",
WDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->timeout)
);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH

View File

@ -212,18 +212,18 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
wdev_lock(wdev);
if (wdev->current_bss) {
const u8 *ie;
const struct element *ssid_elem;
rcu_read_lock();
ie = ieee80211_bss_get_ie(&wdev->current_bss->pub,
WLAN_EID_SSID);
if (ie) {
ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub,
WLAN_EID_SSID);
if (ssid_elem) {
data->flags = 1;
data->length = ie[1];
data->length = ssid_elem->datalen;
if (data->length > IW_ESSID_MAX_SIZE)
ret = -EINVAL;
else
memcpy(ssid, ie + 2, data->length);
memcpy(ssid, ssid_elem->data, data->length);
}
rcu_read_unlock();
} else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {