]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Fix channel number in MBSSID RNR after channel switch
authorMohan Kumar G <mkumarg@qti.qualcomm.com>
Thu, 8 May 2025 17:27:15 +0000 (22:57 +0530)
committerJouni Malinen <j@w1.fi>
Thu, 22 May 2025 09:16:10 +0000 (12:16 +0300)
When channel switch happened in an MBSSID case, the non-transmitting
partial profile RNR element of the first few Beacon frames in the new
channel used the old channel number. This is because after channel
switch, the new MBSSID and RNR elements are not updated immediately as
during channel switch, the new MBSSID and RNR elements are not passed to
the driver together with other beacon data. So beaconing first starts
with old MBSSID and RNR data. Only after channel switch completes and
beacon is set again, these elements are passed to the driver. This delay
causes the first few beacons to contain old RNR and MBSSID elements.

Address this issue by passing the new MBSSID and RNR elements during the
CSA settings itself, thus post channel switch, Beacon frames will have
the new MBSSID and RNR data.

Signed-off-by: Mohan Kumar G <mkumarg@qti.qualcomm.com>
Signed-off-by: Manish Dharanenthiran <manish.dharanenthiran@oss.qualcomm.com>
src/ap/hostapd.c
src/drivers/driver.h
src/drivers/driver_nl80211.c

index 65dc14d60c0772a6bd415e725dd70084106a92fe..f4d78ef6aaa77157b2eaa79998231967d13d8d3a 100644 (file)
@@ -4256,6 +4256,14 @@ void free_beacon_data(struct beacon_data *beacon)
        beacon->proberesp_ies = NULL;
        os_free(beacon->assocresp_ies);
        beacon->assocresp_ies = NULL;
+       os_free(beacon->mbssid.mbssid_elem);
+       beacon->mbssid.mbssid_elem = NULL;
+       os_free(beacon->mbssid.mbssid_elem_offset);
+       beacon->mbssid.mbssid_elem_offset = NULL;
+       os_free(beacon->mbssid.rnr_elem);
+       beacon->mbssid.rnr_elem = NULL;
+       os_free(beacon->mbssid.rnr_elem_offset);
+       beacon->mbssid.rnr_elem_offset = NULL;
 }
 
 
@@ -4264,6 +4272,10 @@ int hostapd_build_beacon_data(struct hostapd_data *hapd,
 {
        struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
        struct wpa_driver_ap_params params;
+       struct hostapd_data *tx_bss;
+       u8 *mbssid_start_eid, *rnr_start_eid;
+       size_t size = 0;
+       int i;
        int ret;
 
        os_memset(beacon, 0, sizeof(*beacon));
@@ -4327,6 +4339,76 @@ int hostapd_build_beacon_data(struct hostapd_data *hapd,
                beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
        }
 
+       /* MBSSID element */
+       if (!params.mbssid.mbssid_elem_len)
+               goto done;
+
+       tx_bss = hostapd_mbssid_get_tx_bss(hapd);
+       beacon->mbssid.mbssid_tx_iface = tx_bss->conf->iface;
+       beacon->mbssid.mbssid_tx_iface_linkid =
+               params.mbssid.mbssid_tx_iface_linkid;
+       beacon->mbssid.mbssid_index = params.mbssid.mbssid_index;
+
+       beacon->mbssid.mbssid_elem_len = params.mbssid.mbssid_elem_len;
+       beacon->mbssid.mbssid_elem_count = params.mbssid.mbssid_elem_count;
+       if (params.mbssid.mbssid_elem) {
+               beacon->mbssid.mbssid_elem =
+                       os_memdup(params.mbssid.mbssid_elem,
+                                 params.mbssid.mbssid_elem_len);
+               if (!beacon->mbssid.mbssid_elem)
+                       goto free_beacon;
+       }
+       beacon->mbssid.ema = params.mbssid.ema;
+
+       if (params.mbssid.mbssid_elem_offset) {
+               beacon->mbssid.mbssid_elem_offset =
+                       os_calloc(beacon->mbssid.mbssid_elem_count,
+                                 sizeof(u8 *));
+               if (!beacon->mbssid.mbssid_elem_offset)
+                       goto free_beacon;
+
+               mbssid_start_eid = beacon->mbssid.mbssid_elem;
+               beacon->mbssid.mbssid_elem_offset[0] = mbssid_start_eid;
+               for (i = 0; i < beacon->mbssid.mbssid_elem_count - 1; i++) {
+                       size = params.mbssid.mbssid_elem_offset[i + 1] -
+                               params.mbssid.mbssid_elem_offset[i];
+                       mbssid_start_eid = mbssid_start_eid + size;
+                       beacon->mbssid.mbssid_elem_offset[i + 1] =
+                               mbssid_start_eid;
+               }
+       }
+
+       /* RNR element */
+       if (!params.mbssid.rnr_elem_len)
+               goto done;
+
+       if (params.mbssid.rnr_elem) {
+               beacon->mbssid.rnr_elem = os_memdup(params.mbssid.rnr_elem,
+                                                   params.mbssid.rnr_elem_len);
+               if (!beacon->mbssid.rnr_elem)
+                       goto free_beacon;
+       }
+
+       beacon->mbssid.rnr_elem_len = params.mbssid.rnr_elem_len;
+       beacon->mbssid.rnr_elem_count = params.mbssid.rnr_elem_count;
+       if (params.mbssid.rnr_elem_offset) {
+               beacon->mbssid.rnr_elem_offset =
+                       os_calloc(beacon->mbssid.rnr_elem_count + 1,
+                                 sizeof(u8 *));
+               if (!beacon->mbssid.rnr_elem_offset)
+                       goto free_beacon;
+
+               rnr_start_eid = beacon->mbssid.rnr_elem;
+               beacon->mbssid.rnr_elem_offset[0] = rnr_start_eid;
+               for (i = 0; i < beacon->mbssid.rnr_elem_count - 1; i++) {
+                       size = params.mbssid.rnr_elem_offset[i + 1] -
+                               params.mbssid.rnr_elem_offset[i];
+                       rnr_start_eid = rnr_start_eid + size;
+                       beacon->mbssid.rnr_elem_offset[i + 1] = rnr_start_eid;
+               }
+       }
+
+done:
        ret = 0;
 free_beacon:
        /* if the function fails, the caller should not free beacon data */
index 2471b4ad8a169edb4fae806f6eb12558076b61fa..54b4a9b180ad09b85e782efef2a3b2717ef9a75d 100644 (file)
@@ -2798,6 +2798,7 @@ struct wpa_channel_info {
  * @proberesp_ies_len: Length of proberesp_ies in octets
  * @proberesp_ies_len: Length of proberesp_ies in octets
  * @probe_resp_len: Length of probe response template (@probe_resp)
+ * @mbssid: MBSSID element(s) to add into Beacon frames
  */
 struct beacon_data {
        u8 *head, *tail;
@@ -2811,6 +2812,8 @@ struct beacon_data {
        size_t proberesp_ies_len;
        size_t assocresp_ies_len;
        size_t probe_resp_len;
+
+       struct mbssid_data mbssid;
 };
 
 /**
index 34167f96837a3676208cd6cbb0e9ad2e05f9b58d..b7c666db470611d308d1b89e7e31d51cae244729 100644 (file)
@@ -11456,8 +11456,8 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
        return pos - buf;
 }
 
-
-static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
+static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings,
+                          bool skip_mbssid)
 {
        if ((settings->head &&
             nla_put(msg, NL80211_ATTR_BEACON_HEAD,
@@ -11479,6 +11479,11 @@ static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
                     settings->probe_resp_len, settings->probe_resp)))
                return -ENOBUFS;
 
+#ifdef CONFIG_IEEE80211AX
+       if (!skip_mbssid && nl80211_mbssid(msg, &settings->mbssid) < 0)
+               return -ENOBUFS;
+#endif /* CONFIG_IEEE80211AX */
+
        return 0;
 }
 
@@ -11583,7 +11588,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
                goto error;
 
        /* beacon_after params */
-       ret = set_beacon_data(msg, &settings->beacon_after);
+       ret = set_beacon_data(msg, &settings->beacon_after, false);
        if (ret)
                goto error;
 
@@ -11592,7 +11597,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
        if (!beacon_csa)
                goto fail;
 
-       ret = set_beacon_data(msg, &settings->beacon_csa);
+       ret = set_beacon_data(msg, &settings->beacon_csa, true);
        if (ret)
                goto error;
 
@@ -11669,7 +11674,7 @@ static int nl80211_switch_color(void *priv, struct cca_settings *settings)
                goto error;
 
        /* beacon_after params */
-       ret = set_beacon_data(msg, &settings->beacon_after);
+       ret = set_beacon_data(msg, &settings->beacon_after, false);
        if (ret)
                goto error;
 
@@ -11680,7 +11685,7 @@ static int nl80211_switch_color(void *priv, struct cca_settings *settings)
                goto error;
        }
 
-       ret = set_beacon_data(msg, &settings->beacon_cca);
+       ret = set_beacon_data(msg, &settings->beacon_cca, true);
        if (ret)
                goto error;