Configure the short beacon count and DTIM count using the s1g_short_beacon_int and s1g_short_beacon_dtim_period values when short beaconing is enabled as per: (1) IEEE80211-2024 9.4.2.5.1 for the short beacon interval (2) IEEE80211-2024 11.1.2.1 for the short beacon DTIM period The short beacon count represents the number of short beacons that will be sent until the next long beacon. This is stored in the struct ps_data as it is fundamentally a power save feature. In addition, use the short beacon variants rather then the traditional variants. Also initialise the short beacon count using the same TSF value to ensure they are in sync at initilisation. The DTIM count and short beacon count are initialised separately as it is perfectly valid to have a short beacon period that differs from the short beacon dtim period. Signed-off-by: Lachlan Hodges <lachlan.hodges@xxxxxxxxxxxxxx> --- net/mac80211/cfg.c | 8 +++++- net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/ieee80211_i.h | 6 ++--- net/mac80211/mesh.c | 2 +- net/mac80211/tx.c | 11 ++++++-- net/mac80211/util.c | 50 +++++++++++++++++++++++++++++++---- 6 files changed, 66 insertions(+), 13 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d955bf8a6654..4f6755244030 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1395,6 +1395,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_link_data *link; struct ieee80211_bss_conf *link_conf; struct ieee80211_chan_req chanreq = { .oper = params->chandef }; + u64 tsf; lockdep_assert_wiphy(local->hw.wiphy); @@ -1653,7 +1654,12 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, goto error; } - ieee80211_recalc_dtim(local, sdata); + tsf = drv_get_tsf(local, sdata); + ieee80211_recalc_dtim(sdata, tsf); + + if (link_conf->s1g_short_beaconing) + ieee80211_recalc_sb_count(sdata, tsf); + ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_SSID); ieee80211_link_info_change_notify(sdata, link, changed); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 54c479910d05..1dac78271045 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -704,7 +704,7 @@ static ssize_t ieee80211_if_parse_tsf( } } - ieee80211_recalc_dtim(local, sdata); + ieee80211_recalc_dtim(sdata, drv_get_tsf(local, sdata)); return buflen; } IEEE80211_IF_FILE_RW(tsf); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 47b51c7eb09c..297ae35a1e79 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -314,6 +314,7 @@ struct ps_data { atomic_t num_sta_ps; /* number of stations in PS mode */ int dtim_count; bool dtim_bc_mc; + int sb_count; /* num short beacons til next long beacon */ }; struct ieee80211_if_ap { @@ -2740,9 +2741,8 @@ void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy, struct wiphy_work *work); int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, struct cfg80211_csa_settings *csa_settings); - -void ieee80211_recalc_dtim(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata); +void ieee80211_recalc_sb_count(struct ieee80211_sub_if_data *sdata, u64 tsf); +void ieee80211_recalc_dtim(struct ieee80211_sub_if_data *sdata, u64 tsf); int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, const struct cfg80211_chan_def *chandef, enum ieee80211_chanctx_mode chanmode, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index d00d9d413c5c..a4a715f6f1c3 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1202,7 +1202,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) return -ENOMEM; } - ieee80211_recalc_dtim(local, sdata); + ieee80211_recalc_dtim(sdata, drv_get_tsf(local, sdata)); ieee80211_link_info_change_notify(sdata, &sdata->deflink, changed); netif_carrier_on(sdata->dev); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6fa883a9250d..4c457b715b22 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4881,6 +4881,13 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, int aid0 = 0; int i, have_bits = 0, n1, n2; struct ieee80211_bss_conf *link_conf = link->conf; + /* + * via IEEE80211-2024 11.1.3.10.2 if we are short beaconing, + * use dot11ShortBeaconDTIMPeriod, else use dot11DTIMPeriod. + */ + u8 dtim_period = link_conf->s1g_short_beaconing ? + link_conf->s1g_short_beacon_dtim_period : + link_conf->dtim_period; /* Generate bitmap for TIM only if there are any STAs in power save * mode. */ @@ -4891,7 +4898,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, IEEE80211_MAX_AID+1); if (!is_template) { if (ps->dtim_count == 0) - ps->dtim_count = link_conf->dtim_period - 1; + ps->dtim_count = dtim_period - 1; else ps->dtim_count--; } @@ -4900,7 +4907,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, *pos++ = WLAN_EID_TIM; *pos++ = 3; *pos++ = ps->dtim_count; - *pos++ = link_conf->dtim_period; + *pos++ = dtim_period; if (ps->dtim_count == 0 && !skb_queue_empty(&ps->bc_buf)) aid0 = 1; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0d85a382746f..47e86461c209 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3913,15 +3913,28 @@ int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr, } EXPORT_SYMBOL(ieee80211_parse_p2p_noa); -void ieee80211_recalc_dtim(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) +void ieee80211_recalc_dtim(struct ieee80211_sub_if_data *sdata, u64 tsf) { - u64 tsf = drv_get_tsf(local, sdata); u64 dtim_count = 0; - u32 beacon_int = sdata->vif.bss_conf.beacon_int * 1024; - u8 dtim_period = sdata->vif.bss_conf.dtim_period; struct ps_data *ps; u8 bcns_from_dtim; + bool short_beaconing = sdata->vif.bss_conf.s1g_short_beaconing; + /* + * When short beaconing, ensure we use the short beacon interval + * as opposed to the beacon interval as per IEEE80211-2024 11.1.2.1. + */ + u32 beacon_int = (short_beaconing ? + sdata->vif.bss_conf.s1g_short_beacon_int : + sdata->vif.bss_conf.beacon_int) * 1024; + /* + * When short beaconing, all DTIM calculations are made using the + * dot11ShortBeaconDTIMPeriod value and the dot11DTIMPeriod value + * is unused as per IEEE80211-2024 9.4.2.5.1. + */ + u8 dtim_period = + short_beaconing ? + sdata->vif.bss_conf.s1g_short_beacon_dtim_period : + sdata->vif.bss_conf.dtim_period; if (tsf == -1ULL || !beacon_int || !dtim_period) return; @@ -3954,6 +3967,33 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local, ps->dtim_count = dtim_count; } +/* + * Given a short beacon period, calculate the current index into + * that period to determine the number of TSBTTs until the next TBTT. + * It is completely valid to have a short beacon period that differs + * from the dtim period (i.e a TBTT thats not a DTIM). + */ +void ieee80211_recalc_sb_count(struct ieee80211_sub_if_data *sdata, u64 tsf) +{ + u32 sb_idx; + struct ps_data *ps = &sdata->bss->ps; + u16 sb_period = sdata->vif.bss_conf.s1g_short_beacon_period; + u32 beacon_int = sdata->vif.bss_conf.s1g_short_beacon_int * 1024; + + /* No mesh / IBSS support for short beaconing */ + if (tsf == -1ULL || !sb_period || + (sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) + return; + + /* find the current TSBTT index in our sb_period */ + do_div(tsf, beacon_int); + sb_idx = do_div(tsf, sb_period); + + /* num TSBTTs until the next TBTT */ + ps->sb_count = sb_idx ? sb_period - sb_idx : 0; +} + static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local, struct ieee80211_chanctx *ctx) { -- 2.43.0