BACKPORT: cfg80211: Squash of all 6GHz changes

Add support for Wi-Fi 6GHz band. squash of commits listed below.

ad8b601 BACKPORT: cfg80211: express channels with a KHz component
666ce0c BACKPORT: cfg80211: fix 6 GHz frequencies to kHz
a4d60a7 BACKPORT: cfg80211: adapt to new channelization of the 6GHz band
2ed68ba BACKPORT: cfg80211: add a helper to identify 6 GHz PSCs
6f5ad8f BACKPORT: ieee80211: add code to obtain and parse 6 GHz operation field
e66b8b1c BACKPORT: ieee80211: add HE ext EIDs and 6 GHz capability defines
bc79097 BACKPORT: cfg80211: handle 6 GHz capability of new station
e3a7357 BACKPORT: cfg80211: add and expose HE 6 GHz band capabilities
b8318c9 BACKPORT: mac80211: add HE 6 GHz Band Capability element
df67878 BACKPORT: mac80211: Add HE 6GHz capabilities element to probe request
0403f9c BACKPORT: cfg80211: treat 6 GHz channels as valid regardless of capability
92a570f BACKPORT: cfg80211: reject HT/VHT capabilities on 6 GHz band
dd5425c BACKPORT: cfg80211: require HE capabilities for 6 GHz band

CRs-Fixed: 2760276
Change-Id: Icecbe2587aba927dcb83bc4a574249dbe408d311
Signed-off-by: Vamsi Krishna <vamsin@codeaurora.org>
Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
Git-commit: 934f4c7dd3a544bb8000f7436f1f0e12e04ebc37
Git-commit: 5e9cf0f0a3e98992184442de24253fe1b9c40f2e
Git-commit: d1a1646c0de7b0083d42a1ada72a3ec243bfcc6d
Git-commit: afbc9c9e8bfe71e8bd12a8c01bedd969fbab8f0e
Git-commit: 821273a5a502eebaae005557907d122d1e9b7b98
Git-commit: 8b30808d9be4183fab17f0b0e68eea88c94ff15a
Git-commit: 43e64bf301fd8c54f0082d91c6ffd4de861baf96
Git-commit: 223952177296c34d9c8de9cde33204caffe55725
Git-commit: 24a2042cb22fdfc7feef0df9622f0d9d71b8ced1
Git-commit: 2ad2274c58ee2dcaf9ccde5c63ff30f59b138f77
Git-commit: ba8f6a037f790147438173029799f54c9d3065f2
Git-commit: 461ce35d5535c1479384f67fcf4bfc3f3610edca
Git-commit: f438136528482f98535889c9a6f99bbacdd92870
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
Signed-off-by: Veerendranath Jakkam <vjakkam@codeaurora.org>
This commit is contained in:
Veerendranath Jakkam 2020-08-28 08:48:22 +05:30
commit 3290a9818c
19 changed files with 2170 additions and 2357 deletions

File diff suppressed because it is too large Load diff

View file

@ -1082,8 +1082,8 @@
idr_preload
idr_remove
idr_replace
ieee80211_frequency_to_channel
ieee80211_get_channel
ieee80211_freq_khz_to_channel
ieee80211_get_channel_khz
ieee80211_hdrlen
iget5_locked
igrab

View file

@ -2060,6 +2060,28 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000
#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000
/**
* ieee80211_he_6ghz_oper - HE 6 GHz operation Information field
* @primary: primary channel
* @control: control flags
* @ccfs0: channel center frequency segment 0
* @ccfs1: channel center frequency segment 1
* @minrate: minimum rate (in 1 Mbps units)
*/
struct ieee80211_he_6ghz_oper {
u8 primary;
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH 0x3
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ 0
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ 1
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ 2
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ 3
#define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4
u8 control;
u8 ccfs0;
u8 ccfs1;
u8 minrate;
} __packed;
/*
* ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size
* @he_oper_ie: byte data of the He Operations IE, stating from the the byte
@ -2086,7 +2108,7 @@ ieee80211_he_oper_size(const u8 *he_oper_ie)
if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS)
oper_len++;
if (he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO)
oper_len += 4;
oper_len += sizeof(struct ieee80211_he_6ghz_oper);
/* Add the first byte (extension ID) to the total length */
oper_len++;
@ -2094,6 +2116,34 @@ ieee80211_he_oper_size(const u8 *he_oper_ie)
return oper_len;
}
/**
* ieee80211_he_6ghz_oper - obtain 6 GHz operation field
* @he_oper: HE operation element (must be pre-validated for size)
* but may be %NULL
*
* Return: a pointer to the 6 GHz operation field, or %NULL
*/
static inline const struct ieee80211_he_6ghz_oper *
ieee80211_he_6ghz_oper(const struct ieee80211_he_operation *he_oper)
{
const u8 *ret = (void *)&he_oper->optional;
u32 he_oper_params;
if (!he_oper)
return NULL;
he_oper_params = le32_to_cpu(he_oper->he_oper_params);
if (!(he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO))
return NULL;
if (he_oper_params & IEEE80211_HE_OPERATION_VHT_OPER_INFO)
ret += 3;
if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS)
ret++;
return (void *)ret;
}
/* HE Spatial Reuse defines */
#define IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT 0x4
#define IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT 0x8
@ -2553,9 +2603,19 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_UORA = 37,
WLAN_EID_EXT_HE_MU_EDCA = 38,
WLAN_EID_EXT_HE_SPR = 39,
WLAN_EID_EXT_NDP_FEEDBACK_REPORT_PARAMSET = 41,
WLAN_EID_EXT_BSS_COLOR_CHG_ANN = 42,
WLAN_EID_EXT_QUIET_TIME_PERIOD_SETUP = 43,
WLAN_EID_EXT_ESS_REPORT = 45,
WLAN_EID_EXT_OPS = 46,
WLAN_EID_EXT_HE_BSS_LOAD = 47,
WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME = 52,
WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55,
WLAN_EID_EXT_NON_INHERITANCE = 56,
WLAN_EID_EXT_KNOWN_BSSID = 57,
WLAN_EID_EXT_SHORT_SSID_LIST = 58,
WLAN_EID_EXT_HE_6GHZ_CAPA = 59,
WLAN_EID_EXT_UL_MU_POWER_CAPA = 60,
};
/* Action category code */
@ -3097,6 +3157,24 @@ struct ieee80211_tspec_ie {
__le16 medium_time;
} __packed;
struct ieee80211_he_6ghz_capa {
/* uses IEEE80211_HE_6GHZ_CAP_* below */
__le16 capa;
} __packed;
/* HE 6 GHz band capabilities */
/* uses enum ieee80211_min_mpdu_spacing values */
#define IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START 0x0007
/* uses enum ieee80211_vht_max_ampdu_length_exp values */
#define IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP 0x0038
/* uses IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_* values */
#define IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN 0x00c0
/* WLAN_HT_CAP_SM_PS_* values */
#define IEEE80211_HE_6GHZ_CAP_SM_PS 0x0600
#define IEEE80211_HE_6GHZ_CAP_RD_RESPONDER 0x0800
#define IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS 0x1000
#define IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS 0x2000
/**
* ieee80211_get_qos_ctl - get pointer to qos control bytes
* @hdr: the frame

View file

@ -132,6 +132,7 @@ enum ieee80211_channel_flags {
* with cfg80211.
*
* @center_freq: center frequency in MHz
* @freq_offset: offset from @center_freq, in KHz
* @hw_value: hardware-specific value for the channel
* @flags: channel flags from &enum ieee80211_channel_flags.
* @orig_flags: channel flags at registration time, used by regulatory
@ -153,6 +154,7 @@ enum ieee80211_channel_flags {
struct ieee80211_channel {
enum nl80211_band band;
u32 center_freq;
u16 freq_offset;
u16 hw_value;
u32 flags;
int max_antenna_gain;
@ -343,10 +345,13 @@ struct ieee80211_sta_he_cap {
*
* @types_mask: interface types mask
* @he_cap: holds the HE capabilities
* @he_6ghz_capa: HE 6 GHz capabilities, must be filled in for a
* 6 GHz band channel (and 0 may be valid value).
*/
struct ieee80211_sband_iftype_data {
u16 types_mask;
struct ieee80211_sta_he_cap he_cap;
struct ieee80211_he_6ghz_capa he_6ghz_capa;
};
/**
@ -498,6 +503,26 @@ ieee80211_get_he_sta_cap(const struct ieee80211_supported_band *sband)
return ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_STATION);
}
/**
* ieee80211_get_he_6ghz_capa - return HE 6 GHz capabilities
* @sband: the sband to search for the STA on
* @iftype: the iftype to search for
*
* Return: the 6GHz capabilities
*/
static inline __le16
ieee80211_get_he_6ghz_capa(const struct ieee80211_supported_band *sband,
enum nl80211_iftype iftype)
{
const struct ieee80211_sband_iftype_data *data =
ieee80211_get_sband_iftype_data(sband, iftype);
if (WARN_ON(!data || !data->he_cap.has_he))
return 0;
return data->he_6ghz_capa.capa;
}
/**
* wiphy_read_of_freq_limits - read frequency limits from device tree
*
@ -608,6 +633,7 @@ struct key_params {
* If edmg is requested (i.e. the .channels member is non-zero),
* chan will define the primary channel and all other
* parameters are ignored.
* @freq1_offset: offset from @center_freq1, in KHz
*/
struct cfg80211_chan_def {
struct ieee80211_channel *chan;
@ -615,6 +641,7 @@ struct cfg80211_chan_def {
u32 center_freq1;
u32 center_freq2;
struct ieee80211_edmg edmg;
u16 freq1_offset;
};
/**
@ -697,6 +724,7 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
return (chandef1->chan == chandef2->chan &&
chandef1->width == chandef2->width &&
chandef1->center_freq1 == chandef2->center_freq1 &&
chandef1->freq1_offset == chandef2->freq1_offset &&
chandef1->center_freq2 == chandef2->center_freq2);
}
@ -1203,6 +1231,7 @@ struct sta_txpwr {
* @he_capa: HE capabilities of station
* @he_capa_len: the length of the HE capabilities
* @airtime_weight: airtime scheduler weight for this station
* @he_6ghz_capa: HE 6 GHz Band capabilities of station
*/
struct station_parameters {
const u8 *supported_rates;
@ -1235,6 +1264,7 @@ struct station_parameters {
u8 he_capa_len;
u16 airtime_weight;
struct sta_txpwr txpwr;
const struct ieee80211_he_6ghz_capa *he_6ghz_capa;
};
/**
@ -5123,30 +5153,107 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
* cfg80211 offers a number of utility functions that can be useful.
*/
/**
* ieee80211_channel_equal - compare two struct ieee80211_channel
*
* @a: 1st struct ieee80211_channel
* @b: 2nd struct ieee80211_channel
* Return: true if center frequency of @a == @b
*/
static inline bool
ieee80211_channel_equal(struct ieee80211_channel *a,
struct ieee80211_channel *b)
{
return (a->center_freq == b->center_freq &&
a->freq_offset == b->freq_offset);
}
/**
* ieee80211_channel_to_khz - convert ieee80211_channel to frequency in KHz
* @chan: struct ieee80211_channel to convert
* Return: The corresponding frequency (in KHz)
*/
static inline u32
ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
{
return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
}
/**
* ieee80211_channel_to_freq_khz - convert channel number to frequency
* @chan: channel number
* @band: band, necessary due to channel number overlap
* Return: The corresponding frequency (in KHz), or 0 if the conversion failed.
*/
u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band);
/**
* ieee80211_channel_to_frequency - convert channel number to frequency
* @chan: channel number
* @band: band, necessary due to channel number overlap
* Return: The corresponding frequency (in MHz), or 0 if the conversion failed.
*/
int ieee80211_channel_to_frequency(int chan, enum nl80211_band band);
static inline int
ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
{
return KHZ_TO_MHZ(ieee80211_channel_to_freq_khz(chan, band));
}
/**
* ieee80211_freq_khz_to_channel - convert frequency to channel number
* @freq: center frequency in KHz
* Return: The corresponding channel, or 0 if the conversion failed.
*/
int ieee80211_freq_khz_to_channel(u32 freq);
/**
* ieee80211_frequency_to_channel - convert frequency to channel number
* @freq: center frequency
* @freq: center frequency in MHz
* Return: The corresponding channel, or 0 if the conversion failed.
*/
int ieee80211_frequency_to_channel(int freq);
static inline int
ieee80211_frequency_to_channel(int freq)
{
return ieee80211_freq_khz_to_channel(MHZ_TO_KHZ(freq));
}
/**
* ieee80211_get_channel_khz - get channel struct from wiphy for specified
* frequency
* @wiphy: the struct wiphy to get the channel for
* @freq: the center frequency (in KHz) of the channel
* Return: The channel struct from @wiphy at @freq.
*/
struct ieee80211_channel *
ieee80211_get_channel_khz(struct wiphy *wiphy, u32 freq);
/**
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
*
* @wiphy: the struct wiphy to get the channel for
* @freq: the center frequency of the channel
*
* @freq: the center frequency (in MHz) of the channel
* Return: The channel struct from @wiphy at @freq.
*/
struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq);
static inline struct ieee80211_channel *
ieee80211_get_channel(struct wiphy *wiphy, int freq)
{
return ieee80211_get_channel_khz(wiphy, MHZ_TO_KHZ(freq));
}
/**
* cfg80211_channel_is_psc - Check if the channel is a 6 GHz PSC
* @chan: control channel to check
*
* The Preferred Scanning Channels (PSC) are defined in
* Draft IEEE P802.11ax/D5.0, 26.17.2.3.3
*/
static inline bool cfg80211_channel_is_psc(struct ieee80211_channel *chan)
{
if (chan->band != NL80211_BAND_6GHZ)
return false;
return ieee80211_frequency_to_channel(chan->center_freq) % 16 == 5;
}
/**
* ieee80211_get_response_rate - get basic rate for a given rate
@ -7170,6 +7277,19 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
u8 *op_class);
/**
* ieee80211_chandef_to_khz - convert chandef to frequency in KHz
*
* @chandef: the chandef to convert
*
* Returns the center frequency of chandef (1st segment) in KHz.
*/
static inline u32
ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef)
{
return MHZ_TO_KHZ(chandef->center_freq1) + chandef->freq1_offset;
}
/*
* cfg80211_tdls_oper_request - request userspace to perform TDLS operation
* @dev: the device on which the operation is requested

View file

@ -2462,6 +2462,9 @@ enum nl80211_commands {
* no roaming occurs between the reauth threshold and PMK expiration,
* disassociation is still forced.
*
* @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from
* association request when used with NL80211_CMD_NEW_STATION).
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -2937,6 +2940,8 @@ enum nl80211_attrs {
NL80211_ATTR_PMK_LIFETIME,
NL80211_ATTR_PMK_REAUTH_THRESHOLD,
NL80211_ATTR_HE_6GHZ_CAPABILITY,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -3515,6 +3520,8 @@ enum nl80211_mpath_info {
* defined in HE capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
* defined
* @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
* given for all 6 GHz band channels
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
*/
enum nl80211_band_iftype_attr {
@ -3525,6 +3532,7 @@ enum nl80211_band_iftype_attr {
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,

View file

@ -2109,7 +2109,7 @@ enum {
IEEE80211_PROBE_FLAG_RANDOM_SN = BIT(2),
};
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
int ieee80211_build_preq_ies(struct ieee80211_sub_if_data *sdata, u8 *buffer,
size_t buffer_len,
struct ieee80211_scan_ies *ie_desc,
const u8 *ie, size_t ie_len,
@ -2149,6 +2149,8 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype);
u8 *ieee80211_ie_build_he_cap(u8 *pos,
const struct ieee80211_sta_he_cap *he_cap,
u8 *end);
void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
u8 *ieee80211_ie_build_he_oper(u8 *pos);
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
const struct ieee80211_supported_band *sband,

View file

@ -587,6 +587,13 @@ int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata,
return 0;
}
int mesh_add_he_6ghz_cap_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
ieee80211_ie_build_he_6ghz_cap(sdata, skb);
return 0;
}
static void ieee80211_mesh_path_timer(struct timer_list *t)
{
struct ieee80211_sub_if_data *sdata =
@ -766,6 +773,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
2 + sizeof(struct ieee80211_vht_operation) +
ie_len_he_cap +
2 + 1 + sizeof(struct ieee80211_he_operation) +
2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
ifmsh->ie_len;
bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
@ -885,6 +893,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
mesh_add_vht_oper_ie(sdata, skb) ||
mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) ||
mesh_add_he_oper_ie(sdata, skb) ||
mesh_add_he_6ghz_cap_ie(sdata, skb) ||
mesh_add_vendor_ies(sdata, skb))
goto out_free;

View file

@ -222,6 +222,8 @@ int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u8 ie_len);
int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
int mesh_add_he_6ghz_cap_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
void ieee80211s_init(void);

View file

@ -238,6 +238,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
2 + sizeof(struct ieee80211_vht_operation) +
ie_len_he_cap +
2 + 1 + sizeof(struct ieee80211_he_operation) +
2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
2 + 8 + /* peering IE */
sdata->u.mesh.ie_len);
if (!skb)
@ -328,7 +329,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
mesh_add_vht_cap_ie(sdata, skb) ||
mesh_add_vht_oper_ie(sdata, skb) ||
mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) ||
mesh_add_he_oper_ie(sdata, skb))
mesh_add_he_oper_ie(sdata, skb) ||
mesh_add_he_6ghz_cap_ie(sdata, skb))
goto free;
}

View file

@ -633,6 +633,8 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
he_cap->he_cap_elem.phy_cap_info);
pos = skb_put(skb, he_cap_size);
ieee80211_ie_build_he_cap(pos, he_cap, pos + he_cap_size);
ieee80211_ie_build_he_6ghz_cap(sdata, skb);
}
static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
@ -699,6 +701,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
2 + 1 + sizeof(struct ieee80211_he_cap_elem) + /* HE */
sizeof(struct ieee80211_he_mcs_nss_supp) +
IEEE80211_HE_PPE_THRES_MAX_LEN +
2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
assoc_data->ie_len + /* extra IEs */
(assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
9, /* WMM */

View file

@ -307,8 +307,9 @@ ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef,
}
/* return false if no more work */
static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
static bool ieee80211_prep_hw_scan(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct cfg80211_scan_request *req;
struct cfg80211_chan_def chandef;
u8 bands_used = 0;
@ -355,7 +356,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
if (req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
flags |= IEEE80211_PROBE_FLAG_MIN_CONTENT;
ielen = ieee80211_build_preq_ies(local,
ielen = ieee80211_build_preq_ies(sdata,
(u8 *)local->hw_scan_req->req.ie,
local->hw_scan_ies_bufsize,
&local->hw_scan_req->ies,
@ -395,9 +396,12 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (WARN_ON(!local->scan_req))
return;
scan_sdata = rcu_dereference_protected(local->scan_sdata,
lockdep_is_held(&local->mtx));
if (hw_scan && !aborted &&
!ieee80211_hw_check(&local->hw, SINGLE_SCAN_ON_ALL_BANDS) &&
ieee80211_prep_hw_scan(local)) {
ieee80211_prep_hw_scan(scan_sdata)) {
int rc;
rc = drv_hw_scan(local,
@ -426,9 +430,6 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
cfg80211_scan_done(scan_req, &local->scan_info);
}
RCU_INIT_POINTER(local->scan_req, NULL);
scan_sdata = rcu_dereference_protected(local->scan_sdata,
lockdep_is_held(&local->mtx));
RCU_INIT_POINTER(local->scan_sdata, NULL);
local->scanning = 0;
@ -770,7 +771,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_idle(local);
if (hw_scan) {
WARN_ON(!ieee80211_prep_hw_scan(local));
WARN_ON(!ieee80211_prep_hw_scan(sdata));
rc = drv_hw_scan(local, sdata, local->hw_scan_req);
} else {
rc = ieee80211_start_sw_scan(local, sdata);
@ -1267,7 +1268,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
ieee80211_build_preq_ies(local, ie, num_bands * iebufsz,
ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz,
&sched_scan_ies, req->ie,
req->ie_len, bands_used, rate_masks, &chandef,
flags);

View file

@ -1630,7 +1630,20 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
}
}
static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
static u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end)
{
if ((end - pos) < 5)
return pos;
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + sizeof(cap);
*pos++ = WLAN_EID_EXT_HE_6GHZ_CAPA;
memcpy(pos, &cap, sizeof(cap));
return pos + 2;
}
static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
u8 *buffer, size_t buffer_len,
const u8 *ie, size_t ie_len,
enum nl80211_band band,
@ -1638,6 +1651,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
struct cfg80211_chan_def *chandef,
size_t *offset, u32 flags)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
const struct ieee80211_sta_he_cap *he_cap;
u8 *pos = buffer, *end = buffer + buffer_len;
@ -1815,6 +1829,14 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
pos = ieee80211_ie_build_he_cap(pos, he_cap, end);
if (!pos)
goto out_err;
if (sband->band == NL80211_BAND_6GHZ) {
enum nl80211_iftype iftype =
ieee80211_vif_type_p2p(&sdata->vif);
__le16 cap = ieee80211_get_he_6ghz_capa(sband, iftype);
pos = ieee80211_write_he_6ghz_cap(pos, cap, end);
}
}
/*
@ -1829,7 +1851,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
return pos - buffer;
}
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
int ieee80211_build_preq_ies(struct ieee80211_sub_if_data *sdata, u8 *buffer,
size_t buffer_len,
struct ieee80211_scan_ies *ie_desc,
const u8 *ie, size_t ie_len,
@ -1844,7 +1866,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
for (i = 0; i < NUM_NL80211_BANDS; i++) {
if (bands_used & BIT(i)) {
pos += ieee80211_build_preq_ies_band(local,
pos += ieee80211_build_preq_ies_band(sdata,
buffer + pos,
buffer_len - pos,
ie, ie_len, i,
@ -1906,7 +1928,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
return NULL;
rate_masks[chan->band] = ratemask;
ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb),
ies_len = ieee80211_build_preq_ies(sdata, skb_tail_pointer(skb),
skb_tailroom(skb), &dummy_ie_desc,
ie, ie_len, BIT(chan->band),
rate_masks, &chandef, flags);
@ -2806,6 +2828,50 @@ end:
return pos;
}
void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_supported_band *sband;
const struct ieee80211_sband_iftype_data *iftd;
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
u8 *pos;
u16 cap;
sband = ieee80211_get_sband(sdata);
if (!sband)
return;
iftd = ieee80211_get_sband_iftype_data(sband, iftype);
if (WARN_ON(!iftd))
return;
cap = le16_to_cpu(iftd->he_6ghz_capa.capa);
cap &= ~IEEE80211_HE_6GHZ_CAP_SM_PS;
switch (sdata->smps_mode) {
case IEEE80211_SMPS_AUTOMATIC:
case IEEE80211_SMPS_NUM_MODES:
WARN_ON(1);
/* fall through */
case IEEE80211_SMPS_OFF:
cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_DISABLED,
IEEE80211_HE_6GHZ_CAP_SM_PS);
break;
case IEEE80211_SMPS_STATIC:
cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_STATIC,
IEEE80211_HE_6GHZ_CAP_SM_PS);
break;
case IEEE80211_SMPS_DYNAMIC:
cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_DYNAMIC,
IEEE80211_HE_6GHZ_CAP_SM_PS);
break;
}
pos = skb_put(skb, 2 + 1 + sizeof(cap));
ieee80211_write_he_6ghz_cap(pos, cpu_to_le16(cap),
pos + 2 + 1 + sizeof(cap));
}
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
const struct cfg80211_chan_def *chandef,
u16 prot_mode, bool rifs_mode)

View file

@ -6,7 +6,7 @@
*
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2018 Intel Corporation
* Copyright 2018-2020 Intel Corporation
*/
#include <linux/export.h>
@ -27,6 +27,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
return;
chandef->chan = chan;
chandef->freq1_offset = chan->freq_offset;
chandef->center_freq2 = 0;
chandef->edmg.bw_config = 0;
chandef->edmg.channels = 0;
@ -153,7 +154,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
if (chandef->center_freq1 != control_freq)
if (ieee80211_chandef_to_khz(chandef) !=
ieee80211_channel_to_khz(chandef->chan))
return false;
if (chandef->center_freq2)
return false;
@ -386,10 +388,11 @@ static u32 cfg80211_get_start_freq(u32 center_freq,
{
u32 start_freq;
if (bandwidth <= 20)
bandwidth = MHZ_TO_KHZ(bandwidth);
if (bandwidth <= MHZ_TO_KHZ(20))
start_freq = center_freq;
else
start_freq = center_freq - bandwidth/2 + 10;
start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
return start_freq;
}
@ -399,10 +402,11 @@ static u32 cfg80211_get_end_freq(u32 center_freq,
{
u32 end_freq;
if (bandwidth <= 20)
bandwidth = MHZ_TO_KHZ(bandwidth);
if (bandwidth <= MHZ_TO_KHZ(20))
end_freq = center_freq;
else
end_freq = center_freq + bandwidth/2 - 10;
end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
return end_freq;
}
@ -417,8 +421,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel_khz(wiphy, freq);
if (!c)
return -EINVAL;
@ -449,8 +453,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
return -EINVAL;
ret = cfg80211_get_chans_dfs_required(wiphy,
chandef->center_freq1,
width);
ieee80211_chandef_to_khz(chandef),
width);
if (ret < 0)
return ret;
else if (ret > 0)
@ -460,8 +464,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
return 0;
ret = cfg80211_get_chans_dfs_required(wiphy,
chandef->center_freq2,
width);
MHZ_TO_KHZ(chandef->center_freq2),
width);
if (ret < 0)
return ret;
else if (ret > 0)
@ -503,8 +507,8 @@ static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
* DFS_AVAILABLE). Return number of usable channels
* (require CAC). Allow DFS and non-DFS channel mix.
*/
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel_khz(wiphy, freq);
if (!c)
return -EINVAL;
@ -536,8 +540,9 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
if (width < 0)
return false;
r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
width);
r1 = cfg80211_get_chans_dfs_usable(wiphy,
MHZ_TO_KHZ(chandef->center_freq1),
width);
if (r1 < 0)
return false;
@ -546,8 +551,8 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
case NL80211_CHAN_WIDTH_80P80:
WARN_ON(!chandef->center_freq2);
r2 = cfg80211_get_chans_dfs_usable(wiphy,
chandef->center_freq2,
width);
MHZ_TO_KHZ(chandef->center_freq2),
width);
if (r2 < 0)
return false;
break;
@ -694,8 +699,8 @@ static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
* If any channel in between is disabled or has not
* had gone through CAC return false
*/
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel_khz(wiphy, freq);
if (!c)
return false;
@ -724,7 +729,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
if (width < 0)
return false;
r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
r = cfg80211_get_chans_dfs_available(wiphy,
MHZ_TO_KHZ(chandef->center_freq1),
width);
/* If any of channels unavailable for cf1 just return */
@ -735,8 +741,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
case NL80211_CHAN_WIDTH_80P80:
WARN_ON(!chandef->center_freq2);
r = cfg80211_get_chans_dfs_available(wiphy,
chandef->center_freq2,
width);
MHZ_TO_KHZ(chandef->center_freq2),
width);
break;
default:
WARN_ON(chandef->center_freq2);
@ -757,8 +763,8 @@ static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel_khz(wiphy, freq);
if (!c)
return 0;
@ -790,14 +796,14 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
return 0;
t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
chandef->center_freq1,
MHZ_TO_KHZ(chandef->center_freq1),
width);
if (!chandef->center_freq2)
return t1;
t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
chandef->center_freq2,
MHZ_TO_KHZ(chandef->center_freq2),
width);
return max(t1, t2);
@ -813,8 +819,8 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel_khz(wiphy, freq);
if (!c || c->flags & prohibited_flags)
return false;
}
@ -910,7 +916,8 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
width = 10;
break;
case NL80211_CHAN_WIDTH_20:
if (!ht_cap->ht_supported)
if (!ht_cap->ht_supported &&
chandef->chan->band != NL80211_BAND_6GHZ)
return false;
/* fall through */
case NL80211_CHAN_WIDTH_20_NOHT:
@ -919,6 +926,8 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
break;
case NL80211_CHAN_WIDTH_40:
width = 40;
if (chandef->chan->band == NL80211_BAND_6GHZ)
break;
if (!ht_cap->ht_supported)
return false;
if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
@ -933,24 +942,29 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
break;
case NL80211_CHAN_WIDTH_80P80:
cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
if (chandef->chan->band != NL80211_BAND_6GHZ &&
cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
return false;
/* fall through */
case NL80211_CHAN_WIDTH_80:
if (!vht_cap->vht_supported)
return false;
prohibited_flags |= IEEE80211_CHAN_NO_80MHZ;
width = 80;
if (chandef->chan->band == NL80211_BAND_6GHZ)
break;
if (!vht_cap->vht_supported)
return false;
break;
case NL80211_CHAN_WIDTH_160:
prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
width = 160;
if (chandef->chan->band == NL80211_BAND_6GHZ)
break;
if (!vht_cap->vht_supported)
return false;
cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
if (cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
cap != IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
return false;
prohibited_flags |= IEEE80211_CHAN_NO_160MHZ;
width = 160;
break;
default:
WARN_ON_ONCE(1);
@ -976,13 +990,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
if (!cfg80211_secondary_chans_ok(wiphy,
ieee80211_chandef_to_khz(chandef),
width, prohibited_flags))
return false;
if (!chandef->center_freq2)
return true;
return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
return cfg80211_secondary_chans_ok(wiphy,
MHZ_TO_KHZ(chandef->center_freq2),
width, prohibited_flags);
}
EXPORT_SYMBOL(cfg80211_chandef_usable);

View file

@ -5,7 +5,7 @@
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018-2019 Intel Corporation
* Copyright (C) 2018-2020 Intel Corporation
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@ -788,6 +788,7 @@ int wiphy_register(struct wiphy *wiphy)
/* sanity check supported bands/channels */
for (band = 0; band < NUM_NL80211_BANDS; band++) {
u16 types = 0;
bool have_he = false;
sband = wiphy->bands[band];
if (!sband)
@ -804,6 +805,11 @@ int wiphy_register(struct wiphy *wiphy)
!sband->n_bitrates))
return -EINVAL;
if (WARN_ON(band == NL80211_BAND_6GHZ &&
(sband->ht_cap.ht_supported ||
sband->vht_cap.vht_supported)))
return -EINVAL;
/*
* Since cfg80211_disable_40mhz_24ghz is global, we can
* modify the sband's ht data even if the driver uses a
@ -848,8 +854,17 @@ int wiphy_register(struct wiphy *wiphy)
return -EINVAL;
types |= iftd->types_mask;
if (i == 0)
have_he = iftd->he_cap.has_he;
else
have_he = have_he &&
iftd->he_cap.has_he;
}
if (WARN_ON(!have_he && band == NL80211_BAND_6GHZ))
return -EINVAL;
have_band = true;
}

View file

@ -652,6 +652,10 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_CONTROL_PORT_NO_PREAUTH] = { .type = NLA_FLAG },
[NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
[NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
[NL80211_ATTR_HE_6GHZ_CAPABILITY] = {
.type = NLA_EXACT_LEN,
.len = sizeof(struct ieee80211_he_6ghz_capa),
},
};
/* policy for the key attributes */
@ -1570,6 +1574,7 @@ static int nl80211_send_coalesce(struct sk_buff *msg,
static int
nl80211_send_iftype_data(struct sk_buff *msg,
const struct ieee80211_supported_band *sband,
const struct ieee80211_sband_iftype_data *iftdata)
{
const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
@ -1593,6 +1598,12 @@ nl80211_send_iftype_data(struct sk_buff *msg,
return -ENOBUFS;
}
if (sband->band == NL80211_BAND_6GHZ &&
nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
sizeof(iftdata->he_6ghz_capa),
&iftdata->he_6ghz_capa))
return -ENOBUFS;
return 0;
}
@ -1641,7 +1652,7 @@ static int nl80211_send_band_rateinfo(struct sk_buff *msg,
if (!iftdata)
return -ENOBUFS;
err = nl80211_send_iftype_data(msg,
err = nl80211_send_iftype_data(msg, sband,
&sband->iftype_data[i]);
if (err)
return err;
@ -5967,6 +5978,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
}
if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
params.airtime_weight =
nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
@ -6101,6 +6116,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
params.he_6ghz_capa =
nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
params.opmode_notif_used = true;
params.opmode_notif =
@ -6145,10 +6164,14 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.vht_capa = NULL;
/* HE requires WME */
if (params.he_capa_len)
if (params.he_capa_len || params.he_6ghz_capa)
return -EINVAL;
}
/* Ensure that HT/VHT capabilities are not set for 6 GHz HE STA */
if (params.he_6ghz_capa && (params.ht_capa || params.vht_capa))
return -EINVAL;
/* When you run into this, adjust the code below for the new flag */
BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);

View file

@ -1693,22 +1693,23 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
const struct ieee80211_channel *chan)
{
const struct ieee80211_freq_range *freq_range = NULL;
u32 max_bandwidth_khz, bw_flags = 0;
u32 max_bandwidth_khz, center_freq_khz, bw_flags = 0;
freq_range = &reg_rule->freq_range;
max_bandwidth_khz = freq_range->max_bandwidth_khz;
center_freq_khz = ieee80211_channel_to_khz(chan);
/* Check if auto calculation requested */
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
/* If we get a reg_rule we can assume that at least 5Mhz fit */
if (!cfg80211_does_bw_fit_range(freq_range,
MHZ_TO_KHZ(chan->center_freq),
center_freq_khz,
MHZ_TO_KHZ(10)))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (!cfg80211_does_bw_fit_range(freq_range,
MHZ_TO_KHZ(chan->center_freq),
center_freq_khz,
MHZ_TO_KHZ(20)))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
@ -1745,7 +1746,7 @@ static void handle_channel(struct wiphy *wiphy,
flags = chan->orig_flags;
reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan));
if (IS_ERR(reg_rule)) {
/*
* We will disable all channels that do not match our
@ -1764,13 +1765,13 @@ static void handle_channel(struct wiphy *wiphy,
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
request_wiphy && request_wiphy == wiphy &&
request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
pr_debug("Disabling freq %d MHz for good\n",
chan->center_freq);
pr_debug("Disabling freq %d.%03d MHz for good\n",
chan->center_freq, chan->freq_offset);
chan->orig_flags |= IEEE80211_CHAN_DISABLED;
chan->flags = chan->orig_flags;
} else {
pr_debug("Disabling freq %d MHz\n",
chan->center_freq);
pr_debug("Disabling freq %d.%03d MHz\n",
chan->center_freq, chan->freq_offset);
chan->flags |= IEEE80211_CHAN_DISABLED;
}
return;
@ -1971,7 +1972,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
sband = wiphy->bands[reg_beacon->chan.band];
chan = &sband->channels[chan_idx];
if (likely(chan->center_freq != reg_beacon->chan.center_freq))
if (likely(!ieee80211_channel_equal(chan, &reg_beacon->chan)))
return;
if (chan->beacon_found)
@ -2304,18 +2305,18 @@ static void handle_channel_custom(struct wiphy *wiphy,
u32 bw_flags = 0;
const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_power_rule *power_rule = NULL;
u32 bw;
u32 bw, center_freq_khz;
center_freq_khz = ieee80211_channel_to_khz(chan);
for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq),
regd, bw);
reg_rule = freq_reg_info_regd(center_freq_khz, regd, bw);
if (!IS_ERR(reg_rule))
break;
}
if (IS_ERR_OR_NULL(reg_rule)) {
pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
chan->center_freq);
pr_debug("Disabling freq %d.%03d MHz as custom regd has no rule that fits it\n",
chan->center_freq, chan->freq_offset);
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
chan->flags |= IEEE80211_CHAN_DISABLED;
} else {
@ -3372,8 +3373,8 @@ static bool pending_reg_beacon(struct ieee80211_channel *beacon_chan)
struct reg_beacon *pending_beacon;
list_for_each_entry(pending_beacon, &reg_pending_beacons, list)
if (beacon_chan->center_freq ==
pending_beacon->chan.center_freq)
if (ieee80211_channel_equal(beacon_chan,
&pending_beacon->chan))
return true;
return false;
}
@ -3402,9 +3403,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
if (!reg_beacon)
return -ENOMEM;
pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
beacon_chan->center_freq,
ieee80211_frequency_to_channel(beacon_chan->center_freq),
pr_debug("Found new beacon on frequency: %d.%03d MHz (Ch %d) on %s\n",
beacon_chan->center_freq, beacon_chan->freq_offset,
ieee80211_freq_khz_to_channel(
ieee80211_channel_to_khz(beacon_chan)),
wiphy_name(wiphy));
memcpy(&reg_beacon->chan, beacon_chan,

View file

@ -1323,8 +1323,8 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
return channel;
}
freq = ieee80211_channel_to_frequency(channel_number, channel->band);
alt_channel = ieee80211_get_channel(wiphy, freq);
freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
alt_channel = ieee80211_get_channel_khz(wiphy, freq);
if (!alt_channel) {
if (channel->band == NL80211_BAND_2GHZ) {
/*

View file

@ -112,24 +112,29 @@
} while (0)
#define CHAN_ENTRY __field(enum nl80211_band, band) \
__field(u32, center_freq)
__field(u32, center_freq) \
__field(u16, freq_offset)
#define CHAN_ASSIGN(chan) \
do { \
if (chan) { \
__entry->band = chan->band; \
__entry->center_freq = chan->center_freq; \
__entry->freq_offset = chan->freq_offset; \
} else { \
__entry->band = 0; \
__entry->center_freq = 0; \
__entry->freq_offset = 0; \
} \
} while (0)
#define CHAN_PR_FMT "band: %d, freq: %u"
#define CHAN_PR_ARG __entry->band, __entry->center_freq
#define CHAN_PR_FMT "band: %d, freq: %u.%03u"
#define CHAN_PR_ARG __entry->band, __entry->center_freq, __entry->freq_offset
#define CHAN_DEF_ENTRY __field(enum nl80211_band, band) \
__field(u32, control_freq) \
__field(u32, freq_offset) \
__field(u32, width) \
__field(u32, center_freq1) \
__field(u32, freq1_offset) \
__field(u32, center_freq2)
#define CHAN_DEF_ASSIGN(chandef) \
do { \
@ -137,21 +142,27 @@
__entry->band = (chandef)->chan->band; \
__entry->control_freq = \
(chandef)->chan->center_freq; \
__entry->freq_offset = \
(chandef)->chan->freq_offset; \
__entry->width = (chandef)->width; \
__entry->center_freq1 = (chandef)->center_freq1;\
__entry->freq1_offset = (chandef)->freq1_offset;\
__entry->center_freq2 = (chandef)->center_freq2;\
} else { \
__entry->band = 0; \
__entry->control_freq = 0; \
__entry->freq_offset = 0; \
__entry->width = 0; \
__entry->center_freq1 = 0; \
__entry->freq1_offset = 0; \
__entry->center_freq2 = 0; \
} \
} while (0)
#define CHAN_DEF_PR_FMT \
"band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u"
"band: %d, control freq: %u.%03u, width: %d, cf1: %u.%03u, cf2: %u"
#define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \
__entry->width, __entry->center_freq1, \
__entry->freq_offset, __entry->width, \
__entry->center_freq1, __entry->freq1_offset, \
__entry->center_freq2
#define SINFO_ENTRY __field(int, generation) \

View file

@ -72,7 +72,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
}
EXPORT_SYMBOL(ieee80211_mandatory_rates);
int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
{
/* see 802.11 17.3.8.3.2 and Annex J
* there are overlapping channel numbers in 5GHz and 2GHz bands */
@ -81,34 +81,39 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
switch (band) {
case NL80211_BAND_2GHZ:
if (chan == 14)
return 2484;
return MHZ_TO_KHZ(2484);
else if (chan < 14)
return 2407 + chan * 5;
return MHZ_TO_KHZ(2407 + chan * 5);
break;
case NL80211_BAND_5GHZ:
if (chan >= 182 && chan <= 196)
return 4000 + chan * 5;
return MHZ_TO_KHZ(4000 + chan * 5);
else
return 5000 + chan * 5;
return MHZ_TO_KHZ(5000 + chan * 5);
break;
case NL80211_BAND_6GHZ:
/* see 802.11ax D4.1 27.3.22.2 */
/* see 802.11ax D6.1 27.3.23.2 */
if (chan == 2)
return MHZ_TO_KHZ(5935);
if (chan <= 253)
return 5940 + chan * 5;
return MHZ_TO_KHZ(5950 + chan * 5);
break;
case NL80211_BAND_60GHZ:
if (chan < 7)
return 56160 + chan * 2160;
return MHZ_TO_KHZ(56160 + chan * 2160);
break;
default:
;
}
return 0; /* not supported */
}
EXPORT_SYMBOL(ieee80211_channel_to_frequency);
EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
int ieee80211_frequency_to_channel(int freq)
int ieee80211_freq_khz_to_channel(u32 freq)
{
/* TODO: just handle MHz for now */
freq = KHZ_TO_MHZ(freq);
/* see 802.11 17.3.8.3.2 and Annex J */
if (freq == 2484)
return 14;
@ -126,9 +131,10 @@ int ieee80211_frequency_to_channel(int freq)
else
return 0;
}
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
EXPORT_SYMBOL(ieee80211_freq_khz_to_channel);
struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
u32 freq)
{
enum nl80211_band band;
struct ieee80211_supported_band *sband;
@ -141,14 +147,16 @@ struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
continue;
for (i = 0; i < sband->n_channels; i++) {
if (sband->channels[i].center_freq == freq)
return &sband->channels[i];
struct ieee80211_channel *chan = &sband->channels[i];
if (ieee80211_channel_to_khz(chan) == freq)
return chan;
}
}
return NULL;
}
EXPORT_SYMBOL(ieee80211_get_channel);
EXPORT_SYMBOL(ieee80211_get_channel_khz);
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
{