6 GHz: Add support for missing 6 GHz operating classes
Add support for missing 6 GHz operating classes as defined in IEEE P802.11ax/D7.0. This is needed to avoid OCV failures on the 6 GHz band when the channel width is larger than 20 MHz. Signed-off-by: Veerendranath Jakkam <vjakkam@codeaurora.org>
This commit is contained in:
parent
66bed14b22
commit
79e3f08d3c
5 changed files with 102 additions and 22 deletions
|
@ -1886,6 +1886,11 @@ const struct oper_class_map global_op_class[] = {
|
||||||
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
|
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
|
||||||
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
|
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
|
||||||
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
|
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
|
||||||
|
{ HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP },
|
||||||
|
{ HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP },
|
||||||
|
{ HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP },
|
||||||
|
{ HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
|
||||||
|
{ HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
|
* IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes.
|
||||||
|
@ -2199,6 +2204,7 @@ int oper_class_bw_to_int(const struct oper_class_map *map)
|
||||||
switch (map->bw) {
|
switch (map->bw) {
|
||||||
case BW20:
|
case BW20:
|
||||||
return 20;
|
return 20;
|
||||||
|
case BW40:
|
||||||
case BW40PLUS:
|
case BW40PLUS:
|
||||||
case BW40MINUS:
|
case BW40MINUS:
|
||||||
return 40;
|
return 40;
|
||||||
|
|
|
@ -232,8 +232,8 @@ struct oper_class_map {
|
||||||
u8 min_chan;
|
u8 min_chan;
|
||||||
u8 max_chan;
|
u8 max_chan;
|
||||||
u8 inc;
|
u8 inc;
|
||||||
enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80, BW4320,
|
enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80,
|
||||||
BW6480, BW8640} bw;
|
BW4320, BW6480, BW8640} bw;
|
||||||
enum { P2P_SUPP, NO_P2P_SUPP } p2p;
|
enum { P2P_SUPP, NO_P2P_SUPP } p2p;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,8 @@ int ocv_derive_all_parameters(struct oci_info *oci)
|
||||||
oci->sec_channel = 1;
|
oci->sec_channel = 1;
|
||||||
else if (op_class_map->bw == BW40MINUS)
|
else if (op_class_map->bw == BW40MINUS)
|
||||||
oci->sec_channel = -1;
|
oci->sec_channel = -1;
|
||||||
|
else if (op_class_map->bw == BW40)
|
||||||
|
oci->sec_channel = (((oci->channel - 1) / 4) % 2) ? -1 : 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,15 +47,15 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
|
static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel,
|
||||||
|
const u8 *center_channels, size_t num_chan)
|
||||||
{
|
{
|
||||||
u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
|
for (i = 0; i < num_chan; i++) {
|
||||||
/*
|
/*
|
||||||
* In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
|
* In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
|
||||||
* so the center channel is 6 channels away from the start/end.
|
* so the center channel is 6 channels away from the start/end.
|
||||||
|
@ -75,8 +75,22 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
|
||||||
u8 center_chan;
|
u8 center_chan;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int no_ir = 0;
|
unsigned int no_ir = 0;
|
||||||
|
const u8 *center_channels;
|
||||||
|
size_t num_chan;
|
||||||
|
const u8 center_channels_5ghz[] = { 42, 58, 106, 122, 138, 155 };
|
||||||
|
const u8 center_channels_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119,
|
||||||
|
135, 151, 167, 183, 199, 215 };
|
||||||
|
|
||||||
center_chan = get_center_80mhz(mode, channel);
|
if (is_6ghz_op_class(op_class)) {
|
||||||
|
center_channels = center_channels_6ghz;
|
||||||
|
num_chan = ARRAY_SIZE(center_channels_6ghz);
|
||||||
|
} else {
|
||||||
|
center_channels = center_channels_5ghz;
|
||||||
|
num_chan = ARRAY_SIZE(center_channels_5ghz);
|
||||||
|
}
|
||||||
|
|
||||||
|
center_chan = get_center_80mhz(mode, channel, center_channels,
|
||||||
|
num_chan);
|
||||||
if (!center_chan)
|
if (!center_chan)
|
||||||
return NOT_ALLOWED;
|
return NOT_ALLOWED;
|
||||||
|
|
||||||
|
@ -106,15 +120,15 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
|
static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel,
|
||||||
|
const u8 *center_channels, size_t num_chan)
|
||||||
{
|
{
|
||||||
u8 center_channels[] = { 50, 114 };
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
|
for (i = 0; i < num_chan; i++) {
|
||||||
/*
|
/*
|
||||||
* In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
|
* In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
|
||||||
* so the center channel is 14 channels away from the start/end.
|
* so the center channel is 14 channels away from the start/end.
|
||||||
|
@ -134,8 +148,21 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
|
||||||
u8 center_chan;
|
u8 center_chan;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int no_ir = 0;
|
unsigned int no_ir = 0;
|
||||||
|
const u8 *center_channels;
|
||||||
|
size_t num_chan;
|
||||||
|
const u8 center_channels_5ghz[] = { 50, 114 };
|
||||||
|
const u8 center_channels_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 };
|
||||||
|
|
||||||
center_chan = get_center_160mhz(mode, channel);
|
if (is_6ghz_op_class(op_class)) {
|
||||||
|
center_channels = center_channels_6ghz;
|
||||||
|
num_chan = ARRAY_SIZE(center_channels_6ghz);
|
||||||
|
} else {
|
||||||
|
center_channels = center_channels_5ghz;
|
||||||
|
num_chan = ARRAY_SIZE(center_channels_5ghz);
|
||||||
|
}
|
||||||
|
|
||||||
|
center_chan = get_center_160mhz(mode, channel, center_channels,
|
||||||
|
num_chan);
|
||||||
if (!center_chan)
|
if (!center_chan)
|
||||||
return NOT_ALLOWED;
|
return NOT_ALLOWED;
|
||||||
|
|
||||||
|
@ -176,11 +203,12 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
|
||||||
enum chan_allowed res, res2;
|
enum chan_allowed res, res2;
|
||||||
|
|
||||||
res2 = res = allow_channel(mode, op_class, channel, &flag);
|
res2 = res = allow_channel(mode, op_class, channel, &flag);
|
||||||
if (bw == BW40MINUS) {
|
if (bw == BW40MINUS || (bw == BW40 && (((channel - 1) / 4) % 2))) {
|
||||||
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
|
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
|
||||||
return NOT_ALLOWED;
|
return NOT_ALLOWED;
|
||||||
res2 = allow_channel(mode, op_class, channel - 4, NULL);
|
res2 = allow_channel(mode, op_class, channel - 4, NULL);
|
||||||
} else if (bw == BW40PLUS) {
|
} else if (bw == BW40PLUS ||
|
||||||
|
(bw == BW40 && !(((channel - 1) / 4) % 2))) {
|
||||||
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
|
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
|
||||||
return NOT_ALLOWED;
|
return NOT_ALLOWED;
|
||||||
res2 = allow_channel(mode, op_class, channel + 4, NULL);
|
res2 = allow_channel(mode, op_class, channel + 4, NULL);
|
||||||
|
@ -343,6 +371,41 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (op_class->op_class == 135) {
|
||||||
|
/* Need at least two 80 MHz segments which do not fall under the
|
||||||
|
* same 160 MHz segment to support 80+80 in 6 GHz.
|
||||||
|
*/
|
||||||
|
int first_seg = 0;
|
||||||
|
int curr_seg = 0;
|
||||||
|
|
||||||
|
for (chan = op_class->min_chan; chan <= op_class->max_chan;
|
||||||
|
chan += op_class->inc) {
|
||||||
|
curr_seg++;
|
||||||
|
if (verify_channel(mode, op_class->op_class, chan,
|
||||||
|
op_class->bw) != NOT_ALLOWED) {
|
||||||
|
if (!first_seg) {
|
||||||
|
first_seg = curr_seg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Supported if at least two non-consecutive 80
|
||||||
|
* MHz segments allowed.
|
||||||
|
*/
|
||||||
|
if ((curr_seg - first_seg) > 1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Supported even if the 80 MHz segments are
|
||||||
|
* consecutive when they do not fall under the
|
||||||
|
* same 160 MHz segment.
|
||||||
|
*/
|
||||||
|
if ((first_seg % 2) == 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
found = 0;
|
found = 0;
|
||||||
for (chan = op_class->min_chan; chan <= op_class->max_chan;
|
for (chan = op_class->min_chan; chan <= op_class->max_chan;
|
||||||
chan += op_class->inc) {
|
chan += op_class->inc) {
|
||||||
|
|
|
@ -556,23 +556,32 @@ static int * wpas_add_channels(const struct oper_class_map *op,
|
||||||
static int * wpas_op_class_freqs(const struct oper_class_map *op,
|
static int * wpas_op_class_freqs(const struct oper_class_map *op,
|
||||||
struct hostapd_hw_modes *mode, int active)
|
struct hostapd_hw_modes *mode, int active)
|
||||||
{
|
{
|
||||||
u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 };
|
u8 channels_80mhz_5ghz[] = { 42, 58, 106, 122, 138, 155 };
|
||||||
u8 channels_160mhz[] = { 50, 114 };
|
u8 channels_160mhz_5ghz[] = { 50, 114 };
|
||||||
|
u8 channels_80mhz_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119, 135, 151,
|
||||||
|
167, 183, 199, 215 };
|
||||||
|
u8 channels_160mhz_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 };
|
||||||
|
const u8 *channels = NULL;
|
||||||
|
size_t num_chan = 0;
|
||||||
|
int is_6ghz = is_6ghz_op_class(op->op_class);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When adding all channels in the operating class, 80 + 80 MHz
|
* When adding all channels in the operating class, 80 + 80 MHz
|
||||||
* operating classes are like 80 MHz channels because we add all valid
|
* operating classes are like 80 MHz channels because we add all valid
|
||||||
* channels anyway.
|
* channels anyway.
|
||||||
*/
|
*/
|
||||||
if (op->bw == BW80 || op->bw == BW80P80)
|
if (op->bw == BW80 || op->bw == BW80P80) {
|
||||||
return wpas_add_channels(op, mode, active, channels_80mhz,
|
channels = is_6ghz ? channels_80mhz_6ghz : channels_80mhz_5ghz;
|
||||||
ARRAY_SIZE(channels_80mhz));
|
num_chan = is_6ghz ? ARRAY_SIZE(channels_80mhz_6ghz) :
|
||||||
|
ARRAY_SIZE(channels_80mhz_5ghz);
|
||||||
|
} else if (op->bw == BW160) {
|
||||||
|
channels = is_6ghz ? channels_160mhz_6ghz :
|
||||||
|
channels_160mhz_5ghz;
|
||||||
|
num_chan = is_6ghz ? ARRAY_SIZE(channels_160mhz_6ghz) :
|
||||||
|
ARRAY_SIZE(channels_160mhz_5ghz);
|
||||||
|
}
|
||||||
|
|
||||||
if (op->bw == BW160)
|
return wpas_add_channels(op, mode, active, channels, num_chan);
|
||||||
return wpas_add_channels(op, mode, active, channels_160mhz,
|
|
||||||
ARRAY_SIZE(channels_160mhz));
|
|
||||||
|
|
||||||
return wpas_add_channels(op, mode, active, NULL, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue