Commit 2a38075c authored by Alexei Avshalom Lazar's avatar Alexei Avshalom Lazar Committed by Johannes Berg

nl80211: Add support for EDMG channels

802.11ay specification defines Enhanced Directional Multi-Gigabit
(EDMG) STA and AP which allow channel bonding of 2 channels and more.

Introduce new NL attributes that are needed for enabling and
configuring EDMG support.

Two new attributes are used by kernel to publish driver's EDMG
capabilities to the userspace:
NL80211_BAND_ATTR_EDMG_CHANNELS - bitmap field that indicates the 2.16
GHz channel(s) that are supported by the driver.
When this attribute is not set it means driver does not support EDMG.
NL80211_BAND_ATTR_EDMG_BW_CONFIG - represent the channel bandwidth
configurations supported by the driver.

Additional two new attributes are used by the userspace for connect
command and for AP configuration:
NL80211_ATTR_WIPHY_EDMG_CHANNELS
NL80211_ATTR_WIPHY_EDMG_BW_CONFIG

New rate info flag - RATE_INFO_FLAGS_EDMG, can be reported from driver
and used for bitrate calculation that will take into account EDMG
according to the 802.11ay specification.
Signed-off-by: default avatarAlexei Avshalom Lazar <ailizaro@codeaurora.org>
Link: https://lore.kernel.org/r/1566138918-3823-2-git-send-email-ailizaro@codeaurora.orgSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 5db16ba8
...@@ -351,7 +351,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, ...@@ -351,7 +351,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC) | BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC) |
BIT_ULL(NL80211_STA_INFO_TX_FAILED); BIT_ULL(NL80211_STA_INFO_TX_FAILED);
sinfo->txrate.flags = RATE_INFO_FLAGS_60G; sinfo->txrate.flags = RATE_INFO_FLAGS_DMG;
sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
sinfo->rxrate.mcs = stats->last_mcs_rx; sinfo->rxrate.mcs = stats->last_mcs_rx;
sinfo->rx_bytes = stats->rx_bytes; sinfo->rx_bytes = stats->rx_bytes;
......
...@@ -330,6 +330,60 @@ struct ieee80211_sband_iftype_data { ...@@ -330,6 +330,60 @@ struct ieee80211_sband_iftype_data {
struct ieee80211_sta_he_cap he_cap; struct ieee80211_sta_he_cap he_cap;
}; };
/**
* enum ieee80211_edmg_bw_config - allowed channel bandwidth configurations
*
* @IEEE80211_EDMG_BW_CONFIG_4: 2.16GHz
* @IEEE80211_EDMG_BW_CONFIG_5: 2.16GHz and 4.32GHz
* @IEEE80211_EDMG_BW_CONFIG_6: 2.16GHz, 4.32GHz and 6.48GHz
* @IEEE80211_EDMG_BW_CONFIG_7: 2.16GHz, 4.32GHz, 6.48GHz and 8.64GHz
* @IEEE80211_EDMG_BW_CONFIG_8: 2.16GHz and 2.16GHz + 2.16GHz
* @IEEE80211_EDMG_BW_CONFIG_9: 2.16GHz, 4.32GHz and 2.16GHz + 2.16GHz
* @IEEE80211_EDMG_BW_CONFIG_10: 2.16GHz, 4.32GHz, 6.48GHz and 2.16GHz+2.16GHz
* @IEEE80211_EDMG_BW_CONFIG_11: 2.16GHz, 4.32GHz, 6.48GHz, 8.64GHz and
* 2.16GHz+2.16GHz
* @IEEE80211_EDMG_BW_CONFIG_12: 2.16GHz, 2.16GHz + 2.16GHz and
* 4.32GHz + 4.32GHz
* @IEEE80211_EDMG_BW_CONFIG_13: 2.16GHz, 4.32GHz, 2.16GHz + 2.16GHz and
* 4.32GHz + 4.32GHz
* @IEEE80211_EDMG_BW_CONFIG_14: 2.16GHz, 4.32GHz, 6.48GHz, 2.16GHz + 2.16GHz
* and 4.32GHz + 4.32GHz
* @IEEE80211_EDMG_BW_CONFIG_15: 2.16GHz, 4.32GHz, 6.48GHz, 8.64GHz,
* 2.16GHz + 2.16GHz and 4.32GHz + 4.32GHz
*/
enum ieee80211_edmg_bw_config {
IEEE80211_EDMG_BW_CONFIG_4 = 4,
IEEE80211_EDMG_BW_CONFIG_5 = 5,
IEEE80211_EDMG_BW_CONFIG_6 = 6,
IEEE80211_EDMG_BW_CONFIG_7 = 7,
IEEE80211_EDMG_BW_CONFIG_8 = 8,
IEEE80211_EDMG_BW_CONFIG_9 = 9,
IEEE80211_EDMG_BW_CONFIG_10 = 10,
IEEE80211_EDMG_BW_CONFIG_11 = 11,
IEEE80211_EDMG_BW_CONFIG_12 = 12,
IEEE80211_EDMG_BW_CONFIG_13 = 13,
IEEE80211_EDMG_BW_CONFIG_14 = 14,
IEEE80211_EDMG_BW_CONFIG_15 = 15,
};
/**
* struct ieee80211_edmg - EDMG configuration
*
* This structure describes most essential parameters needed
* to describe 802.11ay EDMG configuration
*
* @channels: bitmap that indicates the 2.16 GHz channel(s)
* that are allowed to be used for transmissions.
* Bit 0 indicates channel 1, bit 1 indicates channel 2, etc.
* Set to 0 indicate EDMG not supported.
* @bw_config: Channel BW Configuration subfield encodes
* the allowed channel bandwidth configurations
*/
struct ieee80211_edmg {
u8 channels;
enum ieee80211_edmg_bw_config bw_config;
};
/** /**
* struct ieee80211_supported_band - frequency band definition * struct ieee80211_supported_band - frequency band definition
* *
...@@ -346,6 +400,7 @@ struct ieee80211_sband_iftype_data { ...@@ -346,6 +400,7 @@ struct ieee80211_sband_iftype_data {
* @n_bitrates: Number of bitrates in @bitrates * @n_bitrates: Number of bitrates in @bitrates
* @ht_cap: HT capabilities in this band * @ht_cap: HT capabilities in this band
* @vht_cap: VHT capabilities in this band * @vht_cap: VHT capabilities in this band
* @edmg_cap: EDMG capabilities in this band
* @n_iftype_data: number of iftype data entries * @n_iftype_data: number of iftype data entries
* @iftype_data: interface type data entries. Note that the bits in * @iftype_data: interface type data entries. Note that the bits in
* @types_mask inside this structure cannot overlap (i.e. only * @types_mask inside this structure cannot overlap (i.e. only
...@@ -360,6 +415,7 @@ struct ieee80211_supported_band { ...@@ -360,6 +415,7 @@ struct ieee80211_supported_band {
int n_bitrates; int n_bitrates;
struct ieee80211_sta_ht_cap ht_cap; struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap; struct ieee80211_sta_vht_cap vht_cap;
struct ieee80211_edmg edmg_cap;
u16 n_iftype_data; u16 n_iftype_data;
const struct ieee80211_sband_iftype_data *iftype_data; const struct ieee80211_sband_iftype_data *iftype_data;
}; };
...@@ -527,12 +583,17 @@ struct key_params { ...@@ -527,12 +583,17 @@ struct key_params {
* @center_freq1: center frequency of first segment * @center_freq1: center frequency of first segment
* @center_freq2: center frequency of second segment * @center_freq2: center frequency of second segment
* (only with 80+80 MHz) * (only with 80+80 MHz)
* @edmg: define the EDMG channels configuration.
* If edmg is requested (i.e. the .channels member is non-zero),
* chan will define the primary channel and all other
* parameters are ignored.
*/ */
struct cfg80211_chan_def { struct cfg80211_chan_def {
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
enum nl80211_chan_width width; enum nl80211_chan_width width;
u32 center_freq1; u32 center_freq1;
u32 center_freq2; u32 center_freq2;
struct ieee80211_edmg edmg;
}; };
/** /**
...@@ -590,6 +651,19 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1, ...@@ -590,6 +651,19 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
chandef1->center_freq2 == chandef2->center_freq2); chandef1->center_freq2 == chandef2->center_freq2);
} }
/**
* cfg80211_chandef_is_edmg - check if chandef represents an EDMG channel
*
* @chandef: the channel definition
*
* Return: %true if EDMG defined, %false otherwise.
*/
static inline bool
cfg80211_chandef_is_edmg(const struct cfg80211_chan_def *chandef)
{
return chandef->edmg.channels || chandef->edmg.bw_config;
}
/** /**
* cfg80211_chandef_compatible - check if two channel definitions are compatible * cfg80211_chandef_compatible - check if two channel definitions are compatible
* @chandef1: first channel definition * @chandef1: first channel definition
...@@ -1177,15 +1251,17 @@ int cfg80211_check_station_change(struct wiphy *wiphy, ...@@ -1177,15 +1251,17 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
* @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
* @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
* @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
* @RATE_INFO_FLAGS_60G: 60GHz MCS * @RATE_INFO_FLAGS_DMG: 60GHz MCS
* @RATE_INFO_FLAGS_HE_MCS: HE MCS information * @RATE_INFO_FLAGS_HE_MCS: HE MCS information
* @RATE_INFO_FLAGS_EDMG: 60GHz MCS in EDMG mode
*/ */
enum rate_info_flags { enum rate_info_flags {
RATE_INFO_FLAGS_MCS = BIT(0), RATE_INFO_FLAGS_MCS = BIT(0),
RATE_INFO_FLAGS_VHT_MCS = BIT(1), RATE_INFO_FLAGS_VHT_MCS = BIT(1),
RATE_INFO_FLAGS_SHORT_GI = BIT(2), RATE_INFO_FLAGS_SHORT_GI = BIT(2),
RATE_INFO_FLAGS_60G = BIT(3), RATE_INFO_FLAGS_DMG = BIT(3),
RATE_INFO_FLAGS_HE_MCS = BIT(4), RATE_INFO_FLAGS_HE_MCS = BIT(4),
RATE_INFO_FLAGS_EDMG = BIT(5),
}; };
/** /**
...@@ -1225,6 +1301,7 @@ enum rate_info_bw { ...@@ -1225,6 +1301,7 @@ enum rate_info_bw {
* @he_dcm: HE DCM value * @he_dcm: HE DCM value
* @he_ru_alloc: HE RU allocation (from &enum nl80211_he_ru_alloc, * @he_ru_alloc: HE RU allocation (from &enum nl80211_he_ru_alloc,
* only valid if bw is %RATE_INFO_BW_HE_RU) * only valid if bw is %RATE_INFO_BW_HE_RU)
* @n_bonded_ch: In case of EDMG the number of bonded channels (1-4)
*/ */
struct rate_info { struct rate_info {
u8 flags; u8 flags;
...@@ -1235,6 +1312,7 @@ struct rate_info { ...@@ -1235,6 +1312,7 @@ struct rate_info {
u8 he_gi; u8 he_gi;
u8 he_dcm; u8 he_dcm;
u8 he_ru_alloc; u8 he_ru_alloc;
u8 n_bonded_ch;
}; };
/** /**
...@@ -2438,6 +2516,9 @@ struct cfg80211_bss_selection { ...@@ -2438,6 +2516,9 @@ struct cfg80211_bss_selection {
* @fils_erp_rrk_len: Length of @fils_erp_rrk in octets. * @fils_erp_rrk_len: Length of @fils_erp_rrk in octets.
* @want_1x: indicates user-space supports and wants to use 802.1X driver * @want_1x: indicates user-space supports and wants to use 802.1X driver
* offload of 4-way handshake. * offload of 4-way handshake.
* @edmg: define the EDMG channels.
* This may specify multiple channels and bonding options for the driver
* to choose from, based on BSS configuration.
*/ */
struct cfg80211_connect_params { struct cfg80211_connect_params {
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
...@@ -2471,6 +2552,7 @@ struct cfg80211_connect_params { ...@@ -2471,6 +2552,7 @@ struct cfg80211_connect_params {
const u8 *fils_erp_rrk; const u8 *fils_erp_rrk;
size_t fils_erp_rrk_len; size_t fils_erp_rrk_len;
bool want_1x; bool want_1x;
struct ieee80211_edmg edmg;
}; };
/** /**
......
...@@ -52,6 +52,11 @@ ...@@ -52,6 +52,11 @@
#define NL80211_MULTICAST_GROUP_NAN "nan" #define NL80211_MULTICAST_GROUP_NAN "nan"
#define NL80211_MULTICAST_GROUP_TESTMODE "testmode" #define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
#define NL80211_EDMG_BW_CONFIG_MIN 4
#define NL80211_EDMG_BW_CONFIG_MAX 15
#define NL80211_EDMG_CHANNELS_MIN 1
#define NL80211_EDMG_CHANNELS_MAX 0x3c /* 0b00111100 */
/** /**
* DOC: Station handling * DOC: Station handling
* *
...@@ -2361,6 +2366,13 @@ enum nl80211_commands { ...@@ -2361,6 +2366,13 @@ enum nl80211_commands {
* @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection * @NL80211_ATTR_HE_OBSS_PD: nested attribute for OBSS Packet Detection
* functionality. * functionality.
* *
* @NL80211_ATTR_WIPHY_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
* channel(s) that are allowed to be used for EDMG transmissions.
* Defined by IEEE P802.11ay/D4.0 section 9.4.2.251. (u8 attribute)
* @NL80211_ATTR_WIPHY_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
* the allowed channel bandwidth configurations. (u8 attribute)
* Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
*
* @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
...@@ -2820,6 +2832,9 @@ enum nl80211_attrs { ...@@ -2820,6 +2832,9 @@ enum nl80211_attrs {
NL80211_ATTR_HE_OBSS_PD, NL80211_ATTR_HE_OBSS_PD,
NL80211_ATTR_WIPHY_EDMG_CHANNELS,
NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
/* 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,
...@@ -3431,6 +3446,12 @@ enum nl80211_band_iftype_attr { ...@@ -3431,6 +3446,12 @@ enum nl80211_band_iftype_attr {
* @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE
* @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using * @NL80211_BAND_ATTR_IFTYPE_DATA: nested array attribute, with each entry using
* attributes from &enum nl80211_band_iftype_attr * attributes from &enum nl80211_band_iftype_attr
* @NL80211_BAND_ATTR_EDMG_CHANNELS: bitmap that indicates the 2.16 GHz
* channel(s) that are allowed to be used for EDMG transmissions.
* Defined by IEEE P802.11ay/D4.0 section 9.4.2.251.
* @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes
* the allowed channel bandwidth configurations.
* Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13.
* @NL80211_BAND_ATTR_MAX: highest band attribute currently defined * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
* @__NL80211_BAND_ATTR_AFTER_LAST: internal use * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
*/ */
...@@ -3448,6 +3469,9 @@ enum nl80211_band_attr { ...@@ -3448,6 +3469,9 @@ enum nl80211_band_attr {
NL80211_BAND_ATTR_VHT_CAPA, NL80211_BAND_ATTR_VHT_CAPA,
NL80211_BAND_ATTR_IFTYPE_DATA, NL80211_BAND_ATTR_IFTYPE_DATA,
NL80211_BAND_ATTR_EDMG_CHANNELS,
NL80211_BAND_ATTR_EDMG_BW_CONFIG,
/* keep last */ /* keep last */
__NL80211_BAND_ATTR_AFTER_LAST, __NL80211_BAND_ATTR_AFTER_LAST,
NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
......
...@@ -158,10 +158,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, ...@@ -158,10 +158,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap)); memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap); ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
memset(chandef, 0, sizeof(struct cfg80211_chan_def));
chandef->chan = channel; chandef->chan = channel;
chandef->width = NL80211_CHAN_WIDTH_20_NOHT; chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = channel->center_freq; chandef->center_freq1 = channel->center_freq;
chandef->center_freq2 = 0;
if (!ht_oper || !sta_ht_cap.ht_supported) { if (!ht_oper || !sta_ht_cap.ht_supported) {
ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
......
...@@ -262,7 +262,8 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info, ...@@ -262,7 +262,8 @@ static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info,
/* IEEE80211_RADIOTAP_RATE rate */ /* IEEE80211_RADIOTAP_RATE rate */
if (status && status->rate && !(status->rate->flags & if (status && status->rate && !(status->rate->flags &
(RATE_INFO_FLAGS_MCS | (RATE_INFO_FLAGS_MCS |
RATE_INFO_FLAGS_60G | RATE_INFO_FLAGS_DMG |
RATE_INFO_FLAGS_EDMG |
RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_VHT_MCS |
RATE_INFO_FLAGS_HE_MCS))) RATE_INFO_FLAGS_HE_MCS)))
len += 2; len += 2;
...@@ -329,7 +330,8 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_local *local, ...@@ -329,7 +330,8 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_local *local,
if (status && status->rate) { if (status && status->rate) {
if (!(status->rate->flags & (RATE_INFO_FLAGS_MCS | if (!(status->rate->flags & (RATE_INFO_FLAGS_MCS |
RATE_INFO_FLAGS_60G | RATE_INFO_FLAGS_DMG |
RATE_INFO_FLAGS_EDMG |
RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_VHT_MCS |
RATE_INFO_FLAGS_HE_MCS))) RATE_INFO_FLAGS_HE_MCS)))
legacy_rate = status->rate->legacy; legacy_rate = status->rate->legacy;
......
...@@ -14,6 +14,11 @@ ...@@ -14,6 +14,11 @@
#include "core.h" #include "core.h"
#include "rdev-ops.h" #include "rdev-ops.h"
static bool cfg80211_valid_60g_freq(u32 freq)
{
return freq >= 58320 && freq <= 70200;
}
void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type chan_type) enum nl80211_channel_type chan_type)
...@@ -23,6 +28,8 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, ...@@ -23,6 +28,8 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
chandef->chan = chan; chandef->chan = chan;
chandef->center_freq2 = 0; chandef->center_freq2 = 0;
chandef->edmg.bw_config = 0;
chandef->edmg.channels = 0;
switch (chan_type) { switch (chan_type) {
case NL80211_CHAN_NO_HT: case NL80211_CHAN_NO_HT:
...@@ -47,6 +54,91 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, ...@@ -47,6 +54,91 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
} }
EXPORT_SYMBOL(cfg80211_chandef_create); EXPORT_SYMBOL(cfg80211_chandef_create);
static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
{
int max_contiguous = 0;
int num_of_enabled = 0;
int contiguous = 0;
int i;
if (!chandef->edmg.channels || !chandef->edmg.bw_config)
return false;
if (!cfg80211_valid_60g_freq(chandef->chan->center_freq))
return false;
for (i = 0; i < 6; i++) {
if (chandef->edmg.channels & BIT(i)) {
contiguous++;
num_of_enabled++;
} else {
contiguous = 0;
}
max_contiguous = max(contiguous, max_contiguous);
}
/* basic verification of edmg configuration according to
* IEEE P802.11ay/D4.0 section 9.4.2.251
*/
/* check bw_config against contiguous edmg channels */
switch (chandef->edmg.bw_config) {
case IEEE80211_EDMG_BW_CONFIG_4:
case IEEE80211_EDMG_BW_CONFIG_8:
case IEEE80211_EDMG_BW_CONFIG_12:
if (max_contiguous < 1)
return false;
break;
case IEEE80211_EDMG_BW_CONFIG_5:
case IEEE80211_EDMG_BW_CONFIG_9:
case IEEE80211_EDMG_BW_CONFIG_13:
if (max_contiguous < 2)
return false;
break;
case IEEE80211_EDMG_BW_CONFIG_6:
case IEEE80211_EDMG_BW_CONFIG_10:
case IEEE80211_EDMG_BW_CONFIG_14:
if (max_contiguous < 3)
return false;
break;
case IEEE80211_EDMG_BW_CONFIG_7:
case IEEE80211_EDMG_BW_CONFIG_11:
case IEEE80211_EDMG_BW_CONFIG_15:
if (max_contiguous < 4)
return false;
break;
default:
return false;
}
/* check bw_config against aggregated (non contiguous) edmg channels */
switch (chandef->edmg.bw_config) {
case IEEE80211_EDMG_BW_CONFIG_4:
case IEEE80211_EDMG_BW_CONFIG_5:
case IEEE80211_EDMG_BW_CONFIG_6:
case IEEE80211_EDMG_BW_CONFIG_7:
break;
case IEEE80211_EDMG_BW_CONFIG_8:
case IEEE80211_EDMG_BW_CONFIG_9:
case IEEE80211_EDMG_BW_CONFIG_10:
case IEEE80211_EDMG_BW_CONFIG_11:
if (num_of_enabled < 2)
return false;
break;
case IEEE80211_EDMG_BW_CONFIG_12:
case IEEE80211_EDMG_BW_CONFIG_13:
case IEEE80211_EDMG_BW_CONFIG_14:
case IEEE80211_EDMG_BW_CONFIG_15:
if (num_of_enabled < 4 || max_contiguous < 2)
return false;
break;
default:
return false;
}
return true;
}
bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
{ {
u32 control_freq; u32 control_freq;
...@@ -112,6 +204,10 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) ...@@ -112,6 +204,10 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
return false; return false;
} }
if (cfg80211_chandef_is_edmg(chandef) &&
!cfg80211_edmg_chandef_valid(chandef))
return false;
return true; return true;
} }
EXPORT_SYMBOL(cfg80211_chandef_valid); EXPORT_SYMBOL(cfg80211_chandef_valid);
...@@ -721,12 +817,66 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, ...@@ -721,12 +817,66 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
return true; return true;
} }
/* check if the operating channels are valid and supported */
static bool cfg80211_edmg_usable(struct wiphy *wiphy, u8 edmg_channels,
enum ieee80211_edmg_bw_config edmg_bw_config,
int primary_channel,
struct ieee80211_edmg *edmg_cap)
{
struct ieee80211_channel *chan;
int i, freq;
int channels_counter = 0;
if (!edmg_channels && !edmg_bw_config)
return true;
if ((!edmg_channels && edmg_bw_config) ||
(edmg_channels && !edmg_bw_config))
return false;
if (!(edmg_channels & BIT(primary_channel - 1)))
return false;
/* 60GHz channels 1..6 */
for (i = 0; i < 6; i++) {
if (!(edmg_channels & BIT(i)))
continue;
if (!(edmg_cap->channels & BIT(i)))
return false;
channels_counter++;
freq = ieee80211_channel_to_frequency(i + 1,
NL80211_BAND_60GHZ);
chan = ieee80211_get_channel(wiphy, freq);
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
return false;
}
/* IEEE802.11 allows max 4 channels */
if (channels_counter > 4)
return false;
/* check bw_config is a subset of what driver supports
* (see IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13)
*/
if ((edmg_bw_config % 4) > (edmg_cap->bw_config % 4))
return false;
if (edmg_bw_config > edmg_cap->bw_config)
return false;
return true;
}
bool cfg80211_chandef_usable(struct wiphy *wiphy, bool cfg80211_chandef_usable(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef, const struct cfg80211_chan_def *chandef,
u32 prohibited_flags) u32 prohibited_flags)
{ {
struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_ht_cap *ht_cap;
struct ieee80211_sta_vht_cap *vht_cap; struct ieee80211_sta_vht_cap *vht_cap;
struct ieee80211_edmg *edmg_cap;
u32 width, control_freq, cap; u32 width, control_freq, cap;
if (WARN_ON(!cfg80211_chandef_valid(chandef))) if (WARN_ON(!cfg80211_chandef_valid(chandef)))
...@@ -734,6 +884,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, ...@@ -734,6 +884,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap; ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap; vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
edmg_cap = &wiphy->bands[chandef->chan->band]->edmg_cap;
if (edmg_cap->channels &&
!cfg80211_edmg_usable(wiphy,
chandef->edmg.channels,
chandef->edmg.bw_config,
chandef->chan->hw_value,
edmg_cap))
return false;
control_freq = chandef->chan->center_freq; control_freq = chandef->chan->center_freq;
......
...@@ -298,6 +298,13 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { ...@@ -298,6 +298,13 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_EDMG_CHANNELS] = NLA_POLICY_RANGE(NLA_U8,
NL80211_EDMG_CHANNELS_MIN,
NL80211_EDMG_CHANNELS_MAX),
[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG] = NLA_POLICY_RANGE(NLA_U8,
NL80211_EDMG_BW_CONFIG_MIN,
NL80211_EDMG_BW_CONFIG_MAX),
[NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 }, [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
[NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 }, [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
[NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 }, [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
...@@ -1574,6 +1581,15 @@ static int nl80211_send_band_rateinfo(struct sk_buff *msg, ...@@ -1574,6 +1581,15 @@ static int nl80211_send_band_rateinfo(struct sk_buff *msg,
nla_nest_end(msg, nl_iftype_data); nla_nest_end(msg, nl_iftype_data);
} }
/* add EDMG info */
if (sband->edmg_cap.channels &&
(nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_CHANNELS,
sband->edmg_cap.channels) ||
nla_put_u8(msg, NL80211_BAND_ATTR_EDMG_BW_CONFIG,
sband->edmg_cap.bw_config)))
return -ENOBUFS;
/* add bitrates */ /* add bitrates */
nl_rates = nla_nest_start_noflag(msg, NL80211_BAND_ATTR_RATES); nl_rates = nla_nest_start_noflag(msg, NL80211_BAND_ATTR_RATES);
if (!nl_rates) if (!nl_rates)
...@@ -2677,6 +2693,18 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, ...@@ -2677,6 +2693,18 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]); nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2]);
} }
if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
chandef->edmg.channels =
nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
chandef->edmg.bw_config =
nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
} else {
chandef->edmg.bw_config = 0;
chandef->edmg.channels = 0;
}
if (!cfg80211_chandef_valid(chandef)) { if (!cfg80211_chandef_valid(chandef)) {
NL_SET_ERR_MSG(extack, "invalid channel definition"); NL_SET_ERR_MSG(extack, "invalid channel definition");
return -EINVAL; return -EINVAL;
...@@ -9894,6 +9922,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) ...@@ -9894,6 +9922,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
} }
if (info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]) {
connect.edmg.channels =
nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_CHANNELS]);
if (info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG])
connect.edmg.bw_config =
nla_get_u8(info->attrs[NL80211_ATTR_WIPHY_EDMG_BW_CONFIG]);
}
if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
connkeys = nl80211_parse_connkeys(rdev, info, NULL); connkeys = nl80211_parse_connkeys(rdev, info, NULL);
if (IS_ERR(connkeys)) if (IS_ERR(connkeys))
......
...@@ -1043,7 +1043,7 @@ static u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate) ...@@ -1043,7 +1043,7 @@ static u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate)
return (bitrate + 50000) / 100000; return (bitrate + 50000) / 100000;
} }
static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) static u32 cfg80211_calculate_bitrate_dmg(struct rate_info *rate)
{ {
static const u32 __mcs2bitrate[] = { static const u32 __mcs2bitrate[] = {
/* control PHY */ /* control PHY */
...@@ -1090,6 +1090,40 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) ...@@ -1090,6 +1090,40 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
return __mcs2bitrate[rate->mcs]; return __mcs2bitrate[rate->mcs];
} }
static u32 cfg80211_calculate_bitrate_edmg(struct rate_info *rate)
{
static const u32 __mcs2bitrate[] = {
/* control PHY */
[0] = 275,
/* SC PHY */
[1] = 3850,
[2] = 7700,
[3] = 9625,
[4] = 11550,
[5] = 12512, /* 1251.25 mbps */
[6] = 13475,
[7] = 15400,
[8] = 19250,
[9] = 23100,
[10] = 25025,
[11] = 26950,
[12] = 30800,
[13] = 38500,
[14] = 46200,
[15] = 50050,
[16] = 53900,
[17] = 57750,
[18] = 69300,
[19] = 75075,
[20] = 80850,
};
if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate)))
return 0;
return __mcs2bitrate[rate->mcs] * rate->n_bonded_ch;
}
static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
{ {
static const u32 base[4][10] = { static const u32 base[4][10] = {
...@@ -1262,8 +1296,10 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) ...@@ -1262,8 +1296,10 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
{ {
if (rate->flags & RATE_INFO_FLAGS_MCS) if (rate->flags & RATE_INFO_FLAGS_MCS)
return cfg80211_calculate_bitrate_ht(rate); return cfg80211_calculate_bitrate_ht(rate);
if (rate->flags & RATE_INFO_FLAGS_60G) if (rate->flags & RATE_INFO_FLAGS_DMG)
return cfg80211_calculate_bitrate_60g(rate); return cfg80211_calculate_bitrate_dmg(rate);
if (rate->flags & RATE_INFO_FLAGS_EDMG)
return cfg80211_calculate_bitrate_edmg(rate);
if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
return cfg80211_calculate_bitrate_vht(rate); return cfg80211_calculate_bitrate_vht(rate);
if (rate->flags & RATE_INFO_FLAGS_HE_MCS) if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment