A new set of wireless changes:

* validate key indices for key deletion
  * more preamble support in mac80211
  * various 6 GHz scan fixes/improvements
  * a common SAR power limitations API
  * various small fixes & code improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAl/TfYAACgkQB8qZga/f
 l8ShjQ/9Hd6KjvA7keATtdjR7rDHo7H2nBKV/LukpuHsiTRrXTVOAfkcUTOb2hfR
 7SJMzsUXdJGivbwm4lkx5TrIgiJm1hfW3zG0PFOs/bIuXs/KICrb+kLgQWiRIUfa
 RIinf8BGPH3GgcCHDcWFUrnfnBVchrPUx2wIHoCQbCzLHIhB6q6x8jEJA67+smpv
 57tDfUhm6pf6OYOqVN8HYlo0uRAIn1ImneplDelCmCI1dzlneEkMhqZuBXqWpD/I
 C5vU+MjoOsJiW1XkmYOMe6VKQ/Bve06GUWs830S7aROOEfByv+ptlR9IjqvHvPIm
 UI9NivfXQiZr6S7yD1m2xV7a14UMCIzYarwaM/I/NHAWF/Y4vzHFVzQjLfVKqMCV
 dxxsWN+Yg7Gx3T5Fj3NNiQgnPF9ASVqgMrlC59ga+4If0y60V7dOSFuo9HF7AWgP
 NIWKVI3He7Mb5TciM+BX5YQWkJiCSZXs427WLO6p0bp3kAgS6N6BThUraGCogXVF
 1BT/y5G3QzZwg02vL3lxgWglXoH/e63UYCPt0r+i5c83Z+n4YnFSUZyRSViy9Elj
 DkCgdxmP0OtM+FaHxLdYm+FL4GXaGWQVNORIDP0ViSrstPgSxhWIgVj/pKNcKC7g
 bJI/IXm7eQkW5SXOafmhVV0TmvDOt/mM46E0CeWcPTqIhetk3lM=
 =+qd6
 -----END PGP SIGNATURE-----

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

Johannes Berg says:

====================
A new set of wireless changes:
 * validate key indices for key deletion
 * more preamble support in mac80211
 * various 6 GHz scan fixes/improvements
 * a common SAR power limitations API
 * various small fixes & code improvements

* tag 'mac80211-next-for-net-next-2020-12-11' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next: (35 commits)
  mac80211: add ieee80211_set_sar_specs
  nl80211: add common API to configure SAR power limitations
  mac80211: fix a mistake check for rx_stats update
  mac80211: mlme: save ssid info to ieee80211_bss_conf while assoc
  mac80211: Update rate control on channel change
  mac80211: don't filter out beacons once we start CSA
  mac80211: Fix calculation of minimal channel width
  mac80211: ignore country element TX power on 6 GHz
  mac80211: use bitfield helpers for BA session action frames
  mac80211: support Rx timestamp calculation for all preamble types
  mac80211: don't set set TDLS STA bandwidth wider than possible
  mac80211: support driver-based disconnect with reconnect hint
  cfg80211: support immediate reconnect request hint
  mac80211: use struct assignment for he_obss_pd
  cfg80211: remove struct ieee80211_he_bss_color
  nl80211: validate key indexes for cfg80211_registered_device
  cfg80211: include block-tx flag in channel switch started event
  mac80211: disallow band-switch during CSA
  ieee80211: update reduced neighbor report TBTT info length
  cfg80211: Save the regulatory domain when setting custom regulatory
  ...
====================

Link: https://lore.kernel.org/r/20201211142552.209018-1-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2020-12-12 10:07:56 -08:00
commit 00f7763a26
33 changed files with 1041 additions and 227 deletions

View File

@ -1261,6 +1261,7 @@ struct ieee80211_mgmt {
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122 #define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122
#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E 123
/* mgmt header + 1 byte category code */ /* mgmt header + 1 byte category code */
#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u) #define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
@ -3835,15 +3836,15 @@ static inline bool for_each_element_completed(const struct element *element,
#define WLAN_RSNX_CAPA_SAE_H2E BIT(5) #define WLAN_RSNX_CAPA_SAE_H2E BIT(5)
/* /*
* reduced neighbor report, based on Draft P802.11ax_D5.0, * reduced neighbor report, based on Draft P802.11ax_D6.1,
* section 9.4.2.170 * section 9.4.2.170 and accepted contributions.
*/ */
#define IEEE80211_AP_INFO_TBTT_HDR_TYPE 0x03 #define IEEE80211_AP_INFO_TBTT_HDR_TYPE 0x03
#define IEEE80211_AP_INFO_TBTT_HDR_FILTERED 0x04 #define IEEE80211_AP_INFO_TBTT_HDR_FILTERED 0x04
#define IEEE80211_AP_INFO_TBTT_HDR_COLOC 0x08 #define IEEE80211_AP_INFO_TBTT_HDR_COLOC 0x08
#define IEEE80211_AP_INFO_TBTT_HDR_COUNT 0xF0 #define IEEE80211_AP_INFO_TBTT_HDR_COUNT 0xF0
#define IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM 8 #define IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM 9
#define IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM 12 #define IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM 13
#define IEEE80211_RNR_TBTT_PARAMS_OCT_RECOMMENDED 0x01 #define IEEE80211_RNR_TBTT_PARAMS_OCT_RECOMMENDED 0x01
#define IEEE80211_RNR_TBTT_PARAMS_SAME_SSID 0x02 #define IEEE80211_RNR_TBTT_PARAMS_SAME_SSID 0x02

View File

@ -137,6 +137,17 @@ void rfkill_unregister(struct rfkill *rfkill);
*/ */
void rfkill_destroy(struct rfkill *rfkill); void rfkill_destroy(struct rfkill *rfkill);
/**
* rfkill_set_hw_state_reason - Set the internal rfkill hardware block state
* with a reason
* @rfkill: pointer to the rfkill class to modify.
* @blocked: the current hardware block state to set
* @reason: one of &enum rfkill_hard_block_reasons
*
* Prefer to use rfkill_set_hw_state if you don't need any special reason.
*/
bool rfkill_set_hw_state_reason(struct rfkill *rfkill,
bool blocked, unsigned long reason);
/** /**
* rfkill_set_hw_state - Set the internal rfkill hardware block state * rfkill_set_hw_state - Set the internal rfkill hardware block state
* @rfkill: pointer to the rfkill class to modify. * @rfkill: pointer to the rfkill class to modify.
@ -156,7 +167,11 @@ void rfkill_destroy(struct rfkill *rfkill);
* should be blocked) so that drivers need not keep track of the soft * should be blocked) so that drivers need not keep track of the soft
* block state -- which they might not be able to. * block state -- which they might not be able to.
*/ */
bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked); static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
{
return rfkill_set_hw_state_reason(rfkill, blocked,
RFKILL_HARD_BLOCK_SIGNAL);
}
/** /**
* rfkill_set_sw_state - Set the internal rfkill software block state * rfkill_set_sw_state - Set the internal rfkill software block state
@ -256,6 +271,13 @@ static inline void rfkill_destroy(struct rfkill *rfkill)
{ {
} }
static inline bool rfkill_set_hw_state_reason(struct rfkill *rfkill,
bool blocked,
unsigned long reason)
{
return blocked;
}
static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
{ {
return blocked; return blocked;

View File

@ -302,19 +302,6 @@ struct cfg80211_he_bss_color {
bool partial; 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 * struct ieee80211_sta_ht_cap - STA's HT capabilities
* *
@ -1187,6 +1174,7 @@ enum cfg80211_ap_settings_flags {
* @vht_required: stations must support VHT * @vht_required: stations must support VHT
* @twt_responder: Enable Target Wait Time * @twt_responder: Enable Target Wait Time
* @he_required: stations must support HE * @he_required: stations must support HE
* @sae_h2e_required: stations must support direct H2E technique in SAE
* @flags: flags, as defined in enum cfg80211_ap_settings_flags * @flags: flags, as defined in enum cfg80211_ap_settings_flags
* @he_obss_pd: OBSS Packet Detection settings * @he_obss_pd: OBSS Packet Detection settings
* @he_bss_color: BSS Color settings * @he_bss_color: BSS Color settings
@ -1218,7 +1206,7 @@ struct cfg80211_ap_settings {
const struct ieee80211_vht_cap *vht_cap; const struct ieee80211_vht_cap *vht_cap;
const struct ieee80211_he_cap_elem *he_cap; const struct ieee80211_he_cap_elem *he_cap;
const struct ieee80211_he_operation *he_oper; const struct ieee80211_he_operation *he_oper;
bool ht_required, vht_required, he_required; bool ht_required, vht_required, he_required, sae_h2e_required;
bool twt_responder; bool twt_responder;
u32 flags; u32 flags;
struct ieee80211_he_obss_pd he_obss_pd; struct ieee80211_he_obss_pd he_obss_pd;
@ -1744,6 +1732,54 @@ struct station_info {
u8 connected_to_as; u8 connected_to_as;
}; };
/**
* struct cfg80211_sar_sub_specs - sub specs limit
* @power: power limitation in 0.25dbm
* @freq_range_index: index the power limitation applies to
*/
struct cfg80211_sar_sub_specs {
s32 power;
u32 freq_range_index;
};
/**
* struct cfg80211_sar_specs - sar limit specs
* @type: it's set with power in 0.25dbm or other types
* @num_sub_specs: number of sar sub specs
* @sub_specs: memory to hold the sar sub specs
*/
struct cfg80211_sar_specs {
enum nl80211_sar_type type;
u32 num_sub_specs;
struct cfg80211_sar_sub_specs sub_specs[];
};
/**
* @struct cfg80211_sar_chan_ranges - sar frequency ranges
* @start_freq: start range edge frequency
* @end_freq: end range edge frequency
*/
struct cfg80211_sar_freq_ranges {
u32 start_freq;
u32 end_freq;
};
/**
* struct cfg80211_sar_capa - sar limit capability
* @type: it's set via power in 0.25dbm or other types
* @num_freq_ranges: number of frequency ranges
* @freq_ranges: memory to hold the freq ranges.
*
* Note: WLAN driver may append new ranges or split an existing
* range to small ones and then append them.
*/
struct cfg80211_sar_capa {
enum nl80211_sar_type type;
u32 num_freq_ranges;
const struct cfg80211_sar_freq_ranges *freq_ranges;
};
#if IS_ENABLED(CONFIG_CFG80211) #if IS_ENABLED(CONFIG_CFG80211)
/** /**
* cfg80211_get_station - retrieve information about a given station * cfg80211_get_station - retrieve information about a given station
@ -4261,6 +4297,8 @@ struct cfg80211_ops {
struct cfg80211_tid_config *tid_conf); struct cfg80211_tid_config *tid_conf);
int (*reset_tid_config)(struct wiphy *wiphy, struct net_device *dev, int (*reset_tid_config)(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u8 tids); const u8 *peer, u8 tids);
int (*set_sar_specs)(struct wiphy *wiphy,
struct cfg80211_sar_specs *sar);
}; };
/* /*
@ -5029,6 +5067,8 @@ struct wiphy {
u8 max_data_retry_count; u8 max_data_retry_count;
const struct cfg80211_sar_capa *sar_capa;
char priv[] __aligned(NETDEV_ALIGN); char priv[] __aligned(NETDEV_ALIGN);
}; };
@ -6418,13 +6458,15 @@ void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss);
* @dev: network device * @dev: network device
* @buf: 802.11 frame (header + body) * @buf: 802.11 frame (header + body)
* @len: length of the frame data * @len: length of the frame data
* @reconnect: immediate reconnect is desired (include the nl80211 attribute)
* *
* This function is called whenever deauthentication has been processed in * This function is called whenever deauthentication has been processed in
* station mode. This includes both received deauthentication frames and * station mode. This includes both received deauthentication frames and
* locally generated ones. This function may sleep. The caller must hold the * locally generated ones. This function may sleep. The caller must hold the
* corresponding wdev's mutex. * corresponding wdev's mutex.
*/ */
void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len); void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len,
bool reconnect);
/** /**
* cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame * cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame
@ -7531,6 +7573,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
* @dev: the device on which the channel switch started * @dev: the device on which the channel switch started
* @chandef: the future channel definition * @chandef: the future channel definition
* @count: the number of TBTTs until the channel switch happens * @count: the number of TBTTs until the channel switch happens
* @quiet: whether or not immediate quiet was requested by the AP
* *
* Inform the userspace about the channel switch that has just * Inform the userspace about the channel switch that has just
* started, so that it can take appropriate actions (eg. starting * started, so that it can take appropriate actions (eg. starting
@ -7538,7 +7581,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
*/ */
void cfg80211_ch_switch_started_notify(struct net_device *dev, void cfg80211_ch_switch_started_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef, struct cfg80211_chan_def *chandef,
u8 count); u8 count, bool quiet);
/** /**
* ieee80211_operating_class_to_band - convert operating class to band * ieee80211_operating_class_to_band - convert operating class to band

View File

@ -635,9 +635,7 @@ struct ieee80211_fils_discovery {
struct ieee80211_bss_conf { struct ieee80211_bss_conf {
const u8 *bssid; const u8 *bssid;
u8 htc_trig_based_pkt_ext; u8 htc_trig_based_pkt_ext;
bool multi_sta_back_32bit;
bool uora_exists; bool uora_exists;
bool ack_enabled;
u8 uora_ocw_range; u8 uora_ocw_range;
u16 frame_time_rts_th; u16 frame_time_rts_th;
bool he_support; bool he_support;
@ -4197,6 +4195,8 @@ struct ieee80211_ops {
struct ieee80211_vif *vif); struct ieee80211_vif *vif);
void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enabled); struct ieee80211_sta *sta, bool enabled);
int (*set_sar_specs)(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar);
}; };
/** /**
@ -5323,6 +5323,26 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid, void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
const u8 *replay_ctr, gfp_t gfp); const u8 *replay_ctr, gfp_t gfp);
/**
* ieee80211_key_mic_failure - increment MIC failure counter for the key
*
* Note: this is really only safe if no other RX function is called
* at the same time.
*
* @keyconf: the key in question
*/
void ieee80211_key_mic_failure(struct ieee80211_key_conf *keyconf);
/**
* ieee80211_key_replay - increment replay counter for the key
*
* Note: this is really only safe if no other RX function is called
* at the same time.
*
* @keyconf: the key in question
*/
void ieee80211_key_replay(struct ieee80211_key_conf *keyconf);
/** /**
* ieee80211_wake_queue - wake specific queue * ieee80211_wake_queue - wake specific queue
* @hw: pointer as obtained from ieee80211_alloc_hw(). * @hw: pointer as obtained from ieee80211_alloc_hw().
@ -5881,6 +5901,17 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif);
*/ */
void ieee80211_connection_loss(struct ieee80211_vif *vif); void ieee80211_connection_loss(struct ieee80211_vif *vif);
/**
* ieee80211_disconnect - request disconnection
*
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @reconnect: immediate reconnect is desired
*
* Request disconnection from the current network and, if enabled, send a
* hint to the higher layers that immediate reconnect is desired.
*/
void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect);
/** /**
* ieee80211_resume_disconnect - disconnect from AP after resume * ieee80211_resume_disconnect - disconnect from AP after resume
* *

View File

@ -1178,6 +1178,10 @@
* includes the contents of the frame. %NL80211_ATTR_ACK flag is included * includes the contents of the frame. %NL80211_ATTR_ACK flag is included
* if the recipient acknowledged the frame. * if the recipient acknowledged the frame.
* *
* @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is
* passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
* specify the wiphy index to be applied to.
*
* @NL80211_CMD_MAX: highest used command number * @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
@ -1408,6 +1412,8 @@ enum nl80211_commands {
NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
NL80211_CMD_SET_SAR_SPECS,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
@ -2079,7 +2085,8 @@ enum nl80211_commands {
* until the channel switch event. * until the channel switch event.
* @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
* must be blocked on the current channel (before the channel switch * must be blocked on the current channel (before the channel switch
* operation). * operation). Also included in the channel switch started event if quiet
* was requested by the AP.
* @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
* for the time while performing a channel switch. * for the time while performing a channel switch.
* @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel
@ -2534,6 +2541,15 @@ enum nl80211_commands {
* This is a u8 attribute that encapsulates one of the values from * This is a u8 attribute that encapsulates one of the values from
* &enum nl80211_sae_pwe_mechanism. * &enum nl80211_sae_pwe_mechanism.
* *
* @NL80211_ATTR_SAR_SPEC: SAR power limitation specification when
* used with %NL80211_CMD_SET_SAR_SPECS. The message contains fields
* of %nl80211_sar_attrs which specifies the sar type and related
* sar specs. Sar specs contains array of %nl80211_sar_specs_attrs.
*
* @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and
* disassoc events to indicate that an immediate reconnect to the AP
* is desired.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
@ -3025,6 +3041,10 @@ enum nl80211_attrs {
NL80211_ATTR_SAE_PWE, NL80211_ATTR_SAE_PWE,
NL80211_ATTR_RECONNECT_REQUESTED,
NL80211_ATTR_SAR_SPEC,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
@ -7156,4 +7176,96 @@ enum nl80211_sae_pwe_mechanism {
NL80211_SAE_PWE_HASH_TO_ELEMENT, NL80211_SAE_PWE_HASH_TO_ELEMENT,
NL80211_SAE_PWE_BOTH, NL80211_SAE_PWE_BOTH,
}; };
/**
* enum nl80211_sar_type - type of SAR specs
*
* @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit
*
*/
enum nl80211_sar_type {
NL80211_SAR_TYPE_POWER,
/* add new type here */
/* Keep last */
NUM_NL80211_SAR_TYPE,
};
/**
* enum nl80211_sar_attrs - Attributes for SAR spec
*
* @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type.
*
* @NL80211_SAR_ATTR_SPECS: Nested array of SAR power
* limit specifications. Each specification contains a set
* of %nl80211_sar_specs_attrs.
*
* For SET operation, it contains array of %NL80211_SAR_ATTR_SPECS_POWER
* and %NL80211_SAR_ATTR_SPECS_RANGE_INDEX.
*
* For sar_capa dump, it contains array of
* %NL80211_SAR_ATTR_SPECS_START_FREQ
* and %NL80211_SAR_ATTR_SPECS_END_FREQ.
*
* @__NL80211_SAR_ATTR_LAST: Internal
* @NL80211_SAR_ATTR_MAX: highest sar attribute
*
* These attributes are used with %NL80211_CMD_SET_SAR_SPEC
*/
enum nl80211_sar_attrs {
__NL80211_SAR_ATTR_INVALID,
NL80211_SAR_ATTR_TYPE,
NL80211_SAR_ATTR_SPECS,
__NL80211_SAR_ATTR_LAST,
NL80211_SAR_ATTR_MAX = __NL80211_SAR_ATTR_LAST - 1,
};
/**
* enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs
*
* @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual
* power limit value in units of 0.25 dBm if type is
* NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm).
* 0 means userspace doesn't have SAR limitation on this associated range.
*
* @NL80211_SAR_ATTR_SPECS_RANGE_INDEX: Required (u32) value to specify the
* index of exported freq range table and the associated power limitation
* is applied to this range.
*
* Userspace isn't required to set all the ranges advertised by WLAN driver,
* and userspace can skip some certain ranges. These skipped ranges don't
* have SAR limitations, and they are same as setting the
* %NL80211_SAR_ATTR_SPECS_POWER to any unreasonable high value because any
* value higher than regulatory allowed value just means SAR power
* limitation is removed, but it's required to set at least one range.
* It's not allowed to set duplicated range in one SET operation.
*
* Every SET operation overwrites previous SET operation.
*
* @NL80211_SAR_ATTR_SPECS_START_FREQ: Required (u32) value to specify the start
* frequency of this range edge when registering SAR capability to wiphy.
* It's not a channel center frequency. The unit is kHz.
*
* @NL80211_SAR_ATTR_SPECS_END_FREQ: Required (u32) value to specify the end
* frequency of this range edge when registering SAR capability to wiphy.
* It's not a channel center frequency. The unit is kHz.
*
* @__NL80211_SAR_ATTR_SPECS_LAST: Internal
* @NL80211_SAR_ATTR_SPECS_MAX: highest sar specs attribute
*/
enum nl80211_sar_specs_attrs {
__NL80211_SAR_ATTR_SPECS_INVALID,
NL80211_SAR_ATTR_SPECS_POWER,
NL80211_SAR_ATTR_SPECS_RANGE_INDEX,
NL80211_SAR_ATTR_SPECS_START_FREQ,
NL80211_SAR_ATTR_SPECS_END_FREQ,
__NL80211_SAR_ATTR_SPECS_LAST,
NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1,
};
#endif /* __LINUX_NL80211_H */ #endif /* __LINUX_NL80211_H */

View File

@ -69,6 +69,16 @@ enum rfkill_operation {
RFKILL_OP_CHANGE_ALL, RFKILL_OP_CHANGE_ALL,
}; };
/**
* enum rfkill_hard_block_reasons - hard block reasons
* @RFKILL_HARD_BLOCK_SIGNAL: the hardware rfkill signal is active
* @RFKILL_HARD_BLOCK_NOT_OWNER: the NIC is not owned by the host
*/
enum rfkill_hard_block_reasons {
RFKILL_HARD_BLOCK_SIGNAL = 1 << 0,
RFKILL_HARD_BLOCK_NOT_OWNER = 1 << 1,
};
/** /**
* struct rfkill_event - events for userspace on /dev/rfkill * struct rfkill_event - events for userspace on /dev/rfkill
* @idx: index of dev rfkill * @idx: index of dev rfkill
@ -76,6 +86,8 @@ enum rfkill_operation {
* @op: operation code * @op: operation code
* @hard: hard state (0/1) * @hard: hard state (0/1)
* @soft: soft state (0/1) * @soft: soft state (0/1)
* @hard_block_reasons: valid if hard is set. One or several reasons from
* &enum rfkill_hard_block_reasons.
* *
* Structure used for userspace communication on /dev/rfkill, * Structure used for userspace communication on /dev/rfkill,
* used for events from the kernel and control to the kernel. * used for events from the kernel and control to the kernel.
@ -84,7 +96,9 @@ struct rfkill_event {
__u32 idx; __u32 idx;
__u8 type; __u8 type;
__u8 op; __u8 op;
__u8 soft, hard; __u8 soft;
__u8 hard;
__u8 hard_block_reasons;
} __attribute__((packed)); } __attribute__((packed));
/* /*

View File

@ -250,10 +250,10 @@ static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
mgmt->u.action.u.addba_resp.dialog_token = dialog_token; mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
capab = (u16)(amsdu << 0); /* bit 0 A-MSDU support */ capab = u16_encode_bits(amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK);
capab |= (u16)(policy << 1); /* bit 1 aggregation policy */ capab |= u16_encode_bits(policy, IEEE80211_ADDBA_PARAM_POLICY_MASK);
capab |= (u16)(tid << 2); /* bit 5:2 TID number */ capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ capab |= u16_encode_bits(buf_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);

View File

@ -95,10 +95,10 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
mgmt->u.action.u.addba_req.dialog_token = dialog_token; mgmt->u.action.u.addba_req.dialog_token = dialog_token;
capab = (u16)(1 << 0); /* bit 0 A-MSDU support */ capab = IEEE80211_ADDBA_PARAM_AMSDU_MASK;
capab |= (u16)(1 << 1); /* bit 1 aggregation policy */ capab |= IEEE80211_ADDBA_PARAM_POLICY_MASK;
capab |= (u16)(tid << 2); /* bit 5:2 TID number */ capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ capab |= u16_encode_bits(agg_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
@ -950,8 +950,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK; amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; tid = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_TID_MASK);
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; buf_size = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes); buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
txq = sta->sta.txq[tid]; txq = sta->sta.txq[tid];

View File

@ -405,6 +405,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
if (WARN_ON_ONCE(fips_enabled)) if (WARN_ON_ONCE(fips_enabled))
return -EINVAL; return -EINVAL;
break;
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_AES_CMAC:
@ -1121,10 +1122,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->vif.bss_conf.enable_beacon = true; sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p; sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p;
sdata->vif.bss_conf.twt_responder = params->twt_responder; sdata->vif.bss_conf.twt_responder = params->twt_responder;
memcpy(&sdata->vif.bss_conf.he_obss_pd, &params->he_obss_pd, sdata->vif.bss_conf.he_obss_pd = params->he_obss_pd;
sizeof(struct ieee80211_he_obss_pd)); sdata->vif.bss_conf.he_bss_color = params->he_bss_color;
memcpy(&sdata->vif.bss_conf.he_bss_color, &params->he_bss_color,
sizeof(struct ieee80211_he_bss_color));
sdata->vif.bss_conf.s1g = params->chandef.chan->band == sdata->vif.bss_conf.s1g = params->chandef.chan->band ==
NL80211_BAND_S1GHZ; NL80211_BAND_S1GHZ;
@ -3297,6 +3296,7 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
if (cfg80211_get_chandef_type(&params->chandef) != if (cfg80211_get_chandef_type(&params->chandef) !=
cfg80211_get_chandef_type(&sdata->u.ibss.chandef)) cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
return -EINVAL; return -EINVAL;
break;
case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10: case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20_NOHT:
@ -3448,7 +3448,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
IEEE80211_QUEUE_STOP_REASON_CSA); IEEE80211_QUEUE_STOP_REASON_CSA);
cfg80211_ch_switch_started_notify(sdata->dev, &sdata->csa_chandef, cfg80211_ch_switch_started_notify(sdata->dev, &sdata->csa_chandef,
params->count); params->count, params->block_tx);
if (changed) { if (changed) {
ieee80211_bss_info_change_notify(sdata, changed); ieee80211_bss_info_change_notify(sdata, changed);
@ -4073,6 +4073,17 @@ static int ieee80211_reset_tid_config(struct wiphy *wiphy,
return ret; return ret;
} }
static int ieee80211_set_sar_specs(struct wiphy *wiphy,
struct cfg80211_sar_specs *sar)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
if (!local->ops->set_sar_specs)
return -EOPNOTSUPP;
return local->ops->set_sar_specs(&local->hw, sar);
}
const struct cfg80211_ops mac80211_config_ops = { const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface, .add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface, .del_virtual_intf = ieee80211_del_iface,
@ -4175,4 +4186,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.probe_mesh_link = ieee80211_probe_mesh_link, .probe_mesh_link = ieee80211_probe_mesh_link,
.set_tid_config = ieee80211_set_tid_config, .set_tid_config = ieee80211_set_tid_config,
.reset_tid_config = ieee80211_reset_tid_config, .reset_tid_config = ieee80211_reset_tid_config,
.set_sar_specs = ieee80211_set_sar_specs,
}; };

View File

@ -9,6 +9,7 @@
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "driver-ops.h" #include "driver-ops.h"
#include "rate.h"
static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local, static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx) struct ieee80211_chanctx *ctx)
@ -191,11 +192,13 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
return NULL; return NULL;
} }
enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta)
{ {
switch (sta->bandwidth) { enum ieee80211_sta_rx_bandwidth width = ieee80211_sta_cap_rx_bw(sta);
switch (width) {
case IEEE80211_STA_RX_BW_20: case IEEE80211_STA_RX_BW_20:
if (sta->ht_cap.ht_supported) if (sta->sta.ht_cap.ht_supported)
return NL80211_CHAN_WIDTH_20; return NL80211_CHAN_WIDTH_20;
else else
return NL80211_CHAN_WIDTH_20_NOHT; return NL80211_CHAN_WIDTH_20_NOHT;
@ -232,7 +235,7 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
!(sta->sdata->bss && sta->sdata->bss == sdata->bss)) !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
continue; continue;
max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta)); max_bw = max(max_bw, ieee80211_get_sta_bw(sta));
} }
rcu_read_unlock(); rcu_read_unlock();
@ -343,10 +346,42 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH); drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);
} }
static void ieee80211_chan_bw_change(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
struct sta_info *sta;
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[ctx->conf.def.chan->band];
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list,
list) {
enum ieee80211_sta_rx_bandwidth new_sta_bw;
if (!ieee80211_sdata_running(sta->sdata))
continue;
if (rcu_access_pointer(sta->sdata->vif.chanctx_conf) !=
&ctx->conf)
continue;
new_sta_bw = ieee80211_sta_cur_vht_bw(sta);
if (new_sta_bw == sta->sta.bandwidth)
continue;
sta->sta.bandwidth = new_sta_bw;
rate_control_rate_update(local, sband, sta,
IEEE80211_RC_BW_CHANGED);
}
rcu_read_unlock();
}
static void ieee80211_change_chanctx(struct ieee80211_local *local, static void ieee80211_change_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx, struct ieee80211_chanctx *ctx,
const struct cfg80211_chan_def *chandef) const struct cfg80211_chan_def *chandef)
{ {
enum nl80211_chan_width width;
if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) { if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) {
ieee80211_recalc_chanctx_min_def(local, ctx); ieee80211_recalc_chanctx_min_def(local, ctx);
return; return;
@ -354,7 +389,25 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef)); WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
width = ctx->conf.def.width;
ctx->conf.def = *chandef; ctx->conf.def = *chandef;
/* expected to handle only 20/40/80/160 channel widths */
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_40:
case NL80211_CHAN_WIDTH_80:
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
break;
default:
WARN_ON(1);
}
if (chandef->width < width)
ieee80211_chan_bw_change(local, ctx);
drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
ieee80211_recalc_chanctx_min_def(local, ctx); ieee80211_recalc_chanctx_min_def(local, ctx);
@ -362,6 +415,9 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
local->_oper_chandef = *chandef; local->_oper_chandef = *chandef;
ieee80211_hw_config(local, 0); ieee80211_hw_config(local, 0);
} }
if (chandef->width > width)
ieee80211_chan_bw_change(local, ctx);
} }
static struct ieee80211_chanctx * static struct ieee80211_chanctx *
@ -1051,8 +1107,14 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
if (WARN_ON(!chandef)) if (WARN_ON(!chandef))
return -EINVAL; return -EINVAL;
if (old_ctx->conf.def.width > new_ctx->conf.def.width)
ieee80211_chan_bw_change(local, new_ctx);
ieee80211_change_chanctx(local, new_ctx, chandef); ieee80211_change_chanctx(local, new_ctx, chandef);
if (old_ctx->conf.def.width < new_ctx->conf.def.width)
ieee80211_chan_bw_change(local, new_ctx);
vif_chsw[0].vif = &sdata->vif; vif_chsw[0].vif = &sdata->vif;
vif_chsw[0].old_ctx = &old_ctx->conf; vif_chsw[0].old_ctx = &old_ctx->conf;
vif_chsw[0].new_ctx = &new_ctx->conf; vif_chsw[0].new_ctx = &new_ctx->conf;
@ -1443,6 +1505,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
ieee80211_recalc_smps_chanctx(local, ctx); ieee80211_recalc_smps_chanctx(local, ctx);
ieee80211_recalc_radar_chanctx(local, ctx); ieee80211_recalc_radar_chanctx(local, ctx);
ieee80211_recalc_chanctx_min_def(local, ctx); ieee80211_recalc_chanctx_min_def(local, ctx);
ieee80211_chan_bw_change(local, ctx);
list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs, list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
reserved_chanctx_list) { reserved_chanctx_list) {

View File

@ -53,7 +53,7 @@ static const struct file_operations name## _ops = { \
DEBUGFS_READONLY_FILE_OPS(name) DEBUGFS_READONLY_FILE_OPS(name)
#define DEBUGFS_ADD(name) \ #define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, phyd, local, &name## _ops); debugfs_create_file(#name, 0400, phyd, local, &name## _ops)
#define DEBUGFS_ADD_MODE(name, mode) \ #define DEBUGFS_ADD_MODE(name, mode) \
debugfs_create_file(#name, mode, phyd, local, &name## _ops); debugfs_create_file(#name, mode, phyd, local, &name## _ops);

View File

@ -319,7 +319,7 @@ KEY_OPS(key);
#define DEBUGFS_ADD(name) \ #define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, key->debugfs.dir, \ debugfs_create_file(#name, 0400, key->debugfs.dir, \
key, &key_##name##_ops); key, &key_##name##_ops)
#define DEBUGFS_ADD_W(name) \ #define DEBUGFS_ADD_W(name) \
debugfs_create_file(#name, 0600, key->debugfs.dir, \ debugfs_create_file(#name, 0600, key->debugfs.dir, \
key, &key_##name##_ops); key, &key_##name##_ops);

View File

@ -642,7 +642,7 @@ IEEE80211_IF_FILE(dot11MeshConnectedToAuthServer,
#define DEBUGFS_ADD_MODE(name, mode) \ #define DEBUGFS_ADD_MODE(name, mode) \
debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \ debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \
sdata, &name##_ops); sdata, &name##_ops)
#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400) #define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
@ -711,7 +711,7 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
struct dentry *dir = debugfs_create_dir("mesh_stats", struct dentry *dir = debugfs_create_dir("mesh_stats",
sdata->vif.debugfs_dir); sdata->vif.debugfs_dir);
#define MESHSTATS_ADD(name)\ #define MESHSTATS_ADD(name)\
debugfs_create_file(#name, 0400, dir, sdata, &name##_ops); debugfs_create_file(#name, 0400, dir, sdata, &name##_ops)
MESHSTATS_ADD(fwded_mcast); MESHSTATS_ADD(fwded_mcast);
MESHSTATS_ADD(fwded_unicast); MESHSTATS_ADD(fwded_unicast);
@ -728,7 +728,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
sdata->vif.debugfs_dir); sdata->vif.debugfs_dir);
#define MESHPARAMS_ADD(name) \ #define MESHPARAMS_ADD(name) \
debugfs_create_file(#name, 0600, dir, sdata, &name##_ops); debugfs_create_file(#name, 0600, dir, sdata, &name##_ops)
MESHPARAMS_ADD(dot11MeshMaxRetries); MESHPARAMS_ADD(dot11MeshMaxRetries);
MESHPARAMS_ADD(dot11MeshRetryTimeout); MESHPARAMS_ADD(dot11MeshRetryTimeout);

View File

@ -985,7 +985,7 @@ STA_OPS(he_capa);
#define DEBUGFS_ADD(name) \ #define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, \ debugfs_create_file(#name, 0400, \
sta->debugfs_dir, sta, &sta_ ##name## _ops); sta->debugfs_dir, sta, &sta_ ##name## _ops)
#define DEBUGFS_ADD_COUNTER(name, field) \ #define DEBUGFS_ADD_COUNTER(name, field) \
debugfs_create_ulong(#name, 0400, sta->debugfs_dir, &sta->field); debugfs_create_ulong(#name, 0400, sta->debugfs_dir, &sta->field);

View File

@ -452,7 +452,9 @@ struct ieee80211_if_managed {
unsigned long probe_timeout; unsigned long probe_timeout;
int probe_send_count; int probe_send_count;
bool nullfunc_failed; bool nullfunc_failed;
bool connection_loss; u8 connection_loss:1,
driver_disconnect:1,
reconnect:1;
struct cfg80211_bss *associated; struct cfg80211_bss *associated;
struct ieee80211_mgd_auth_data *auth_data; struct ieee80211_mgd_auth_data *auth_data;
@ -1587,13 +1589,8 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
{ {
WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START && WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START &&
status->flag & RX_FLAG_MACTIME_END); status->flag & RX_FLAG_MACTIME_END);
if (status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END)) return !!(status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END |
return true; RX_FLAG_MACTIME_PLCP_START));
/* can't handle non-legacy preamble yet */
if (status->flag & RX_FLAG_MACTIME_PLCP_START &&
status->encoding == RX_ENC_LEGACY)
return true;
return false;
} }
void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata); void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata);
@ -2280,7 +2277,6 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
enum ieee80211_chanctx_mode chanmode, enum ieee80211_chanctx_mode chanmode,
u8 radar_detect); u8 radar_detect);
int ieee80211_max_num_channels(struct ieee80211_local *local); int ieee80211_max_num_channels(struct ieee80211_local *local);
enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta);
void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx); struct ieee80211_chanctx *ctx);

View File

@ -1300,3 +1300,52 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
return &key->conf; return &key->conf;
} }
EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_add); EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_add);
void ieee80211_key_mic_failure(struct ieee80211_key_conf *keyconf)
{
struct ieee80211_key *key;
key = container_of(keyconf, struct ieee80211_key, conf);
switch (key->conf.cipher) {
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
key->u.aes_cmac.icverrors++;
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
key->u.aes_gmac.icverrors++;
break;
default:
/* ignore the others for now, we don't keep counters now */
break;
}
}
EXPORT_SYMBOL_GPL(ieee80211_key_mic_failure);
void ieee80211_key_replay(struct ieee80211_key_conf *keyconf)
{
struct ieee80211_key *key;
key = container_of(keyconf, struct ieee80211_key, conf);
switch (key->conf.cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256:
key->u.ccmp.replays++;
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
key->u.aes_cmac.replays++;
break;
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
key->u.aes_gmac.replays++;
break;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
key->u.gcmp.replays++;
break;
}
}
EXPORT_SYMBOL_GPL(ieee80211_key_replay);

View File

@ -1417,6 +1417,17 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return; return;
} }
if (sdata->vif.bss_conf.chandef.chan->band !=
csa_ie.chandef.chan->band) {
sdata_info(sdata,
"AP %pM switches to different band (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
ifmgd->associated->bssid,
csa_ie.chandef.chan->center_freq,
csa_ie.chandef.width, csa_ie.chandef.center_freq1,
csa_ie.chandef.center_freq2);
goto lock_and_drop_connection;
}
if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef, if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
IEEE80211_CHAN_DISABLED)) { IEEE80211_CHAN_DISABLED)) {
sdata_info(sdata, sdata_info(sdata,
@ -1429,9 +1440,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
csa_ie.chandef.width, csa_ie.chandef.center_freq1, csa_ie.chandef.width, csa_ie.chandef.center_freq1,
csa_ie.chandef.freq1_offset, csa_ie.chandef.freq1_offset,
csa_ie.chandef.center_freq2); csa_ie.chandef.center_freq2);
ieee80211_queue_work(&local->hw, goto lock_and_drop_connection;
&ifmgd->csa_connection_drop_work);
return;
} }
if (cfg80211_chandef_identical(&csa_ie.chandef, if (cfg80211_chandef_identical(&csa_ie.chandef,
@ -1493,6 +1502,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
sdata->csa_chandef = csa_ie.chandef; sdata->csa_chandef = csa_ie.chandef;
sdata->csa_block_tx = csa_ie.mode; sdata->csa_block_tx = csa_ie.mode;
ifmgd->csa_ignored_same_chan = false; ifmgd->csa_ignored_same_chan = false;
ifmgd->beacon_crc_valid = false;
if (sdata->csa_block_tx) if (sdata->csa_block_tx)
ieee80211_stop_vif_queues(local, sdata, ieee80211_stop_vif_queues(local, sdata,
@ -1500,7 +1510,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef,
csa_ie.count); csa_ie.count, csa_ie.mode);
if (local->ops->channel_switch) { if (local->ops->channel_switch) {
/* use driver's channel switch callback */ /* use driver's channel switch callback */
@ -1516,6 +1526,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
TU_TO_EXP_TIME((csa_ie.count - 1) * TU_TO_EXP_TIME((csa_ie.count - 1) *
cbss->beacon_interval)); cbss->beacon_interval));
return; return;
lock_and_drop_connection:
mutex_lock(&local->mtx);
mutex_lock(&local->chanctx_mtx);
drop_connection: drop_connection:
/* /*
* This is just so that the disconnect flow will know that * This is just so that the disconnect flow will know that
@ -1560,9 +1573,17 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
chan_increment = 1; chan_increment = 1;
break; break;
case NL80211_BAND_5GHZ: case NL80211_BAND_5GHZ:
case NL80211_BAND_6GHZ:
chan_increment = 4; chan_increment = 4;
break; break;
case NL80211_BAND_6GHZ:
/*
* In the 6 GHz band, the "maximum transmit power level"
* field in the triplets is reserved, and thus will be
* zero and we shouldn't use it to control TX power.
* The actual TX power will be given in the transmit
* power envelope element instead.
*/
return false;
} }
/* find channel */ /* find channel */
@ -2382,6 +2403,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* clear bssid only after building the needed mgmt frames */ /* clear bssid only after building the needed mgmt frames */
eth_zero_addr(ifmgd->bssid); eth_zero_addr(ifmgd->bssid);
sdata->vif.bss_conf.ssid_len = 0;
/* remove AP and TDLS peers */ /* remove AP and TDLS peers */
sta_info_flush(sdata); sta_info_flush(sdata);
@ -2720,7 +2743,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get);
static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata,
const u8 *buf, size_t len, bool tx, const u8 *buf, size_t len, bool tx,
u16 reason) u16 reason, bool reconnect)
{ {
struct ieee80211_event event = { struct ieee80211_event event = {
.type = MLME_EVENT, .type = MLME_EVENT,
@ -2729,7 +2752,7 @@ static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata,
}; };
if (tx) if (tx)
cfg80211_tx_mlme_mgmt(sdata->dev, buf, len); cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, reconnect);
else else
cfg80211_rx_mlme_mgmt(sdata->dev, buf, len); cfg80211_rx_mlme_mgmt(sdata->dev, buf, len);
@ -2751,13 +2774,18 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
tx = !sdata->csa_block_tx; tx = !sdata->csa_block_tx;
/* AP is probably out of range (or not reachable for another reason) so if (!ifmgd->driver_disconnect) {
* remove the bss struct for that AP. /*
*/ * AP is probably out of range (or not reachable for another
cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated); * reason) so remove the bss struct for that AP.
*/
cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated);
}
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, ifmgd->driver_disconnect ?
WLAN_REASON_DEAUTH_LEAVING :
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
tx, frame_buf); tx, frame_buf);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
sdata->vif.csa_active = false; sdata->vif.csa_active = false;
@ -2770,7 +2798,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx, ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
ifmgd->reconnect);
ifmgd->reconnect = false;
sdata_unlock(sdata); sdata_unlock(sdata);
} }
@ -2789,6 +2819,13 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
sdata_info(sdata, "Connection to AP %pM lost\n", sdata_info(sdata, "Connection to AP %pM lost\n",
ifmgd->bssid); ifmgd->bssid);
__ieee80211_disconnect(sdata); __ieee80211_disconnect(sdata);
ifmgd->connection_loss = false;
} else if (ifmgd->driver_disconnect) {
sdata_info(sdata,
"Driver requested disconnection from AP %pM\n",
ifmgd->bssid);
__ieee80211_disconnect(sdata);
ifmgd->driver_disconnect = false;
} else { } else {
ieee80211_mgd_probe_ap(sdata, true); ieee80211_mgd_probe_ap(sdata, true);
} }
@ -2827,6 +2864,21 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif)
} }
EXPORT_SYMBOL(ieee80211_connection_loss); EXPORT_SYMBOL(ieee80211_connection_loss);
void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_hw *hw = &sdata->local->hw;
trace_api_disconnect(sdata, reconnect);
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
return;
sdata->u.mgd.driver_disconnect = true;
sdata->u.mgd.reconnect = reconnect;
ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
}
EXPORT_SYMBOL(ieee80211_disconnect);
static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
bool assoc) bool assoc)
@ -3130,7 +3182,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, 0, 0, false, NULL); ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false,
reason_code); reason_code, false);
return; return;
} }
@ -3179,7 +3231,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, 0, 0, false, NULL); ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code,
false);
} }
static void ieee80211_get_rates(struct ieee80211_supported_band *sband, static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
@ -3199,8 +3252,8 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
*have_higher_than_11mbit = true; *have_higher_than_11mbit = true;
/* /*
* Skip HT, VHT and HE BSS membership selectors since they're * Skip HT, VHT, HE and SAE H2E only BSS membership selectors
* not rates. * since they're not rates.
* *
* Note: Even though the membership selector and the basic * Note: Even though the membership selector and the basic
* rate flag share the same bit, they are not exactly * rate flag share the same bit, they are not exactly
@ -3208,7 +3261,8 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
*/ */
if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) || if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) ||
supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY) || supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY) ||
supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY)) supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY) ||
supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E))
continue; continue;
for (j = 0; j < sband->n_bitrates; j++) { for (j = 0; j < sband->n_bitrates; j++) {
@ -3494,14 +3548,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
le32_get_bits(elems->he_operation->he_oper_params, le32_get_bits(elems->he_operation->he_oper_params,
IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK); IEEE80211_HE_OPERATION_RTS_THRESHOLD_MASK);
bss_conf->multi_sta_back_32bit =
sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP;
bss_conf->ack_enabled =
sta->sta.he_cap.he_cap_elem.mac_cap_info[2] &
IEEE80211_HE_MAC_CAP2_ACK_EN;
bss_conf->uora_exists = !!elems->uora_element; bss_conf->uora_exists = !!elems->uora_element;
if (elems->uora_element) if (elems->uora_element)
bss_conf->uora_ocw_range = elems->uora_element[0]; bss_conf->uora_ocw_range = elems->uora_element[0];
@ -4199,7 +4245,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
true, deauth_buf); true, deauth_buf);
ieee80211_report_disconnect(sdata, deauth_buf, ieee80211_report_disconnect(sdata, deauth_buf,
sizeof(deauth_buf), true, sizeof(deauth_buf), true,
WLAN_REASON_DEAUTH_LEAVING); WLAN_REASON_DEAUTH_LEAVING,
false);
return; return;
} }
@ -4344,7 +4391,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
tx, frame_buf); tx, frame_buf);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
reason); reason, false);
} }
static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) static int ieee80211_auth(struct ieee80211_sub_if_data *sdata)
@ -4716,7 +4763,8 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
if (ifmgd->auth_data) if (ifmgd->auth_data)
ieee80211_destroy_auth_data(sdata, false); ieee80211_destroy_auth_data(sdata, false);
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
IEEE80211_DEAUTH_FRAME_LEN); IEEE80211_DEAUTH_FRAME_LEN,
false);
} }
/* This is a bit of a hack - we should find a better and more generic /* This is a bit of a hack - we should find a better and more generic
@ -5430,7 +5478,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
ieee80211_report_disconnect(sdata, frame_buf, ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true, sizeof(frame_buf), true,
WLAN_REASON_UNSPECIFIED); WLAN_REASON_UNSPECIFIED,
false);
} }
sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
@ -5471,6 +5520,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgd_assoc_data *assoc_data; struct ieee80211_mgd_assoc_data *assoc_data;
const struct cfg80211_bss_ies *beacon_ies; const struct cfg80211_bss_ies *beacon_ies;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
const u8 *ssidie, *ht_ie, *vht_ie; const u8 *ssidie, *ht_ie, *vht_ie;
int i, err; int i, err;
bool override = false; bool override = false;
@ -5488,6 +5538,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
} }
memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]); memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]);
assoc_data->ssid_len = ssidie[1]; assoc_data->ssid_len = ssidie[1];
memcpy(bss_conf->ssid, assoc_data->ssid, assoc_data->ssid_len);
bss_conf->ssid_len = assoc_data->ssid_len;
rcu_read_unlock(); rcu_read_unlock();
if (ifmgd->associated) { if (ifmgd->associated) {
@ -5502,7 +5554,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ieee80211_report_disconnect(sdata, frame_buf, ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true, sizeof(frame_buf), true,
WLAN_REASON_UNSPECIFIED); WLAN_REASON_UNSPECIFIED,
false);
} }
if (ifmgd->auth_data && !ifmgd->auth_data->done) { if (ifmgd->auth_data && !ifmgd->auth_data->done) {
@ -5801,7 +5854,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_destroy_auth_data(sdata, false); ieee80211_destroy_auth_data(sdata, false);
ieee80211_report_disconnect(sdata, frame_buf, ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true, sizeof(frame_buf), true,
req->reason_code); req->reason_code, false);
return 0; return 0;
} }
@ -5821,7 +5874,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_destroy_assoc_data(sdata, false, true); ieee80211_destroy_assoc_data(sdata, false, true);
ieee80211_report_disconnect(sdata, frame_buf, ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true, sizeof(frame_buf), true,
req->reason_code); req->reason_code, false);
return 0; return 0;
} }
@ -5836,7 +5889,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
req->reason_code, tx, frame_buf); req->reason_code, tx, frame_buf);
ieee80211_report_disconnect(sdata, frame_buf, ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true, sizeof(frame_buf), true,
req->reason_code); req->reason_code, false);
return 0; return 0;
} }
@ -5869,7 +5922,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
frame_buf); frame_buf);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
req->reason_code); req->reason_code, false);
return 0; return 0;
} }

View File

@ -32,16 +32,6 @@
#include "wme.h" #include "wme.h"
#include "rate.h" #include "rate.h"
static inline void ieee80211_rx_stats(struct net_device *dev, u32 len)
{
struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
u64_stats_update_begin(&tstats->syncp);
tstats->rx_packets++;
tstats->rx_bytes += len;
u64_stats_update_end(&tstats->syncp);
}
/* /*
* monitor mode reception * monitor mode reception
* *
@ -842,7 +832,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (skb) { if (skb) {
skb->dev = sdata->dev; skb->dev = sdata->dev;
ieee80211_rx_stats(skb->dev, skb->len); dev_sw_netstats_rx_add(skb->dev, skb->len);
netif_receive_skb(skb); netif_receive_skb(skb);
} }
} }
@ -1757,7 +1747,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
} else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
sta->rx_stats.last_rx = jiffies; sta->rx_stats.last_rx = jiffies;
} else if (!ieee80211_is_s1g_beacon(hdr->frame_control) && } else if (!ieee80211_is_s1g_beacon(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1)) { !is_multicast_ether_addr(hdr->addr1)) {
/* /*
* Mesh beacons will update last_rx when if they are found to * Mesh beacons will update last_rx when if they are found to
* match the current local configuration when processed. * match the current local configuration when processed.
@ -2559,7 +2549,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
skb = rx->skb; skb = rx->skb;
xmit_skb = NULL; xmit_skb = NULL;
ieee80211_rx_stats(dev, skb->len); dev_sw_netstats_rx_add(dev, skb->len);
if (rx->sta) { if (rx->sta) {
/* The seqno index has the same property as needed /* The seqno index has the same property as needed
@ -3698,7 +3688,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
} }
prev_dev = sdata->dev; prev_dev = sdata->dev;
ieee80211_rx_stats(sdata->dev, skb->len); dev_sw_netstats_rx_add(sdata->dev, skb->len);
} }
if (prev_dev) { if (prev_dev) {
@ -4411,7 +4401,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
skb->dev = fast_rx->dev; skb->dev = fast_rx->dev;
ieee80211_rx_stats(fast_rx->dev, skb->len); dev_sw_netstats_rx_add(fast_rx->dev, skb->len);
/* The seqno index has the same property as needed /* The seqno index has the same property as needed
* for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS

View File

@ -2,7 +2,7 @@
/* /*
* Portions of this file * Portions of this file
* Copyright(c) 2016-2017 Intel Deutschland GmbH * Copyright(c) 2016-2017 Intel Deutschland GmbH
* Copyright (C) 2018 - 2019 Intel Corporation * Copyright (C) 2018 - 2020 Intel Corporation
*/ */
#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
@ -2086,6 +2086,27 @@ TRACE_EVENT(api_connection_loss,
) )
); );
TRACE_EVENT(api_disconnect,
TP_PROTO(struct ieee80211_sub_if_data *sdata, bool reconnect),
TP_ARGS(sdata, reconnect),
TP_STRUCT__entry(
VIF_ENTRY
__field(int, reconnect)
),
TP_fast_assign(
VIF_ASSIGN;
__entry->reconnect = reconnect;
),
TP_printk(
VIF_PR_FMT " reconnect:%d",
VIF_PR_ARG, __entry->reconnect
)
);
TRACE_EVENT(api_cqm_rssi_notify, TRACE_EVENT(api_cqm_rssi_notify,
TP_PROTO(struct ieee80211_sub_if_data *sdata, TP_PROTO(struct ieee80211_sub_if_data *sdata,
enum nl80211_cqm_rssi_threshold_event rssi_event, enum nl80211_cqm_rssi_threshold_event rssi_event,

View File

@ -38,16 +38,6 @@
/* misc utils */ /* misc utils */
static inline void ieee80211_tx_stats(struct net_device *dev, u32 len)
{
struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
u64_stats_update_begin(&tstats->syncp);
tstats->tx_packets++;
tstats->tx_bytes += len;
u64_stats_update_end(&tstats->syncp);
}
static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
struct sk_buff *skb, int group_addr, struct sk_buff *skb, int group_addr,
int next_frag_len) int next_frag_len)
@ -3386,7 +3376,7 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
if (key) if (key)
info->control.hw_key = &key->conf; info->control.hw_key = &key->conf;
ieee80211_tx_stats(skb->dev, skb->len); dev_sw_netstats_tx_add(skb->dev, 1, skb->len);
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
@ -4004,7 +3994,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
goto out; goto out;
} }
ieee80211_tx_stats(dev, skb->len); dev_sw_netstats_tx_add(dev, 1, skb->len);
ieee80211_xmit(sdata, sta, skb); ieee80211_xmit(sdata, sta, skb);
} }
@ -4231,7 +4221,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
ieee80211_tx_stats(dev, skb->len); dev_sw_netstats_tx_add(dev, 1, skb->len);
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;

View File

@ -3666,6 +3666,7 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
u64 ts = status->mactime; u64 ts = status->mactime;
struct rate_info ri; struct rate_info ri;
u16 rate; u16 rate;
u8 n_ltf;
if (WARN_ON(!ieee80211_have_rx_timestamp(status))) if (WARN_ON(!ieee80211_have_rx_timestamp(status)))
return 0; return 0;
@ -3676,11 +3677,58 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
/* Fill cfg80211 rate info */ /* Fill cfg80211 rate info */
switch (status->encoding) { switch (status->encoding) {
case RX_ENC_HE:
ri.flags |= RATE_INFO_FLAGS_HE_MCS;
ri.mcs = status->rate_idx;
ri.nss = status->nss;
ri.he_ru_alloc = status->he_ru;
if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
/*
* See P802.11ax_D6.0, section 27.3.4 for
* VHT PPDU format.
*/
if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
mpdu_offset += 2;
ts += 36;
/*
* TODO:
* For HE MU PPDU, add the HE-SIG-B.
* For HE ER PPDU, add 8us for the HE-SIG-A.
* For HE TB PPDU, add 4us for the HE-STF.
* Add the HE-LTF durations - variable.
*/
}
break;
case RX_ENC_HT: case RX_ENC_HT:
ri.mcs = status->rate_idx; ri.mcs = status->rate_idx;
ri.flags |= RATE_INFO_FLAGS_MCS; ri.flags |= RATE_INFO_FLAGS_MCS;
if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
ri.flags |= RATE_INFO_FLAGS_SHORT_GI; ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
/*
* See P802.11REVmd_D3.0, section 19.3.2 for
* HT PPDU format.
*/
if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
mpdu_offset += 2;
if (status->enc_flags & RX_ENC_FLAG_HT_GF)
ts += 24;
else
ts += 32;
/*
* Add Data HT-LTFs per streams
* TODO: add Extension HT-LTFs, 4us per LTF
*/
n_ltf = ((ri.mcs >> 3) & 3) + 1;
n_ltf = n_ltf == 3 ? 4 : n_ltf;
ts += n_ltf * 4;
}
break; break;
case RX_ENC_VHT: case RX_ENC_VHT:
ri.flags |= RATE_INFO_FLAGS_VHT_MCS; ri.flags |= RATE_INFO_FLAGS_VHT_MCS;
@ -3688,6 +3736,23 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
ri.nss = status->nss; ri.nss = status->nss;
if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
ri.flags |= RATE_INFO_FLAGS_SHORT_GI; ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
/*
* See P802.11REVmd_D3.0, section 21.3.2 for
* VHT PPDU format.
*/
if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
mpdu_offset += 2;
ts += 36;
/*
* Add VHT-LTFs per streams
*/
n_ltf = (ri.nss != 1) && (ri.nss % 2) ?
ri.nss + 1 : ri.nss;
ts += 4 * n_ltf;
}
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
@ -3711,7 +3776,6 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift)); ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
if (status->flag & RX_FLAG_MACTIME_PLCP_START) { if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
/* TODO: handle HT/VHT preambles */
if (status->band == NL80211_BAND_5GHZ) { if (status->band == NL80211_BAND_5GHZ) {
ts += 20 << shift; ts += 20 << shift;
mpdu_offset += 2; mpdu_offset += 2;

View File

@ -465,12 +465,18 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
* IEEE80211-2016 specification makes higher bandwidth operation * IEEE80211-2016 specification makes higher bandwidth operation
* possible on the TDLS link if the peers have wider bandwidth * possible on the TDLS link if the peers have wider bandwidth
* capability. * capability.
*
* However, in this case, and only if the TDLS peer is authorized,
* limit to the tdls_chandef so that the configuration here isn't
* wider than what's actually requested on the channel context.
*/ */
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW)) test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) &&
return bw; test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
sta->tdls_chandef.chan)
bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width)); bw = min(bw, ieee80211_chan_width_to_rx_bw(sta->tdls_chandef.width));
else
bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width));
return bw; return bw;
} }

View File

@ -40,6 +40,7 @@ struct rfkill {
enum rfkill_type type; enum rfkill_type type;
unsigned long state; unsigned long state;
unsigned long hard_block_reasons;
u32 idx; u32 idx;
@ -265,6 +266,7 @@ static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill,
ev->hard = !!(rfkill->state & RFKILL_BLOCK_HW); ev->hard = !!(rfkill->state & RFKILL_BLOCK_HW);
ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW | ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW |
RFKILL_BLOCK_SW_PREV)); RFKILL_BLOCK_SW_PREV));
ev->hard_block_reasons = rfkill->hard_block_reasons;
spin_unlock_irqrestore(&rfkill->lock, flags); spin_unlock_irqrestore(&rfkill->lock, flags);
} }
@ -522,19 +524,29 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type)
} }
#endif #endif
bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) bool rfkill_set_hw_state_reason(struct rfkill *rfkill,
bool blocked, unsigned long reason)
{ {
unsigned long flags; unsigned long flags;
bool ret, prev; bool ret, prev;
BUG_ON(!rfkill); BUG_ON(!rfkill);
if (WARN(reason &
~(RFKILL_HARD_BLOCK_SIGNAL | RFKILL_HARD_BLOCK_NOT_OWNER),
"hw_state reason not supported: 0x%lx", reason))
return blocked;
spin_lock_irqsave(&rfkill->lock, flags); spin_lock_irqsave(&rfkill->lock, flags);
prev = !!(rfkill->state & RFKILL_BLOCK_HW); prev = !!(rfkill->hard_block_reasons & reason);
if (blocked) if (blocked) {
rfkill->state |= RFKILL_BLOCK_HW; rfkill->state |= RFKILL_BLOCK_HW;
else rfkill->hard_block_reasons |= reason;
rfkill->state &= ~RFKILL_BLOCK_HW; } else {
rfkill->hard_block_reasons &= ~reason;
if (!rfkill->hard_block_reasons)
rfkill->state &= ~RFKILL_BLOCK_HW;
}
ret = !!(rfkill->state & RFKILL_BLOCK_ANY); ret = !!(rfkill->state & RFKILL_BLOCK_ANY);
spin_unlock_irqrestore(&rfkill->lock, flags); spin_unlock_irqrestore(&rfkill->lock, flags);
@ -546,7 +558,7 @@ bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
return ret; return ret;
} }
EXPORT_SYMBOL(rfkill_set_hw_state); EXPORT_SYMBOL(rfkill_set_hw_state_reason);
static void __rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) static void __rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
{ {
@ -744,6 +756,16 @@ static ssize_t soft_store(struct device *dev, struct device_attribute *attr,
} }
static DEVICE_ATTR_RW(soft); static DEVICE_ATTR_RW(soft);
static ssize_t hard_block_reasons_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rfkill *rfkill = to_rfkill(dev);
return sprintf(buf, "0x%lx\n", rfkill->hard_block_reasons);
}
static DEVICE_ATTR_RO(hard_block_reasons);
static u8 user_state_from_blocked(unsigned long state) static u8 user_state_from_blocked(unsigned long state)
{ {
if (state & RFKILL_BLOCK_HW) if (state & RFKILL_BLOCK_HW)
@ -796,6 +818,7 @@ static struct attribute *rfkill_dev_attrs[] = {
&dev_attr_state.attr, &dev_attr_state.attr,
&dev_attr_soft.attr, &dev_attr_soft.attr,
&dev_attr_hard.attr, &dev_attr_hard.attr,
&dev_attr_hard_block_reasons.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(rfkill_dev); ATTRIBUTE_GROUPS(rfkill_dev);
@ -811,6 +834,7 @@ static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{ {
struct rfkill *rfkill = to_rfkill(dev); struct rfkill *rfkill = to_rfkill(dev);
unsigned long flags; unsigned long flags;
unsigned long reasons;
u32 state; u32 state;
int error; int error;
@ -823,10 +847,13 @@ static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
return error; return error;
spin_lock_irqsave(&rfkill->lock, flags); spin_lock_irqsave(&rfkill->lock, flags);
state = rfkill->state; state = rfkill->state;
reasons = rfkill->hard_block_reasons;
spin_unlock_irqrestore(&rfkill->lock, flags); spin_unlock_irqrestore(&rfkill->lock, flags);
error = add_uevent_var(env, "RFKILL_STATE=%d", error = add_uevent_var(env, "RFKILL_STATE=%d",
user_state_from_blocked(state)); user_state_from_blocked(state));
return error; if (error)
return error;
return add_uevent_var(env, "RFKILL_HW_BLOCK_REASON=0x%lx", reasons);
} }
void rfkill_pause_polling(struct rfkill *rfkill) void rfkill_pause_polling(struct rfkill *rfkill)

View File

@ -433,6 +433,8 @@ void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev);
/* internal helpers */ /* internal helpers */
bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher); bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev,
int key_idx, bool pairwise);
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx, struct key_params *params, int key_idx,
bool pairwise, const u8 *mac_addr); bool pairwise, const u8 *mac_addr);

View File

@ -4,7 +4,7 @@
* *
* Copyright (c) 2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2015 Intel Deutschland GmbH * Copyright (c) 2015 Intel Deutschland GmbH
* Copyright (C) 2019 Intel Corporation * Copyright (C) 2019-2020 Intel Corporation
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
@ -81,7 +81,8 @@ static void cfg80211_process_auth(struct wireless_dev *wdev,
} }
static void cfg80211_process_deauth(struct wireless_dev *wdev, static void cfg80211_process_deauth(struct wireless_dev *wdev,
const u8 *buf, size_t len) const u8 *buf, size_t len,
bool reconnect)
{ {
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
@ -89,7 +90,7 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev,
u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL); nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL);
if (!wdev->current_bss || if (!wdev->current_bss ||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
@ -100,7 +101,8 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev,
} }
static void cfg80211_process_disassoc(struct wireless_dev *wdev, static void cfg80211_process_disassoc(struct wireless_dev *wdev,
const u8 *buf, size_t len) const u8 *buf, size_t len,
bool reconnect)
{ {
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
@ -108,7 +110,8 @@ static void cfg80211_process_disassoc(struct wireless_dev *wdev,
u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL); nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect,
GFP_KERNEL);
if (WARN_ON(!wdev->current_bss || if (WARN_ON(!wdev->current_bss ||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
@ -133,9 +136,9 @@ void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
if (ieee80211_is_auth(mgmt->frame_control)) if (ieee80211_is_auth(mgmt->frame_control))
cfg80211_process_auth(wdev, buf, len); cfg80211_process_auth(wdev, buf, len);
else if (ieee80211_is_deauth(mgmt->frame_control)) else if (ieee80211_is_deauth(mgmt->frame_control))
cfg80211_process_deauth(wdev, buf, len); cfg80211_process_deauth(wdev, buf, len, false);
else if (ieee80211_is_disassoc(mgmt->frame_control)) else if (ieee80211_is_disassoc(mgmt->frame_control))
cfg80211_process_disassoc(wdev, buf, len); cfg80211_process_disassoc(wdev, buf, len, false);
} }
EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt); EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt);
@ -180,22 +183,23 @@ void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss)
} }
EXPORT_SYMBOL(cfg80211_abandon_assoc); EXPORT_SYMBOL(cfg80211_abandon_assoc);
void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len,
bool reconnect)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_mgmt *mgmt = (void *)buf; struct ieee80211_mgmt *mgmt = (void *)buf;
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
trace_cfg80211_tx_mlme_mgmt(dev, buf, len); trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect);
if (WARN_ON(len < 2)) if (WARN_ON(len < 2))
return; return;
if (ieee80211_is_deauth(mgmt->frame_control)) if (ieee80211_is_deauth(mgmt->frame_control))
cfg80211_process_deauth(wdev, buf, len); cfg80211_process_deauth(wdev, buf, len, reconnect);
else else
cfg80211_process_disassoc(wdev, buf, len); cfg80211_process_disassoc(wdev, buf, len, reconnect);
} }
EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt); EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt);

View File

@ -399,6 +399,18 @@ nl80211_unsol_bcast_probe_resp_policy[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX +
.len = IEEE80211_MAX_DATA_LEN } .len = IEEE80211_MAX_DATA_LEN }
}; };
static const struct nla_policy
sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = {
[NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 },
[NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 },
};
static const struct nla_policy
sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
[NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE),
[NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
};
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD }, [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@ -718,6 +730,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_SAE_PWE] = [NL80211_ATTR_SAE_PWE] =
NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK, NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
NL80211_SAE_PWE_BOTH), NL80211_SAE_PWE_BOTH),
[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
[NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
}; };
/* policy for the key attributes */ /* policy for the key attributes */
@ -2094,6 +2108,56 @@ fail:
return -ENOBUFS; return -ENOBUFS;
} }
static int
nl80211_put_sar_specs(struct cfg80211_registered_device *rdev,
struct sk_buff *msg)
{
struct nlattr *sar_capa, *specs, *sub_freq_range;
u8 num_freq_ranges;
int i;
if (!rdev->wiphy.sar_capa)
return 0;
num_freq_ranges = rdev->wiphy.sar_capa->num_freq_ranges;
sar_capa = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC);
if (!sar_capa)
return -ENOSPC;
if (nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, rdev->wiphy.sar_capa->type))
goto fail;
specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS);
if (!specs)
goto fail;
/* report supported freq_ranges */
for (i = 0; i < num_freq_ranges; i++) {
sub_freq_range = nla_nest_start(msg, i + 1);
if (!sub_freq_range)
goto fail;
if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_START_FREQ,
rdev->wiphy.sar_capa->freq_ranges[i].start_freq))
goto fail;
if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_END_FREQ,
rdev->wiphy.sar_capa->freq_ranges[i].end_freq))
goto fail;
nla_nest_end(msg, sub_freq_range);
}
nla_nest_end(msg, specs);
nla_nest_end(msg, sar_capa);
return 0;
fail:
nla_nest_cancel(msg, sar_capa);
return -ENOBUFS;
}
struct nl80211_dump_wiphy_state { struct nl80211_dump_wiphy_state {
s64 filter_wiphy; s64 filter_wiphy;
long start; long start;
@ -2343,6 +2407,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST); CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
CMD(update_connect_params, UPDATE_CONNECT_PARAMS); CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
CMD(update_ft_ies, UPDATE_FT_IES); CMD(update_ft_ies, UPDATE_FT_IES);
if (rdev->wiphy.sar_capa)
CMD(set_sar_specs, SET_SAR_SPECS);
} }
#undef CMD #undef CMD
@ -2668,6 +2734,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
if (nl80211_put_tid_config_support(rdev, msg)) if (nl80211_put_tid_config_support(rdev, msg))
goto nla_put_failure; goto nla_put_failure;
state->split_start++;
break;
case 16:
if (nl80211_put_sar_specs(rdev, msg))
goto nla_put_failure;
/* done */ /* done */
state->split_start = 0; state->split_start = 0;
@ -4239,9 +4310,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
return err; return err;
if (key.idx < 0)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
@ -4257,6 +4325,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
key.type != NL80211_KEYTYPE_GROUP) key.type != NL80211_KEYTYPE_GROUP)
return -EINVAL; return -EINVAL;
if (!cfg80211_valid_key_idx(rdev, key.idx,
key.type == NL80211_KEYTYPE_PAIRWISE))
return -EINVAL;
if (!rdev->ops->del_key) if (!rdev->ops->del_key)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -5017,6 +5089,8 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
params->vht_required = true; params->vht_required = true;
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY) if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
params->he_required = true; params->he_required = true;
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_SAE_H2E)
params->sae_h2e_required = true;
} }
} }
@ -8241,12 +8315,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
} }
if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) { if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
if (!wiphy_ext_feature_isset(wiphy,
NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
err = -EOPNOTSUPP;
goto out_free;
}
request->duration = request->duration =
nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]); nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
request->duration_mandatory = request->duration_mandatory =
@ -11175,6 +11243,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_P2P_DEVICE:
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL; return -EINVAL;
break;
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_CLIENT:
@ -14669,6 +14738,111 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
} }
} }
static int nl80211_set_sar_sub_specs(struct cfg80211_registered_device *rdev,
struct cfg80211_sar_specs *sar_specs,
struct nlattr *spec[], int index)
{
u32 range_index, i;
if (!sar_specs || !spec)
return -EINVAL;
if (!spec[NL80211_SAR_ATTR_SPECS_POWER] ||
!spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX])
return -EINVAL;
range_index = nla_get_u32(spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]);
/* check if range_index exceeds num_freq_ranges */
if (range_index >= rdev->wiphy.sar_capa->num_freq_ranges)
return -EINVAL;
/* check if range_index duplicates */
for (i = 0; i < index; i++) {
if (sar_specs->sub_specs[i].freq_range_index == range_index)
return -EINVAL;
}
sar_specs->sub_specs[index].power =
nla_get_s32(spec[NL80211_SAR_ATTR_SPECS_POWER]);
sar_specs->sub_specs[index].freq_range_index = range_index;
return 0;
}
static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct nlattr *spec[NL80211_SAR_ATTR_SPECS_MAX + 1];
struct nlattr *tb[NL80211_SAR_ATTR_MAX + 1];
struct cfg80211_sar_specs *sar_spec;
enum nl80211_sar_type type;
struct nlattr *spec_list;
u32 specs;
int rem, err;
if (!rdev->wiphy.sar_capa || !rdev->ops->set_sar_specs)
return -EOPNOTSUPP;
if (!info->attrs[NL80211_ATTR_SAR_SPEC])
return -EINVAL;
nla_parse_nested(tb, NL80211_SAR_ATTR_MAX,
info->attrs[NL80211_ATTR_SAR_SPEC],
NULL, NULL);
if (!tb[NL80211_SAR_ATTR_TYPE] || !tb[NL80211_SAR_ATTR_SPECS])
return -EINVAL;
type = nla_get_u32(tb[NL80211_SAR_ATTR_TYPE]);
if (type != rdev->wiphy.sar_capa->type)
return -EINVAL;
specs = 0;
nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem)
specs++;
if (specs > rdev->wiphy.sar_capa->num_freq_ranges)
return -EINVAL;
sar_spec = kzalloc(sizeof(*sar_spec) +
specs * sizeof(struct cfg80211_sar_sub_specs),
GFP_KERNEL);
if (!sar_spec)
return -ENOMEM;
sar_spec->type = type;
specs = 0;
nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) {
nla_parse_nested(spec, NL80211_SAR_ATTR_SPECS_MAX,
spec_list, NULL, NULL);
switch (type) {
case NL80211_SAR_TYPE_POWER:
if (nl80211_set_sar_sub_specs(rdev, sar_spec,
spec, specs)) {
err = -EINVAL;
goto error;
}
break;
default:
err = -EINVAL;
goto error;
}
specs++;
}
sar_spec->num_sub_specs = specs;
rdev->cur_cmd_info = info;
err = rdev_set_sar_specs(rdev, sar_spec);
rdev->cur_cmd_info = NULL;
error:
kfree(sar_spec);
return err;
}
static const struct genl_ops nl80211_ops[] = { static const struct genl_ops nl80211_ops[] = {
{ {
.cmd = NL80211_CMD_GET_WIPHY, .cmd = NL80211_CMD_GET_WIPHY,
@ -15522,6 +15696,14 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV | .internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{
.cmd = NL80211_CMD_SET_SAR_SPECS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = nl80211_set_sar_specs,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
},
}; };
static struct genl_family nl80211_fam __ro_after_init = { static struct genl_family nl80211_fam __ro_after_init = {
@ -15857,7 +16039,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
const u8 *buf, size_t len, const u8 *buf, size_t len,
enum nl80211_commands cmd, gfp_t gfp, enum nl80211_commands cmd, gfp_t gfp,
int uapsd_queues, const u8 *req_ies, int uapsd_queues, const u8 *req_ies,
size_t req_ies_len) size_t req_ies_len, bool reconnect)
{ {
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
@ -15879,6 +16061,9 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies))) nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies)))
goto nla_put_failure; goto nla_put_failure;
if (reconnect && nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED))
goto nla_put_failure;
if (uapsd_queues >= 0) { if (uapsd_queues >= 0) {
struct nlattr *nla_wmm = struct nlattr *nla_wmm =
nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME); nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME);
@ -15907,7 +16092,8 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
size_t len, gfp_t gfp) size_t len, gfp_t gfp)
{ {
nl80211_send_mlme_event(rdev, netdev, buf, len, nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0); NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0,
false);
} }
void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
@ -15917,23 +16103,25 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
{ {
nl80211_send_mlme_event(rdev, netdev, buf, len, nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_ASSOCIATE, gfp, uapsd_queues, NL80211_CMD_ASSOCIATE, gfp, uapsd_queues,
req_ies, req_ies_len); req_ies, req_ies_len, false);
} }
void nl80211_send_deauth(struct cfg80211_registered_device *rdev, void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf, struct net_device *netdev, const u8 *buf,
size_t len, gfp_t gfp) size_t len, bool reconnect, gfp_t gfp)
{ {
nl80211_send_mlme_event(rdev, netdev, buf, len, nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0); NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0,
reconnect);
} }
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf, struct net_device *netdev, const u8 *buf,
size_t len, gfp_t gfp) size_t len, bool reconnect, gfp_t gfp)
{ {
nl80211_send_mlme_event(rdev, netdev, buf, len, nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0); NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0,
reconnect);
} }
void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
@ -15964,7 +16152,7 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1, nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
NULL, 0); NULL, 0, false);
} }
EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt); EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
@ -17065,7 +17253,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef, struct cfg80211_chan_def *chandef,
gfp_t gfp, gfp_t gfp,
enum nl80211_commands notif, enum nl80211_commands notif,
u8 count) u8 count, bool quiet)
{ {
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
@ -17086,9 +17274,13 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
if (nl80211_send_chandef(msg, chandef)) if (nl80211_send_chandef(msg, chandef))
goto nla_put_failure; goto nla_put_failure;
if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) && if (notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) {
(nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count))) if (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count))
goto nla_put_failure; goto nla_put_failure;
if (quiet &&
nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX))
goto nla_put_failure;
}
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
@ -17121,13 +17313,13 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
cfg80211_sched_dfs_chan_update(rdev); cfg80211_sched_dfs_chan_update(rdev);
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
NL80211_CMD_CH_SWITCH_NOTIFY, 0); NL80211_CMD_CH_SWITCH_NOTIFY, 0, false);
} }
EXPORT_SYMBOL(cfg80211_ch_switch_notify); EXPORT_SYMBOL(cfg80211_ch_switch_notify);
void cfg80211_ch_switch_started_notify(struct net_device *dev, void cfg80211_ch_switch_started_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef, struct cfg80211_chan_def *chandef,
u8 count) u8 count, bool quiet)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy; struct wiphy *wiphy = wdev->wiphy;
@ -17136,7 +17328,8 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev,
trace_cfg80211_ch_switch_started_notify(dev, chandef); trace_cfg80211_ch_switch_started_notify(dev, chandef);
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count); NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
count, quiet);
} }
EXPORT_SYMBOL(cfg80211_ch_switch_started_notify); EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Portions of this file * Portions of this file
* Copyright (C) 2018 Intel Corporation * Copyright (C) 2018, 2020 Intel Corporation
*/ */
#ifndef __NET_WIRELESS_NL80211_H #ifndef __NET_WIRELESS_NL80211_H
#define __NET_WIRELESS_NL80211_H #define __NET_WIRELESS_NL80211_H
@ -69,10 +69,12 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
const u8 *req_ies, size_t req_ies_len); const u8 *req_ies, size_t req_ies_len);
void nl80211_send_deauth(struct cfg80211_registered_device *rdev, void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
struct net_device *netdev, struct net_device *netdev,
const u8 *buf, size_t len, gfp_t gfp); const u8 *buf, size_t len,
bool reconnect, gfp_t gfp);
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, struct net_device *netdev,
const u8 *buf, size_t len, gfp_t gfp); const u8 *buf, size_t len,
bool reconnect, gfp_t gfp);
void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
struct net_device *netdev, struct net_device *netdev,
const u8 *addr, gfp_t gfp); const u8 *addr, gfp_t gfp);

View File

@ -1346,4 +1346,16 @@ static inline int rdev_reset_tid_config(struct cfg80211_registered_device *rdev,
return ret; return ret;
} }
static inline int rdev_set_sar_specs(struct cfg80211_registered_device *rdev,
struct cfg80211_sar_specs *sar)
{
int ret;
trace_rdev_set_sar_specs(&rdev->wiphy, sar);
ret = rdev->ops->set_sar_specs(&rdev->wiphy, sar);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */ #endif /* __CFG80211_RDEV_OPS */

View File

@ -1616,7 +1616,7 @@ static const struct ieee80211_reg_rule *
__freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw) __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
{ {
const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy); const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
const u32 bws[] = {0, 1, 2, 4, 5, 8, 10, 16, 20}; static const u32 bws[] = {0, 1, 2, 4, 5, 8, 10, 16, 20};
const struct ieee80211_reg_rule *reg_rule; const struct ieee80211_reg_rule *reg_rule;
int i = ARRAY_SIZE(bws) - 1; int i = ARRAY_SIZE(bws) - 1;
u32 bw; u32 bw;
@ -2547,6 +2547,7 @@ static void handle_band_custom(struct wiphy *wiphy,
void wiphy_apply_custom_regulatory(struct wiphy *wiphy, void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
const struct ieee80211_regdomain *regd) const struct ieee80211_regdomain *regd)
{ {
const struct ieee80211_regdomain *new_regd, *tmp;
enum nl80211_band band; enum nl80211_band band;
unsigned int bands_set = 0; unsigned int bands_set = 0;
@ -2566,6 +2567,13 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
* on your device's supported bands. * on your device's supported bands.
*/ */
WARN_ON(!bands_set); WARN_ON(!bands_set);
new_regd = reg_copy_regd(regd);
if (IS_ERR(new_regd))
return;
tmp = get_wiphy_regdom(wiphy);
rcu_assign_pointer(wiphy->regd, new_regd);
rcu_free_regdom(tmp);
} }
EXPORT_SYMBOL(wiphy_apply_custom_regulatory); EXPORT_SYMBOL(wiphy_apply_custom_regulatory);

View File

@ -726,7 +726,7 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
int n_channels, count = 0, err; int n_channels, count = 0, err;
struct cfg80211_scan_request *request, *rdev_req = rdev->scan_req; struct cfg80211_scan_request *request, *rdev_req = rdev->scan_req;
LIST_HEAD(coloc_ap_list); LIST_HEAD(coloc_ap_list);
bool need_scan_psc; bool need_scan_psc = true;
const struct ieee80211_sband_iftype_data *iftd; const struct ieee80211_sband_iftype_data *iftd;
rdev_req->scan_6ghz = true; rdev_req->scan_6ghz = true;
@ -770,20 +770,18 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev)
(void *)&request->channels[n_channels]; (void *)&request->channels[n_channels];
/* /*
* PSC channels should not be scanned if all the reported co-located APs * PSC channels should not be scanned in case of direct scan with 1 SSID
* are indicating that all APs in the same ESS are co-located * and at least one of the reported co-located APs with same SSID
* indicating that all APs in the same ESS are co-located
*/ */
if (count) { if (count && request->n_ssids == 1 && request->ssids[0].ssid_len) {
need_scan_psc = false;
list_for_each_entry(ap, &coloc_ap_list, list) { list_for_each_entry(ap, &coloc_ap_list, list) {
if (!ap->colocated_ess) { if (ap->colocated_ess &&
need_scan_psc = true; cfg80211_find_ssid_match(ap, request)) {
need_scan_psc = false;
break; break;
} }
} }
} else {
need_scan_psc = true;
} }
/* /*
@ -1901,6 +1899,9 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
tmp.pub.beacon_interval = beacon_interval; tmp.pub.beacon_interval = beacon_interval;
tmp.pub.capability = capability; tmp.pub.capability = capability;
tmp.ts_boottime = data->boottime_ns; tmp.ts_boottime = data->boottime_ns;
tmp.parent_tsf = data->parent_tsf;
ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
if (non_tx_data) { if (non_tx_data) {
tmp.pub.transmitted_bss = non_tx_data->tx_bss; tmp.pub.transmitted_bss = non_tx_data->tx_bss;
ts = bss_from_pub(non_tx_data->tx_bss)->ts; ts = bss_from_pub(non_tx_data->tx_bss)->ts;

View File

@ -2679,19 +2679,23 @@ DEFINE_EVENT(netdev_frame_event, cfg80211_rx_mlme_mgmt,
); );
TRACE_EVENT(cfg80211_tx_mlme_mgmt, TRACE_EVENT(cfg80211_tx_mlme_mgmt,
TP_PROTO(struct net_device *netdev, const u8 *buf, int len), TP_PROTO(struct net_device *netdev, const u8 *buf, int len,
TP_ARGS(netdev, buf, len), bool reconnect),
TP_ARGS(netdev, buf, len, reconnect),
TP_STRUCT__entry( TP_STRUCT__entry(
NETDEV_ENTRY NETDEV_ENTRY
__dynamic_array(u8, frame, len) __dynamic_array(u8, frame, len)
__field(int, reconnect)
), ),
TP_fast_assign( TP_fast_assign(
NETDEV_ASSIGN; NETDEV_ASSIGN;
memcpy(__get_dynamic_array(frame), buf, len); memcpy(__get_dynamic_array(frame), buf, len);
__entry->reconnect = reconnect;
), ),
TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x", TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x reconnect:%d",
NETDEV_PR_ARG, NETDEV_PR_ARG,
le16_to_cpup((__le16 *)__get_dynamic_array(frame))) le16_to_cpup((__le16 *)__get_dynamic_array(frame)),
__entry->reconnect)
); );
DECLARE_EVENT_CLASS(netdev_mac_evt, DECLARE_EVENT_CLASS(netdev_mac_evt,
@ -3542,6 +3546,25 @@ TRACE_EVENT(rdev_reset_tid_config,
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x", TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x",
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids) WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids)
); );
TRACE_EVENT(rdev_set_sar_specs,
TP_PROTO(struct wiphy *wiphy, struct cfg80211_sar_specs *sar),
TP_ARGS(wiphy, sar),
TP_STRUCT__entry(
WIPHY_ENTRY
__field(u16, type)
__field(u16, num)
),
TP_fast_assign(
WIPHY_ASSIGN;
__entry->type = sar->type;
__entry->num = sar->num_sub_specs;
),
TP_printk(WIPHY_PR_FMT ", Set type:%d, num_specs:%d",
WIPHY_PR_ARG, __entry->type, __entry->num)
);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH

View File

@ -272,18 +272,53 @@ bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher)
return false; return false;
} }
static bool
cfg80211_igtk_cipher_supported(struct cfg80211_registered_device *rdev)
{
struct wiphy *wiphy = &rdev->wiphy;
int i;
for (i = 0; i < wiphy->n_cipher_suites; i++) {
switch (wiphy->cipher_suites[i]) {
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:
return true;
}
}
return false;
}
bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev,
int key_idx, bool pairwise)
{
int max_key_idx;
if (pairwise)
max_key_idx = 3;
else if (wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION) ||
wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
max_key_idx = 7;
else if (cfg80211_igtk_cipher_supported(rdev))
max_key_idx = 5;
else
max_key_idx = 3;
if (key_idx < 0 || key_idx > max_key_idx)
return false;
return true;
}
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
struct key_params *params, int key_idx, struct key_params *params, int key_idx,
bool pairwise, const u8 *mac_addr) bool pairwise, const u8 *mac_addr)
{ {
int max_key_idx = 5; if (!cfg80211_valid_key_idx(rdev, key_idx, pairwise))
if (wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION) ||
wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
max_key_idx = 7;
if (key_idx < 0 || key_idx > max_key_idx)
return -EINVAL; return -EINVAL;
if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
@ -335,6 +370,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
if (key_idx > 3) if (key_idx > 3)
return -EINVAL; return -EINVAL;
break;
default: default:
break; break;
} }

View File

@ -1421,39 +1421,78 @@ static int cfg80211_wext_siwpmksa(struct net_device *dev,
} }
} }
#define DEFINE_WEXT_COMPAT_STUB(func, type) \
static int __ ## func(struct net_device *dev, \
struct iw_request_info *info, \
union iwreq_data *wrqu, \
char *extra) \
{ \
return func(dev, info, (type *)wrqu, extra); \
}
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwname, char)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwfreq, struct iw_freq)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwfreq, struct iw_freq)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwmode, u32)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwmode, u32)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwrange, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwap, struct sockaddr)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwap, struct sockaddr)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwmlme, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwscan, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwessid, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwessid, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwrate, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwrate, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwrts, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwrts, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwfrag, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwfrag, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwretry, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwretry, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwencode, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwencode, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwpower, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwpower, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwgenie, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_giwauth, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwauth, struct iw_param)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwencodeext, struct iw_point)
DEFINE_WEXT_COMPAT_STUB(cfg80211_wext_siwpmksa, struct iw_point)
static const iw_handler cfg80211_handlers[] = { static const iw_handler cfg80211_handlers[] = {
[IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, [IW_IOCTL_IDX(SIOCGIWNAME)] = __cfg80211_wext_giwname,
[IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, [IW_IOCTL_IDX(SIOCSIWFREQ)] = __cfg80211_wext_siwfreq,
[IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, [IW_IOCTL_IDX(SIOCGIWFREQ)] = __cfg80211_wext_giwfreq,
[IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, [IW_IOCTL_IDX(SIOCSIWMODE)] = __cfg80211_wext_siwmode,
[IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, [IW_IOCTL_IDX(SIOCGIWMODE)] = __cfg80211_wext_giwmode,
[IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, [IW_IOCTL_IDX(SIOCGIWRANGE)] = __cfg80211_wext_giwrange,
[IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, [IW_IOCTL_IDX(SIOCSIWAP)] = __cfg80211_wext_siwap,
[IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, [IW_IOCTL_IDX(SIOCGIWAP)] = __cfg80211_wext_giwap,
[IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, [IW_IOCTL_IDX(SIOCSIWMLME)] = __cfg80211_wext_siwmlme,
[IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, [IW_IOCTL_IDX(SIOCSIWSCAN)] = cfg80211_wext_siwscan,
[IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, [IW_IOCTL_IDX(SIOCGIWSCAN)] = __cfg80211_wext_giwscan,
[IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, [IW_IOCTL_IDX(SIOCSIWESSID)] = __cfg80211_wext_siwessid,
[IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, [IW_IOCTL_IDX(SIOCGIWESSID)] = __cfg80211_wext_giwessid,
[IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, [IW_IOCTL_IDX(SIOCSIWRATE)] = __cfg80211_wext_siwrate,
[IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, [IW_IOCTL_IDX(SIOCGIWRATE)] = __cfg80211_wext_giwrate,
[IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, [IW_IOCTL_IDX(SIOCSIWRTS)] = __cfg80211_wext_siwrts,
[IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, [IW_IOCTL_IDX(SIOCGIWRTS)] = __cfg80211_wext_giwrts,
[IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, [IW_IOCTL_IDX(SIOCSIWFRAG)] = __cfg80211_wext_siwfrag,
[IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, [IW_IOCTL_IDX(SIOCGIWFRAG)] = __cfg80211_wext_giwfrag,
[IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, [IW_IOCTL_IDX(SIOCSIWTXPOW)] = cfg80211_wext_siwtxpower,
[IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, [IW_IOCTL_IDX(SIOCGIWTXPOW)] = cfg80211_wext_giwtxpower,
[IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, [IW_IOCTL_IDX(SIOCSIWRETRY)] = __cfg80211_wext_siwretry,
[IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, [IW_IOCTL_IDX(SIOCGIWRETRY)] = __cfg80211_wext_giwretry,
[IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, [IW_IOCTL_IDX(SIOCSIWENCODE)] = __cfg80211_wext_siwencode,
[IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, [IW_IOCTL_IDX(SIOCGIWENCODE)] = __cfg80211_wext_giwencode,
[IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, [IW_IOCTL_IDX(SIOCSIWPOWER)] = __cfg80211_wext_siwpower,
[IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, [IW_IOCTL_IDX(SIOCGIWPOWER)] = __cfg80211_wext_giwpower,
[IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, [IW_IOCTL_IDX(SIOCSIWGENIE)] = __cfg80211_wext_siwgenie,
[IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, [IW_IOCTL_IDX(SIOCSIWAUTH)] = __cfg80211_wext_siwauth,
[IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, [IW_IOCTL_IDX(SIOCGIWAUTH)] = __cfg80211_wext_giwauth,
[IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= __cfg80211_wext_siwencodeext,
[IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa, [IW_IOCTL_IDX(SIOCSIWPMKSA)] = __cfg80211_wext_siwpmksa,
}; };
const struct iw_handler_def cfg80211_wext_handler = { const struct iw_handler_def cfg80211_wext_handler = {