Skip to content

Add known-station tracking and per-SSID configuration overrides - #22

Open
grzegorz914 wants to merge 4 commits into
openwrt:masterfrom
grzegorz914:master
Open

Add known-station tracking and per-SSID configuration overrides#22
grzegorz914 wants to merge 4 commits into
openwrt:masterfrom
grzegorz914:master

Conversation

@grzegorz914

@grzegorz914 grzegorz914 commented Jul 25, 2026

Copy link
Copy Markdown

Summary

  • Add known-station tracking with cold-start exploratory candidates: persist the best signal ever observed for a station on each node, synced between peers over the existing remote protocol, so stations that never probe/report RRM measurements once associated can still be found as roaming candidates. Candidates found only through this fallback are exploratory and are never used for a forced kick or an outright probe/assoc rejection, only a passive BSS-transition-request.
  • Add per-SSID configuration overrides via a new usteer_ssid UCI section type keyed by SSID, overriding signal thresholds, roam-scan/trigger tuning, band-steering (including a new band_steering_enabled toggle - band steering had no explicit on/off switch before, only an implicit one via a non-zero interval), load-kick, aggressiveness (plus its MAC-list), and a further batch of station/node-scoped policy fields (sta_block_timeout, local_sta_timeout, max_retry_band, seen_policy_timeout, assoc_steering, probe_steering, max_neighbor_reports, load_balancing_threshold, steer_reject_timeout, roam_process_timeout, roam_kick_delay, initial_connect_delay, node_up_script) for stations on that SSID only. Any option left unset falls back to the global setting, so existing single-SSID configs are unaffected.
  • probe_steering was previously configurable only via a hardcoded default (config.probe_steering = 0 in usteer_init_defaults()) - it was never wired into the global UCI config policy, so there was no way to actually turn it on. It's now settable per-SSID.
  • ssid_config.h/.c's enum/policy/struct field order mirrors struct usteer_config's declaration order throughout, to keep the two structures easy to diff against each other as fields are added.

Test plan

  • Compiles cleanly for ipq806x/generic (arm_cortex-a15_neon-vfpv4) and ramips/mt7620 (mipsel_24kc)
  • Running on 4 production APs (mixed ipq806x/ramips) for this session; known-station cold-start behavior and per-SSID overrides verified live against real client roaming/steering events

Persist the best signal ever observed for a station on each node
(known.c), synced between usteer peers over the existing remote
protocol (remote.c). Stations that never probe or report RRM
measurements once associated never generate live sta_info data on
any node but their current one, so the normal candidate scan can
never find them a roaming target no matter how bad their signal
gets - this fallback consults the persisted record instead.

Candidates found only through this fallback are exploratory: the
signal was never actually observed on that node, just marked
"worth exploring" once a peer reports the station connected
elsewhere. They are only ever used to trigger a passive
BSS-transition-request, never a forced kick or an outright
probe/assoc rejection, since the reading backing them could be
stale or simply never realized.

Adds a known_stations/known_stations_timeout UCI toggle and a
delete_known ubus method for manually discarding stale entries.

Signed-off-by: Grzegorz Kaczor <grzegorz914@icloud.com>
Add a usteer_ssid UCI section type keyed by SSID that overrides
selected global settings (signal thresholds, roam-scan/trigger
tuning, band-steering, load-kick, aggressiveness and its MAC-list)
for stations on that SSID only, via the new SSID_CFG(ssid, field)
lookup (ssid_config.c). Any option left unset on a usteer_ssid
section falls back to the corresponding global usteer setting, so
existing single-SSID configs keep working unchanged.

Also moves per-station aggressiveness from struct sta (global to
the station) to struct sta_info (per station+node), since a station
seen on multiple SSIDs must use each SSID's own aggressiveness for
decisions made on that SSID's nodes.

Signed-off-by: Grzegorz Kaczor <grzegorz914@icloud.com>
Band steering previously had no explicit on/off switch - it was only
implicitly active whenever band_steering_interval was non-zero. Add
a real band_steering_enabled bool (global and per-SSID, following
the same pattern as load_kick_enabled) that gates the actual
steering action in usteer_band_steering_perform_steer(), alongside
the existing interval check.

Defaults to true, preserving existing behavior for configs that
already rely on a non-zero band_steering_interval.

Signed-off-by: Grzegorz Kaczor <grzegorz914@icloud.com>
Add sta_block_timeout, local_sta_timeout, max_retry_band,
seen_policy_timeout, assoc_steering, probe_steering,
max_neighbor_reports, load_balancing_threshold, steer_reject_timeout,
roam_process_timeout, roam_kick_delay, initial_connect_delay and
node_up_script as per-SSID overrides, mirroring the pattern already
used for the SNR/band-steering/load-kick fields: each is consulted
in a station+node scoped context (SSID_CFG(ssid, field)) that was
previously only reading the network-wide global, and falls back to
the global value when no override exists.

node_up_script needed different handling than the others: its real
storage isn't config.node_up_script (that struct field is dead) but
a private static in local_node.c set via config_set_node_up_script(),
so it can't use the SSID_CFG() macro's built-in "fall back to
config.field" - the per-SSID override is resolved manually at the
one call site instead, falling back to that static when unset.

probe_steering was previously configurable only via a hardcoded
default in usteer_init_defaults() (config.probe_steering = 0) - it
was never wired into the global UCI config policy in ubus.c, so
there was no way to actually turn it on. It's now settable per-SSID.

Enum/policy/struct field order in ssid_config.h/.c mirrors struct
usteer_config's declaration order throughout, to keep the two
structures easy to diff against each other as fields are added.

Signed-off-by: Grzegorz Kaczor <grzegorz914@icloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant