From: John Crispin <john@xxxxxxxxxxx> Add the core code for handling bss color collision events and triggering CCA inside the kernel. The caller of hostapd_switch_color() will be added in the following commits. Tested-by: Peter Chiu <chui-hao.chiu@xxxxxxxxxxxx> Co-developed-by: Lorenzo Bianconi <lorenzo@xxxxxxxxxx> Signed-off-by: Lorenzo Bianconi <lorenzo@xxxxxxxxxx> Signed-off-by: John Crispin <john@xxxxxxxxxxx> Signed-off-by: Ryder Lee <ryder.lee@xxxxxxxxxxxx> --- src/ap/ap_drv_ops.h | 11 +++ src/ap/hostapd.c | 141 ++++++++++++++++++++++++++++++++++- src/ap/hostapd.h | 17 +++++ src/common/ieee802_11_defs.h | 6 ++ src/drivers/driver.h | 31 ++++++++ 5 files changed, 205 insertions(+), 1 deletion(-) diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index b4d6395ae..d15f9defe 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -300,6 +300,17 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd, return hapd->driver->switch_channel(hapd->drv_priv, settings); } +#ifdef CONFIG_IEEE80211AX +static inline int hostapd_drv_switch_color(struct hostapd_data *hapd, + struct cca_settings *settings) +{ + if (!hapd->driver || !hapd->driver->switch_color || !hapd->drv_priv) + return -1; + + return hapd->driver->switch_color(hapd->drv_priv, settings); +} +#endif /* CONFIG_IEEE80211AX */ + static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf, size_t buflen) { diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 4b88641a2..c602f7c13 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -66,7 +66,10 @@ static int setup_interface2(struct hostapd_iface *iface); static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); static void hostapd_interface_setup_failure_handler(void *eloop_ctx, void *timeout_ctx); - +#ifdef CONFIG_IEEE80211AX +static void hostapd_switch_color_timeout_handler(void *eloop_data, + void *user_ctx); +#endif /* CONFIG_IEEE80211AX */ int hostapd_for_each_interface(struct hapd_interfaces *interfaces, int (*cb)(struct hostapd_iface *iface, @@ -462,6 +465,10 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd) } eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL); #endif /* CONFIG_SAE */ + +#ifdef CONFIG_IEEE80211AX + eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL); +#endif /* CONFIG_IEEE80211AX */ } @@ -3706,6 +3713,138 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, hostapd_enable_iface(iface); } + +#ifdef CONFIG_IEEE80211AX +void hostapd_cleanup_cca_params(struct hostapd_data *hapd) +{ + hapd->cca_count = 0; + hapd->cca_color = 0; + hapd->cca_c_off_beacon = 0; + hapd->cca_c_off_proberesp = 0; + hapd->cca_in_progress = false; +} + + +static int hostapd_fill_cca_settings(struct hostapd_data *hapd, + struct cca_settings *settings) +{ + struct hostapd_iface *iface = hapd->iface; + u8 old_color; + int ret; + + if (!iface || iface->conf->he_op.he_bss_color_disabled) + return -1; + + old_color = iface->conf->he_op.he_bss_color; + iface->conf->he_op.he_bss_color = hapd->cca_color; + ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); + if (ret) + return ret; + + iface->conf->he_op.he_bss_color = old_color; + + settings->cca_count = hapd->cca_count; + settings->cca_color = hapd->cca_color, + hapd->cca_in_progress = true; + + ret = hostapd_build_beacon_data(hapd, &settings->beacon_cca); + if (ret) { + free_beacon_data(&settings->beacon_after); + return ret; + } + + settings->counter_offset_beacon = hapd->cca_c_off_beacon; + settings->counter_offset_presp = hapd->cca_c_off_proberesp; + + return 0; +} + + +static void hostapd_switch_color_timeout_handler(void *eloop_data, + void *user_ctx) +{ + struct hostapd_data *hapd = (struct hostapd_data *) eloop_data; + os_time_t delta_t; + unsigned int b; + int i, r; + + /* CCA can be triggered once the handler constantly receives + * color collision events to for at least + * DOT11BSS_COLOR_COLLISION_AP_PERIOD (50s by default). + */ + delta_t = hapd->last_color_collision.sec - + hapd->first_color_collision.sec; + if (delta_t < DOT11BSS_COLOR_COLLISION_AP_PERIOD) + return; + + r = os_random() % HE_OPERATION_BSS_COLOR_MAX; + for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) { + if (r && !(hapd->color_collision_bitmap & (1 << r))) + break; + + r = (r + 1) % HE_OPERATION_BSS_COLOR_MAX; + } + + if (i == HE_OPERATION_BSS_COLOR_MAX) { + /* there are no free colors so turn bss coloring off */ + wpa_printf(MSG_INFO, + "no free colors left, turning of BSS coloring"); + hapd->iface->conf->he_op.he_bss_color_disabled = 1; + hapd->iface->conf->he_op.he_bss_color = os_random() % 63 + 1; + for (b = 0; b < hapd->iface->num_bss; b++) + ieee802_11_set_beacon(hapd->iface->bss[b]); + return; + } + + for (b = 0; b < hapd->iface->num_bss; b++) { + struct hostapd_data *bss = hapd->iface->bss[b]; + struct cca_settings settings; + int ret; + + hostapd_cleanup_cca_params(bss); + bss->cca_color = r; + bss->cca_count = 10; + + if (hostapd_fill_cca_settings(bss, &settings)) { + hostapd_cleanup_cca_params(bss); + continue; + } + + ret = hostapd_drv_switch_color(bss, &settings); + if (ret) + hostapd_cleanup_cca_params(bss); + + free_beacon_data(&settings.beacon_cca); + free_beacon_data(&settings.beacon_after); + } +} + + +void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap) +{ + struct os_reltime now; + + if (hapd->cca_in_progress) + return; + + if (os_get_reltime(&now)) + return; + + hapd->color_collision_bitmap = bitmap; + hapd->last_color_collision = now; + + if (eloop_is_timeout_registered(hostapd_switch_color_timeout_handler, + hapd, NULL)) + return; + + hapd->first_color_collision = now; + /* 10s window as margin for persistent color collision reporting */ + eloop_register_timeout(DOT11BSS_COLOR_COLLISION_AP_PERIOD + 10, 0, + hostapd_switch_color_timeout_handler, + hapd, NULL); +} +#endif /* CONFIG_IEEE80211AX */ + #endif /* NEED_AP_MLME */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index b30aa2ff6..f46fa8fb0 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -295,6 +295,17 @@ struct hostapd_data { unsigned int cs_c_off_ecsa_beacon; unsigned int cs_c_off_ecsa_proberesp; +#ifdef CONFIG_IEEE80211AX + bool cca_in_progress; + u8 cca_count; + u8 cca_color; + unsigned int cca_c_off_beacon; + unsigned int cca_c_off_proberesp; + struct os_reltime first_color_collision; + struct os_reltime last_color_collision; + u64 color_collision_bitmap; +#endif + #ifdef CONFIG_P2P struct p2p_data *p2p; struct p2p_group *p2p_group; @@ -664,6 +675,12 @@ void hostapd_periodic_iface(struct hostapd_iface *iface); int hostapd_owe_trans_get_info(struct hostapd_data *hapd); void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx); + +#ifdef CONFIG_IEEE80211AX +void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap); +void hostapd_cleanup_cca_params(struct hostapd_data *hapd); +#endif /* CONFIG_IEEE80211AX */ + /* utils.c */ int hostapd_register_probereq_cb(struct hostapd_data *hapd, int (*cb)(void *ctx, const u8 *sa, diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 928b53500..38b66d414 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -2305,6 +2305,7 @@ struct ieee80211_spatial_reuse { #define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30)) #define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31)) #define HE_OPERATION_BSS_COLOR_OFFSET 24 +#define HE_OPERATION_BSS_COLOR_MAX 64 /* Spatial Reuse defines */ #define SPATIAL_REUSE_SRP_DISALLOWED BIT(0) @@ -2470,6 +2471,11 @@ enum mscs_description_subelem { */ #define FD_MAX_INTERVAL_6GHZ 20 /* TUs */ +/* IEEE802.11/D6.0 - 26.17.3.5.1, AP needs to wait and see the collision + * persists for at least the minimum default timeout + */ +#define DOT11BSS_COLOR_COLLISION_AP_PERIOD 50 + /* Protected Vendor-specific QoS Management Action frame identifiers - WFA */ #define QM_ACTION_VENDOR_TYPE 0x506f9a1a #define QM_ACTION_OUI_TYPE 0x1a diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 111e7e408..71c10715f 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2406,6 +2406,26 @@ struct csa_settings { u16 counter_offset_presp[2]; }; +/** + * struct cca_settings - Settings for color switch command + * @cca_count: Count in Beacon frames (TBTT) to perform the switch + * @cca_color: The new color that we are switching to + * @beacon_cca: Beacon/probe resp/asooc resp info for color switch period + * @beacon_after: Next beacon/probe resp/asooc resp info + * @counter_offset_beacon: Offset to the count field in beacon's tail + * @counter_offset_presp: Offset to the count field in probe resp. + */ +struct cca_settings { + u8 cca_count; + u8 cca_color; + + struct beacon_data beacon_cca; + struct beacon_data beacon_after; + + u16 counter_offset_beacon; + u16 counter_offset_presp; +}; + /* TDLS peer capabilities for send_tdls_mgmt() */ enum tdls_peer_capability { TDLS_PEER_HT = BIT(0), @@ -3988,6 +4008,17 @@ struct wpa_driver_ops { */ int (*switch_channel)(void *priv, struct csa_settings *settings); + /** + * switch_color - Announce color switch and migrate the BSS to the + * given color + * @priv: Private driver interface data + * @settings: Settings for CCA period and new color + * Returns: 0 on success, -1 on failure + * + * This function is used to move the BSS to its new color. + */ + int (*switch_color)(void *priv, struct cca_settings *settings); + /** * add_tx_ts - Add traffic stream * @priv: Private driver interface data -- 2.35.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap