BSS coloring: Handling of collision events and triggering CCA
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@mediatek.com> Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> Signed-off-by: John Crispin <john@phrozen.org> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
This commit is contained in:
parent
2f336ca580
commit
654d2395dd
5 changed files with 205 additions and 0 deletions
|
@ -300,6 +300,17 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
|
||||||
return hapd->driver->switch_channel(hapd->drv_priv, settings);
|
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,
|
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
|
||||||
size_t buflen)
|
size_t buflen)
|
||||||
{
|
{
|
||||||
|
|
141
src/ap/hostapd.c
141
src/ap/hostapd.c
|
@ -66,6 +66,10 @@ static int setup_interface2(struct hostapd_iface *iface);
|
||||||
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
|
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||||
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
|
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
|
||||||
void *timeout_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 hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||||
|
@ -462,6 +466,10 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||||
}
|
}
|
||||||
eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
|
eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
|
||||||
#endif /* CONFIG_SAE */
|
#endif /* CONFIG_SAE */
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211AX
|
||||||
|
eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL);
|
||||||
|
#endif /* CONFIG_IEEE80211AX */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3707,6 +3715,139 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||||
hostapd_enable_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 (50 s 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 & BIT(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 off 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;
|
||||||
|
/* 10 s 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 */
|
#endif /* NEED_AP_MLME */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -295,6 +295,17 @@ struct hostapd_data {
|
||||||
unsigned int cs_c_off_ecsa_beacon;
|
unsigned int cs_c_off_ecsa_beacon;
|
||||||
unsigned int cs_c_off_ecsa_proberesp;
|
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 /* CONFIG_IEEE80211AX */
|
||||||
|
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
struct p2p_data *p2p;
|
struct p2p_data *p2p;
|
||||||
struct p2p_group *p2p_group;
|
struct p2p_group *p2p_group;
|
||||||
|
@ -664,6 +675,9 @@ void hostapd_periodic_iface(struct hostapd_iface *iface);
|
||||||
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
|
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
|
||||||
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
|
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
|
||||||
|
|
||||||
|
void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap);
|
||||||
|
void hostapd_cleanup_cca_params(struct hostapd_data *hapd);
|
||||||
|
|
||||||
/* utils.c */
|
/* utils.c */
|
||||||
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||||
int (*cb)(void *ctx, const u8 *sa,
|
int (*cb)(void *ctx, const u8 *sa,
|
||||||
|
|
|
@ -2332,6 +2332,7 @@ struct ieee80211_spatial_reuse {
|
||||||
#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
|
#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
|
||||||
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
|
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
|
||||||
#define HE_OPERATION_BSS_COLOR_OFFSET 24
|
#define HE_OPERATION_BSS_COLOR_OFFSET 24
|
||||||
|
#define HE_OPERATION_BSS_COLOR_MAX 64
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum he_6ghz_ap_type - Allowed Access Point types for 6 GHz Band
|
* enum he_6ghz_ap_type - Allowed Access Point types for 6 GHz Band
|
||||||
|
@ -2508,6 +2509,12 @@ enum mscs_description_subelem {
|
||||||
*/
|
*/
|
||||||
#define FD_MAX_INTERVAL_6GHZ 20 /* TUs */
|
#define FD_MAX_INTERVAL_6GHZ 20 /* TUs */
|
||||||
|
|
||||||
|
/* IEEE Std 802.11ax-2021, 26.17.3.5.1: AP needs to wait and see the collision
|
||||||
|
* persists for at least the minimum default timeout
|
||||||
|
* dot11BSSColorCollisionAPPeriod (50 seconds)
|
||||||
|
*/
|
||||||
|
#define DOT11BSS_COLOR_COLLISION_AP_PERIOD 50
|
||||||
|
|
||||||
/* Protected Vendor-specific QoS Management Action frame identifiers - WFA */
|
/* Protected Vendor-specific QoS Management Action frame identifiers - WFA */
|
||||||
#define QM_ACTION_VENDOR_TYPE 0x506f9a1a
|
#define QM_ACTION_VENDOR_TYPE 0x506f9a1a
|
||||||
#define QM_ACTION_OUI_TYPE 0x1a
|
#define QM_ACTION_OUI_TYPE 0x1a
|
||||||
|
|
|
@ -2406,6 +2406,27 @@ struct csa_settings {
|
||||||
u16 counter_offset_presp[2];
|
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 Response/(Re)Association Response frame info for
|
||||||
|
* color switch period
|
||||||
|
* @beacon_after: Next Beacon/Probe Response/(Re)Association Response frame info
|
||||||
|
* @counter_offset_beacon: Offset to the count field in Beacon frame tail
|
||||||
|
* @counter_offset_presp: Offset to the count field in Probe Response frame
|
||||||
|
*/
|
||||||
|
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() */
|
/* TDLS peer capabilities for send_tdls_mgmt() */
|
||||||
enum tdls_peer_capability {
|
enum tdls_peer_capability {
|
||||||
TDLS_PEER_HT = BIT(0),
|
TDLS_PEER_HT = BIT(0),
|
||||||
|
@ -3988,6 +4009,17 @@ struct wpa_driver_ops {
|
||||||
*/
|
*/
|
||||||
int (*switch_channel)(void *priv, struct csa_settings *settings);
|
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
|
* add_tx_ts - Add traffic stream
|
||||||
* @priv: Private driver interface data
|
* @priv: Private driver interface data
|
||||||
|
|
Loading…
Reference in a new issue