From 765ef9735ee87ccb8e58df2d7e3cba53851ac8ef Mon Sep 17 00:00:00 2001 From: Muna Sinada Date: Wed, 2 Mar 2022 15:32:49 -0800 Subject: [PATCH] ru_puncturing: add bitmap to EHT operation element Add RU puncturing bitmap to the EHT operation element. Bits set to 1 indicate that the subchannel is punctured, otherwise active. Signed-off-by: Muna Sinada Signed-off-by: Aloka Dixit --- hostapd/ctrl_iface.c | 36 +++++++++++++ src/ap/hw_features.c | 64 +++++++++++++++++++++++ src/ap/ieee802_11.c | 73 ++++++++++++++++++++++++++ src/ap/ieee802_11.h | 1 + src/ap/ieee802_11_eht.c | 27 +++++++++- src/ap/ieee802_11_he.c | 16 ++++++ src/ap/ieee802_11_vht.c | 7 +++ src/common/hw_features_common.c | 92 +++++++++++++++++++++++++++++++++ src/common/hw_features_common.h | 2 + src/common/ieee802_11_defs.h | 1 + 10 files changed, 318 insertions(+), 1 deletion(-) --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -909,6 +909,61 @@ static int hostapd_is_usable_edmg(struct return 1; } +static int hostapd_is_usable_ru_punct_bitmap(struct hostapd_iface *iface) +{ + struct hostapd_config *conf = iface->conf; + u8 bw, start_chan; + + if (!conf->ru_punct_bitmap) { + conf->ru_punct_ofdma = 0; + return 1; + } + +#ifdef CONFIG_IEEE80211BE + if (!conf->ieee80211be) { + wpa_printf(MSG_ERROR, + "Currently RU puncturing is supported only if ieee80211be is enabled"); + return 0; + } + + if (iface->freq >= 2412 && iface->freq <= 2484) { + wpa_printf(MSG_ERROR, + "RU puncturing not supported in 2.4 GHz"); + return 0; + } + + switch (conf->eht_oper_chwidth) { + case 0: + wpa_printf(MSG_ERROR, + "RU puncturing is supported only in 80 MHz and 160 MHz"); + return 0; + case 1: + bw = 80; + start_chan = conf->eht_oper_centr_freq_seg0_idx - 6; + break; + case 2: + bw = 160; + start_chan = conf->eht_oper_centr_freq_seg0_idx - 14; + break; + default: + return 0; + } + + if (is_ru_punct_bitmap_valid(bw, + (conf->channel - start_chan) / 4, + conf->ru_punct_bitmap, + conf->ru_punct_ofdma) == false) { + wpa_printf(MSG_ERROR, "Invalid RU puncturing bitmap"); + return 0; + } + + return 1; +#else + wpa_printf(MSG_ERROR, + "Currently RU puncturing is supported only if ieee80211be is enabled"); + return 0; +#endif /* CONFIG_IEEE80211BE */ +} static bool hostapd_is_usable_punct_bitmap(struct hostapd_iface *iface) { @@ -990,6 +1045,9 @@ static int hostapd_is_usable_chans(struc if (err <= 0) return err; + if (!hostapd_is_usable_ru_punct_bitmap(iface)) + return 0; + if (!hostapd_is_usable_punct_bitmap(iface)) return 0; --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -233,6 +233,7 @@ u16 copy_sta_eht_capab(struct hostapd_da enum ieee80211_op_mode opmode, const u8 *he_capab, size_t he_capab_len, const u8 *eht_capab, size_t eht_capab_len); +void ru_punct_update_bw(u16 bitmap, u8 pri_chan, enum oper_chan_width *width, u8 *seg0, u8 *seg1); size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, u8 *elem_count, const u8 *known_bss, size_t known_bss_len, size_t *rnr_len); --- a/src/ap/ieee802_11_eht.c +++ b/src/ap/ieee802_11_eht.c @@ -224,6 +224,12 @@ u8 * hostapd_eid_eht_operation(struct ho else chwidth = conf->eht_oper_chwidth; + if (hapd->iconf->ru_punct_bitmap && !hapd->iface->ru_punct_supp_bw) { + hapd->iconf->ru_punct_bitmap = 0; + wpa_printf(MSG_ERROR, + "Driver does not support RU puncturing. Setting bitmap to 0"); + } + seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf); if (!seg0) seg0 = hapd->iconf->channel; @@ -239,6 +245,12 @@ u8 * hostapd_eid_eht_operation(struct ho break; case CONF_OPER_CHWIDTH_160MHZ: oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ; + if (hapd->iconf->ru_punct_bitmap && + hapd->iface->ru_punct_supp_bw == CONF_OPER_CHWIDTH_320MHZ) { + hapd->iconf->ru_punct_bitmap = 0; + wpa_printf(MSG_ERROR, + "Driver does not support RU puncturing for bandwidths less than 320 MHz. Setting bitmap to 0"); + } seg1 = seg0; if (hapd->iconf->channel < seg0) seg0 -= 8; @@ -249,6 +261,7 @@ u8 * hostapd_eid_eht_operation(struct ho oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_80MHZ; break; case CONF_OPER_CHWIDTH_USE_HT: + hapd->iconf->ru_punct_bitmap = 0; if ((is_6ghz_op_class(hapd->iconf->op_class) && op_class_to_bandwidth(hapd->iconf->op_class) == 40) || hapd->iconf->secondary_channel) @@ -258,6 +271,7 @@ u8 * hostapd_eid_eht_operation(struct ho break; default: + hapd->iconf->ru_punct_bitmap = 0; oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_20MHZ; break; } @@ -265,6 +279,11 @@ u8 * hostapd_eid_eht_operation(struct ho oper->oper_info.ccfs0 = seg0; oper->oper_info.ccfs1 = seg1; + if (hapd->iconf->ru_punct_bitmap) { + oper->oper_params |= EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT; + oper->oper_info.disabled_chan_bitmap = host_to_le16(hapd->iconf->ru_punct_bitmap); + } + if (hapd->iconf->punct_bitmap) { oper->oper_params |= EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT; oper->oper_info.disabled_chan_bitmap = --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -234,6 +234,22 @@ u8 * hostapd_eid_he_operation(struct hos } #endif /* CONFIG_IEEE80211BE */ + if (hapd->iconf->ru_punct_bitmap) { + hapd->iconf->he_oper_chwidth = + hostapd_get_oper_chwidth(hapd->iconf); + hapd->iconf->he_oper_centr_freq_seg0_idx = seg0; + hapd->iconf->he_oper_centr_freq_seg1_idx = seg1; + + punct_update_legacy_bw(hapd->iconf->ru_punct_bitmap, + hapd->iconf->channel, + &hapd->iconf->he_oper_chwidth, + &hapd->iconf->he_oper_centr_freq_seg0_idx, + &hapd->iconf->he_oper_centr_freq_seg1_idx); + + seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx; + seg1 = hapd->iconf->he_oper_centr_freq_seg1_idx; + } + if (!seg0) seg0 = hapd->iconf->channel; --- a/src/ap/ieee802_11_vht.c +++ b/src/ap/ieee802_11_vht.c @@ -110,6 +110,13 @@ u8 * hostapd_eid_vht_operation(struct ho } #endif /* CONFIG_IEEE80211BE */ + if (hapd->iconf->ru_punct_bitmap) + punct_update_legacy_bw(hapd->iconf->ru_punct_bitmap, + hapd->iconf->channel, + &hapd->iconf->vht_oper_chwidth, + &hapd->iconf->vht_oper_centr_freq_seg0_idx, + &hapd->iconf->vht_oper_centr_freq_seg1_idx); + /* * center freq = 5 GHz + (5 * index) * So index 42 gives center freq 5.210 GHz --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -884,6 +884,96 @@ int chan_pri_allowed(const struct hostap (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20); } +/* IEEE P802.11be/D1.31, December 2021, Table 36-30 5-bit punctured channel + * indication for the non-OFDMA case in an EHT MU PPDU + */ +static const u16 ru_punct_bitmap_80[] = {0xF, 0xE, 0xD, 0xB, 0x7}; +static const u16 ru_punct_bitmap_160[] = {0xFF, 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, + 0xDF, 0xBF, 0x7F, 0xFC, 0xF3, 0xCF, + 0x3F}; +static const u16 ru_punct_bitmap_320[] = {0xFFFF, 0xFFFC, 0xFFF3, 0xFFCF, + 0xFF3F, 0xFCFF, 0xF3FF, 0xCFFF, + 0x3FFF, 0xFFF0, 0xFF0F, 0xF0FF, + 0x0FFF, 0xFFC0, 0xFF30, 0xFCF0, + 0xF3F0, 0xCFF0, 0x3FF0, 0x0FFC, + 0x0FF3, 0x0FCF, 0x0F3F, 0x0CFF, + 0x03FF}; + + +bool is_ru_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 ru_punct_bitmap, + u8 ru_punct_ofdma) +{ + u8 i, non_ofdma_bitmap_count, ofdma_block_count = 1; + u16 bitmap; + const u16 *non_ofdma_bitmap; + + if (!ru_punct_bitmap) /* All channels active */ + return true; + + bitmap = ~ru_punct_bitmap; + + switch (bw) { + case 80: + bitmap &= 0xF; + non_ofdma_bitmap = &ru_punct_bitmap_80[0]; + non_ofdma_bitmap_count = ARRAY_SIZE(ru_punct_bitmap_80); + break; + + case 160: + bitmap &= 0xFF; + non_ofdma_bitmap = &ru_punct_bitmap_160[0]; + non_ofdma_bitmap_count = ARRAY_SIZE(ru_punct_bitmap_160); + break; + + case 320: + bitmap &= 0xFFFF; + non_ofdma_bitmap = &ru_punct_bitmap_320[0]; + non_ofdma_bitmap_count = ARRAY_SIZE(ru_punct_bitmap_320); + break; + + default: + return false; + } + + if (!bitmap) /* No channel active */ + return false; + + if (!(bitmap & BIT(pri_ch_bit_pos))) { + wpa_printf(MSG_DEBUG, "Primary channel cannot be punctured"); + return false; + } + + /* Check for non-OFDMA puncturing patterns */ + for (i = 0; i < non_ofdma_bitmap_count; i++) + if (non_ofdma_bitmap[i] == bitmap) + return true; + + if (!ru_punct_ofdma) + return false; + + /* Check for OFDMA puncturing patterns */ + for (i = 0; i < ofdma_block_count; i++) { + switch ((bitmap >> (i * 4)) & 0xF) { + /* IEEE P802.11be/D1.31, December 2021, 36.3.12.11.2 Preamble + * puncturing for PPDUs in an OFDMA transmission + */ + case 0xF: + case 0x7: + case 0xB: + case 0xD: + case 0xE: + case 0x3: + case 0xC: + case 0x9: + case 0x0: + break; + default: + return false; + } + } + + return true; +} /* IEEE P802.11be/D3.0, Table 36-30 - Definition of the Punctured Channel * Information field in the U-SIG for an EHT MU PPDU using non-OFDMA --- a/src/common/hw_features_common.h +++ b/src/common/hw_features_common.h @@ -57,5 +57,7 @@ int chan_bw_allowed(const struct hostapd int ht40_plus, int pri); int chan_pri_allowed(const struct hostapd_channel_data *chan); bool is_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 punct_bitmap); +bool is_ru_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 ru_punct_bitmap, + u8 ru_punct_ofdma); #endif /* HW_FEATURES_COMMON_H */