]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: support returning the S1G short beacon skb
authorLachlan Hodges <lachlan.hodges@morsemicro.com>
Thu, 17 Jul 2025 07:42:05 +0000 (17:42 +1000)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 18 Jul 2025 12:14:44 +0000 (14:14 +0200)
When short beaconing is enabled, check the value of the sb_count
to determine whether we are to send a long beacon or short beacon.
sb_count represents the number of short beacons until the next
long beacon, where if its value is 0 we are to send a long beacon.
The value is then reset to the long beacon period, which represents
the number of beacon intervals between each long beacon. The decrement
process follows the same cadence as the decrement of the DTIM count value.

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

index 6fa883a9250d91729cb56058627ad1baa3a59125..f3a065313a31a615c40611cc5030cd6a5fddc526 100644 (file)
@@ -5290,14 +5290,14 @@ ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon,
 }
 
 static struct sk_buff *
-ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
-                       struct ieee80211_vif *vif,
-                       struct ieee80211_link_data *link,
-                       struct ieee80211_mutable_offsets *offs,
-                       bool is_template,
-                       struct beacon_data *beacon,
-                       struct ieee80211_chanctx_conf *chanctx_conf,
-                       u8 ema_index)
+__ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         struct ieee80211_link_data *link,
+                         struct ieee80211_mutable_offsets *offs,
+                         bool is_template,
+                         struct beacon_data *beacon,
+                         struct ieee80211_chanctx_conf *chanctx_conf,
+                         u8 ema_index)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
@@ -5358,6 +5358,71 @@ ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
        return skb;
 }
 
+static bool ieee80211_s1g_need_long_beacon(struct ieee80211_sub_if_data *sdata,
+                                          struct ieee80211_link_data *link)
+{
+       struct ps_data *ps = &sdata->u.ap.ps;
+
+       if (ps->sb_count == 0)
+               ps->sb_count = link->conf->s1g_long_beacon_period - 1;
+       else
+               ps->sb_count--;
+
+       return ps->sb_count == 0;
+}
+
+static struct sk_buff *
+ieee80211_s1g_short_beacon_get(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_link_data *link,
+                              struct ieee80211_chanctx_conf *chanctx_conf,
+                              struct s1g_short_beacon_data *sb,
+                              bool is_template)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_if_ap *ap = &sdata->u.ap;
+       struct sk_buff *skb;
+
+       skb = dev_alloc_skb(local->tx_headroom + sb->short_head_len +
+                           sb->short_tail_len + 256 +
+                           local->hw.extra_beacon_tailroom);
+       if (!skb)
+               return NULL;
+
+       skb_reserve(skb, local->tx_headroom);
+       skb_put_data(skb, sb->short_head, sb->short_head_len);
+
+       ieee80211_beacon_add_tim(sdata, link, &ap->ps, skb, is_template);
+
+       if (sb->short_tail)
+               skb_put_data(skb, sb->short_tail, sb->short_tail_len);
+
+       ieee80211_beacon_get_finish(hw, vif, link, NULL, NULL, skb,
+                                   chanctx_conf, 0);
+       return skb;
+}
+
+static struct sk_buff *
+ieee80211_beacon_get_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                       struct ieee80211_link_data *link,
+                       struct ieee80211_mutable_offsets *offs,
+                       bool is_template, struct beacon_data *beacon,
+                       struct ieee80211_chanctx_conf *chanctx_conf,
+                       u8 ema_index, struct s1g_short_beacon_data *s1g_sb)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       if (!sdata->vif.cfg.s1g || !s1g_sb ||
+           ieee80211_s1g_need_long_beacon(sdata, link))
+               return __ieee80211_beacon_get_ap(hw, vif, link, offs,
+                                                is_template, beacon,
+                                                chanctx_conf, ema_index);
+
+       return ieee80211_s1g_short_beacon_get(hw, vif, link, chanctx_conf,
+                                             s1g_sb, is_template);
+}
+
 static struct ieee80211_ema_beacons *
 ieee80211_beacon_get_ap_ema_list(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
@@ -5381,7 +5446,7 @@ ieee80211_beacon_get_ap_ema_list(struct ieee80211_hw *hw,
                        ieee80211_beacon_get_ap(hw, vif, link,
                                                &ema->bcn[ema->cnt].offs,
                                                is_template, beacon,
-                                               chanctx_conf, ema->cnt);
+                                               chanctx_conf, ema->cnt, NULL);
                if (!ema->bcn[ema->cnt].skb)
                        break;
        }
@@ -5410,6 +5475,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
        struct ieee80211_sub_if_data *sdata = NULL;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_link_data *link;
+       struct s1g_short_beacon_data *s1g_short_bcn = NULL;
 
        rcu_read_lock();
 
@@ -5431,6 +5497,13 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
                if (!beacon)
                        goto out;
 
+               if (vif->cfg.s1g && link->u.ap.s1g_short_beacon) {
+                       s1g_short_bcn =
+                               rcu_dereference(link->u.ap.s1g_short_beacon);
+                       if (!s1g_short_bcn)
+                               goto out;
+               }
+
                if (ema_beacons) {
                        *ema_beacons =
                                ieee80211_beacon_get_ap_ema_list(hw, vif, link,
@@ -5451,8 +5524,8 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
 
                        skb = ieee80211_beacon_get_ap(hw, vif, link, offs,
                                                      is_template, beacon,
-                                                     chanctx_conf,
-                                                     ema_index);
+                                                     chanctx_conf, ema_index,
+                                                     s1g_short_bcn);
                }
        } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
                struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;