]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
BSS coloring: Handling of collision events and triggering CCA
authorJohn Crispin <john@phrozen.org>
Mon, 21 Mar 2022 11:10:30 +0000 (12:10 +0100)
committerJouni Malinen <j@w1.fi>
Sat, 16 Apr 2022 14:06:06 +0000 (17:06 +0300)
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>
src/ap/ap_drv_ops.h
src/ap/hostapd.c
src/ap/hostapd.h
src/common/ieee802_11_defs.h
src/drivers/driver.h

index b4d6395ae2af25d402121a949f80153c58487da2..d15f9defef96141bc3825f9402742f3dac423bbd 100644 (file)
@@ -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)
 {
index 81488a2ef2809005055467ccb670a72e1abb51f5..32d2225610dffd072667beadf3b319d67c7984ad 100644 (file)
@@ -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 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,
@@ -462,6 +466,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 */
 }
 
 
@@ -3707,6 +3715,139 @@ 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 (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 */
 
 
index 6c8723baf1a8a6ddc9b15992d47e03cb4aedaeea..a1ac45f8998caf0c862ccd6ab78692655719aaef 100644 (file)
@@ -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 /* CONFIG_IEEE80211AX */
+
 #ifdef CONFIG_P2P
        struct p2p_data *p2p;
        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);
 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 */
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
                                 int (*cb)(void *ctx, const u8 *sa,
index 343ea722846a0e80996ab07230fd58d32ffe8581..1d4f21ba008c1ba8b6a4d6ae7350266830251ac0 100644 (file)
@@ -2332,6 +2332,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
 
 /**
  * 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 */
 
+/* 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 */
 #define QM_ACTION_VENDOR_TYPE 0x506f9a1a
 #define QM_ACTION_OUI_TYPE 0x1a
index 111e7e408125277f67dc14e0a13672c06b8bd6ad..dd2f62bed9802d54b4cc4edc1a1d5f8a2f928a75 100644 (file)
@@ -2406,6 +2406,27 @@ 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 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() */
 enum tdls_peer_capability {
        TDLS_PEER_HT = BIT(0),
@@ -3988,6 +4009,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