From patchwork Sun Oct 20 18:47:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nils Rottgardt X-Patchwork-Id: 1999635 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=QWYHvNxP; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:3::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=patchwork.ozlabs.org) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XWnYW4rYHz1xwK for ; Mon, 21 Oct 2024 05:49:51 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=eo3aF1RDO9KL8dtpQHGFgZlSW44zrU+h+CJZulhkfO0=; b=QWYHvNxPcL/Xj1 w//Y8B6ZDUXt6wMkp4L+XJTaRcYxnsazUbuSVtpyYx3apa5K3DhvOtluLJoEW/lrnJHSM9pdusHKz uVkhWq9YHWRpGlfdrWbDQ8Oa5+lphWBRKC++44gzpnbsx4m/LJ5rKr2fi2eoavpyi/woEEOU5w5YV evLZYxsPva71m9jmnTljgKIdXMSMck3RMUATMQpWhsy6W5EPLO1Hc68SFWQ10FjktyCkgwBm1oC/P oQZG91PKiDfBPoIsPDv5Qqx8N7b9ri1WyvLPF0OkswCsDKAvlsNUUPUNx6WMS58RRTlSxW+1W27Jh gETzIKnM3/McmWqSraWQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1t2ayn-00000005Hvw-1g7L; Sun, 20 Oct 2024 18:48:41 +0000 Received: from mail-smtp-out-01-pmx.wtnet.de ([84.46.103.117]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1t2ay4-00000005Hs8-45Na for openwrt-devel@lists.openwrt.org; Sun, 20 Oct 2024 18:48:00 +0000 Received: from mail-cust-in-01-pmx.wtnet.de (mail-cust-in-01-pmx.wtnet.de [84.46.103.101]) by mail-smtp-out-01-pmx.wtnet.de (8.15.2/8.15.2/Debian-15~mysql) with ESMTP id 49KIlng7019111; Sun, 20 Oct 2024 20:47:49 +0200 X-WT-Originating-IP: 134.101.207.191 X-WT-Authenticated-As: ellerau@wtnet.de Received: from viserver1.ham.lan (134.101.207.191.dynamic-pppoe.dt.ipv4.wtnet.de [134.101.207.191]) (authenticated bits=0) by mail-cust-in-01-pmx.wtnet.de (8.15.2/8.15.2/Debian-15~mysql) with ESMTPA id 49KIlmV4010322; Sun, 20 Oct 2024 20:47:48 +0200 Received: from Dell-7706.muc.lan (unknown [192.168.177.109]) by viserver1.ham.lan (Postfix) with ESMTP id AE79761DA8; Sun, 20 Oct 2024 20:47:48 +0200 (CEST) From: Nils Hendrik Rottgardt To: openwrt-devel@lists.openwrt.org Cc: Nils Hendrik Rottgardt Subject: [PATCH usteer v2] New aggressive roaming to support Intel Wifi Cards Date: Sun, 20 Oct 2024 20:47:32 +0200 Message-Id: <20241020184732.17031-1-n.rottgardt@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: References: MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241020_114758_464159_D3DEB651 X-CRM114-Status: GOOD ( 19.12 ) X-Spam-Score: -0.5 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Intel Wifi Cards (and based on OpenWRT forum posts also some other devices) does not understand the actual transition request frame because of missing disassociation_timer combined with disassociation [...] Content analysis details: (-0.5 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [84.46.103.117 listed in list.dnswl.org] 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [84.46.103.117 listed in sa-accredit.habeas.com] 0.0 DKIM_ADSP_CUSTOM_MED No valid author signature, adsp_override is CUSTOM_MED -0.0 SPF_PASS SPF: sender matches SPF record 0.0 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [84.46.103.117 listed in sa-trusted.bondedsender.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 1.0 FORGED_GMAIL_RCVD 'From' gmail.com does not match 'Received' headers 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [n.rottgardt(at)gmail.com] 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [84.46.103.117 listed in bl.score.senderscore.com] 0.0 FREEMAIL_FORGED_FROMDOMAIN 2nd level domains in From and EnvelopeFrom freemail headers are different 0.9 NML_ADSP_CUSTOM_MED ADSP custom_med hit, and not from a mailing list X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org Intel Wifi Cards (and based on OpenWRT forum posts also some other devices) does not understand the actual transition request frame because of missing disassociation_timer combined with disassociation_imminent = true. So they and other devices send a BSS-TM-RESP with status=1 (error). This patch will add some new options and also fix the inconsistent disassocition_timer/_imminent call to bss_transition_request. - Added aggressive roaming (disaccociation_timer) - Added 3 new options in config to enable aggressive roaming for all or specific MAC addresses - Calling bss_transition_request with disassociation_imminent = false as new default - Using abridged flag to put priority on neighbor provided Signed-off-by: Nils Hendrik Rottgardt --- band_steering.c | 10 ++++-- local_node.c | 21 ++++++++++-- main.c | 2 ++ openwrt/usteer/files/etc/config/usteer | 9 ++++++ openwrt/usteer/files/etc/init.d/usteer | 4 ++- policy.c | 17 ++++++++-- sta.c | 24 ++++++++++++++ ubus.c | 45 +++++++++++++++++++------- usteer.h | 30 +++++++++++++---- 9 files changed, 134 insertions(+), 28 deletions(-) diff --git a/band_steering.c b/band_steering.c index 7fce1df..d7ff8cf 100644 --- a/band_steering.c +++ b/band_steering.c @@ -81,6 +81,8 @@ void usteer_band_steering_perform_steer(struct usteer_local_node *ln) ln->band_steering_interval = 0; list_for_each_entry(si, &ln->node.sta_info, node_list) { + /* TODO: Steer only if Client supports > 4000 Frequency */ + /* Check if client is eligable to be steerd */ if (!usteer_policy_can_perform_roam(si)) continue; @@ -91,8 +93,12 @@ void usteer_band_steering_perform_steer(struct usteer_local_node *ln) continue; } - if (si->bss_transition) - usteer_ubus_band_steering_request(si); + if (si->bss_transition) { + if (si->sta->aggressive) + usteer_ubus_band_steering_request(si, 0, true, config.aggressive_disassoc_timer, true, config.aggressive_disassoc_timer); + else + usteer_ubus_band_steering_request(si, 0, false, 0, true, 100); + } si->band_steering.below_snr = false; } diff --git a/local_node.c b/local_node.c index e74d945..6aa7008 100644 --- a/local_node.c +++ b/local_node.c @@ -748,7 +748,7 @@ usteer_local_node_process_bss_tm_queries(struct uloop_timeout *timeout) if (!si) continue; - usteer_ubus_bss_transition_request(si, query->dialog_token, false, false, validity_period, NULL); + usteer_ubus_bss_transition_request(si, query->dialog_token, config.aggressive_all, validity_period, true, validity_period, NULL); } /* Free pending queries we can not handle */ @@ -977,8 +977,23 @@ void config_get_ssid_list(struct blob_buf *buf) blobmsg_add_blob(buf, config.ssid_list); } -void -usteer_local_nodes_init(struct ubus_context *ctx) +void config_set_aggressive_mac_list(struct blob_attr *data) +{ + free(config.aggressive_mac_list); + + if (data && blobmsg_len(data)) + config.aggressive_mac_list = blob_memdup(data); + else + config.aggressive_mac_list = NULL; +} + +void config_get_aggressive_mac_list(struct blob_buf *buf) +{ + if (config.aggressive_mac_list) + blobmsg_add_blob(buf, config.aggressive_mac_list); +} + +void usteer_local_nodes_init(struct ubus_context *ctx) { usteer_register_events(ctx); ubus_lookup(ctx, "hostapd.*", node_list_cb, NULL); diff --git a/main.c b/main.c index 99aa6ad..b07b624 100644 --- a/main.c +++ b/main.c @@ -96,6 +96,8 @@ void usteer_init_defaults(void) config.remote_update_interval = 1000; config.initial_connect_delay = 0; config.remote_node_timeout = 10; + config.aggressive_all = false; + config.aggressive_disassoc_timer = 100; config.steer_reject_timeout = 60000; diff --git a/openwrt/usteer/files/etc/config/usteer b/openwrt/usteer/files/etc/config/usteer index f53c338..2fe47f3 100644 --- a/openwrt/usteer/files/etc/config/usteer +++ b/openwrt/usteer/files/etc/config/usteer @@ -71,6 +71,15 @@ config usteer # Timeout (ms) for which a client will not be steered after rejecting a BSS-transition-request #option steer_reject_timeout 60000 + # Use aggressvice roaming to push clients to another AP + #option aggressive_all 0 + + # List of MACs to enable aggressive roaming on. If not set all macs will handled aggressive + #list aggressive_mac_list '' + + # Disassociation imminent tuner - in aggresive mode the time a client has to roam away before disconnected hardly + #option aggressive_disassoc_timer 100 + # Timeout (in ms) after which a association following a disassociation is not seen # as a roam #option roam_process_timeout 5000 diff --git a/openwrt/usteer/files/etc/init.d/usteer b/openwrt/usteer/files/etc/init.d/usteer index 07fd99e..fdc8211 100755 --- a/openwrt/usteer/files/etc/init.d/usteer +++ b/openwrt/usteer/files/etc/init.d/usteer @@ -69,8 +69,10 @@ uci_usteer() { uci_option_to_json_bool "$cfg" local_mode uci_option_to_json_bool "$cfg" load_kick_enabled uci_option_to_json_bool "$cfg" assoc_steering + uci_option_to_json_bool "$cfg" aggressive_all uci_option_to_json_string "$cfg" node_up_script uci_option_to_json_string_array "$cfg" ssid_list + uci_option_to_json_string_array "$cfg" aggressive_mac_list uci_option_to_json_string_array "$cfg" event_log_types for opt in \ @@ -84,7 +86,7 @@ uci_usteer() { initial_connect_delay steer_reject_timeout roam_process_timeout\ roam_kick_delay roam_scan_tries roam_scan_timeout \ roam_scan_snr roam_scan_interval \ - roam_trigger_snr roam_trigger_interval \ + roam_trigger_snr roam_trigger_interval aggressive_disassoc_timer\ band_steering_interval band_steering_min_snr link_measurement_interval \ load_kick_threshold load_kick_delay load_kick_min_clients \ load_kick_reason_code diff --git a/policy.c b/policy.c index 8c5d244..e66f2d4 100644 --- a/policy.c +++ b/policy.c @@ -370,8 +370,15 @@ usteer_roam_trigger_sm(struct usteer_local_node *ln, struct sta_info *si) break; } - usteer_ubus_bss_transition_request(si, 1, false, false, 100, candidate->node); - si->kick_time = current_time + config.roam_kick_delay; + if (si->sta->aggressive) { + // TODO: Disaccociation Timer noch konfigurierbar machen + usteer_ubus_bss_transition_request(si, 1, true, config.aggressive_disassoc_timer, true, config.aggressive_disassoc_timer, candidate->node); + si->roam_disassoc_time = current_time + (100 * 100); + } else { + usteer_ubus_bss_transition_request(si, 1, false, 0, true, 100, candidate->node); + si->kick_time = current_time + config.roam_kick_delay; + } + usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, &ev); break; } @@ -400,7 +407,11 @@ bool usteer_policy_can_perform_roam(struct sta_info *si) /* Skip if connection is established shorter than the trigger-interval */ if (current_time - si->connected_since < config.roam_trigger_interval) return false; - + + /* Skip on aggressive roaming in progress - wait 10s after disassociation event*/ + if (current_time - si->roam_disassoc_time < 10000) + return false; + return true; } diff --git a/sta.c b/sta.c index ed7e40e..6cce149 100644 --- a/sta.c +++ b/sta.c @@ -76,6 +76,28 @@ usteer_sta_info_timeout(struct usteer_timeout_queue *q, struct usteer_timeout *t usteer_sta_info_del(si); } +static void +usteer_sta_update_aggressive(struct sta *sta) +{ + struct blob_attr *cur; + int rem; + char sta_mac[18]; + sprintf(sta_mac, MAC_ADDR_FMT, MAC_ADDR_DATA(sta->addr)); + + if (config.aggressive_all) + sta->aggressive = true; + else { + sta->aggressive = false; + blobmsg_for_each_attr(cur, config.aggressive_mac_list, rem) { + if (strcmp(blobmsg_get_string(cur), sta_mac) != 0) + continue; + + sta->aggressive = true; + break; + } + } +} + struct sta_info * usteer_sta_info_get(struct sta *sta, struct usteer_node *node, bool *create) { @@ -105,6 +127,8 @@ usteer_sta_info_get(struct sta *sta, struct usteer_node *node, bool *create) si->created = current_time; *create = true; + usteer_sta_update_aggressive(sta); + /* Node is by default not connected. */ usteer_sta_disconnected(si); diff --git a/ubus.c b/ubus.c index 40daf74..fd6e224 100644 --- a/ubus.c +++ b/ubus.c @@ -162,6 +162,9 @@ struct cfg_item { _cfg(U32, remote_update_interval), \ _cfg(U32, remote_node_timeout), \ _cfg(BOOL, assoc_steering), \ + _cfg(BOOL, aggressive_all), \ + _cfg(ARRAY_CB, aggressive_mac_list), \ + _cfg(U32, aggressive_disassoc_timer), \ _cfg(I32, min_connect_snr), \ _cfg(I32, min_snr), \ _cfg(U32, min_snr_kick_delay), \ @@ -668,11 +671,12 @@ usteer_ubus_disassoc_add_neighbors(struct sta_info *si) } int usteer_ubus_bss_transition_request(struct sta_info *si, - uint8_t dialog_token, - bool disassoc_imminent, - bool abridged, - uint8_t validity_period, - struct usteer_node *target_node) + uint8_t dialog_token, + bool disassoc_imminent, + uint8_t disassoc_timer, + bool abridged, + uint8_t validity_period, + struct usteer_node *target_node) { struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node); @@ -680,17 +684,28 @@ int usteer_ubus_bss_transition_request(struct sta_info *si, blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr)); blobmsg_add_u32(&b, "dialog_token", dialog_token); blobmsg_add_u8(&b, "disassociation_imminent", disassoc_imminent); + if (disassoc_imminent) { + blobmsg_add_u32(&b, "disassociation_timer", disassoc_timer); + } blobmsg_add_u8(&b, "abridged", abridged); blobmsg_add_u32(&b, "validity_period", validity_period); if (!target_node) { + // Add all known neighbors if no specific target set + MSG(DEBUG, "ROAMING requested for sta=" MAC_ADDR_FMT " without target\n", MAC_ADDR_DATA(si->sta->addr)); usteer_ubus_disassoc_add_neighbors(si); } else { + MSG(DEBUG, "ROAMING requested for sta=" MAC_ADDR_FMT " to %s with disassociation timer %i\n", MAC_ADDR_DATA(si->sta->addr), usteer_node_name(target_node), disassoc_timer); usteer_ubus_disassoc_add_neighbor(si, target_node); } return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100); } -int usteer_ubus_band_steering_request(struct sta_info *si) +int usteer_ubus_band_steering_request(struct sta_info *si, + uint8_t dialog_token, + bool disassoc_imminent, + uint8_t disassoc_timer, + bool abridged, + uint8_t validity_period) { struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node); struct usteer_node *node; @@ -698,10 +713,13 @@ int usteer_ubus_band_steering_request(struct sta_info *si) blob_buf_init(&b, 0); blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr)); - blobmsg_add_u32(&b, "dialog_token", 0); - blobmsg_add_u8(&b, "disassociation_imminent", false); - blobmsg_add_u8(&b, "abridged", false); - blobmsg_add_u32(&b, "validity_period", 100); + blobmsg_add_u32(&b, "dialog_token", dialog_token); + blobmsg_add_u8(&b, "disassociation_imminent", disassoc_imminent); + if (disassoc_imminent) { + blobmsg_add_u32(&b, "disassociation_timer", disassoc_timer); + } + blobmsg_add_u8(&b, "abridged", abridged); + blobmsg_add_u32(&b, "validity_period", validity_period); c = blobmsg_open_array(&b, "neighbors"); for_each_local_node(node) { @@ -711,8 +729,11 @@ int usteer_ubus_band_steering_request(struct sta_info *si) usteer_add_nr_entry(si->node, node); } blobmsg_close_array(&b, c); - - return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100); + if (sizeof(si->node) > 0) { + MSG(DEBUG, "BAND STEERING requested for sta=" MAC_ADDR_FMT " with disassociation timer %i\n", MAC_ADDR_DATA(si->sta->addr), disassoc_timer); + return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100); + } else + MSG(DEBUG, "BAND STEERING no targets found for sta=" MAC_ADDR_FMT "\n", MAC_ADDR_DATA(si->sta->addr)); } int usteer_ubus_trigger_link_measurement(struct sta_info *si) diff --git a/usteer.h b/usteer.h index f692fb8..f771c37 100644 --- a/usteer.h +++ b/usteer.h @@ -170,6 +170,10 @@ struct usteer_config { uint32_t remote_update_interval; uint32_t remote_node_timeout; + bool aggressive_all; + struct blob_attr *aggressive_mac_list; + uint32_t aggressive_disassoc_timer; + int32_t min_snr; uint32_t min_snr_kick_delay; int32_t min_connect_snr; @@ -190,7 +194,7 @@ struct usteer_config { uint32_t roam_kick_delay; uint32_t band_steering_interval; - int32_t band_steering_min_snr; + int32_t band_steering_min_snr; uint32_t link_measurement_interval; @@ -255,6 +259,7 @@ struct sta_info { uint8_t roam_tries; uint64_t roam_event; uint64_t roam_kick; + uint64_t roam_disassoc_time; uint64_t roam_scan_start; uint64_t roam_scan_timeout_start; @@ -285,6 +290,8 @@ struct sta { uint8_t seen_2ghz : 1; uint8_t seen_5ghz : 1; + bool aggressive; + uint8_t addr[6]; }; @@ -336,13 +343,19 @@ bool usteer_band_steering_is_target(struct usteer_local_node *ln, struct usteer_ void usteer_ubus_init(struct ubus_context *ctx); void usteer_ubus_kick_client(struct sta_info *si); int usteer_ubus_trigger_client_scan(struct sta_info *si); -int usteer_ubus_band_steering_request(struct sta_info *si); +int usteer_ubus_band_steering_request(struct sta_info *si, + uint8_t dialog_token, + bool disassoc_imminent, + uint8_t disassoc_timer, + bool abridged, + uint8_t validity_period); int usteer_ubus_bss_transition_request(struct sta_info *si, - uint8_t dialog_token, - bool disassoc_imminent, - bool abridged, - uint8_t validity_period, - struct usteer_node *target_node); + uint8_t dialog_token, + bool disassoc_imminent, + uint8_t disassoc_timer, + bool abridged, + uint8_t validity_period, + struct usteer_node *target_node); struct sta *usteer_sta_get(const uint8_t *addr, bool create); struct sta_info *usteer_sta_info_get(struct sta *sta, struct usteer_node *node, bool *create); @@ -376,6 +389,9 @@ void config_get_node_up_script(struct blob_buf *buf); void config_set_ssid_list(struct blob_attr *data); void config_get_ssid_list(struct blob_buf *buf); +void config_set_aggressive_mac_list(struct blob_attr *data); +void config_get_aggressive_mac_list(struct blob_buf *buf); + int usteer_interface_init(void); void usteer_interface_add(const char *name); void usteer_sta_node_cleanup(struct usteer_node *node);