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 @@ -898,6 +898,63 @@ static int hostapd_is_usable_edmg(struct } +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 int hostapd_is_usable_chans(struct hostapd_iface *iface) { int secondary_freq; @@ -920,6 +977,9 @@ static int hostapd_is_usable_chans(struc if (!hostapd_is_usable_edmg(iface)) return 0; + if (!hostapd_is_usable_ru_punct_bitmap(iface)) + return 0; + if (!iface->conf->secondary_channel) return 1; --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -8066,4 +8066,77 @@ u8 * hostapd_eid_mbssid(struct hostapd_d return eid; } + +static void ru_punct_update_bw_80(u8 bitmap, u8 pri_chan, u8 *seg0) +{ + u8 first_chan = *seg0 - 6, sec_chan; + + switch (bitmap) { + case 0x6: + *seg0 = 0; + return; + case 0x8: + case 0x4: + case 0x2: + case 0x1: + case 0xC: + case 0x3: + if (pri_chan < *seg0) + *seg0 -= 4; + else + *seg0 += 4; + break; + } + + if (pri_chan < *seg0) + sec_chan = pri_chan + 4; + else + sec_chan = pri_chan - 4; + + if (bitmap & BIT((sec_chan - first_chan) / 4)) + *seg0 = 0; +} + + +static void ru_punct_update_bw_160(u8 bitmap, u8 pri_chan, u8 *width, u8 *seg0) +{ + if (pri_chan < *seg0) { + *seg0 -= 8; + if (bitmap & 0x0F) { + *width = 0; + ru_punct_update_bw_80(bitmap & 0xF, + pri_chan, + seg0); + } + } else { + *seg0 += 8; + if (bitmap & 0xF0) { + *width = 0; + ru_punct_update_bw_80((bitmap & 0xF0) >> 4, + pri_chan, + seg0); + } + } +} + + +void ru_punct_update_bw(u16 bitmap, u8 pri_chan, u8 *width, u8 *seg0, u8 *seg1) +{ + if (!bitmap || !(*width) || ((*width) == 3)) + return; + + if (((*width) == 1) && (bitmap & 0xF)) { + *width = 0; + ru_punct_update_bw_80(bitmap & 0xF, pri_chan, seg0); + } + + if ((*width) == 2 && (bitmap & 0xFF)) { + *width = 1; + *seg1 = 0; + ru_punct_update_bw_160(bitmap & 0xFF, pri_chan, width, seg0); + } + + /* Add for 320 MHz */ +} + #endif /* CONFIG_NATIVE_WINDOWS */ --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -228,4 +228,5 @@ u8 * hostapd_eid_eht_operation(struct ho u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, enum ieee80211_op_mode opmode, const u8 *he_capab, const u8 *eht_capab, size_t eht_capab_len); +void ru_punct_update_bw(u16 bitmap, u8 pri_chan, u8 *width, u8 *seg0, u8 *seg1); #endif /* IEEE802_11_H */ --- a/src/ap/ieee802_11_eht.c +++ b/src/ap/ieee802_11_eht.c @@ -196,17 +196,37 @@ u8 * hostapd_eid_eht_operation(struct ho else chwidth = hapd->iconf->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"); + } + switch (chwidth) { case CHANWIDTH_320MHZ: oper->width = EHT_OPERATION_CHANNEL_WIDTH_320MHZ; break; case CHANWIDTH_160MHZ: oper->width = EHT_OPERATION_CHANNEL_WIDTH_160MHZ; + if (hapd->iconf->ru_punct_bitmap && + hapd->iface->ru_punct_supp_bw == CHANWIDTH_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"); + } break; case CHANWIDTH_80MHZ: oper->width = EHT_OPERATION_CHANNEL_WIDTH_80MHZ; + if (hapd->iconf->ru_punct_bitmap && + ((hapd->iface->ru_punct_supp_bw == CHANWIDTH_160MHZ) || + (hapd->iface->ru_punct_supp_bw == CHANWIDTH_320MHZ))) { + hapd->iconf->ru_punct_bitmap = 0; + wpa_printf(MSG_ERROR, + "Driver does not support RU puncturing for bandwidths less than 160 MHz. Setting bitmap to 0"); + } break; case CHANWIDTH_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) @@ -216,10 +236,16 @@ u8 * hostapd_eid_eht_operation(struct ho break; default: + hapd->iconf->ru_punct_bitmap = 0; oper->width = EHT_OPERATION_CHANNEL_WIDTH_20MHZ; break; } + if (hapd->iconf->ru_punct_bitmap) { + oper->disable_sub_chan_bitmap_present = 1; + oper->disabled_subchannel_bitmap = host_to_le16(hapd->iconf->ru_punct_bitmap); + } + pos += oper_size; return pos; --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -215,6 +215,22 @@ u8 * hostapd_eid_he_operation(struct hos u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf); u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf); + 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; + + ru_punct_update_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 @@ -98,6 +98,13 @@ u8 * hostapd_eid_vht_operation(struct ho oper = (struct ieee80211_vht_operation *) pos; os_memset(oper, 0, sizeof(*oper)); + if (hapd->iconf->ru_punct_bitmap) + ru_punct_update_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 @@ -824,3 +824,95 @@ int chan_pri_allowed(const struct hostap return !(chan->flag & HOSTAPD_CHAN_DISABLED) && (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; +} --- a/src/common/hw_features_common.h +++ b/src/common/hw_features_common.h @@ -55,5 +55,7 @@ u32 num_chan_to_bw(int num_chans); int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw, int ht40_plus, int pri); int chan_pri_allowed(const struct hostapd_channel_data *chan); +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 */