From 831e650fc40e8273506ab2c99f89da864a7b20dc Mon Sep 17 00:00:00 2001 From: g0tar Date: Tue, 16 Jun 2026 12:16:30 +0200 Subject: [PATCH 1/6] ubus: do not reiterate bss_transition_request over each SSID When having multiple SSIDs, bss_transition_request is sent for each one subscribed despite the fact, that ubus_invoke() is invoked using id not sub->id. This creates redundant copies of requests and BSS-TM-RESPs polluting air. Consider similar sanitization in del_client_interface(). --- src/utils/ubus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/ubus.c b/src/utils/ubus.c index 8e7b679..bdd111a 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -1289,7 +1289,7 @@ int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struc { if (sub->subscribed) { int timeout = 1; //TDO: Maybe ID is wrong?! OR CHECK HERE ID - ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000); + if(!ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000)) break; } } @@ -1329,7 +1329,7 @@ int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct { if (sub->subscribed) { int timeout = 1; //TDO: Maybe ID is wrong?! OR CHECK HERE ID - ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000); + if(!ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000)) break; } } From e7fb5dd62740a43c6ce4a7a9a406b1c03fddf7b4 Mon Sep 17 00:00:00 2001 From: g0tar Date: Tue, 16 Jun 2026 13:49:03 +0200 Subject: [PATCH 2/6] ubus: clean up bss_transition_request The request is supposed to be send to kicking_ap only, no need to iterate over all SSIDs. --- src/utils/ubus.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/utils/ubus.c b/src/utils/ubus.c index bdd111a..685684a 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -1285,13 +1285,8 @@ int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struc } blobmsg_close_array(&b, nbs); - list_for_each_entry(sub, &hostapd_sock_list, list) - { - if (sub->subscribed) { - int timeout = 1; //TDO: Maybe ID is wrong?! OR CHECK HERE ID - if(!ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000)) break; - } - } + int timeout = 1; + ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000); blob_buf_free(&b); dawn_unregmem(&b); @@ -1325,13 +1320,8 @@ int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct } blobmsg_close_array(&b, nbs); - list_for_each_entry(sub, &hostapd_sock_list, list) - { - if (sub->subscribed) { - int timeout = 1; //TDO: Maybe ID is wrong?! OR CHECK HERE ID - if(!ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000)) break; - } - } + int timeout = 1; + ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000); blob_buf_free(&b); dawn_unregmem(&b); From a00a8b489ae41f3fa336c7378e0b01a2b0d1ef8b Mon Sep 17 00:00:00 2001 From: g0tar Date: Tue, 16 Jun 2026 15:08:21 +0200 Subject: [PATCH 3/6] ubus: do not duplicate del_client request Fixes #261. Fixes #62. --- src/utils/ubus.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/utils/ubus.c b/src/utils/ubus.c index 685684a..62108d9 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -1247,14 +1247,9 @@ void del_client_interface(uint32_t id, const struct dawn_mac client_addr, uint32 blobmsg_add_u8(&b, "deauth", deauth); blobmsg_add_u32(&b, "ban_time", ban_time); + int timeout = 1; + ubus_invoke(ctx, id, "del_client", b.head, NULL, NULL, timeout * 1000); - list_for_each_entry(sub, &hostapd_sock_list, list) - { - if (sub->subscribed) { - int timeout = 1; - ubus_invoke(ctx, id, "del_client", b.head, NULL, NULL, timeout * 1000); - } - } blob_buf_free(&b); dawn_unregmem(&b); } From 0815cd1d4c11f2b076ee8b8ae1dadf6af4219c8e Mon Sep 17 00:00:00 2001 From: g0tar Date: Tue, 16 Jun 2026 16:31:58 +0200 Subject: [PATCH 4/6] ubus: suppress not imminent bss_transition_request with empty candidates list Client asked to move using absolute RSSI kicking (method 2) should have at least some candidate_ap (on kick_nr_list), otherwise the request is futile and only torments client having weak signal already. Do not waste air resources unless NR was deliberately disabled. If the client doesn't provide beacons using 802.1k we cannot really do anything *polite* to help it make handover decision, it's up to the device to recognize weak signal and search for something better. --- src/utils/ubus.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/utils/ubus.c b/src/utils/ubus.c index 62108d9..dfc1202 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -1280,8 +1280,11 @@ int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struc } blobmsg_close_array(&b, nbs); - int timeout = 1; - ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000); + // do not ask to leave without providing candidates, unless NR explicitly disabled or unavailable (consider empty rrm_mode) + if (neighbors_added || (dawn_metric.disassoc_nr_length <= 0) || (dawn_metric.set_hostapd_nr <= 0) || (timeout_config.update_beacon_reports <= 0) ) { + int timeout = 1; + ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000); + } blob_buf_free(&b); dawn_unregmem(&b); From 9681810e2fd96f68fa827d7d9e93a59c2235a22f Mon Sep 17 00:00:00 2001 From: g0tar Date: Tue, 16 Jun 2026 16:37:57 +0200 Subject: [PATCH 5/6] ubus: clean up unused structs --- src/utils/ubus.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/utils/ubus.c b/src/utils/ubus.c index dfc1202..fa78654 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -1237,7 +1237,6 @@ void del_client_all_interfaces(const struct dawn_mac client_addr, uint32_t reaso } void del_client_interface(uint32_t id, const struct dawn_mac client_addr, uint32_t reason, uint8_t deauth, uint32_t ban_time) { - struct hostapd_sock_entry *sub; struct blob_buf b = {0}; blob_buf_init(&b, 0); @@ -1255,7 +1254,6 @@ void del_client_interface(uint32_t id, const struct dawn_mac client_addr, uint32 } int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, uint32_t duration) { - struct hostapd_sock_entry* sub; struct blob_buf b = { 0 }; dawnlog_debug_func("Entering..."); @@ -1293,7 +1291,6 @@ int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struc } int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, int threshold, uint32_t duration) { - struct hostapd_sock_entry *sub; struct blob_buf b = {0}; dawnlog_debug_func("Entering..."); From 1cd73579e5dde35b5aa8feee81163f2ea49d9342 Mon Sep 17 00:00:00 2001 From: g0tar Date: Tue, 16 Jun 2026 17:29:27 +0200 Subject: [PATCH 6/6] ubus: suppress BSS transition request with empty NR for static AP list with disabled 802.1k update_beacon_reports '0' shouldn't make difference for set_hostapd_nr '1' --- src/utils/ubus.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/utils/ubus.c b/src/utils/ubus.c index fa78654..14d784e 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -1278,8 +1278,11 @@ int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struc } blobmsg_close_array(&b, nbs); - // do not ask to leave without providing candidates, unless NR explicitly disabled or unavailable (consider empty rrm_mode) - if (neighbors_added || (dawn_metric.disassoc_nr_length <= 0) || (dawn_metric.set_hostapd_nr <= 0) || (timeout_config.update_beacon_reports <= 0) ) { + // do not ask to leave without providing candidates, unless NRs are explicitly disabled or unavailable + if (neighbors_added || + (dawn_metric.disassoc_nr_length <= 0) || (dawn_metric.set_hostapd_nr <= 0) || + // disabling 802.11k shouldn't matter unless we build dynamic NR list (consider empty rrm_mode) + ((timeout_config.update_beacon_reports <= 0) && (dawn_metric.set_hostapd_nr == 2)) ) { int timeout = 1; ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000); }