From 2b0bb0b37e0f34be67be5d8e115a60354d55fce0 Mon Sep 17 00:00:00 2001 From: Nils Hendrik Rottgardt <n.rottga...@gmail.com> Date: Tue, 8 Oct 2024 23:30:19 +0200 Subject: [usteer] New aggressive roaming to support Intel Wifi Cards (and also other devices)
Intel Wifi Cards does not understand the actual implementation because of missing disassociation_timer and disassociation_imminent = true. So they and other devices send a BSS-TM-RESP with status=1 (error). This patch with add some new options to correct this behavior and also fix the wrong bss_transition_request call. - Added aggressive roaming (disaccociation_timer) and corrected calling bss_transition_request with disassociation_imminent = false. - Added 3 new options in config to control aggressive roaming for all or specific MAC addresses. - sta: corrected some linebreaks Signed-off-by: Nils Hendrik Rottgardt <n.rottga...@gmail.com> --- band_steering.c | 27 +- local_node.c | 267 ++++++++++++-------- main.c | 56 +++-- openwrt/usteer/files/etc/config/usteer | 9 + openwrt/usteer/files/etc/init.d/usteer | 4 +- policy.c | 148 +++++++---- sta.c | 101 +++++--- ubus.c | 335 ++++++++++++++----------- usteer.h | 123 +++++---- 9 files changed, 654 insertions(+), 416 deletions(-) diff --git a/band_steering.c b/band_steering.c index 7fce1df..470f904 100644 --- a/band_steering.c +++ b/band_steering.c @@ -37,18 +37,18 @@ bool usteer_band_steering_is_target(struct usteer_local_node *ln, struct usteer_ if (!usteer_policy_node_below_max_assoc(node)) return false; - + /* ToDo: Skip nodes with active load-kick */ - - return true; - } + return true; +} static bool usteer_band_steering_has_target_iface(struct usteer_local_node *ln) { struct usteer_node *node; - for_each_local_node(node) { + for_each_local_node(node) + { if (usteer_band_steering_is_target(ln, node)) return true; } @@ -73,26 +73,35 @@ void usteer_band_steering_perform_steer(struct usteer_local_node *ln) return; /* Only steer every interval */ - if (ln->band_steering_interval < min_count) { + if (ln->band_steering_interval < min_count) + { ln->band_steering_interval++; return; } ln->band_steering_interval = 0; - list_for_each_entry(si, &ln->node.sta_info, node_list) { + list_for_each_entry(si, &ln->node.sta_info, node_list) + { /* Check if client is eligable to be steerd */ if (!usteer_policy_can_perform_roam(si)) continue; /* Skip clients with insufficient SNR-state */ - if (si->band_steering.below_snr) { + if (si->band_steering.below_snr) + { si->band_steering.below_snr = false; continue; } if (si->bss_transition) - usteer_ubus_band_steering_request(si); + { + // usteer_ubus_band_steering_request(si, 0, false, 100, true, 100); + 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..b415196 100644 --- a/local_node.c +++ b/local_node.c @@ -12,9 +12,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2020 embedd.ch - * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> - * Copyright (C) 2020 John Crispin <j...@phrozen.org> + * Copyright (C) 2020 embedd.ch + * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> + * Copyright (C) 2020 John Crispin <j...@phrozen.org> */ #include <sys/types.h> @@ -51,7 +51,8 @@ usteer_local_node_pending_bss_tm_free(struct usteer_local_node *ln) { struct usteer_bss_tm_query *query, *tmp; - list_for_each_entry_safe(query, tmp, &ln->bss_tm_queries, list) { + list_for_each_entry_safe(query, tmp, &ln->bss_tm_queries, list) + { list_del(&query->list); free(query); } @@ -62,7 +63,8 @@ usteer_free_node(struct ubus_context *ctx, struct usteer_local_node *ln) { struct usteer_node_handler *h; - list_for_each_entry(h, &node_handlers, list) { + list_for_each_entry(h, &node_handlers, list) + { if (!h->free_node) continue; h->free_node(&ln->node); @@ -80,11 +82,13 @@ usteer_free_node(struct ubus_context *ctx, struct usteer_local_node *ln) free(ln); } -struct usteer_local_node *usteer_local_node_by_bssid(uint8_t *bssid) { +struct usteer_local_node *usteer_local_node_by_bssid(uint8_t *bssid) +{ struct usteer_local_node *ln; struct usteer_node *n; - for_each_local_node(n) { + for_each_local_node(n) + { ln = container_of(n, struct usteer_local_node, node); if (!memcmp(n->bssid, bssid, 6)) return ln; @@ -95,7 +99,7 @@ struct usteer_local_node *usteer_local_node_by_bssid(uint8_t *bssid) { static void usteer_handle_remove(struct ubus_context *ctx, struct ubus_subscriber *s, - uint32_t id) + uint32_t id) { struct usteer_local_node *ln = container_of(s, struct usteer_local_node, ev); @@ -105,16 +109,17 @@ usteer_handle_remove(struct ubus_context *ctx, struct ubus_subscriber *s, static int usteer_handle_bss_tm_query(struct usteer_local_node *ln, struct blob_attr *msg) { - enum { + enum + { BSS_TM_QUERY_ADDRESS, BSS_TM_QUERY_DIALOG_TOKEN, BSS_TM_QUERY_CANDIDATE_LIST, __BSS_TM_QUERY_MAX }; struct blobmsg_policy policy[__BSS_TM_QUERY_MAX] = { - [BSS_TM_QUERY_ADDRESS] = { .name = "address", .type = BLOBMSG_TYPE_STRING }, - [BSS_TM_QUERY_DIALOG_TOKEN] = { .name = "dialog-token", .type = BLOBMSG_TYPE_INT8 }, - [BSS_TM_QUERY_CANDIDATE_LIST] = { .name = "candidate-list", .type = BLOBMSG_TYPE_STRING }, + [BSS_TM_QUERY_ADDRESS] = {.name = "address", .type = BLOBMSG_TYPE_STRING}, + [BSS_TM_QUERY_DIALOG_TOKEN] = {.name = "dialog-token", .type = BLOBMSG_TYPE_INT8}, + [BSS_TM_QUERY_CANDIDATE_LIST] = {.name = "candidate-list", .type = BLOBMSG_TYPE_STRING}, }; struct blob_attr *tb[__BSS_TM_QUERY_MAX]; struct usteer_bss_tm_query *query; @@ -131,7 +136,7 @@ usteer_handle_bss_tm_query(struct usteer_local_node *ln, struct blob_attr *msg) query->dialog_token = blobmsg_get_u8(tb[BSS_TM_QUERY_DIALOG_TOKEN]); - sta_addr = (uint8_t *) ether_aton(blobmsg_get_string(tb[BSS_TM_QUERY_ADDRESS])); + sta_addr = (uint8_t *)ether_aton(blobmsg_get_string(tb[BSS_TM_QUERY_ADDRESS])); if (!sta_addr) return 0; @@ -146,14 +151,15 @@ usteer_handle_bss_tm_query(struct usteer_local_node *ln, struct blob_attr *msg) static int usteer_handle_bss_tm_response(struct usteer_local_node *ln, struct blob_attr *msg) { - enum { + enum + { BSS_TM_RESPONSE_ADDRESS, BSS_TM_RESPONSE_STATUS_CODE, __BSS_TM_RESPONSE_MAX }; struct blobmsg_policy policy[__BSS_TM_RESPONSE_MAX] = { - [BSS_TM_RESPONSE_ADDRESS] = { .name = "address", .type = BLOBMSG_TYPE_STRING }, - [BSS_TM_RESPONSE_STATUS_CODE] = { .name = "status-code", .type = BLOBMSG_TYPE_INT8 }, + [BSS_TM_RESPONSE_ADDRESS] = {.name = "address", .type = BLOBMSG_TYPE_STRING}, + [BSS_TM_RESPONSE_STATUS_CODE] = {.name = "status-code", .type = BLOBMSG_TYPE_INT8}, }; struct blob_attr *tb[__BSS_TM_RESPONSE_MAX]; struct sta_info *si; @@ -165,7 +171,7 @@ usteer_handle_bss_tm_response(struct usteer_local_node *ln, struct blob_attr *ms if (!tb[BSS_TM_RESPONSE_ADDRESS] || !tb[BSS_TM_RESPONSE_STATUS_CODE]) return 0; - sta_addr = (uint8_t *) ether_aton(blobmsg_get_string(tb[BSS_TM_RESPONSE_ADDRESS])); + sta_addr = (uint8_t *)ether_aton(blobmsg_get_string(tb[BSS_TM_RESPONSE_ADDRESS])); if (!sta_addr) return 0; @@ -180,7 +186,8 @@ usteer_handle_bss_tm_response(struct usteer_local_node *ln, struct blob_attr *ms si->bss_transition_response.status_code = blobmsg_get_u8(tb[BSS_TM_RESPONSE_STATUS_CODE]); si->bss_transition_response.timestamp = current_time; - if (si->bss_transition_response.status_code) { + if (si->bss_transition_response.status_code) + { /* Cancel imminent kick in case BSS transition was rejected */ si->kick_time = 0; } @@ -191,7 +198,8 @@ usteer_handle_bss_tm_response(struct usteer_local_node *ln, struct blob_attr *ms static int usteer_local_node_handle_beacon_report(struct usteer_local_node *ln, struct blob_attr *msg) { - enum { + enum + { BR_ADDRESS, BR_BSSID, BR_RCPI, @@ -199,10 +207,10 @@ usteer_local_node_handle_beacon_report(struct usteer_local_node *ln, struct blob __BR_MAX }; struct blobmsg_policy policy[__BR_MAX] = { - [BR_ADDRESS] = { .name = "address", .type = BLOBMSG_TYPE_STRING }, - [BR_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, - [BR_RCPI] = { .name = "rcpi", .type = BLOBMSG_TYPE_INT16 }, - [BR_RSNI] = { .name = "rsni", .type = BLOBMSG_TYPE_INT16 }, + [BR_ADDRESS] = {.name = "address", .type = BLOBMSG_TYPE_STRING}, + [BR_BSSID] = {.name = "bssid", .type = BLOBMSG_TYPE_STRING}, + [BR_RCPI] = {.name = "rcpi", .type = BLOBMSG_TYPE_INT16}, + [BR_RSNI] = {.name = "rsni", .type = BLOBMSG_TYPE_INT16}, }; struct blob_attr *tb[__BR_MAX]; struct usteer_node *node; @@ -213,7 +221,7 @@ usteer_local_node_handle_beacon_report(struct usteer_local_node *ln, struct blob if (!tb[BR_ADDRESS] || !tb[BR_BSSID] || !tb[BR_RCPI] || !tb[BR_RSNI]) return 0; - addr = (uint8_t *) ether_aton(blobmsg_get_string(tb[BR_ADDRESS])); + addr = (uint8_t *)ether_aton(blobmsg_get_string(tb[BR_ADDRESS])); if (!addr) return 0; @@ -221,7 +229,7 @@ usteer_local_node_handle_beacon_report(struct usteer_local_node *ln, struct blob if (!sta) return 0; - addr = (uint8_t *) ether_aton(blobmsg_get_string(tb[BR_BSSID])); + addr = (uint8_t *)ether_aton(blobmsg_get_string(tb[BR_BSSID])); if (!addr) return 0; @@ -230,25 +238,26 @@ usteer_local_node_handle_beacon_report(struct usteer_local_node *ln, struct blob return 0; usteer_measurement_report_add(sta, node, - (uint8_t)blobmsg_get_u16(tb[BR_RCPI]), - (uint8_t)blobmsg_get_u16(tb[BR_RSNI]), - current_time); + (uint8_t)blobmsg_get_u16(tb[BR_RCPI]), + (uint8_t)blobmsg_get_u16(tb[BR_RSNI]), + current_time); return 0; } static int usteer_local_node_handle_link_measurement_report(struct usteer_local_node *ln, struct blob_attr *msg) { - enum { + enum + { LMR_ADDRESS, LMR_RCPI, LMR_RSNI, __LMR_MAX }; struct blobmsg_policy policy[__LMR_MAX] = { - [LMR_ADDRESS] = { .name = "address", .type = BLOBMSG_TYPE_STRING }, - [LMR_RCPI] = { .name = "rcpi", .type = BLOBMSG_TYPE_INT16 }, - [LMR_RSNI] = { .name = "rsni", .type = BLOBMSG_TYPE_INT16 }, + [LMR_ADDRESS] = {.name = "address", .type = BLOBMSG_TYPE_STRING}, + [LMR_RCPI] = {.name = "rcpi", .type = BLOBMSG_TYPE_INT16}, + [LMR_RSNI] = {.name = "rsni", .type = BLOBMSG_TYPE_INT16}, }; struct blob_attr *tb[__LMR_MAX]; uint8_t *addr; @@ -258,7 +267,7 @@ usteer_local_node_handle_link_measurement_report(struct usteer_local_node *ln, s if (!tb[LMR_ADDRESS] || !tb[LMR_RCPI] || !tb[LMR_RSNI]) return 0; - addr = (uint8_t *) ether_aton(blobmsg_get_string(tb[LMR_ADDRESS])); + addr = (uint8_t *)ether_aton(blobmsg_get_string(tb[LMR_ADDRESS])); if (!addr) return 0; @@ -267,18 +276,19 @@ usteer_local_node_handle_link_measurement_report(struct usteer_local_node *ln, s return 0; usteer_measurement_report_add(sta, &ln->node, - (uint8_t)blobmsg_get_u16(tb[LMR_RCPI]), - (uint8_t)blobmsg_get_u16(tb[LMR_RSNI]), - current_time); + (uint8_t)blobmsg_get_u16(tb[LMR_RCPI]), + (uint8_t)blobmsg_get_u16(tb[LMR_RSNI]), + current_time); return 0; } static int usteer_handle_event(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { - enum { + enum + { EVENT_ADDR, EVENT_SIGNAL, EVENT_TARGET, @@ -286,10 +296,10 @@ usteer_handle_event(struct ubus_context *ctx, struct ubus_object *obj, __EVENT_MAX }; struct blobmsg_policy policy[__EVENT_MAX] = { - [EVENT_ADDR] = { .name = "address", .type = BLOBMSG_TYPE_STRING }, - [EVENT_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 }, - [EVENT_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, - [EVENT_FREQ] = { .name = "freq", .type = BLOBMSG_TYPE_INT32 }, + [EVENT_ADDR] = {.name = "address", .type = BLOBMSG_TYPE_STRING}, + [EVENT_SIGNAL] = {.name = "signal", .type = BLOBMSG_TYPE_INT32}, + [EVENT_TARGET] = {.name = "target", .type = BLOBMSG_TYPE_STRING}, + [EVENT_FREQ] = {.name = "freq", .type = BLOBMSG_TYPE_INT32}, }; enum usteer_event_type ev_type = __EVENT_TYPE_MAX; struct blob_attr *tb[__EVENT_MAX]; @@ -306,17 +316,25 @@ usteer_handle_event(struct ubus_context *ctx, struct ubus_object *obj, ln = container_of(obj, struct usteer_local_node, ev.obj); - if(!strcmp(method, "bss-transition-query")) { + if (!strcmp(method, "bss-transition-query")) + { return usteer_handle_bss_tm_query(ln, msg); - } else if(!strcmp(method, "bss-transition-response")) { + } + else if (!strcmp(method, "bss-transition-response")) + { return usteer_handle_bss_tm_response(ln, msg); - } else if(!strcmp(method, "beacon-report")) { + } + else if (!strcmp(method, "beacon-report")) + { return usteer_local_node_handle_beacon_report(ln, msg); - } else if(!strcmp(method, "link-measurement-report")) { + } + else if (!strcmp(method, "link-measurement-report")) + { return usteer_local_node_handle_link_measurement_report(ln, msg); } - for (i = 0; i < ARRAY_SIZE(event_types); i++) { + for (i = 0; i < ARRAY_SIZE(event_types); i++) + { if (strcmp(method, event_types[i]) != 0) continue; @@ -331,20 +349,20 @@ usteer_handle_event(struct ubus_context *ctx, struct ubus_object *obj, return UBUS_STATUS_INVALID_ARGUMENT; if (tb[EVENT_SIGNAL]) - signal = (int32_t) blobmsg_get_u32(tb[EVENT_SIGNAL]); + signal = (int32_t)blobmsg_get_u32(tb[EVENT_SIGNAL]); if (tb[EVENT_FREQ]) freq = blobmsg_get_u32(tb[EVENT_FREQ]); addr_str = blobmsg_data(tb[EVENT_ADDR]); - addr = (uint8_t *) ether_aton(addr_str); + addr = (uint8_t *)ether_aton(addr_str); if (!addr) return UBUS_STATUS_INVALID_ARGUMENT; ret = usteer_handle_sta_event(node, addr, ev_type, freq, signal); MSG(DEBUG, "received %s event from %s, signal=%d, freq=%d, handled:%s\n", - method, addr_str, signal, freq, ret ? "true" : "false"); + method, addr_str, signal, freq, ret ? "true" : "false"); return ret ? 0 : 17 /* WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA */; } @@ -352,27 +370,32 @@ usteer_handle_event(struct ubus_context *ctx, struct ubus_object *obj, static void usteer_local_node_assoc_update(struct sta_info *si, struct blob_attr *data) { - enum { + enum + { MSG_ASSOC, __MSG_MAX, }; static struct blobmsg_policy policy[__MSG_MAX] = { - [MSG_ASSOC] = { "assoc", BLOBMSG_TYPE_BOOL }, + [MSG_ASSOC] = {"assoc", BLOBMSG_TYPE_BOOL}, }; struct blob_attr *tb[__MSG_MAX]; struct usteer_remote_node *rn; struct sta_info *remote_si; blobmsg_parse(policy, __MSG_MAX, tb, blobmsg_data(data), blobmsg_data_len(data)); - if (tb[MSG_ASSOC] && blobmsg_get_u8(tb[MSG_ASSOC])) { - if (si->connected == STA_NOT_CONNECTED) { + if (tb[MSG_ASSOC] && blobmsg_get_u8(tb[MSG_ASSOC])) + { + if (si->connected == STA_NOT_CONNECTED) + { /* New connection. Check if STA roamed. */ - for_each_remote_node(rn) { + for_each_remote_node(rn) + { remote_si = usteer_sta_info_get(si->sta, &rn->node, NULL); if (!remote_si) continue; - if (current_time - remote_si->last_connected < config.roam_process_timeout) { + if (current_time - remote_si->last_connected < config.roam_process_timeout) + { rn->node.roam_events.source++; /* Don't abort looking for roam sources here. * The client might have roamed via another node @@ -424,11 +447,13 @@ usteer_local_node_update_sta_rrm_wnm(struct sta_info *si, struct blob_attr *clie if (!wnm_blob) return; - blobmsg_for_each_attr(cur, wnm_blob, rem) { + blobmsg_for_each_attr(cur, wnm_blob, rem) + { if (blobmsg_type(cur) != BLOBMSG_TYPE_INT32) return; - - if (i == 2) { + + if (i == 2) + { if (blobmsg_get_u32(cur) & (1 << 3)) si->bss_transition = true; } @@ -450,13 +475,15 @@ usteer_local_node_set_assoc(struct usteer_local_node *ln, struct blob_attr *cl) usteer_update_time(); - list_for_each_entry(si, &node->sta_info, node_list) { + list_for_each_entry(si, &node->sta_info, node_list) + { if (si->connected) si->connected = STA_DISCONNECTED; } - blobmsg_for_each_attr(cur, cl, rem) { - uint8_t *addr = (uint8_t *) ether_aton(blobmsg_name(cur)); + blobmsg_for_each_attr(cur, cl, rem) + { + uint8_t *addr = (uint8_t *)ether_aton(blobmsg_name(cur)); bool create; if (!addr) @@ -464,14 +491,16 @@ usteer_local_node_set_assoc(struct usteer_local_node *ln, struct blob_attr *cl) sta = usteer_sta_get(addr, true); si = usteer_sta_info_get(sta, node, &create); - list_for_each_entry(h, &node_handlers, list) { + list_for_each_entry(h, &node_handlers, list) + { if (!h->update_sta) continue; h->update_sta(node, si); } usteer_local_node_assoc_update(si, cur); - if (si->connected == STA_CONNECTED) { + if (si->connected == STA_CONNECTED) + { si->last_connected = current_time; n_assoc++; } @@ -482,12 +511,13 @@ usteer_local_node_set_assoc(struct usteer_local_node *ln, struct blob_attr *cl) node->n_assoc = n_assoc; - list_for_each_entry(si, &node->sta_info, node_list) { + list_for_each_entry(si, &node->sta_info, node_list) + { if (si->connected != STA_DISCONNECTED) continue; usteer_sta_disconnected(si); - MSG(VERBOSE, "station "MAC_ADDR_FMT" disconnected from node %s\n", + MSG(VERBOSE, "station " MAC_ADDR_FMT " disconnected from node %s\n", MAC_ADDR_DATA(si->sta->addr), usteer_node_name(node)); } } @@ -495,14 +525,15 @@ usteer_local_node_set_assoc(struct usteer_local_node *ln, struct blob_attr *cl) static void usteer_local_node_list_cb(struct ubus_request *req, int type, struct blob_attr *msg) { - enum { + enum + { MSG_FREQ, MSG_CLIENTS, __MSG_MAX, }; static struct blobmsg_policy policy[__MSG_MAX] = { - [MSG_FREQ] = { "freq", BLOBMSG_TYPE_INT32 }, - [MSG_CLIENTS] = { "clients", BLOBMSG_TYPE_TABLE }, + [MSG_FREQ] = {"freq", BLOBMSG_TYPE_INT32}, + [MSG_CLIENTS] = {"clients", BLOBMSG_TYPE_TABLE}, }; struct blob_attr *tb[__MSG_MAX]; struct usteer_local_node *ln; @@ -522,7 +553,8 @@ usteer_local_node_list_cb(struct ubus_request *req, int type, struct blob_attr * static void usteer_local_node_status_cb(struct ubus_request *req, int type, struct blob_attr *msg) { - enum { + enum + { MSG_FREQ, MSG_CHANNEL, MSG_OP_CLASS, @@ -530,10 +562,10 @@ usteer_local_node_status_cb(struct ubus_request *req, int type, struct blob_attr __MSG_MAX, }; static struct blobmsg_policy policy[__MSG_MAX] = { - [MSG_FREQ] = { "freq", BLOBMSG_TYPE_INT32 }, - [MSG_CHANNEL] = { "channel", BLOBMSG_TYPE_INT32 }, - [MSG_OP_CLASS] = { "op_class", BLOBMSG_TYPE_INT32 }, - [MSG_BEACON_INTERVAL] = { "beacon_interval", BLOBMSG_TYPE_INT32 }, + [MSG_FREQ] = {"freq", BLOBMSG_TYPE_INT32}, + [MSG_CHANNEL] = {"channel", BLOBMSG_TYPE_INT32}, + [MSG_OP_CLASS] = {"op_class", BLOBMSG_TYPE_INT32}, + [MSG_BEACON_INTERVAL] = {"beacon_interval", BLOBMSG_TYPE_INT32}, }; struct blob_attr *tb[__MSG_MAX]; struct usteer_local_node *ln; @@ -548,7 +580,7 @@ usteer_local_node_status_cb(struct ubus_request *req, int type, struct blob_attr if (tb[MSG_CHANNEL]) node->channel = blobmsg_get_u32(tb[MSG_CHANNEL]); if (tb[MSG_OP_CLASS]) - node->op_class = blobmsg_get_u32(tb[MSG_OP_CLASS]); + node->op_class = blobmsg_get_u32(tb[MSG_OP_CLASS]); /* Local-Node */ if (tb[MSG_BEACON_INTERVAL]) @@ -559,8 +591,7 @@ static void usteer_local_node_rrm_nr_cb(struct ubus_request *req, int type, struct blob_attr *msg) { static const struct blobmsg_policy policy = { - "value", BLOBMSG_TYPE_ARRAY - }; + "value", BLOBMSG_TYPE_ARRAY}; struct usteer_local_node *ln; struct blob_attr *tb; @@ -596,8 +627,8 @@ usteer_add_rrm_data(struct usteer_local_node *ln, struct usteer_node *node) return false; blobmsg_add_field(&b, BLOBMSG_TYPE_ARRAY, "", - blobmsg_data(node->rrm_nr), - blobmsg_data_len(node->rrm_nr)); + blobmsg_data(node->rrm_nr), + blobmsg_data_len(node->rrm_nr)); return true; } @@ -610,16 +641,19 @@ usteer_local_node_prepare_rrm_set(struct usteer_local_node *ln) void *c; c = blobmsg_open_array(&b, "list"); - for_each_local_node(node) { + for_each_local_node(node) + { if (i >= config.max_neighbor_reports) break; if (usteer_add_rrm_data(ln, node)) i++; } - while (i < config.max_neighbor_reports) { + while (i < config.max_neighbor_reports) + { node = usteer_node_get_next_neighbor(&ln->node, last_remote_neighbor); - if (!node) { + if (!node) + { /* No more nodes available */ break; } @@ -628,7 +662,7 @@ usteer_local_node_prepare_rrm_set(struct usteer_local_node *ln) if (usteer_add_rrm_data(ln, node)) i++; } - + blobmsg_close_array(&b, c); } @@ -640,13 +674,15 @@ usteer_local_node_state_next(struct uloop_timeout *timeout) ln = container_of(timeout, struct usteer_local_node, req_timer); ln->req_state++; - if (ln->req_state >= __REQ_MAX) { + if (ln->req_state >= __REQ_MAX) + { ln->req_state = REQ_IDLE; return; } blob_buf_init(&b, 0); - switch (ln->req_state) { + switch (ln->req_state) + { case REQ_CLIENTS: ubus_invoke_async(ubus_ctx, ln->obj_id, "get_clients", b.head, &ln->req); ln->req.data_cb = usteer_local_node_list_cb; @@ -680,17 +716,19 @@ usteer_local_node_request_link_measurement(struct usteer_local_node *ln) node = &ln->node; - if (ln->link_measurement_tries < min_count) { + if (ln->link_measurement_tries < min_count) + { ln->link_measurement_tries++; return; } - + ln->link_measurement_tries = 0; if (!config.link_measurement_interval) return; - list_for_each_entry(si, &node->sta_info, node_list) { + list_for_each_entry(si, &node->sta_info, node_list) + { if (si->connected != STA_CONNECTED) continue; @@ -708,7 +746,8 @@ usteer_local_node_update(struct uloop_timeout *timeout) ln = container_of(timeout, struct usteer_local_node, update); node = &ln->node; - list_for_each_entry(h, &node_handlers, list) { + list_for_each_entry(h, &node_handlers, list) + { if (!h->update_node) continue; @@ -739,7 +778,8 @@ usteer_local_node_process_bss_tm_queries(struct uloop_timeout *timeout) validity_period = 10000 / usteer_local_node_get_beacon_interval(ln); /* ~ 10 seconds */ - list_for_each_entry_safe(query, tmp, &ln->bss_tm_queries, list) { + list_for_each_entry_safe(query, tmp, &ln->bss_tm_queries, list) + { sta = usteer_sta_get(query->sta_addr, false); if (!sta) continue; @@ -748,7 +788,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 */ @@ -808,7 +848,8 @@ usteer_check_node_enabled(struct usteer_local_node *ln) struct blob_attr *cur; int rem; - blobmsg_for_each_attr(cur, config.ssid_list, rem) { + blobmsg_for_each_attr(cur, config.ssid_list, rem) + { if (strcmp(blobmsg_get_string(cur), ln->node.ssid) != 0) continue; @@ -821,7 +862,8 @@ usteer_check_node_enabled(struct usteer_local_node *ln) ln->node.disabled = ssid_disabled; - if (ssid_disabled) { + if (ssid_disabled) + { MSG(INFO, "Disconnecting from local node %s\n", usteer_node_name(&ln->node)); usteer_local_node_state_reset(ln); usteer_sta_node_cleanup(&ln->node); @@ -866,7 +908,8 @@ usteer_register_node(struct ubus_context *ctx, const char *name, uint32_t id) blobmsg_add_u8(&b, "bss_transition", 1); ubus_invoke(ctx, id, "bss_mgmt_enable", b.head, NULL, NULL, 1000); - list_for_each_entry(h, &node_handlers, list) { + list_for_each_entry(h, &node_handlers, list) + { if (!h->init_node) continue; @@ -879,11 +922,11 @@ usteer_register_node(struct ubus_context *ctx, const char *name, uint32_t id) static void usteer_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, - const char *type, struct blob_attr *msg) + const char *type, struct blob_attr *msg) { static const struct blobmsg_policy policy[2] = { - { .name = "id", .type = BLOBMSG_TYPE_INT32 }, - { .name = "path", .type = BLOBMSG_TYPE_STRING }, + {.name = "id", .type = BLOBMSG_TYPE_INT32}, + {.name = "path", .type = BLOBMSG_TYPE_STRING}, }; struct blob_attr *tb[2]; const char *path; @@ -901,8 +944,7 @@ static void usteer_register_events(struct ubus_context *ctx) { static struct ubus_event_handler handler = { - .cb = usteer_event_handler - }; + .cb = usteer_event_handler}; ubus_register_event_handler(ctx, &handler, "ubus.object.add"); } @@ -913,8 +955,7 @@ node_list_cb(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv) usteer_register_node(ctx, obj->path, obj->id); } -int -usteer_local_node_get_beacon_interval(struct usteer_local_node *ln) +int usteer_local_node_get_beacon_interval(struct usteer_local_node *ln) { /* Check if beacon-interval is not available (pre-21.02+) */ if (ln->beacon_interval < 1) @@ -937,7 +978,8 @@ void config_set_node_up_script(struct blob_attr *data) free(node_up_script); - if (!strlen(val)) { + if (!strlen(val)) + { node_up_script = NULL; return; } @@ -977,8 +1019,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..96386ca 100644 --- a/main.c +++ b/main.c @@ -12,9 +12,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2020 embedd.ch - * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> - * Copyright (C) 2020 John Crispin <j...@phrozen.org> + * Copyright (C) 2020 embedd.ch + * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> + * Copyright (C) 2020 John Crispin <j...@phrozen.org> */ #include <unistd.h> @@ -35,7 +35,7 @@ static int dump_time; LIST_HEAD(node_handlers); -const char * const event_types[__EVENT_TYPE_MAX] = { +const char *const event_types[__EVENT_TYPE_MAX] = { [EVENT_TYPE_PROBE] = "probe", [EVENT_TYPE_AUTH] = "auth", [EVENT_TYPE_ASSOC] = "assoc", @@ -65,7 +65,6 @@ void debug_msg(int level, const char *func, int line, const char *format, ...) else vfprintf(stderr, format, ap); va_end(ap); - } void debug_msg_cont(int level, const char *format, ...) @@ -96,6 +95,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; @@ -127,26 +128,26 @@ void usteer_init_defaults(void) void usteer_update_time(void) { struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - current_time = (uint64_t) ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + current_time = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; } static int usage(const char *prog) { fprintf(stderr, "Usage: %s [options]\n" - "Options:\n" - " -v: Increase debug level (repeat for more messages):\n" - " 1: info messages\n" - " 2: debug messages\n" - " 3: verbose debug messages\n" - " 4: include network messages\n" - " 5: include extra testing messages\n" - " -i <name>: Connect to other instances on interface <name>\n" - " -s: Output log messages via syslog instead of stderr\n" - " -D <n>: Do not daemonize, wait for <n> seconds and print\n" - " remote hosts and nodes\n" - "\n", prog); + "Options:\n" + " -v: Increase debug level (repeat for more messages):\n" + " 1: info messages\n" + " 2: debug messages\n" + " 3: verbose debug messages\n" + " 4: include network messages\n" + " 5: include extra testing messages\n" + " -i <name>: Connect to other instances on interface <name>\n" + " -s: Output log messages via syslog instead of stderr\n" + " -D <n>: Do not daemonize, wait for <n> seconds and print\n" + " remote hosts and nodes\n" + "\n", + prog); return 1; } @@ -187,8 +188,10 @@ int main(int argc, char **argv) usteer_init_defaults(); - while ((ch = getopt(argc, argv, "D:i:sv")) != -1) { - switch(ch) { + while ((ch = getopt(argc, argv, "D:i:sv")) != -1) + { + switch (ch) + { case 'v': config.debug_level++; break; @@ -213,19 +216,24 @@ int main(int argc, char **argv) uloop_init(); ubus_ctx = ubus_connect(NULL); - if (!ubus_ctx) { + if (!ubus_ctx) + { fprintf(stderr, "Failed to connect to ubus\n"); return -1; } ubus_add_uloop(ubus_ctx); - if (dump_time) { + if (dump_time) + { dump_timer.cb = usteer_dump_timeout; uloop_timeout_set(&dump_timer, dump_time * 1000); - } else { + } + else + { usteer_ubus_init(ubus_ctx); usteer_local_nodes_init(ubus_ctx); } + uloop_run(); uloop_done(); 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..7085114 100644 --- a/policy.c +++ b/policy.c @@ -12,9 +12,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2020 embedd.ch - * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> - * Copyright (C) 2020 John Crispin <j...@phrozen.org> + * Copyright (C) 2020 embedd.ch + * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> + * Copyright (C) 2020 John Crispin <j...@phrozen.org> */ #include "usteer.h" @@ -45,8 +45,7 @@ below_assoc_threshold(struct usteer_node *node_cur, struct usteer_node *node_new static bool better_signal_strength(int signal_cur, int signal_new) { - const bool is_better = signal_new - signal_cur - > (int) config.signal_diff_threshold; + const bool is_better = signal_new - signal_cur > (int)config.signal_diff_threshold; if (!config.signal_diff_threshold) return false; @@ -58,7 +57,7 @@ static bool below_load_threshold(struct usteer_node *node) { return node->n_assoc >= config.load_kick_min_clients && - node->load > config.load_kick_threshold; + node->load > config.load_kick_threshold; } static bool @@ -67,8 +66,7 @@ has_better_load(struct usteer_node *node_cur, struct usteer_node *node_new) return !below_load_threshold(node_cur) && below_load_threshold(node_new); } -bool -usteer_policy_node_below_max_assoc(struct usteer_node *node) +bool usteer_policy_node_below_max_assoc(struct usteer_node *node) { return !node->max_assoc || node->n_assoc < node->max_assoc; } @@ -81,7 +79,7 @@ over_min_signal(struct usteer_node *node, int signal) if (config.roam_trigger_snr && signal < usteer_snr_to_signal(node, config.roam_trigger_snr)) return false; - + return true; } @@ -101,7 +99,7 @@ is_better_candidate(struct sta_info *si_cur, struct sta_info *si_new) return 0; if (below_assoc_threshold(current_node, new_node) && - !below_assoc_threshold(new_node, current_node)) + !below_assoc_threshold(new_node, current_node)) reasons |= (1 << UEV_SELECT_REASON_NUM_ASSOC); if (better_signal_strength(current_signal, new_signal)) @@ -121,7 +119,8 @@ find_better_candidate(struct sta_info *si_ref, struct uevent *ev, uint32_t requi struct sta *sta = si_ref->sta; uint32_t reasons; - list_for_each_entry(si, &sta->nodes, list) { + list_for_each_entry(si, &sta->nodes, list) + { if (si == si_ref) continue; @@ -141,7 +140,8 @@ find_better_candidate(struct sta_info *si_ref, struct uevent *ev, uint32_t requi if (!(reasons & required_criteria)) continue; - if (ev) { + if (ev) + { ev->si_other = si; ev->select_reasons = reasons; } @@ -153,8 +153,7 @@ find_better_candidate(struct sta_info *si_ref, struct uevent *ev, uint32_t requi return candidate; } -int -usteer_snr_to_signal(struct usteer_node *node, int snr) +int usteer_snr_to_signal(struct usteer_node *node, int snr) { int noise = -95; @@ -167,8 +166,7 @@ usteer_snr_to_signal(struct usteer_node *node, int snr) return noise + snr; } -bool -usteer_check_request(struct sta_info *si, enum usteer_event_type type) +bool usteer_check_request(struct sta_info *si, enum usteer_event_type type) { struct uevent ev = { .si_cur = si, @@ -182,25 +180,30 @@ usteer_check_request(struct sta_info *si, enum usteer_event_type type) if (type == EVENT_TYPE_AUTH) goto out; - if (type == EVENT_TYPE_ASSOC) { + if (type == EVENT_TYPE_ASSOC) + { /* Check if assoc request has lower signal than min_signal. * If this is the case, block assoc even when assoc steering is enabled. * * Otherwise, the client potentially ends up in a assoc - kick loop. */ - if (config.min_snr && si->signal < usteer_snr_to_signal(si->node, config.min_snr)) { + if (config.min_snr && si->signal < usteer_snr_to_signal(si->node, config.min_snr)) + { ev.reason = UEV_REASON_LOW_SIGNAL; ev.threshold.cur = si->signal; ev.threshold.ref = usteer_snr_to_signal(si->node, config.min_snr); ret = false; goto out; - } else if (!config.assoc_steering) { + } + else if (!config.assoc_steering) + { goto out; } } min_signal = usteer_snr_to_signal(si->node, config.min_connect_snr); - if (si->signal < min_signal) { + if (si->signal < min_signal) + { ev.reason = UEV_REASON_LOW_SIGNAL; ev.threshold.cur = si->signal; ev.threshold.ref = min_signal; @@ -208,7 +211,8 @@ usteer_check_request(struct sta_info *si, enum usteer_event_type type) goto out; } - if (current_time - si->created < config.initial_connect_delay) { + if (current_time - si->created < config.initial_connect_delay) + { ev.reason = UEV_REASON_CONNECT_DELAY; ev.threshold.cur = current_time - si->created; ev.threshold.ref = config.initial_connect_delay; @@ -224,7 +228,8 @@ usteer_check_request(struct sta_info *si, enum usteer_event_type type) ret = false; out: - switch (type) { + switch (type) + { case EVENT_TYPE_PROBE: ev.type = ret ? UEV_PROBE_REQ_ACCEPT : UEV_PROBE_REQ_DENY; break; @@ -238,7 +243,8 @@ out: break; } - if (!ret && si->stats[type].blocked_cur >= config.max_retry_band) { + if (!ret && si->stats[type].blocked_cur >= config.max_retry_band) + { ev.reason = UEV_REASON_RETRY_EXCEEDED; ev.threshold.cur = si->stats[type].blocked_cur; ev.threshold.ref = config.max_retry_band; @@ -262,19 +268,23 @@ is_more_kickable(struct sta_info *si_cur, struct sta_info *si_new) static void usteer_roam_set_state(struct sta_info *si, enum roam_trigger_state state, - struct uevent *ev) + struct uevent *ev) { /* NOP in case we remain idle */ - if (si->roam_state == state && si->roam_state == ROAM_TRIGGER_IDLE) { + if (si->roam_state == state && si->roam_state == ROAM_TRIGGER_IDLE) + { si->roam_tries = 0; return; } si->roam_event = current_time; - if (si->roam_state == state) { + if (si->roam_state == state) + { si->roam_tries++; - } else { + } + else + { si->roam_tries = 0; } @@ -287,7 +297,8 @@ usteer_roam_sm_start_scan(struct sta_info *si, struct uevent *ev) { /* Start scanning in case we are not timeout-constrained or timeout has expired */ if (!config.roam_scan_timeout || - current_time > si->roam_scan_timeout_start + config.roam_scan_timeout) { + current_time > si->roam_scan_timeout_start + config.roam_scan_timeout) + { usteer_roam_set_state(si, ROAM_TRIGGER_SCAN, ev); return; } @@ -326,9 +337,11 @@ usteer_roam_trigger_sm(struct usteer_local_node *ln, struct sta_info *si) .si_cur = si, }; - switch (si->roam_state) { + switch (si->roam_state) + { case ROAM_TRIGGER_SCAN: - if (!si->roam_tries) { + if (!si->roam_tries) + { si->roam_scan_start = current_time; } @@ -341,11 +354,15 @@ usteer_roam_trigger_sm(struct usteer_local_node *ln, struct sta_info *si) break; /* Check if no node was found within roam_scan_tries tries */ - if (config.roam_scan_tries && si->roam_tries >= config.roam_scan_tries) { - if (!config.roam_scan_timeout) { + if (config.roam_scan_tries && si->roam_tries >= config.roam_scan_tries) + { + if (!config.roam_scan_timeout) + { /* Prepare to kick client */ usteer_roam_set_state(si, ROAM_TRIGGER_SCAN_DONE, &ev); - } else { + } + else + { /* Kick in scan timeout */ si->roam_scan_timeout_start = current_time; usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, &ev); @@ -365,13 +382,24 @@ usteer_roam_trigger_sm(struct usteer_local_node *ln, struct sta_info *si) case ROAM_TRIGGER_SCAN_DONE: candidate = usteer_roam_sm_found_better_node(si, &ev, ROAM_TRIGGER_SCAN_DONE); /* Kick back in case no better node is found */ - if (!candidate) { + if (!candidate) + { usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, &ev); 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 +428,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; } @@ -433,8 +465,10 @@ usteer_local_node_roam_check(struct usteer_local_node *ln, struct uevent *ev) usteer_update_time(); min_signal = usteer_snr_to_signal(&ln->node, min_signal); - list_for_each_entry(si, &ln->node.sta_info, node_list) { - if (!usteer_local_node_roam_sm_active(si, min_signal)) { + list_for_each_entry(si, &ln->node.sta_info, node_list) + { + if (!usteer_local_node_roam_sm_active(si, min_signal)) + { usteer_roam_set_state(si, ROAM_TRIGGER_IDLE, ev); continue; } @@ -464,14 +498,18 @@ usteer_local_node_snr_kick(struct usteer_local_node *ln) min_signal = usteer_snr_to_signal(&ln->node, config.min_snr); ev.threshold.ref = min_signal; - list_for_each_entry(si, &ln->node.sta_info, node_list) { + list_for_each_entry(si, &ln->node.sta_info, node_list) + { if (si->connected != STA_CONNECTED) continue; - if (si->signal >= min_signal) { + if (si->signal >= min_signal) + { si->below_min_snr = 0; continue; - } else { + } + else + { si->below_min_snr++; } @@ -501,10 +539,11 @@ usteer_local_node_load_kick(struct usteer_local_node *ln) unsigned int min_count = DIV_ROUND_UP(config.load_kick_delay, config.local_sta_update); if (!config.load_kick_enabled || !config.load_kick_threshold || - !config.load_kick_delay) + !config.load_kick_delay) return; - if (node->load < config.load_kick_threshold) { + if (node->load < config.load_kick_threshold) + { if (!ln->load_thr_count) return; @@ -515,7 +554,8 @@ usteer_local_node_load_kick(struct usteer_local_node *ln) goto out; } - if (++ln->load_thr_count <= min_count) { + if (++ln->load_thr_count <= min_count) + { if (ln->load_thr_count > 1) return; @@ -526,14 +566,16 @@ usteer_local_node_load_kick(struct usteer_local_node *ln) } ln->load_thr_count = 0; - if (node->n_assoc < config.load_kick_min_clients) { + if (node->n_assoc < config.load_kick_min_clients) + { ev.type = UEV_LOAD_KICK_MIN_CLIENTS; ev.threshold.cur = node->n_assoc; ev.threshold.ref = config.load_kick_min_clients; goto out; } - list_for_each_entry(si, &ln->node.sta_info, node_list) { + list_for_each_entry(si, &ln->node.sta_info, node_list) + { struct sta_info *tmp; if (si->connected != STA_CONNECTED) @@ -546,13 +588,15 @@ usteer_local_node_load_kick(struct usteer_local_node *ln) if (!tmp) continue; - if (is_more_kickable(kick2, si)) { + if (is_more_kickable(kick2, si)) + { kick2 = si; candidate = tmp; } } - if (!kick1) { + if (!kick1) + { ev.type = UEV_LOAD_KICK_NO_CLIENT; goto out; } @@ -578,7 +622,8 @@ usteer_local_node_perform_kick(struct usteer_local_node *ln) { struct sta_info *si; - list_for_each_entry(si, &ln->node.sta_info, node_list) { + list_for_each_entry(si, &ln->node.sta_info, node_list) + { if (!si->kick_time || si->kick_time > current_time) continue; @@ -586,8 +631,7 @@ usteer_local_node_perform_kick(struct usteer_local_node *ln) } } -void -usteer_local_node_kick(struct usteer_local_node *ln) +void usteer_local_node_kick(struct usteer_local_node *ln) { struct uevent ev = { .node_local = &ln->node, diff --git a/sta.c b/sta.c index ed7e40e..42c0576 100644 --- a/sta.c +++ b/sta.c @@ -12,9 +12,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2020 embedd.ch - * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> - * Copyright (C) 2020 John Crispin <j...@phrozen.org> + * Copyright (C) 2020 embedd.ch + * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> + * Copyright (C) 2020 John Crispin <j...@phrozen.org> */ #include "usteer.h" @@ -28,24 +28,22 @@ avl_macaddr_cmp(const void *k1, const void *k2, void *ptr) AVL_TREE(stations, avl_macaddr_cmp, false, NULL); static struct usteer_timeout_queue tq; -static void -usteer_sta_del(struct sta *sta) +static void usteer_sta_del(struct sta *sta) { MSG(DEBUG, "Delete station " MAC_ADDR_FMT "\n", - MAC_ADDR_DATA(sta->addr)); + MAC_ADDR_DATA(sta->addr)); avl_delete(&stations, &sta->avl); usteer_measurement_report_sta_cleanup(sta); free(sta); } -static void -usteer_sta_info_del(struct sta_info *si) +static void usteer_sta_info_del(struct sta_info *si) { struct sta *sta = si->sta; MSG(DEBUG, "Delete station " MAC_ADDR_FMT " entry for node %s\n", - MAC_ADDR_DATA(sta->addr), usteer_node_name(si->node)); + MAC_ADDR_DATA(sta->addr), usteer_node_name(si->node)); usteer_timeout_cancel(&tq, &si->timeout); list_del(&si->list); @@ -56,8 +54,7 @@ usteer_sta_info_del(struct sta_info *si) usteer_sta_del(sta); } -void -usteer_sta_node_cleanup(struct usteer_node *node) +void usteer_sta_node_cleanup(struct usteer_node *node) { struct sta_info *si, *tmp; @@ -68,20 +65,42 @@ usteer_sta_node_cleanup(struct usteer_node *node) usteer_sta_info_del(si); } -static void -usteer_sta_info_timeout(struct usteer_timeout_queue *q, struct usteer_timeout *t) +static void usteer_sta_info_timeout(struct usteer_timeout_queue *q, struct usteer_timeout *t) { struct sta_info *si = container_of(t, struct sta_info, timeout); usteer_sta_info_del(si); } -struct sta_info * -usteer_sta_info_get(struct sta *sta, struct usteer_node *node, bool *create) +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) { struct sta_info *si; - list_for_each_entry(si, &sta->nodes, list) { + list_for_each_entry(si, &sta->nodes, list) + { if (si->node != node) continue; @@ -95,7 +114,7 @@ usteer_sta_info_get(struct sta *sta, struct usteer_node *node, bool *create) return NULL; MSG(DEBUG, "Create station " MAC_ADDR_FMT " entry for node %s\n", - MAC_ADDR_DATA(sta->addr), usteer_node_name(node)); + MAC_ADDR_DATA(sta->addr), usteer_node_name(node)); si = calloc(1, sizeof(*si)); si->node = node; @@ -105,15 +124,15 @@ 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); return si; } - -void -usteer_sta_info_update_timeout(struct sta_info *si, int timeout) +void usteer_sta_info_update_timeout(struct sta_info *si, int timeout) { if (si->connected == STA_CONNECTED) usteer_timeout_cancel(&tq, &si->timeout); @@ -123,8 +142,7 @@ usteer_sta_info_update_timeout(struct sta_info *si, int timeout) usteer_sta_info_del(si); } -struct sta * -usteer_sta_get(const uint8_t *addr, bool create) +struct sta *usteer_sta_get(const uint8_t *addr, bool create) { struct sta *sta; @@ -154,14 +172,14 @@ void usteer_sta_disconnected(struct sta_info *si) usteer_sta_info_update_timeout(si, config.local_sta_timeout); } -void -usteer_sta_info_update(struct sta_info *si, int signal, bool avg) +void usteer_sta_info_update(struct sta_info *si, int signal, bool avg) { /* ignore probe request signal when connected */ if (si->connected == STA_CONNECTED && si->signal != NO_SIGNAL && !avg) signal = NO_SIGNAL; - if (signal != NO_SIGNAL) { + if (signal != NO_SIGNAL) + { si->signal = signal; usteer_band_steering_sta_update(si); } @@ -176,9 +194,8 @@ usteer_sta_info_update(struct sta_info *si, int signal, bool avg) usteer_sta_info_update_timeout(si, config.local_sta_timeout); } -bool -usteer_handle_sta_event(struct usteer_node *node, const uint8_t *addr, - enum usteer_event_type type, int freq, int signal) +bool usteer_handle_sta_event(struct usteer_node *node, const uint8_t *addr, + enum usteer_event_type type, int freq, int signal) { struct sta *sta; struct sta_info *si; @@ -199,11 +216,14 @@ usteer_handle_sta_event(struct usteer_node *node, const uint8_t *addr, si->stats[type].blocked_cur = 0; ret = usteer_check_request(si, type); - if (!ret) { + if (!ret) + { si->stats[type].blocked_cur++; si->stats[type].blocked_total++; si->stats[type].blocked_last_time = current_time; - } else { + } + else + { si->stats[type].blocked_cur = 0; } @@ -213,23 +233,22 @@ usteer_handle_sta_event(struct usteer_node *node, const uint8_t *addr, return ret; } -bool -usteer_sta_supports_beacon_measurement_mode(struct sta_info *si, enum usteer_beacon_measurement_mode mode) +bool usteer_sta_supports_beacon_measurement_mode(struct sta_info *si, enum usteer_beacon_measurement_mode mode) { - switch (mode) { - case BEACON_MEASUREMENT_PASSIVE: - return si->rrm & (1 << 4); - case BEACON_MEASUREMENT_ACTIVE: - return si->rrm & (1 << 5); - case BEACON_MEASUREMENT_TABLE: - return si->rrm & (1 << 6); + switch (mode) + { + case BEACON_MEASUREMENT_PASSIVE: + return si->rrm & (1 << 4); + case BEACON_MEASUREMENT_ACTIVE: + return si->rrm & (1 << 5); + case BEACON_MEASUREMENT_TABLE: + return si->rrm & (1 << 6); } return false; } -bool -usteer_sta_supports_link_measurement(struct sta_info *si) +bool usteer_sta_supports_link_measurement(struct sta_info *si) { return si->rrm & (1 << 0); } diff --git a/ubus.c b/ubus.c index 40daf74..066a3c3 100644 --- a/ubus.c +++ b/ubus.c @@ -12,9 +12,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2020 embedd.ch - * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> - * Copyright (C) 2020 John Crispin <j...@phrozen.org> + * Copyright (C) 2020 embedd.ch + * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> + * Copyright (C) 2020 John Crispin <j...@phrozen.org> */ #include <sys/types.h> @@ -41,17 +41,19 @@ blobmsg_open_table_mac(struct blob_buf *buf, uint8_t *addr) static int usteer_ubus_get_clients(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { struct sta_info *si; struct sta *sta; void *_s, *_cur_n; blob_buf_init(&b, 0); - avl_for_each_element(&stations, sta, avl) { + avl_for_each_element(&stations, sta, avl) + { _s = blobmsg_open_table_mac(&b, sta->addr); - list_for_each_entry(si, &sta->nodes, list) { + list_for_each_entry(si, &sta->nodes, list) + { _cur_n = blobmsg_open_table(&b, usteer_node_name(si->node)); blobmsg_add_u8(&b, "connected", si->connected); blobmsg_add_u32(&b, "signal", si->signal); @@ -64,7 +66,10 @@ usteer_ubus_get_clients(struct ubus_context *ctx, struct ubus_object *obj, } static struct blobmsg_policy client_arg[] = { - { .name = "address", .type = BLOBMSG_TYPE_STRING, }, + { + .name = "address", + .type = BLOBMSG_TYPE_STRING, + }, }; static void @@ -81,8 +86,8 @@ usteer_ubus_add_stats(struct sta_info_stats *stats, const char *name) static int usteer_ubus_get_client_info(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { struct sta_info *si; struct sta *sta; @@ -95,7 +100,7 @@ usteer_ubus_get_client_info(struct ubus_context *ctx, struct ubus_object *obj, if (!mac_str) return UBUS_STATUS_INVALID_ARGUMENT; - mac = (uint8_t *) ether_aton(blobmsg_data(mac_str)); + mac = (uint8_t *)ether_aton(blobmsg_data(mac_str)); if (!mac) return UBUS_STATUS_INVALID_ARGUMENT; @@ -107,7 +112,8 @@ usteer_ubus_get_client_info(struct ubus_context *ctx, struct ubus_object *obj, blobmsg_add_u8(&b, "2ghz", sta->seen_2ghz); blobmsg_add_u8(&b, "5ghz", sta->seen_5ghz); _n = blobmsg_open_table(&b, "nodes"); - list_for_each_entry(si, &sta->nodes, list) { + list_for_each_entry(si, &sta->nodes, list) + { _cur_n = blobmsg_open_table(&b, usteer_node_name(si->node)); blobmsg_add_u8(&b, "connected", si->connected); blobmsg_add_u32(&b, "signal", si->signal); @@ -124,7 +130,8 @@ usteer_ubus_get_client_info(struct ubus_context *ctx, struct ubus_object *obj, return 0; } -enum cfg_type { +enum cfg_type +{ CFG_BOOL, CFG_I32, CFG_U32, @@ -132,64 +139,71 @@ enum cfg_type { CFG_STRING_CB, }; -struct cfg_item { +struct cfg_item +{ enum cfg_type type; - union { + union + { bool *BOOL; uint32_t *U32; int32_t *I32; - struct { + struct + { void (*set)(struct blob_attr *data); void (*get)(struct blob_buf *buf); } CB; } ptr; }; -#define __config_items \ - _cfg(BOOL, syslog), \ - _cfg(U32, debug_level), \ - _cfg(BOOL, ipv6), \ - _cfg(BOOL, local_mode), \ - _cfg(U32, sta_block_timeout), \ - _cfg(U32, local_sta_timeout), \ - _cfg(U32, local_sta_update), \ - _cfg(U32, max_neighbor_reports), \ - _cfg(U32, max_retry_band), \ - _cfg(U32, seen_policy_timeout), \ - _cfg(U32, measurement_report_timeout), \ - _cfg(U32, load_balancing_threshold), \ - _cfg(U32, band_steering_threshold), \ - _cfg(U32, remote_update_interval), \ - _cfg(U32, remote_node_timeout), \ - _cfg(BOOL, assoc_steering), \ - _cfg(I32, min_connect_snr), \ - _cfg(I32, min_snr), \ - _cfg(U32, min_snr_kick_delay), \ - _cfg(U32, steer_reject_timeout), \ - _cfg(U32, roam_process_timeout), \ - _cfg(I32, roam_scan_snr), \ - _cfg(U32, roam_scan_tries), \ - _cfg(U32, roam_scan_timeout), \ - _cfg(U32, roam_scan_interval), \ - _cfg(I32, roam_trigger_snr), \ - _cfg(U32, roam_trigger_interval), \ - _cfg(U32, roam_kick_delay), \ - _cfg(U32, signal_diff_threshold), \ - _cfg(U32, initial_connect_delay), \ - _cfg(BOOL, load_kick_enabled), \ - _cfg(U32, load_kick_threshold), \ - _cfg(U32, load_kick_delay), \ - _cfg(U32, load_kick_min_clients), \ - _cfg(U32, load_kick_reason_code), \ - _cfg(U32, band_steering_interval), \ - _cfg(I32, band_steering_min_snr), \ - _cfg(U32, link_measurement_interval), \ - _cfg(ARRAY_CB, interfaces), \ - _cfg(STRING_CB, node_up_script), \ - _cfg(ARRAY_CB, event_log_types), \ - _cfg(ARRAY_CB, ssid_list) - -enum cfg_items { +#define __config_items \ + _cfg(BOOL, syslog), \ + _cfg(U32, debug_level), \ + _cfg(BOOL, ipv6), \ + _cfg(BOOL, local_mode), \ + _cfg(U32, sta_block_timeout), \ + _cfg(U32, local_sta_timeout), \ + _cfg(U32, local_sta_update), \ + _cfg(U32, max_neighbor_reports), \ + _cfg(U32, max_retry_band), \ + _cfg(U32, seen_policy_timeout), \ + _cfg(U32, measurement_report_timeout), \ + _cfg(U32, load_balancing_threshold), \ + _cfg(U32, band_steering_threshold), \ + _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), \ + _cfg(U32, steer_reject_timeout), \ + _cfg(U32, roam_process_timeout), \ + _cfg(I32, roam_scan_snr), \ + _cfg(U32, roam_scan_tries), \ + _cfg(U32, roam_scan_timeout), \ + _cfg(U32, roam_scan_interval), \ + _cfg(I32, roam_trigger_snr), \ + _cfg(U32, roam_trigger_interval), \ + _cfg(U32, roam_kick_delay), \ + _cfg(U32, signal_diff_threshold), \ + _cfg(U32, initial_connect_delay), \ + _cfg(BOOL, load_kick_enabled), \ + _cfg(U32, load_kick_threshold), \ + _cfg(U32, load_kick_delay), \ + _cfg(U32, load_kick_min_clients), \ + _cfg(U32, load_kick_reason_code), \ + _cfg(U32, band_steering_interval), \ + _cfg(I32, band_steering_min_snr), \ + _cfg(U32, link_measurement_interval), \ + _cfg(ARRAY_CB, interfaces), \ + _cfg(STRING_CB, node_up_script), \ + _cfg(ARRAY_CB, event_log_types), \ + _cfg(ARRAY_CB, ssid_list) + +enum cfg_items +{ #define _cfg(_type, _name) CFG_##_name __config_items, #undef _cfg @@ -197,7 +211,7 @@ enum cfg_items { }; static const struct blobmsg_policy config_policy[__CFG_MAX] = { -#define _cfg_policy(_type, _name) [CFG_##_name] = { .name = #_name, .type = BLOBMSG_TYPE_ ## _type } +#define _cfg_policy(_type, _name) [CFG_##_name] = {.name = #_name, .type = BLOBMSG_TYPE_##_type} #define _cfg_policy_BOOL(_name) _cfg_policy(BOOL, _name) #define _cfg_policy_U32(_name) _cfg_policy(INT32, _name) #define _cfg_policy_I32(_name) _cfg_policy(INT32, _name) @@ -212,31 +226,33 @@ static const struct cfg_item config_data[__CFG_MAX] = { #define _cfg_data_BOOL(_name) .ptr.BOOL = &config._name #define _cfg_data_U32(_name) .ptr.U32 = &config._name #define _cfg_data_I32(_name) .ptr.I32 = &config._name -#define _cfg_data_ARRAY_CB(_name) .ptr.CB = { .set = config_set_##_name, .get = config_get_##_name } -#define _cfg_data_STRING_CB(_name) .ptr.CB = { .set = config_set_##_name, .get = config_get_##_name } -#define _cfg(_type, _name) [CFG_##_name] = { .type = CFG_##_type, _cfg_data_##_type(_name) } +#define _cfg_data_ARRAY_CB(_name) .ptr.CB = {.set = config_set_##_name, .get = config_get_##_name} +#define _cfg_data_STRING_CB(_name) .ptr.CB = {.set = config_set_##_name, .get = config_get_##_name} +#define _cfg(_type, _name) [CFG_##_name] = {.type = CFG_##_type, _cfg_data_##_type(_name)} __config_items, #undef _cfg }; static int usteer_ubus_get_config(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { int i; blob_buf_init(&b, 0); - for (i = 0; i < __CFG_MAX; i++) { - switch(config_data[i].type) { + for (i = 0; i < __CFG_MAX; i++) + { + switch (config_data[i].type) + { case CFG_BOOL: blobmsg_add_u8(&b, config_policy[i].name, - *config_data[i].ptr.BOOL); + *config_data[i].ptr.BOOL); break; case CFG_I32: case CFG_U32: blobmsg_add_u32(&b, config_policy[i].name, - *config_data[i].ptr.U32); + *config_data[i].ptr.U32); break; case CFG_ARRAY_CB: case CFG_STRING_CB: @@ -250,8 +266,8 @@ usteer_ubus_get_config(struct ubus_context *ctx, struct ubus_object *obj, static int usteer_ubus_set_config(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { struct blob_attr *tb[__CFG_MAX]; int i; @@ -260,8 +276,10 @@ usteer_ubus_set_config(struct ubus_context *ctx, struct ubus_object *obj, usteer_init_defaults(); blobmsg_parse(config_policy, __CFG_MAX, tb, blob_data(msg), blob_len(msg)); - for (i = 0; i < __CFG_MAX; i++) { - switch(config_data[i].type) { + for (i = 0; i < __CFG_MAX; i++) + { + switch (config_data[i].type) + { case CFG_BOOL: if (!tb[i]) continue; @@ -307,12 +325,12 @@ void usteer_dump_node(struct blob_buf *buf, struct usteer_node *node) if (node->rrm_nr) blobmsg_add_field(buf, BLOBMSG_TYPE_ARRAY, "rrm_nr", - blobmsg_data(node->rrm_nr), - blobmsg_data_len(node->rrm_nr)); + blobmsg_data(node->rrm_nr), + blobmsg_data_len(node->rrm_nr)); if (node->node_info) blobmsg_add_field(buf, BLOBMSG_TYPE_TABLE, "node_info", - blob_data(node->node_info), - blob_len(node->node_info)); + blob_data(node->node_info), + blob_len(node->node_info)); blobmsg_close_table(buf, c); } @@ -325,15 +343,15 @@ void usteer_dump_host(struct blob_buf *buf, struct usteer_remote_host *host) blobmsg_add_u32(buf, "id", (uint32_t)(uintptr_t)host->avl.key); if (host->host_info) blobmsg_add_field(buf, BLOBMSG_TYPE_TABLE, "host_info", - blobmsg_data(host->host_info), - blobmsg_len(host->host_info)); + blobmsg_data(host->host_info), + blobmsg_len(host->host_info)); blobmsg_close_table(buf, c); } static int usteer_ubus_local_info(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { struct usteer_node *node; @@ -349,8 +367,8 @@ usteer_ubus_local_info(struct ubus_context *ctx, struct ubus_object *obj, static int usteer_ubus_remote_hosts(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { struct usteer_remote_host *host; @@ -366,8 +384,8 @@ usteer_ubus_remote_hosts(struct ubus_context *ctx, struct ubus_object *obj, static int usteer_ubus_remote_info(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { struct usteer_remote_node *rn; @@ -383,21 +401,22 @@ usteer_ubus_remote_info(struct ubus_context *ctx, struct ubus_object *obj, static const char *usteer_get_roam_sm_name(enum roam_trigger_state state) { - switch (state) { - case ROAM_TRIGGER_IDLE: - return "ROAM_TRIGGER_IDLE"; - case ROAM_TRIGGER_SCAN: - return "ROAM_TRIGGER_SCAN"; - case ROAM_TRIGGER_SCAN_DONE: - return "ROAM_TRIGGER_SCAN_DONE"; + switch (state) + { + case ROAM_TRIGGER_IDLE: + return "ROAM_TRIGGER_IDLE"; + case ROAM_TRIGGER_SCAN: + return "ROAM_TRIGGER_SCAN"; + case ROAM_TRIGGER_SCAN_DONE: + return "ROAM_TRIGGER_SCAN_DONE"; } return "N/A"; } static int usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { struct usteer_measurement_report *mr; struct usteer_node *node; @@ -406,10 +425,12 @@ usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object * blob_buf_init(&b, 0); - for_each_local_node(node) { + for_each_local_node(node) + { n = blobmsg_open_table(&b, usteer_node_name(node)); - list_for_each_entry(si, &node->sta_info, node_list) { + list_for_each_entry(si, &node->sta_info, node_list) + { if (si->connected != STA_CONNECTED) continue; @@ -423,7 +444,7 @@ usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object * blobmsg_close_table(&b, t); t = blobmsg_open_table(&b, "roam-state-machine"); - blobmsg_add_string(&b, "state",usteer_get_roam_sm_name(si->roam_state)); + blobmsg_add_string(&b, "state", usteer_get_roam_sm_name(si->roam_state)); blobmsg_add_u32(&b, "tries", si->roam_tries); blobmsg_add_u64(&b, "event", si->roam_event ? current_time - si->roam_event : 0); blobmsg_add_u32(&b, "kick-count", si->kick_count); @@ -458,7 +479,8 @@ usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object * /* Measurements */ a = blobmsg_open_array(&b, "measurements"); - list_for_each_entry(mr, &si->sta->measurements, sta_list) { + list_for_each_entry(mr, &si->sta->measurements, sta_list) + { t = blobmsg_open_table(&b, ""); blobmsg_add_string(&b, "node", usteer_node_name(mr->node)); blobmsg_add_u32(&b, "rcpi", mr->rcpi); @@ -480,30 +502,32 @@ usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object * return 0; } -enum { +enum +{ NODE_DATA_NODE, NODE_DATA_VALUES, __NODE_DATA_MAX, }; static const struct blobmsg_policy set_node_data_policy[] = { - [NODE_DATA_NODE] = { "node", BLOBMSG_TYPE_STRING }, - [NODE_DATA_VALUES] = { "data", BLOBMSG_TYPE_TABLE }, + [NODE_DATA_NODE] = {"node", BLOBMSG_TYPE_STRING}, + [NODE_DATA_VALUES] = {"data", BLOBMSG_TYPE_TABLE}, }; static const struct blobmsg_policy del_node_data_policy[] = { - [NODE_DATA_NODE] = { "node", BLOBMSG_TYPE_STRING }, - [NODE_DATA_VALUES] = { "names", BLOBMSG_TYPE_ARRAY }, + [NODE_DATA_NODE] = {"node", BLOBMSG_TYPE_STRING}, + [NODE_DATA_VALUES] = {"names", BLOBMSG_TYPE_ARRAY}, }; static void usteer_update_kvlist_data(struct kvlist *kv, struct blob_attr *data, - bool delete) + bool delete) { struct blob_attr *cur; int rem; - blobmsg_for_each_attr(cur, data, rem) { + blobmsg_for_each_attr(cur, data, rem) + { if (delete) kvlist_delete(kv, blobmsg_get_string(cur)); else @@ -520,7 +544,7 @@ usteer_update_kvlist_blob(struct blob_attr **dest, struct kvlist *kv) blob_buf_init(&b, 0); kvlist_for_each(kv, name, val) blobmsg_add_field(&b, blobmsg_type(val), name, - blobmsg_data(val), blobmsg_len(val)); + blobmsg_data(val), blobmsg_len(val)); val = b.head; if (!blobmsg_len(val)) @@ -531,8 +555,8 @@ usteer_update_kvlist_blob(struct blob_attr **dest, struct kvlist *kv) static int usteer_ubus_update_node_data(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { const struct blobmsg_policy *policy; struct blob_attr *tb[__NODE_DATA_MAX]; @@ -550,10 +574,11 @@ usteer_ubus_update_node_data(struct ubus_context *ctx, struct ubus_object *obj, name = blobmsg_get_string(tb[NODE_DATA_NODE]); val = tb[NODE_DATA_VALUES]; - if (delete && blobmsg_check_array(val, BLOBMSG_TYPE_STRING) < 0) + if (delete &&blobmsg_check_array(val, BLOBMSG_TYPE_STRING) < 0) return UBUS_STATUS_INVALID_ARGUMENT; - if (strcmp(name, "*") != 0) { + if (strcmp(name, "*") != 0) + { ln = avl_find_element(&local_nodes, name, ln, node.avl); if (!ln) return UBUS_STATUS_NOT_FOUND; @@ -598,9 +623,9 @@ static bool usteer_add_nr_entry(struct usteer_node *ln, struct usteer_node *node) { struct blobmsg_policy policy[3] = { - { .type = BLOBMSG_TYPE_STRING }, - { .type = BLOBMSG_TYPE_STRING }, - { .type = BLOBMSG_TYPE_STRING }, + {.type = BLOBMSG_TYPE_STRING}, + {.type = BLOBMSG_TYPE_STRING}, + {.type = BLOBMSG_TYPE_STRING}, }; struct blob_attr *tb[3]; @@ -614,15 +639,15 @@ usteer_add_nr_entry(struct usteer_node *ln, struct usteer_node *node) return false; blobmsg_parse_array(policy, ARRAY_SIZE(tb), tb, - blobmsg_data(node->rrm_nr), - blobmsg_data_len(node->rrm_nr)); + blobmsg_data(node->rrm_nr), + blobmsg_data_len(node->rrm_nr)); if (!tb[2]) return false; blobmsg_add_field(&b, BLOBMSG_TYPE_STRING, "", - blobmsg_data(tb[2]), - blobmsg_data_len(tb[2])); - + blobmsg_data(tb[2]), + blobmsg_data_len(tb[2])); + return true; } @@ -644,7 +669,8 @@ usteer_ubus_disassoc_add_neighbors(struct sta_info *si) void *c; c = blobmsg_open_array(&b, "neighbors"); - for_each_local_node(node) { + for_each_local_node(node) + { if (i >= config.max_neighbor_reports) break; if (si->node == node) @@ -653,9 +679,11 @@ usteer_ubus_disassoc_add_neighbors(struct sta_info *si) i++; } - while (i < config.max_neighbor_reports) { + while (i < config.max_neighbor_reports) + { node = usteer_node_get_next_neighbor(si->node, last_remote_neighbor); - if (!node) { + if (!node) + { /* No more nodes available */ break; } @@ -668,11 +696,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 +709,32 @@ 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) { + 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 { + } + 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,21 +742,31 @@ 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) { + for_each_local_node(node) + { if (!usteer_band_steering_is_target(ln, node)) continue; - + // TODO: Funktioniert nicht, Targets werden nicht korrekt ausgewiesen. 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) @@ -733,7 +787,8 @@ int usteer_ubus_trigger_client_scan(struct sta_info *si) { struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node); - if (!usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE)) { + if (!usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE)) + { MSG(DEBUG, "STA does not support beacon measurement sta=" MAC_ADDR_FMT "\n", MAC_ADDR_DATA(si->sta->addr)); return 0; } diff --git a/usteer.h b/usteer.h index f692fb8..26eeff0 100644 --- a/usteer.h +++ b/usteer.h @@ -12,9 +12,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * - * Copyright (C) 2020 embedd.ch - * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> - * Copyright (C) 2020 John Crispin <j...@phrozen.org> + * Copyright (C) 2020 embedd.ch + * Copyright (C) 2020 Felix Fietkau <n...@nbd.name> + * Copyright (C) 2020 John Crispin <j...@phrozen.org> */ #ifndef __APMGR_H @@ -31,36 +31,40 @@ #define NO_SIGNAL 0xff -#define __STR(x) #x -#define _STR(x) __STR(x) +#define __STR(x) #x +#define _STR(x) __STR(x) -#define APMGR_V6_MCAST_GROUP "ff02::4150" +#define APMGR_V6_MCAST_GROUP "ff02::4150" -#define APMGR_PORT 16720 /* AP */ -#define APMGR_PORT_STR _STR(APMGR_PORT) -#define APMGR_BUFLEN (64 * 1024) +#define APMGR_PORT 16720 /* AP */ +#define APMGR_PORT_STR _STR(APMGR_PORT) +#define APMGR_BUFLEN (64 * 1024) -#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) -enum usteer_event_type { +enum usteer_event_type +{ EVENT_TYPE_PROBE, EVENT_TYPE_ASSOC, EVENT_TYPE_AUTH, __EVENT_TYPE_MAX, }; -enum usteer_node_type { +enum usteer_node_type +{ NODE_TYPE_LOCAL, NODE_TYPE_REMOTE, }; -enum usteer_sta_connection_state { +enum usteer_sta_connection_state +{ STA_NOT_CONNECTED = 0, STA_CONNECTED = 1, STA_DISCONNECTED = 2, }; -enum usteer_beacon_measurement_mode { +enum usteer_beacon_measurement_mode +{ BEACON_MEASUREMENT_PASSIVE = 0, BEACON_MEASUREMENT_ACTIVE = 1, BEACON_MEASUREMENT_TABLE = 2, @@ -70,7 +74,8 @@ struct sta_info; struct usteer_local_node; struct usteer_remote_host; -struct usteer_node { +struct usteer_node +{ struct avl_node avl; struct list_head sta_info; struct list_head measurements; @@ -91,7 +96,8 @@ struct usteer_node { int max_assoc; int load; - struct { + struct + { int source; int target; } roam_events; @@ -99,14 +105,16 @@ struct usteer_node { uint64_t created; }; -struct usteer_scan_request { +struct usteer_scan_request +{ int n_freq; int *freq; bool passive; }; -struct usteer_scan_result { +struct usteer_scan_result +{ uint8_t bssid[6]; char ssid[33]; @@ -114,7 +122,8 @@ struct usteer_scan_result { int signal; }; -struct usteer_survey_data { +struct usteer_survey_data +{ uint16_t freq; int8_t noise; @@ -122,14 +131,16 @@ struct usteer_survey_data { uint64_t time_busy; }; -struct usteer_freq_data { +struct usteer_freq_data +{ uint16_t freq; uint8_t txpower; bool dfs; }; -struct usteer_node_handler { +struct usteer_node_handler +{ struct list_head list; void (*init_node)(struct usteer_node *); @@ -137,14 +148,15 @@ struct usteer_node_handler { void (*update_node)(struct usteer_node *); void (*update_sta)(struct usteer_node *, struct sta_info *); void (*get_survey)(struct usteer_node *, void *, - void (*cb)(void *priv, struct usteer_survey_data *d)); + void (*cb)(void *priv, struct usteer_survey_data *d)); void (*get_freqlist)(struct usteer_node *, void *, - void (*cb)(void *priv, struct usteer_freq_data *f)); + void (*cb)(void *priv, struct usteer_freq_data *f)); int (*scan)(struct usteer_node *, struct usteer_scan_request *, - void *, void (*cb)(void *priv, struct usteer_scan_result *r)); + void *, void (*cb)(void *priv, struct usteer_scan_result *r)); }; -struct usteer_config { +struct usteer_config +{ bool syslog; uint32_t debug_level; @@ -170,6 +182,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 +206,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; @@ -208,7 +224,8 @@ struct usteer_config { struct blob_attr *ssid_list; }; -struct usteer_bss_tm_query { +struct usteer_bss_tm_query +{ struct list_head list; /* Can't use sta_info here, as the STA might already be deleted */ @@ -216,20 +233,23 @@ struct usteer_bss_tm_query { uint8_t dialog_token; }; -struct sta_info_stats { +struct sta_info_stats +{ uint32_t requests; uint32_t blocked_cur; uint32_t blocked_total; uint32_t blocked_last_time; }; -enum roam_trigger_state { +enum roam_trigger_state +{ ROAM_TRIGGER_IDLE, ROAM_TRIGGER_SCAN, ROAM_TRIGGER_SCAN_DONE, }; -struct sta_info { +struct sta_info +{ struct list_head list; struct list_head node_list; @@ -255,15 +275,18 @@ 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; - struct { + struct + { uint8_t status_code; uint64_t timestamp; } bss_transition_response; - struct { + struct + { bool below_snr; } band_steering; @@ -277,7 +300,8 @@ struct sta_info { uint8_t connected : 2; }; -struct sta { +struct sta +{ struct avl_node avl; struct list_head nodes; struct list_head measurements; @@ -285,10 +309,13 @@ struct sta { uint8_t seen_2ghz : 1; uint8_t seen_5ghz : 1; + bool aggressive; + uint8_t addr[6]; }; -struct usteer_measurement_report { +struct usteer_measurement_report +{ struct usteer_timeout timeout; struct list_head list; @@ -311,13 +338,13 @@ extern struct list_head node_handlers; extern struct avl_tree stations; extern struct ubus_object usteer_obj; extern uint64_t current_time; -extern const char * const event_types[__EVENT_TYPE_MAX]; +extern const char *const event_types[__EVENT_TYPE_MAX]; extern struct blob_attr *host_info_blob; void usteer_update_time(void); void usteer_init_defaults(void); bool usteer_handle_sta_event(struct usteer_node *node, const uint8_t *addr, - enum usteer_event_type type, int freq, int signal); + enum usteer_event_type type, int freq, int signal); int usteer_snr_to_signal(struct usteer_node *node, int snr); @@ -336,13 +363,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 +409,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); @@ -390,7 +426,7 @@ void usteer_dump_host(struct blob_buf *buf, struct usteer_remote_host *host); int usteer_measurement_get_rssi(struct usteer_measurement_report *report); -struct usteer_measurement_report * usteer_measurement_report_get(struct sta *sta, struct usteer_node *node, bool create); +struct usteer_measurement_report *usteer_measurement_report_get(struct sta *sta, struct usteer_node *node, bool create); void usteer_measurement_report_node_cleanup(struct usteer_node *node); void usteer_measurement_report_sta_cleanup(struct sta *sta); void usteer_measurement_report_del(struct usteer_measurement_report *mr); @@ -398,6 +434,5 @@ void usteer_measurement_report_del(struct usteer_measurement_report *mr); struct usteer_measurement_report * usteer_measurement_report_add(struct sta *sta, struct usteer_node *node, uint8_t rcpi, uint8_t rsni, uint64_t timestamp); - int usteer_ubus_trigger_link_measurement(struct sta_info *si); #endif -- 2.39.5 _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel