]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: support initialising an S1G short beaconing BSS
authorLachlan Hodges <lachlan.hodges@morsemicro.com>
Thu, 17 Jul 2025 07:42:03 +0000 (17:42 +1000)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 18 Jul 2025 12:14:43 +0000 (14:14 +0200)
Introduce the ability to parse the short beacon data and long
beacon period. The long beacon period represents the number of beacon
intervals between each long beacon transmission. Additionally,
as a BSS cannot change its configuration such that short beaconing
is dynamically disabled/enabled without tearing down the interface
- we ensure we have an existing short beacon before performing
the update.

Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
Link: https://patch.msgid.link/20250717074205.312577-3-lachlan.hodges@morsemicro.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h

index 577fd6a8c372f6cd544db6e74207365b5f358cf3..a2dbaad2f6d3ff6d73142f7a6fb952c4d839728d 100644 (file)
@@ -758,6 +758,8 @@ struct ieee80211_parsed_tpe {
  *     be updated to 1, even if bss_param_ch_cnt didn't change. This allows
  *     the link to know that it heard the latest value from its own beacon
  *     (as opposed to hearing its value from another link's beacon).
+ * @s1g_long_beacon_period: number of beacon intervals between each long
+ *     beacon transmission.
  */
 struct ieee80211_bss_conf {
        struct ieee80211_vif *vif;
@@ -857,6 +859,8 @@ struct ieee80211_bss_conf {
 
        u8 bss_param_ch_cnt;
        u8 bss_param_ch_cnt_link_id;
+
+       u8 s1g_long_beacon_period;
 };
 
 /**
index b99e39cb808be6855f834844a931d9d3fd12fdff..2f97e2d5bb8bc17afe6b2dd20ebf7d0d466c1dc5 100644 (file)
@@ -1071,6 +1071,47 @@ ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
+static int
+ieee80211_set_s1g_short_beacon(struct ieee80211_sub_if_data *sdata,
+                              struct ieee80211_link_data *link,
+                              struct cfg80211_s1g_short_beacon *params)
+{
+       struct s1g_short_beacon_data *new;
+       struct s1g_short_beacon_data *old =
+               sdata_dereference(link->u.ap.s1g_short_beacon, sdata);
+       size_t new_len =
+               sizeof(*new) + params->short_head_len + params->short_tail_len;
+
+       if (!params->update)
+               return 0;
+
+       if (!params->short_head)
+               return -EINVAL;
+
+       new = kzalloc(new_len, GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+
+       /* Memory layout: | struct | head | tail | */
+       new->short_head = (u8 *)new + sizeof(*new);
+       new->short_head_len = params->short_head_len;
+       memcpy(new->short_head, params->short_head, params->short_head_len);
+
+       if (params->short_tail) {
+               new->short_tail = new->short_head + params->short_head_len;
+               new->short_tail_len = params->short_tail_len;
+               memcpy(new->short_tail, params->short_tail,
+                      params->short_tail_len);
+       }
+
+       rcu_assign_pointer(link->u.ap.s1g_short_beacon, new);
+
+       if (old)
+               kfree_rcu(old, rcu_head);
+
+       return 0;
+}
+
 static int ieee80211_set_ftm_responder_params(
                                struct ieee80211_sub_if_data *sdata,
                                const u8 *lci, size_t lci_len,
@@ -1493,8 +1534,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        link_conf->twt_responder = params->twt_responder;
        link_conf->he_obss_pd = params->he_obss_pd;
        link_conf->he_bss_color = params->beacon.he_bss_color;
-       sdata->vif.cfg.s1g = params->chandef.chan->band ==
-                                 NL80211_BAND_S1GHZ;
+       link_conf->s1g_long_beacon_period = params->s1g_long_beacon_period;
+       sdata->vif.cfg.s1g = params->chandef.chan->band == NL80211_BAND_S1GHZ;
 
        sdata->vif.cfg.ssid_len = params->ssid_len;
        if (params->ssid_len)
@@ -1541,6 +1582,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        if (err < 0)
                goto error;
 
+       if (sdata->vif.cfg.s1g) {
+               err = ieee80211_set_s1g_short_beacon(sdata, link,
+                                                    &params->s1g_short_beacon);
+               if (err < 0)
+                       goto error;
+       }
+
        err = drv_start_ap(sdata->local, sdata, link_conf);
        if (err) {
                old = sdata_dereference(link->u.ap.beacon, sdata);
@@ -1619,6 +1667,13 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
        if (err < 0)
                return err;
 
+       if (link->u.ap.s1g_short_beacon) {
+               err = ieee80211_set_s1g_short_beacon(sdata, link,
+                                                    &params->s1g_short_beacon);
+               if (err < 0)
+                       return err;
+       }
+
        if (beacon->he_bss_color_valid &&
            beacon->he_bss_color.enabled != link_conf->he_bss_color.enabled) {
                link_conf->he_bss_color.enabled = beacon->he_bss_color.enabled;
@@ -1650,6 +1705,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
        struct probe_resp *old_probe_resp;
        struct fils_discovery_data *old_fils_discovery;
        struct unsol_bcast_probe_resp_data *old_unsol_bcast_probe_resp;
+       struct s1g_short_beacon_data *old_s1g_short_beacon;
        struct cfg80211_chan_def chandef;
        struct ieee80211_link_data *link =
                sdata_dereference(sdata->link[link_id], sdata);
@@ -1668,6 +1724,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
        old_unsol_bcast_probe_resp =
                sdata_dereference(link->u.ap.unsol_bcast_probe_resp,
                                  sdata);
+       old_s1g_short_beacon =
+               sdata_dereference(link->u.ap.s1g_short_beacon, sdata);
 
        /* abort any running channel switch or color change */
        link_conf->csa_active = false;
@@ -1690,6 +1748,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
        RCU_INIT_POINTER(link->u.ap.probe_resp, NULL);
        RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL);
        RCU_INIT_POINTER(link->u.ap.unsol_bcast_probe_resp, NULL);
+       RCU_INIT_POINTER(link->u.ap.s1g_short_beacon, NULL);
        kfree_rcu(old_beacon, rcu_head);
        if (old_probe_resp)
                kfree_rcu(old_probe_resp, rcu_head);
@@ -1697,6 +1756,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
                kfree_rcu(old_fils_discovery, rcu_head);
        if (old_unsol_bcast_probe_resp)
                kfree_rcu(old_unsol_bcast_probe_resp, rcu_head);
+       if (old_s1g_short_beacon)
+               kfree_rcu(old_s1g_short_beacon, rcu_head);
 
        kfree(link_conf->ftmr_params);
        link_conf->ftmr_params = NULL;
@@ -1720,6 +1781,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
        link_conf->enable_beacon = false;
        sdata->beacon_rate_set = false;
        sdata->vif.cfg.ssid_len = 0;
+       sdata->vif.cfg.s1g = false;
        clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_link_info_change_notify(sdata, link,
                                          BSS_CHANGED_BEACON_ENABLED);
index 9c0603eb580fc3a3338e7b56358a89c5ec44bc2d..61cd1cc098ac1041550e984f198d9c3b8307570f 100644 (file)
@@ -296,6 +296,14 @@ struct unsol_bcast_probe_resp_data {
        u8 data[];
 };
 
+struct s1g_short_beacon_data {
+       struct rcu_head rcu_head;
+       u8 *short_head;
+       u8 *short_tail;
+       int short_head_len;
+       int short_tail_len;
+};
+
 struct ps_data {
        /* yes, this looks ugly, but guarantees that we can later use
         * bitmap_empty :)
@@ -1042,6 +1050,7 @@ struct ieee80211_link_data_ap {
        struct probe_resp __rcu *probe_resp;
        struct fils_discovery_data __rcu *fils_discovery;
        struct unsol_bcast_probe_resp_data __rcu *unsol_bcast_probe_resp;
+       struct s1g_short_beacon_data __rcu *s1g_short_beacon;
 
        /* to be used after channel switch. */
        struct cfg80211_beacon_data *next_beacon;