From b42193f518a6de73fd0be59e443637146a60ca45 Mon Sep 17 00:00:00 2001 From: Ian Clowes Date: Mon, 31 Jan 2022 11:40:55 +0000 Subject: [PATCH] kicking: improve kicking algorithm - Tweak disassociate / kick NR code to reduce build overhead - Add set_hostapd_nrdynamic == 2 to build of AP local station NR from what current clients hear elsewhere - Tighten up hex string length usage for strncpy(), etc [cleanup commit message] Signed-off-by: Nick Hainke --- src/include/datastorage.h | 7 +- src/include/ubus.h | 2 + src/storage/datastorage.c | 162 +++++++++++++++++++++++--------------- src/test/test_storage.c | 38 +++------ src/utils/dawn_uci.c | 2 + src/utils/msghandler.c | 8 ++ src/utils/ubus.c | 123 +++++++++++++++++++++-------- 7 files changed, 217 insertions(+), 125 deletions(-) diff --git a/src/include/datastorage.h b/src/include/datastorage.h index 7e0113f..8bb84c7 100644 --- a/src/include/datastorage.h +++ b/src/include/datastorage.h @@ -74,6 +74,7 @@ struct probe_metric_s { int min_number_to_kick; // kick_clients() int chan_util_avg_period; int set_hostapd_nr; + int disassoc_nr_length; // FIXME: Is there a standard for how many? Use 6 as default to suit iOS. int kicking; int kicking_threshold; int duration; @@ -192,7 +193,7 @@ typedef struct hostapd_notify_entry_s { } hostapd_notify_entry; // ---------------- Defines ---------------- - +// FIXME: Is this enough of the NR to allow 802.11 operations to work? Should we go for max possible length of 256 * 2 + 1 #define NEIGHBOR_REPORT_LEN 200 /* Neighbor report string elements * [Elemen ID|1][LENGTH|1][BSSID|6][BSSID INFORMATION|4][Operating Class|1][Channel Number|1][PHY Type|1][Operational Subelements] @@ -259,7 +260,7 @@ typedef struct ap_s { time_t time; // remove_old...entries // (2) uint32_t station_count; // compare_station_count() <- better_ap_available() // (1) uint8_t ssid[SSID_MAX_LEN + 1]; // compare_sid() < -better_ap_available() // (1) - char neighbor_report[NEIGHBOR_REPORT_LEN]; // (1) // TODO: Check whether we should store and AP one or generate on fly for client + char neighbor_report[NEIGHBOR_REPORT_LEN + 1]; // (1) // This is the self-NR of the AP uint32_t op_class; // ubus_send_beacon_report() // (1) uint32_t channel; // ubus_send_beacon_report() // (1) //uint32_t collision_domain; // TODO: ap_get_collision_count() never evaluated? @@ -345,7 +346,7 @@ void send_beacon_requests(ap *a, int id); /* Utils */ struct kicking_nr { - char nr[NEIGHBOR_REPORT_LEN]; + ap *nr_ap; int score; struct kicking_nr *next; }; diff --git a/src/include/ubus.h b/src/include/ubus.h index 21f5471..edba7b8 100644 --- a/src/include/ubus.h +++ b/src/include/ubus.h @@ -60,6 +60,8 @@ void del_client_all_interfaces(const struct dawn_mac client_addr, uint32_t reaso */ void update_hostapd_sockets(struct uloop_timeout *t); +void ubus_set_nr_from_clients(struct kicking_nr* ap_list); + void ubus_send_beacon_request(client *c, ap *a, int id); void uloop_add_data_cbs(); diff --git a/src/storage/datastorage.c b/src/storage/datastorage.c index f24a035..c8d8db3 100644 --- a/src/storage/datastorage.c +++ b/src/storage/datastorage.c @@ -277,68 +277,88 @@ static int compare_station_count(ap* ap_entry_own, ap* ap_entry_to_compare, stru return 0; } -static struct kicking_nr *find_position(struct kicking_nr *nrlist, int score) { - struct kicking_nr *ret = NULL; - - dawnlog_debug_func("Entering..."); - - while (nrlist && nrlist->score < score) { - ret = nrlist; - nrlist = nrlist->next; - } - return ret; -} - static void remove_kicking_nr_list(struct kicking_nr *nr_list) { - struct kicking_nr *n; - dawnlog_debug_func("Entering..."); while(nr_list) { - n = nr_list->next; - dawn_free(nr_list); - nr_list = n; - } -} - -static struct kicking_nr *prune_kicking_nr_list(struct kicking_nr *nr_list, int min_score) { - struct kicking_nr *next; - - dawnlog_debug_func("Entering..."); - - while (nr_list && nr_list->score <= min_score) { - next = nr_list->next; + struct kicking_nr* next = nr_list->next; dawn_free(nr_list); nr_list = next; } - return nr_list; } -static struct kicking_nr *insert_kicking_nr(struct kicking_nr *head, char *nr, int score, bool prune) { - struct kicking_nr *new_entry, *pos; - +#if 0 +static void prune_kicking_nr_list(struct kicking_nr **nr_list, int min_score) { dawnlog_debug_func("Entering..."); - if (prune) - head = prune_kicking_nr_list(head, score - dawn_metric.kicking_threshold); - - // we are giving no error information here (not really critical) - if (!(new_entry = dawn_malloc(sizeof (struct kicking_nr)))) - return head; - - strncpy(new_entry->nr, nr, NEIGHBOR_REPORT_LEN); - new_entry->score = score; - pos = find_position(head, score); - if (pos) { - new_entry->next = pos->next; - pos -> next = new_entry; - } else { - new_entry->next = head; - head = new_entry; + while (*nr_list) { + if ((*nr_list)->score <= min_score) + { + struct kicking_nr* next = (*nr_list)->next; + dawn_free(*nr_list); + *nr_list = next; + } + else + { + nr_list = &((*nr_list)->next); + } } - return head; + + return; +} +#endif + +static void insert_kicking_nr_by_bssid(struct kicking_nr** nrlist, ap* nr_ap) { + dawnlog_debug_func("Entering..."); + dawn_mutex_require(&ap_array_mutex); + + // Look for the proposed BSSID in the current list + while (*nrlist && mac_compare_bb((*nrlist)->nr_ap->bssid_addr, nr_ap->bssid_addr) < 0) { + nrlist = &((*nrlist)->next); + } + + // If it isn't there then add it + if (!*nrlist || mac_compare_bb((*nrlist)->nr_ap->bssid_addr, nr_ap->bssid_addr) != 0) + { + // we are giving no error information here (not really critical) + struct kicking_nr* new_entry = dawn_malloc(sizeof(struct kicking_nr)); + + if (new_entry) + { + new_entry->nr_ap = nr_ap; + new_entry->score = 0; + + new_entry->next = *nrlist; + *nrlist = new_entry; + } + } + + return; } +static void insert_kicking_nr_by_score(struct kicking_nr** nrlist, ap* nr_ap, int score) { + dawnlog_debug_func("Entering..."); + dawn_mutex_require(&ap_array_mutex); + + // we are giving no error information here (not really critical) + struct kicking_nr* new_entry = dawn_malloc(sizeof(struct kicking_nr)); + + if (!new_entry) + return; + + new_entry->nr_ap = nr_ap; + new_entry->score = score; + + // Order entries high-low score so we can read first N highest values + while (*nrlist && (*nrlist)->score > score) { + nrlist = &((*nrlist)->next); + } + + new_entry->next = *nrlist; + *nrlist = new_entry; + + return; +} int better_ap_available(ap *kicking_ap, struct dawn_mac client_mac, struct kicking_nr **neighbor_report) { dawnlog_debug_func("Entering..."); @@ -430,12 +450,14 @@ int better_ap_available(ap *kicking_ap, struct dawn_mac client_mac, struct kicki else { dawnlog_trace("Better AP after full evaluation - add to NR (%s pruning)\n", ap_outcome == 2 ? "with" : "without"); - // Pointer is NULL if we're only finding a better AP without actually using it + // NR is NULL if we're only testing for a better AP without actually using it if (neighbor_report != NULL) { - // Test this_kick_outcome for pruning - *neighbor_report = insert_kicking_nr(*neighbor_report, candidate_ap->neighbor_report, - score_to_compare, ap_outcome == 2); + // FIXME: Do we need to prune this list as we build it? trying new approach to send N best entries to hostapd + // if (ap_outcome == 2) + // prune_kicking_nr_list(neighbor_report, score_to_compare - dawn_metric.kicking_threshold); + + insert_kicking_nr_by_score(neighbor_report, candidate_ap, score_to_compare); } // If we find a single candidate then we will be kicking @@ -471,6 +493,9 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) { int kicked_clients = 0; + // Keep a list of nearby APs to update local AP Neighbor Report from + struct kicking_nr* ap_nr_list = NULL; + dawnlog_info("AP BSSID " MACSTR ": Looking for candidates to kick\n", MAC2STR(kicking_ap->bssid_addr.u8)); // Seach for BSSID @@ -478,7 +503,7 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) { // Go through clients while (j != NULL && mac_is_equal_bb(j->bssid_addr, kicking_ap->bssid_addr)) { - struct kicking_nr *neighbor_report = NULL; + struct kicking_nr *kick_nr_list = NULL; int do_kick = 0; @@ -486,7 +511,14 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) { dawnlog_info("Station " MACSTR ": Suppressing check due to MAC list entry\n", MAC2STR(j->client_addr.u8)); } else { - do_kick = better_ap_available(kicking_ap, j->client_addr, &neighbor_report); + do_kick = better_ap_available(kicking_ap, j->client_addr, &kick_nr_list); + } + + // If we found any candidates (even if too low to kick to) add the highest scoring one to local AP NR set + if (dawn_metric.set_hostapd_nr == 2 && kick_nr_list) + { + dawnlog_trace("Adding " MACSTR "as local NR entry candidate\n", MAC2STR(kick_nr_list->nr_ap->bssid_addr.u8)); + insert_kicking_nr_by_bssid(&ap_nr_list, kick_nr_list->nr_ap); } // better ap available @@ -527,8 +559,8 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) { if (dawnlog_showing(DAWNLOG_INFO)) { - for (struct kicking_nr* n = neighbor_report; n; n = n->next) - dawnlog_info("Kicking NR entry: " NR_MACSTR ", score=%d\n", NR_MAC2STR(n->nr), n->score); + for (struct kicking_nr* n = kick_nr_list; n; n = n->next) + dawnlog_info("Kicking NR entry: " NR_MACSTR ", score=%d\n", NR_MAC2STR(n->nr_ap->neighbor_report), n->score); } // here we should send a messsage to set the probe.count for all aps to the min that there is no delay between switching @@ -538,7 +570,7 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) { // don't deauth station? <- deauth is better! // maybe we can use handovers... //del_client_interface(id, client_array[j].client_addr, NO_MORE_STAS, 1, 1000); - int sync_kick = wnm_disassoc_imminent(id, j->client_addr, neighbor_report, 12); + int sync_kick = wnm_disassoc_imminent(id, j->client_addr, kick_nr_list, 12); // Synchronous kick is a test harness feature to indicate arrays have been updated, so don't change further if (sync_kick) @@ -572,12 +604,18 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) { j->kick_count = 0; } - remove_kicking_nr_list(neighbor_report); - neighbor_report = NULL; + remove_kicking_nr_list(kick_nr_list); + kick_nr_list = NULL; j = j->next_entry_bc; } + if (dawn_metric.set_hostapd_nr == 2) + ubus_set_nr_from_clients(ap_nr_list); + + remove_kicking_nr_list(ap_nr_list); + ap_nr_list = NULL; + dawnlog_trace("KICKING: --------- AP Finished ---------\n"); dawn_mutex_unlock(&ap_array_mutex); @@ -1318,9 +1356,9 @@ static void print_ap_entry(int level, ap *entry) { { dawnlog_info("ssid: %s, bssid_addr: " MACSTR ", freq: %d, ht: %d, vht: %d, chan_utilz: %d, neighbor_report: %s\n", entry->ssid, MAC2STR(entry->bssid_addr.u8), entry->freq, entry->ht_support, entry->vht_support, entry->channel_utilization, - //entry->collision_domain, ap_get_collision_count(entry->collision_domain), // TODO: Fix format string if readding - entry->neighbor_report - ); + //entry->collision_domain, ap_get_collision_count(entry->collision_domain), // TODO: Fix format string if readding + entry->neighbor_report + ); } } diff --git a/src/test/test_storage.c b/src/test/test_storage.c index c753d91..4f1bfaa 100644 --- a/src/test/test_storage.c +++ b/src/test/test_storage.c @@ -42,7 +42,7 @@ int ret = 0; if (neighbor_list != NULL) { - // Fake a client being disassociated and then rejoining on the recommended neoghbor + // Fake a client being disassociated and then rejoining on the recommended neighbor client *mc = client_array_get_client(client_addr); mc = client_array_delete(mc, true); // Originally, there was only one AP, not a list of them; that AP is at the tail of the list @@ -50,9 +50,9 @@ int ret = 0; while (neighbor_list && neighbor_list->next) neighbor_list = neighbor_list->next; for (int n=0; n < ETH_ALEN; n++) - sscanf(neighbor_list->nr + n*2, "%2hhx", mc->bssid_addr.u8 + n); + sscanf(neighbor_list->nr_ap->neighbor_report + n*2, "%2hhx", mc->bssid_addr.u8 + n); insert_client_to_array(mc, 0); - printf("BSS TRANSITION TO " NR_MACSTR "\n", NR_MAC2STR(neighbor_list->nr)); + printf("BSS TRANSITION TO " NR_MACSTR "\n", NR_MAC2STR(neighbor_list->nr_ap->neighbor_report)); // Tell caller not to change the arrays any further ret = 1; @@ -588,6 +588,7 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) dawn_metric.min_number_to_kick = 3; dawn_metric.chan_util_avg_period = 3; dawn_metric.set_hostapd_nr = 1; + dawn_metric.disassoc_nr_length = 6; dawn_metric.kicking = 0; dawn_metric.duration = 0; dawn_metric.rrm_mode_mask = WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE | @@ -624,6 +625,7 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) else if (!strncmp(fn, "min_number_to_kick=", 19)) load_int(&dawn_metric.min_number_to_kick, fn + 19); else if (!strncmp(fn, "chan_util_avg_period=", 21)) load_int(&dawn_metric.chan_util_avg_period, fn + 21); else if (!strncmp(fn, "set_hostapd_nr=", 15)) load_int(&dawn_metric.set_hostapd_nr, fn + 15); + else if (!strncmp(fn, "disassoc_nr_length=", 19)) load_int(&dawn_metric.disassoc_nr_length, fn + 19); else if (!strncmp(fn, "kicking=", 8)) load_int(&dawn_metric.kicking, fn + 8); else if (!strncmp(fn, "duration=", 9)) load_int(&dawn_metric.duration, fn + 9); else if (!strncmp(fn, "rrm_mode=", 9)) dawn_metric.rrm_mode_mask = parse_rrm_mode(dawn_metric.rrm_mode_order, fn + 9); @@ -873,44 +875,26 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) } else if (strcmp(*argv, "better_ap_available") == 0) { - args_required = 4; + args_required = 5; if (curr_arg + args_required <= argc) { struct dawn_mac bssid_mac; struct dawn_mac client_mac; uint32_t autokick; + uint32_t with_nr; int tr = 9999; // Tamper evident value hwaddr_aton(argv[1], bssid_mac.u8); hwaddr_aton(argv[2], client_mac.u8); load_u32(&autokick, argv[3]); + load_u32(&with_nr, argv[4]); - char nb[NEIGHBOR_REPORT_LEN] = "TAMPER EVIDENT NEIGHBOR REPORT INITIALISATION STRING"; - struct kicking_nr neighbor = {0}; - struct kicking_nr *neighbor_list = &neighbor; + struct kicking_nr *neighbor_list = NULL; - if (curr_arg + 5 <= argc) - { - args_required = 5; + tr = better_ap_available(ap_array_get_ap(bssid_mac), client_mac, with_nr ? &neighbor_list : NULL); - if (strcmp(argv[4], "\0") == 0) // Provide a way to set an empty string - { - strcpy(nb, ""); - } - else - { - strcpy(nb, argv[4]); - } - strncpy(neighbor.nr, nb, NEIGHBOR_REPORT_LEN); - tr = better_ap_available(ap_array_get_ap(bssid_mac), client_mac, &neighbor_list); - } - else - { - tr = better_ap_available(ap_array_get_ap(bssid_mac), client_mac, NULL); - } - - printf("better_ap_available returned %d (with neighbour report %s)\n", tr, nb); + printf("better_ap_available returned %d (with neighbour report %s)\n", tr, neighbor_list ? neighbor_list->nr_ap->neighbor_report : "NONE"); } } else if (strcmp(*argv, "eval_probe_metric") == 0) diff --git a/src/utils/dawn_uci.c b/src/utils/dawn_uci.c index 70e18c0..2a78947 100644 --- a/src/utils/dawn_uci.c +++ b/src/utils/dawn_uci.c @@ -241,6 +241,7 @@ struct probe_metric_s uci_get_dawn_metric() { .eval_probe_req = 0, .min_number_to_kick = 3, .set_hostapd_nr = 1, + .disassoc_nr_length = 6, .max_station_diff = 1, .bandwidth_threshold = 6, .use_driver_recog = 1, @@ -295,6 +296,7 @@ struct probe_metric_s uci_get_dawn_metric() { DAWN_SET_CONFIG_INT(ret, global_s, eval_probe_req); DAWN_SET_CONFIG_INT(ret, global_s, min_number_to_kick); DAWN_SET_CONFIG_INT(ret, global_s, set_hostapd_nr); + DAWN_SET_CONFIG_INT(ret, global_s, disassoc_nr_length); DAWN_SET_CONFIG_INT(ret, global_s, max_station_diff); DAWN_SET_CONFIG_INT(ret, global_s, bandwidth_threshold); DAWN_SET_CONFIG_INT(ret, global_s, use_driver_recog); diff --git a/src/utils/msghandler.c b/src/utils/msghandler.c index 16b07e3..8e84268 100644 --- a/src/utils/msghandler.c +++ b/src/utils/msghandler.c @@ -566,8 +566,16 @@ int parse_to_clients(struct blob_attr* msg) { ap_entry->op_class = ap_entry->channel = 0; if (tb[CLIENT_TABLE_NEIGHBOR]) { + // Copy part of report that we have space for, and discard remainder strncpy(ap_entry->neighbor_report, blobmsg_get_string(tb[CLIENT_TABLE_NEIGHBOR]), NEIGHBOR_REPORT_LEN); + ap_entry->neighbor_report[NEIGHBOR_REPORT_LEN] = '\0'; sscanf(ap_entry->neighbor_report + NR_OP_CLASS, "%2x%2x", &ap_entry->op_class, &ap_entry->channel); + + int nrl = strlen(ap_entry->neighbor_report); + if (nrl == NEIGHBOR_REPORT_LEN) + dawnlog_warning("Neighbor Report possibly truncated - hex length of %d\n", nrl); + else + dawnlog_debug("Neighbor Report - hex length of %d\n", nrl); } else { ap_entry->neighbor_report[0] = '\0'; diff --git a/src/utils/ubus.c b/src/utils/ubus.c index a142d94..1844b54 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -94,7 +94,7 @@ struct hostapd_sock_entry { /* [Elemen ID|1][LENGTH|1][BSSID|6][BSSID INFORMATION|4][Operating Class|1][Channel Number|1][PHY Type|1][Operational Subelements] */ - char neighbor_report[NEIGHBOR_REPORT_LEN]; + char neighbor_report[NEIGHBOR_REPORT_LEN + 1]; struct ubus_subscriber subscriber; struct ubus_event_handler wait_handler; @@ -947,7 +947,7 @@ void update_clients(struct uloop_timeout *t) { dawnlog_debug_func("Entering..."); ubus_get_clients(); - if(dawn_metric.set_hostapd_nr) + if(dawn_metric.set_hostapd_nr == 1) ubus_set_nr(); // maybe to much?! don't set timer again... uloop_timeout_set(&client_timer, timeout_config.update_client * 1000); @@ -1084,6 +1084,7 @@ void ubus_set_nr(){ struct hostapd_sock_entry *sub; int timeout = 1; + // FIXME: Should we then call ubus_get_nr() to cache it locally? list_for_each_entry(sub, &hostapd_sock_list, list) { if (sub->subscribed) { @@ -1160,10 +1161,14 @@ int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct blobmsg_add_u8(&b, "abridged", 1); // prefer aps in neighborlist void* nbs = blobmsg_open_array(&b, "neighbors"); - while(neighbor_list != NULL) { - dawnlog_info("BSS TRANSITION NEIGHBOR " NR_MACSTR ", Score=%d\n", NR_MAC2STR(neighbor_list->nr), neighbor_list->score); - blobmsg_add_string(&b, NULL, neighbor_list->nr); + + // Add the first N AP, where list order id high->low score + int neighbors_added = 0; + while(neighbors_added < dawn_metric.disassoc_nr_length && neighbor_list != NULL) { + dawnlog_info("BSS TRANSITION NEIGHBOR " NR_MACSTR ", Score=%d\n", NR_MAC2STR(neighbor_list->nr_ap->neighbor_report), neighbor_list->score); + blobmsg_add_string(&b, NULL, neighbor_list->nr_ap->neighbor_report); neighbor_list = neighbor_list->next; + neighbors_added++; } blobmsg_close_array(&b, nbs); @@ -1708,6 +1713,7 @@ int uci_send_via_network() blobmsg_add_u32(&b, "min_number_to_kick", dawn_metric.min_number_to_kick); blobmsg_add_u32(&b, "chan_util_avg_period", dawn_metric.chan_util_avg_period); blobmsg_add_u32(&b, "set_hostapd_nr", dawn_metric.set_hostapd_nr); + blobmsg_add_u32(&b, "disassoc_nr_length", dawn_metric.disassoc_nr_length); blobmsg_add_u32(&b, "duration", dawn_metric.duration); blobmsg_add_string(&b, "rrm_mode", get_rrm_mode_string(dawn_metric.rrm_mode_order)); band_table = blobmsg_open_table(&b, "band_metrics"); @@ -1966,7 +1972,7 @@ int build_network_overview(struct blob_buf *b) { char *nr; nr = blobmsg_alloc_string_buffer(b, "neighbor_report", NEIGHBOR_REPORT_LEN); - sprintf(nr, "%s", m->neighbor_report); // TODO: Why not strcpy() + strcpy(nr, m->neighbor_report); blobmsg_add_string_buffer(b); char *iface; @@ -2053,45 +2059,96 @@ static int mac_is_in_entry_list(const struct dawn_mac mac, const struct mac_entr return 0; } -// TODO: Does all APs constitute neighbor report? How about using list of AP connected -// clients can also see (from probe_set) to give more (physically) local set? // Here, we let the user configure a list of preferred APs that clients can see, and then // add the rest of all APs. hostapd inserts this list backwards, so we must start with // the regular APs, then add the preferred ones, which are already ordered backwards. -int ap_get_nr(struct blob_buf *b_local, struct dawn_mac own_bssid_addr, const char *ssid) { - - ap *i, *own_ap; - struct mac_entry_s *preferred_list, *n; - +int ap_get_nr(struct blob_buf* b_local, struct dawn_mac own_bssid_addr, const char* ssid) { dawnlog_debug_func("Entering..."); - void* nbs = blobmsg_open_array(b_local, "list"); + int ret = 0; + + dawn_mutex_lock(&ap_array_mutex); dawn_mutex_require(&ap_array_mutex); - own_ap = ap_array_get_ap(own_bssid_addr); + ap* own_ap = ap_array_get_ap(own_bssid_addr); + if (!own_ap) - return -1; - for (int band = 0; band < __DAWN_BAND_MAX; band++) { - preferred_list = dawn_metric.neighbors[band]; - if (own_ap->freq <= max_band_freq[band]) - break; + ret = -1; + else + { + void* nbs = blobmsg_open_array(b_local, "list"); + + struct mac_entry_s* preferred_list = NULL; + for (int band = 0; band < __DAWN_BAND_MAX; band++) { + preferred_list = dawn_metric.neighbors[band]; + if (own_ap->freq <= max_band_freq[band]) + break; + } + + for (ap* i = ap_set; i != NULL; i = i->next_ap) { + if (i != own_ap && !strncmp((char*)i->ssid, ssid, SSID_MAX_LEN) && + !mac_is_in_entry_list(i->bssid_addr, preferred_list)) + { + blobmsg_add_nr(b_local, i); + } + } + + for (struct mac_entry_s* n = preferred_list; n; n = n->next_mac) { + dawn_mutex_require(&ap_array_mutex); + ap* j = ap_array_get_ap(n->mac); + if (j) + blobmsg_add_nr(b_local, j); + } + + blobmsg_close_array(b_local, nbs); } - for (i = ap_set; i != NULL; i = i->next_ap) { - if (i != own_ap && !strncmp((char *)i->ssid, ssid, SSID_MAX_LEN) && - !mac_is_in_entry_list(i->bssid_addr, preferred_list)) - { - blobmsg_add_nr(b_local, i); + dawn_mutex_unlock(&ap_array_mutex); + + return ret; +} + +// Use list of specifc AP to create local NR +// TODO: Do we need to do the reverse insert thing mentioned above? +void ubus_set_nr_from_clients(struct kicking_nr *ap_list) { + dawnlog_debug_func("Entering..."); + + struct hostapd_sock_entry* sub; + int timeout = 1; + + int has_content = 0; + + list_for_each_entry(sub, &hostapd_sock_list, list) + { + if (sub->subscribed) { + struct blob_buf b = { 0 }; + blob_buf_init(&b, 0); + dawn_regmem(&b); + + void* nbs = blobmsg_open_array(&b, "list"); + + struct kicking_nr* this_ap = ap_list; + while (this_ap) + { + // Candidates in this list will be for one SSID - so match that to the hostapd socket + if (strncmp((char*)this_ap->nr_ap->ssid, sub->ssid, SSID_MAX_LEN) == 0) + { + blobmsg_add_nr(&b, this_ap->nr_ap); + has_content = 1; + } + + this_ap = this_ap->next; + } + + blobmsg_close_array(&b, nbs); + + if (has_content) + ubus_invoke(ctx, sub->id, "rrm_nr_set", b.head, NULL, NULL, timeout * 1000); + + blob_buf_free(&b); + dawn_unregmem(&b); } } - - for (n = preferred_list; n; n = n->next_mac) { - if ((i = ap_array_get_ap(n->mac))) - blobmsg_add_nr(b_local, i); - } - blobmsg_close_array(b_local, nbs); - - return 0; } void uloop_add_data_cbs() {