EHT: Add 320 channel width support

Add initial changes to support 320 MHz channel width.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com>
This commit is contained in:
Veerendranath Jakkam 2022-05-13 21:47:41 +05:30 committed by Jouni Malinen
parent bafe35df03
commit 085a3fc76e
16 changed files with 121 additions and 13 deletions

View file

@ -2527,6 +2527,9 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
case 160:
bandwidth = CHAN_WIDTH_160;
break;
case 320:
bandwidth = CHAN_WIDTH_320;
break;
default:
bandwidth = CHAN_WIDTH_20;
break;

View file

@ -1163,6 +1163,8 @@ hostapd_set_oper_chwidth(struct hostapd_config *conf,
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
conf->eht_oper_chwidth = oper_chwidth;
if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
oper_chwidth = CONF_OPER_CHWIDTH_160MHZ;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
@ -1192,6 +1194,9 @@ hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
if (center_idx_to_bw_6ghz(oper_centr_freq_seg0_idx) == 4)
oper_centr_freq_seg0_idx +=
conf->channel > oper_centr_freq_seg0_idx ? 16 : -16;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)

View file

@ -986,6 +986,8 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
params.ch_width = 160;
else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
params.ch_width = 320;
}
if (hapd->iface->conf->op_class)

View file

@ -838,6 +838,9 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
case CHAN_WIDTH_160:
txt = "160";
break;
case CHAN_WIDTH_320:
txt = "320";
break;
default:
txt = NULL;
break;
@ -899,6 +902,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
case CHAN_WIDTH_160:
chwidth = CONF_OPER_CHWIDTH_160MHZ;
break;
case CHAN_WIDTH_320:
chwidth = CONF_OPER_CHWIDTH_320MHZ;
break;
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
@ -1173,6 +1179,15 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd,
}
}
#ifdef CONFIG_IEEE80211BE
if (hapd->iface->conf->ieee80211be && acs_res->ch_width == 320) {
hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_320MHZ);
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf, acs_res->vht_seg1_center_ch);
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
}
#endif /* CONFIG_IEEE80211BE */
out:
ret = hostapd_acs_completed(hapd->iface, err);
if (ret) {

View file

@ -3516,6 +3516,9 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
case 160:
hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ);
break;
case 320:
hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_320MHZ);
break;
default:
return -1;
}
@ -3715,6 +3718,9 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
case 160:
bw = CONF_OPER_CHWIDTH_160MHZ;
break;
case 320:
bw = CONF_OPER_CHWIDTH_320MHZ;
break;
default:
wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
freq_params->bandwidth);

View file

@ -1087,13 +1087,14 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
iface->conf->ieee80211n || iface->conf->ieee80211ac ||
iface->conf->ieee80211ax) &&
iface->conf->ieee80211ax || iface->conf->ieee80211be) &&
iface->conf->channel == 14) {
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE/EHT on channel 14");
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
iface->conf->ieee80211n = 0;
iface->conf->ieee80211ac = 0;
iface->conf->ieee80211ax = 0;
iface->conf->ieee80211be = 0;
}
iface->current_mode = NULL;

View file

@ -197,9 +197,7 @@ u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid)
seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf);
switch (chwidth) {
#if 0 /* FIX: Need to clean up CHANWIDTH_* use for protocol vs. internal
* needs to be able to define this. */
case CHANWIDTH_320MHZ:
case CONF_OPER_CHWIDTH_320MHZ:
oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ;
seg1 = seg0;
if (hapd->iconf->channel < seg0)
@ -207,7 +205,6 @@ u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid)
else
seg0 += 16;
break;
#endif
case CONF_OPER_CHWIDTH_160MHZ:
oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ;
seg1 = seg0;
@ -286,10 +283,12 @@ static bool check_valid_eht_mcs(struct hostapd_data *hapd,
EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY);
switch (hapd->iface->conf->eht_oper_chwidth) {
/* TODO: CHANWIDTH_320MHZ */
case CONF_OPER_CHWIDTH_320MHZ:
mcs_count++;
/* fall through */
case CONF_OPER_CHWIDTH_80P80MHZ:
case CONF_OPER_CHWIDTH_160MHZ:
mcs_count = 2;
mcs_count++;
break;
default:
break;

View file

@ -219,7 +219,7 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
pos += 6; /* skip the fixed part */
if (is_6ghz_op_class(hapd->iconf->op_class)) {
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx;
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
u8 control;

View file

@ -429,6 +429,7 @@ enum chan_width {
CHAN_WIDTH_4320,
CHAN_WIDTH_6480,
CHAN_WIDTH_8640,
CHAN_WIDTH_320,
CHAN_WIDTH_UNKNOWN
};
@ -445,6 +446,7 @@ enum oper_chan_width {
CONF_OPER_CHWIDTH_6480MHZ,
CONF_OPER_CHWIDTH_8640MHZ,
CONF_OPER_CHWIDTH_40MHZ_6GHZ,
CONF_OPER_CHWIDTH_320MHZ,
};
enum key_flag {

View file

@ -392,6 +392,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
{
if (!he_cap || !he_cap->he_supported)
he_enabled = 0;
if (!eht_cap || !eht_cap->eht_supported)
eht_enabled = 0;
os_memset(data, 0, sizeof(*data));
data->mode = mode;
data->freq = freq;
@ -408,6 +410,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
data->bandwidth = 160;
else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
data->bandwidth = 320;
else if (sec_channel_offset)
data->bandwidth = 40;
else
@ -483,9 +487,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return 0;
}
#if 0 /* FIX: Figure out how to handle CHANWIDTH_320MHZ */
if (data->eht_enabled) switch (oper_chwidth) {
case CHANWIDTH_320MHZ:
case CONF_OPER_CHWIDTH_320MHZ:
if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
wpa_printf(MSG_ERROR,
@ -493,8 +496,9 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
}
break;
default:
break;
}
#endif
if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) {
case CONF_OPER_CHWIDTH_USE_HT:
@ -673,6 +677,41 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
}
break;
case CONF_OPER_CHWIDTH_320MHZ:
data->bandwidth = 320;
if (!data->eht_enabled || !is_6ghz_freq(freq)) {
wpa_printf(MSG_ERROR,
"320 MHz: EHT not enabled or not a 6 GHz channel");
return -1;
}
if (center_segment1) {
wpa_printf(MSG_ERROR,
"320 MHz: center segment 1 should not be set");
return -1;
}
if (center_segment0 == channel + 30 ||
center_segment0 == channel + 26 ||
center_segment0 == channel + 22 ||
center_segment0 == channel + 18 ||
center_segment0 == channel + 14 ||
center_segment0 == channel + 10 ||
center_segment0 == channel + 6 ||
center_segment0 == channel + 2 ||
center_segment0 == channel - 2 ||
center_segment0 == channel - 6 ||
center_segment0 == channel - 10 ||
center_segment0 == channel - 14 ||
center_segment0 == channel - 18 ||
center_segment0 == channel - 22 ||
center_segment0 == channel - 26 ||
center_segment0 == channel - 30)
data->center_freq1 = 5000 + center_segment0 * 5;
else {
wpa_printf(MSG_ERROR,
"320 MHz: wrong center segment 0");
return -1;
}
break;
default:
break;
}
@ -785,6 +824,7 @@ u32 num_chan_to_bw(int num_chans)
case 2:
case 4:
case 8:
case 16:
return num_chans * 20;
default:
return 20;
@ -818,6 +858,9 @@ int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
case 160:
bw_mask = HOSTAPD_CHAN_WIDTH_160;
break;
case 320:
bw_mask = HOSTAPD_CHAN_WIDTH_320;
break;
default:
bw_mask = 0;
break;

View file

@ -1060,6 +1060,9 @@ ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
case CONF_OPER_CHWIDTH_80P80MHZ:
*op_class = 135;
break;
case CONF_OPER_CHWIDTH_320MHZ:
*op_class = 137;
break;
default:
if (sec_channel)
*op_class = 132;
@ -1157,6 +1160,9 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
case CHAN_WIDTH_8640:
cw = CONF_OPER_CHWIDTH_8640MHZ;
break;
case CHAN_WIDTH_320:
cw = CONF_OPER_CHWIDTH_320MHZ;
break;
}
if (ieee80211_freq_to_channel_ext(freq, sec_channel, cw, op_class,
@ -1452,6 +1458,7 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
if (chan < 1 || chan > 233)
return -1;
return 5950 + chan * 5;
@ -2265,6 +2272,9 @@ int center_idx_to_bw_6ghz(u8 idx)
/* channels 15, 47, 79...*/
if ((idx & 0x1f) == 0xf)
return 3; /* 160 MHz */
/* channels 31, 63, 95, 127, 159, 191 */
if ((idx & 0x1f) == 0x1f && idx < 192)
return 4; /* 320 MHz */
return -1;
}
@ -2287,7 +2297,7 @@ bool is_6ghz_freq(int freq)
bool is_6ghz_op_class(u8 op_class)
{
return op_class >= 131 && op_class <= 136;
return op_class >= 131 && op_class <= 137;
}
@ -2593,6 +2603,8 @@ int op_class_to_bandwidth(u8 op_class)
return 160;
case 136: /* UHB channels, 20 MHz: 2 */
return 20;
case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
return 320;
case 180: /* 60 GHz band, channels 1..8 */
return 2160;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
@ -2655,6 +2667,8 @@ enum oper_chan_width op_class_to_ch_width(u8 op_class)
return CONF_OPER_CHWIDTH_80P80MHZ;
case 136: /* UHB channels, 20 MHz: 2 */
return CONF_OPER_CHWIDTH_USE_HT;
case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
return CONF_OPER_CHWIDTH_320MHZ;
case 180: /* 60 GHz band, channels 1..8 */
return CONF_OPER_CHWIDTH_2160MHZ;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */

View file

@ -66,6 +66,7 @@ enum hostapd_chan_width_attr {
HOSTAPD_CHAN_WIDTH_40M = BIT(3),
HOSTAPD_CHAN_WIDTH_80 = BIT(4),
HOSTAPD_CHAN_WIDTH_160 = BIT(5),
HOSTAPD_CHAN_WIDTH_320 = BIT(6),
};
/* Filter gratuitous ARP */

View file

@ -117,6 +117,8 @@ const char * channel_width_to_string(enum chan_width width)
return "80+80 MHz";
case CHAN_WIDTH_160:
return "160 MHz";
case CHAN_WIDTH_320:
return "320 MHz";
default:
return "unknown";
}
@ -136,6 +138,8 @@ int channel_width_to_int(enum chan_width width)
case CHAN_WIDTH_80P80:
case CHAN_WIDTH_160:
return 160;
case CHAN_WIDTH_320:
return 320;
default:
return 0;
}

View file

@ -215,6 +215,8 @@ enum chan_width convert2width(int width)
return CHAN_WIDTH_80P80;
case NL80211_CHAN_WIDTH_160:
return CHAN_WIDTH_160;
case NL80211_CHAN_WIDTH_320:
return CHAN_WIDTH_320;
}
return CHAN_WIDTH_UNKNOWN;
}
@ -4941,6 +4943,9 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
case 160:
cw = NL80211_CHAN_WIDTH_160;
break;
case 320:
cw = NL80211_CHAN_WIDTH_320;
break;
default:
return -EINVAL;
}

View file

@ -674,6 +674,9 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
case CHAN_WIDTH_80P80:
freq1 = cf1 - 30;
break;
case CHAN_WIDTH_320:
freq1 = cf1 - 150;
break;
case CHAN_WIDTH_UNKNOWN:
case CHAN_WIDTH_2160:
case CHAN_WIDTH_4320:
@ -2791,6 +2794,9 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv,
case NL80211_CHAN_WIDTH_160:
ed.sta_opmode.chan_width = CHAN_WIDTH_160;
break;
case NL80211_CHAN_WIDTH_320:
ed.sta_opmode.chan_width = CHAN_WIDTH_320;
break;
default:
ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
break;

View file

@ -5989,6 +5989,8 @@ static int parse_freq(int chwidth, int freq2)
return CONF_OPER_CHWIDTH_80MHZ;
case 160:
return CONF_OPER_CHWIDTH_160MHZ;
case 320:
return CONF_OPER_CHWIDTH_320MHZ;
default:
wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
chwidth);