diff --git a/src/include/datastorage.h b/src/include/datastorage.h index 8bcce6b..1ecfd5e 100644 --- a/src/include/datastorage.h +++ b/src/include/datastorage.h @@ -153,7 +153,7 @@ typedef struct probe_entry_s { struct probe_entry_s* next_probe_skip; struct dawn_mac client_addr; struct dawn_mac bssid_addr; - uint8_t ssid[SSID_MAX_LEN + 1]; // parse_to_beacon_rep() + //uint8_t ssid[SSID_MAX_LEN + 1]; // parse_to_beacon_rep() struct dawn_mac target_addr; // TODO: Never evaluated? uint32_t signal; // eval_probe_metric() uint32_t freq; // eval_probe_metric() @@ -204,8 +204,16 @@ typedef struct hostapd_notify_entry_s { #define NR_PHY 24 // ---------------- Global variables ---------------- +struct probe_head_s { + int node_count; + int skip_count; + int skip_ratio; -extern struct probe_entry_s *probe_set; + struct probe_entry_s* first_probe; + struct probe_entry_s* first_probe_skip; +}; + +extern struct probe_head_s probe_set; extern pthread_mutex_t probe_array_mutex; /* AP, Client */ @@ -283,11 +291,13 @@ extern struct client_s *client_set_bc; extern pthread_mutex_t client_array_mutex; // ---------------- Functions ---------------- -probe_entry *insert_to_array(probe_entry *entry, int inc_counter, int save_80211k, int is_beacon, time_t expiry); +probe_entry *insert_to_probe_array(probe_entry *entry, int is_local, int save_80211k, int is_beacon, time_t expiry); -int probe_array_delete(probe_entry *entry); +int probe_array_delete(struct dawn_mac client_addr, struct dawn_mac bssid_addr); -probe_entry *probe_array_get_entry(struct dawn_mac bssid_addr, struct dawn_mac client_addr); +probe_entry* probe_array_find_first_entry(struct dawn_mac client_mac, struct dawn_mac bssid_mac, int do_bssid); + +probe_entry *probe_array_get_entry(struct dawn_mac client_addr, struct dawn_mac bssid_addr); void remove_old_probe_entries(time_t current_time, long long int threshold); @@ -301,9 +311,9 @@ void print_client_req_entry(int level, client_req_entry *entry); // ---------------- Functions ---------------- -int probe_array_update_rssi(struct dawn_mac bssid_addr, struct dawn_mac client_addr, uint32_t rssi, int send_network); +probe_entry* probe_array_update_rssi(struct dawn_mac client_addr, struct dawn_mac bssid_addr, uint32_t rssi, int send_network); -int probe_array_update_rcpi_rsni(struct dawn_mac bssid_addr, struct dawn_mac client_addr, uint32_t rcpi, uint32_t rsni, int send_network); +probe_entry* probe_array_update_rcpi_rsni(struct dawn_mac client_addr, struct dawn_mac bssid_addr, uint32_t rcpi, uint32_t rsni, int send_network); void remove_old_client_entries(time_t current_time, long long int threshold); @@ -313,6 +323,8 @@ int kick_clients(struct dawn_mac bssid, uint32_t id); void update_iw_info(struct dawn_mac bssid); +client** client_find_first_bc_entry(struct dawn_mac bssid_mac, struct dawn_mac client_mac, int do_client); + void client_array_insert(client *entry, client ** insert_pos); client *client_array_get_client(const struct dawn_mac client_addr); @@ -336,14 +348,9 @@ ap *ap_array_get_ap(struct dawn_mac bssid_mac); int probe_array_set_all_probe_count(struct dawn_mac client_addr, uint32_t probe_count); //int ap_get_collision_count(int col_domain); - -void send_beacon_reports(ap *a, int id); +void send_beacon_requests(ap *a, int id); /* Utils */ -// deprecate use of this - it makes things slow -#define SORT_LENGTH 5 -extern char sort_string[]; - struct kicking_nr { char nr[NEIGHBOR_REPORT_LEN]; int score; diff --git a/src/include/dawn_uci.h b/src/include/dawn_uci.h index 97d3219..83e01d5 100644 --- a/src/include/dawn_uci.h +++ b/src/include/dawn_uci.h @@ -46,12 +46,6 @@ struct network_config_s uci_get_dawn_network(); */ bool uci_get_dawn_hostapd_dir(); -/** - * Function that returns the sort order. - * @return the sort order. - */ -bool uci_get_dawn_sort_order(); - int uci_set_network(char* uci_cmd); /** diff --git a/src/include/ubus.h b/src/include/ubus.h index ec6d170..99fbb38 100644 --- a/src/include/ubus.h +++ b/src/include/ubus.h @@ -60,7 +60,7 @@ void del_client_all_interfaces(const struct dawn_mac client_addr, uint32_t reaso */ void update_hostapd_sockets(struct uloop_timeout *t); -void ubus_send_beacon_report(client *c, ap *a, int id); +void ubus_send_beacon_request(client *c, ap *a, int id); void uloop_add_data_cbs(); diff --git a/src/main.c b/src/main.c index 4151115..aac4fb3 100644 --- a/src/main.c +++ b/src/main.c @@ -114,7 +114,6 @@ int main(int argc, char **argv) { timeout_config = time_config; // TODO: Refactor... uci_get_dawn_hostapd_dir(); - uci_get_dawn_sort_order(); init_mutex(); diff --git a/src/storage/datastorage.c b/src/storage/datastorage.c index abbb537..90d0825 100644 --- a/src/storage/datastorage.c +++ b/src/storage/datastorage.c @@ -19,8 +19,6 @@ struct local_config_s local_config; #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -static int probe_compare(probe_entry *probe1, probe_entry *probe2); - static int is_connected(struct dawn_mac bssid_mac, struct dawn_mac client_mac); static int compare_station_count(ap* ap_entry_own, ap* ap_entry_to_compare, struct dawn_mac client_addr); @@ -40,13 +38,8 @@ const int max_band_freq[__DAWN_BAND_MAX] = { 5925 // This may cause trouble because there's overlap between bands in different countries }; -// Ratio of skiping entries to all entries. -// Approx sqrt() of large data set, and power of 2 for efficient division when adding entries. -#define DAWN_PROBE_SKIP_RATIO 128 -static struct probe_entry_s* probe_skip_set = NULL; -static uint32_t probe_skip_entry_last = 0; -struct probe_entry_s* probe_set = NULL; -static uint32_t probe_entry_last = 0; +// FIXME: Using ratio of 4 to exercise skip handling in small network. Set to 32, 64 or 128 for real use on larger network. +struct probe_head_s probe_set = { 0, 0, 4, NULL, NULL }; pthread_mutex_t probe_array_mutex; struct ap_s *ap_set = NULL; @@ -65,9 +58,6 @@ pthread_mutex_t client_array_mutex; struct mac_entry_s* mac_set = NULL; int mac_set_last = 0; -// TODO: No longer used in code: retained to not break message xfer, etc -char sort_string[SORT_LENGTH]; - /* ** The ..._find_first() functions perform an efficient search of the core storage linked lists. ** "Skipping" linear searches and binary searches are used depending on anticipated array size. @@ -81,83 +71,50 @@ char sort_string[SORT_LENGTH]; ** then the target element does not exist, but can be inserted by using the returned reference. */ -static struct probe_entry_s** probe_skip_array_find_first_entry(struct dawn_mac client_mac, struct dawn_mac bssid_mac, bool do_bssid) +// Probe entries are ordered by client MAC and BSSID so that all APs for a client appear in a block +probe_entry* probe_array_find_first_entry(struct dawn_mac client_mac, struct dawn_mac bssid_mac, int do_bssid) { - int lo = 0; - struct probe_entry_s** lo_ptr = &probe_skip_set; - int hi = probe_skip_entry_last; - dawnlog_debug_func("Entering..."); - while (lo < hi) { - struct probe_entry_s** i = lo_ptr; - int scan_pos = lo; + struct probe_entry_s* curr_node = probe_set.first_probe; + struct probe_entry_s* curr_skip = probe_set.first_probe_skip; - // m is next test position of binary search - int m = (lo + hi) / 2; - - // find entry with ordinal position m - while (scan_pos++ < m) - { - i = &((*i)->next_probe_skip); - } - - int this_cmp = mac_compare_bb((*i)->client_addr, client_mac); + int this_cmp = 0; + while (curr_skip != NULL) { + this_cmp = mac_compare_bb(curr_skip->client_addr, client_mac); if (this_cmp == 0 && do_bssid) - this_cmp = mac_compare_bb((*i)->bssid_addr, bssid_mac); + this_cmp = mac_compare_bb(curr_skip->bssid_addr, bssid_mac); - if (this_cmp < 0) - { - lo = m + 1; - lo_ptr = &((*i)->next_probe_skip); - } - else - { - hi = m; - } - } - - return lo_ptr; -} - -static probe_entry** probe_array_find_first_entry(struct dawn_mac client_mac, struct dawn_mac bssid_mac, bool do_bssid) -{ - probe_entry** lo_skip_ptr = &probe_skip_set; - probe_entry** lo_ptr = &probe_set; - - dawnlog_debug_func("Entering..."); - - while ((*lo_skip_ptr != NULL)) - { - int this_cmp = mac_compare_bb(((*lo_skip_ptr))->client_addr, client_mac); - - if (this_cmp == 0 && do_bssid) - this_cmp = mac_compare_bb(((*lo_skip_ptr))->bssid_addr, bssid_mac); - - if (this_cmp >= 0) + if (this_cmp >= 0) { break; - - lo_ptr = &((*lo_skip_ptr)->next_probe); - lo_skip_ptr = &((*lo_skip_ptr)->next_probe_skip); + } + else { + curr_node = curr_skip; + curr_skip = curr_skip->next_probe_skip; + } } - while ((*lo_ptr != NULL)) - { - int this_cmp = mac_compare_bb((*lo_ptr)->client_addr, client_mac); + while (curr_node != NULL) { + this_cmp = mac_compare_bb(curr_node->client_addr, client_mac); if (this_cmp == 0 && do_bssid) - this_cmp = mac_compare_bb((*lo_ptr)->bssid_addr, bssid_mac); + this_cmp = mac_compare_bb(curr_node->bssid_addr, bssid_mac); - if (this_cmp >= 0) + if (this_cmp >= 0) { break; - - lo_ptr = &((*lo_ptr)->next_probe); + } + else { + curr_node = curr_node->next_probe; + } } - return lo_ptr; -} + // Search including BSSID means that an exact match is required + if (do_bssid && curr_node && this_cmp != 0) + curr_node = NULL; + return curr_node; +} // Manage a list of client entries sorted by BSSID and client MAC static struct client_s** client_skip_array_find_first_entry(struct dawn_mac client_mac, struct dawn_mac bssid_mac, bool do_bssid) { @@ -199,7 +156,7 @@ static struct client_s** client_skip_array_find_first_entry(struct dawn_mac clie return lo_ptr; } -static client** client_find_first_bc_entry(struct dawn_mac bssid_mac, struct dawn_mac client_mac, bool do_client) +client** client_find_first_bc_entry(struct dawn_mac bssid_mac, struct dawn_mac client_mac, int do_client) { client ** lo_skip_ptr = &client_skip_set; client ** lo_ptr = &client_set_bc; @@ -290,7 +247,7 @@ struct mac_entry_s* mac_find_entry(struct dawn_mac mac) return ret; } -void send_beacon_reports(ap *a, int id) { +void send_beacon_requests(ap *a, int id) { pthread_mutex_lock(&client_array_mutex); dawnlog_debug_func("Entering..."); @@ -308,7 +265,7 @@ void send_beacon_reports(ap *a, int id) { !!(i->rrm_enabled_capa & WLAN_RRM_CAPS_BEACON_REPORT_TABLE)); if (i->rrm_enabled_capa & dawn_metric.rrm_mode_mask) - ubus_send_beacon_report(i, a, id); + ubus_send_beacon_request(i, a, id); i = i->next_entry_bc; } @@ -464,11 +421,9 @@ int better_ap_available(ap *kicking_ap, struct dawn_mac client_mac, struct kicki dawnlog_debug_func("Entering..."); // This remains set to the current AP of client for rest of function - probe_entry* own_probe = *probe_array_find_first_entry(client_mac, kicking_ap->bssid_addr, true); + probe_entry* own_probe = probe_array_get_entry(client_mac, kicking_ap->bssid_addr); int own_score = -1; - if (own_probe != NULL - && mac_is_equal_bb(own_probe->client_addr, client_mac) - && mac_is_equal_bb(own_probe->bssid_addr, kicking_ap->bssid_addr)) { + if (own_probe != NULL) { own_score = eval_probe_metric(own_probe, kicking_ap); //TODO: Should the -2 return be handled? dawnlog_trace("Current AP score = %d for:\n", own_score); print_probe_entry(DAWNLOG_TRACE, own_probe); @@ -482,8 +437,8 @@ int better_ap_available(ap *kicking_ap, struct dawn_mac client_mac, struct kicki int max_score = own_score; int kick = 0; int ap_count = 0; - // Now go through all AP entries for this client looking for better score - probe_entry* i = *probe_array_find_first_entry(client_mac, dawn_mac_null, false); + // Now go through all probe entries for this client looking for better score + probe_entry* i = probe_array_find_first_entry(client_mac, dawn_mac_null, false); while (i != NULL && mac_is_equal_bb(i->client_addr, client_mac)) { if (i == own_probe) { @@ -720,8 +675,8 @@ void update_iw_info(struct dawn_mac bssid_mac) { iee80211_calculate_expected_throughput_mbit(get_expected_throughput_iwinfo(j->client_addr))); if (rssi != INT_MIN) { - if (!probe_array_update_rssi(j->bssid_addr, j->client_addr, rssi, true)) { - dawnlog_warning("Failed to update rssi!\n"); + if (!probe_array_update_rssi(j->client_addr, j->bssid_addr, rssi, true)) { + dawnlog_info("Failed to update rssi!\n"); } else { dawnlog_trace("Updated rssi: %d\n", rssi); @@ -891,71 +846,56 @@ client *client_array_delete(client *entry, int unlink_only) { return ret; } -static __inline__ int probe_compare(probe_entry* probe1, probe_entry* probe2) { - int ret = 0; - - if (ret == 0) - { - ret = mac_compare_bb(probe1->client_addr, probe2->client_addr); - } - - if (ret == 0) - { - ret = mac_compare_bb(probe1->bssid_addr, probe2->bssid_addr); - } - -#if 0 - // TODO: Is this needed for ordering? Is it a key field? - if (ret == 0) - { - ret = ((probe1->freq < 5000) && (probe2->freq >= 5000)); - } - - // TODO: Is this needed for ordering? Is it a key field? - if (ret == 0) - { - ret = (probe1->signal < probe2->signal); - } -#endif - - return ret; -} - -static __inline__ void probe_array_unlink_next(probe_entry** i) -{ -probe_entry* victim = *i; - - dawnlog_debug_func("Entering..."); - - // TODO: Can we pre-test that entry is in skip set with - // if ((*s)->next_probe_skip != NULL)... ??? - for (struct probe_entry_s** s = &probe_skip_set; *s != NULL; s = &((*s)->next_probe_skip)) { - if (*s == victim) { - *s = (*s)->next_probe_skip; - - probe_skip_entry_last--; - break; - } - } - - *i = victim->next_probe; - dawn_free(victim); - victim = NULL; - - probe_entry_last--; -} - -int probe_array_delete(probe_entry *entry) { +int probe_array_delete(struct dawn_mac client_mac, struct dawn_mac bssid_mac) { int found_in_array = false; + struct probe_entry_s** node_ref = &probe_set.first_probe; + struct probe_entry_s** skip_ref = &probe_set.first_probe_skip; - dawnlog_debug_func("Entering..."); + int cmp = 0; + while ((*skip_ref) != NULL) { + cmp = mac_compare_bb((*skip_ref)->client_addr, client_mac); - for (probe_entry** i = &probe_set; *i != NULL; i = &((*i)->next_probe)) { - if (*i == entry) { - probe_array_unlink_next(i); - found_in_array = true; + if (cmp == 0) + cmp = mac_compare_bb((*skip_ref)->bssid_addr, bssid_mac); + + if (cmp >= 0) { break; } + else { + node_ref = &((*skip_ref)->next_probe); + skip_ref = &((*skip_ref)->next_probe_skip); + } + } + + while ((*node_ref) != NULL) { + cmp = mac_compare_bb((*node_ref)->client_addr, client_mac); + + if (cmp == 0) + cmp = mac_compare_bb((*node_ref)->bssid_addr, bssid_mac); + + if (cmp >= 0) { + break; + } + else { + node_ref = &((*node_ref)->next_probe); + } + } + + if (*node_ref && cmp == 0) { + struct probe_entry_s* victim = *node_ref; + + *node_ref = victim->next_probe; + probe_set.node_count--; + + if (*skip_ref == victim) + { + *skip_ref = victim->next_probe_skip; + probe_set.skip_count--; + } + + dawn_free(victim); + victim = NULL; + found_in_array = true; } return found_in_array; @@ -969,72 +909,58 @@ int probe_array_set_all_probe_count(struct dawn_mac client_addr, uint32_t probe_ // MUSTDO: Has some code been lost here? updated never set... Certain to hit not found... pthread_mutex_lock(&probe_array_mutex); - for (probe_entry *i = probe_set; i != NULL; i = i->next_probe) { - if (mac_is_equal_bb(client_addr, i->client_addr)) { - dawnlog_debug("Setting probecount for given mac!\n"); - i->counter = probe_count; - } else if (mac_compare_bb(client_addr, i->client_addr) > 0) { - dawnlog_info("MAC not found!\n"); - break; - } + for (probe_entry *i = probe_array_find_first_entry(client_addr, dawn_mac_null, false); + i != NULL && mac_is_equal_bb(client_addr, i->client_addr); + i = i->next_probe) { + dawnlog_debug("Setting probecount for given mac!\n"); + i->counter = probe_count; } pthread_mutex_unlock(&probe_array_mutex); return updated; } -int probe_array_update_rssi(struct dawn_mac bssid_addr, struct dawn_mac client_addr, uint32_t rssi, int send_network) +probe_entry* probe_array_update_rssi(struct dawn_mac client_addr, struct dawn_mac bssid_addr, uint32_t rssi, int send_network) { - int updated = 0; - dawnlog_debug_func("Entering..."); - probe_entry* i = probe_array_get_entry(bssid_addr, client_addr); + probe_entry* entry = probe_array_get_entry(client_addr, bssid_addr); - if (i != NULL) { - i->signal = rssi; - updated = 1; - if (send_network) - { - ubus_send_probe_via_network(i); - } - } - - return updated; -} - -int probe_array_update_rcpi_rsni(struct dawn_mac bssid_addr, struct dawn_mac client_addr, uint32_t rcpi, uint32_t rsni, int send_network) -{ - int updated = 0; - - dawnlog_debug_func("Entering..."); - - pthread_mutex_lock(&probe_array_mutex); - - probe_entry* i = probe_array_get_entry(bssid_addr, client_addr); - - if (i != NULL) { - i->rcpi = rcpi; - i->rsni = rsni; - updated = 1; + if (entry) { + entry->signal = rssi; if (send_network) - ubus_send_probe_via_network(i); + ubus_send_probe_via_network(entry); } - pthread_mutex_unlock(&probe_array_mutex); - - return updated; + return entry; } -probe_entry *probe_array_get_entry(struct dawn_mac bssid_mac, struct dawn_mac client_mac) { +probe_entry* probe_array_update_rcpi_rsni(struct dawn_mac client_addr, struct dawn_mac bssid_addr, uint32_t rcpi, uint32_t rsni, int send_network) +{ dawnlog_debug_func("Entering..."); - probe_entry* ret = *probe_array_find_first_entry(client_mac, bssid_mac, true); + probe_entry* entry = probe_array_get_entry(client_addr, bssid_addr); - // Check if we've been given the insert position rather than actually finding the entry - if ((ret == NULL) || !mac_is_equal_bb(ret->client_addr, client_mac) || !mac_is_equal_bb(ret->bssid_addr, bssid_mac)) - ret = NULL; + if (entry) { + // FIXME: Do we need the -1 tests here? + if (rcpi != -1) + entry->rcpi = rcpi; + + if (rsni != -1) + entry->rsni = rsni; + + if (send_network) + ubus_send_probe_via_network(entry); + } + + return entry; +} + +probe_entry *probe_array_get_entry(struct dawn_mac client_mac, struct dawn_mac bssid_mac) { + dawnlog_debug_func("Entering..."); + + probe_entry* ret = probe_array_find_first_entry(client_mac, bssid_mac, true); return ret; } @@ -1043,79 +969,105 @@ void print_probe_array() { if (dawnlog_showing(DAWNLOG_DEBUG)) { dawnlog_debug("------------------\n"); - dawnlog_debug("Probe Entry Last: %d\n", probe_entry_last); - for (probe_entry* i = probe_set; i != NULL; i = i->next_probe) { + // dawnlog_debug("Probe Entry Last: %d\n", probe_entry_last); + for (probe_entry* i = probe_set.first_probe; i != NULL; i = i->next_probe) { print_probe_entry(DAWNLOG_DEBUG, i); } dawnlog_debug("------------------\n"); } } -static struct probe_entry_s* insert_to_skip_array(struct probe_entry_s* entry) { - - dawnlog_debug_func("Entering..."); - - struct probe_entry_s** insert_pos = probe_skip_array_find_first_entry(entry->client_addr, entry->bssid_addr, true); - - entry->next_probe_skip = *insert_pos; - *insert_pos = entry; - probe_skip_entry_last++; - - return entry; -} - -probe_entry* insert_to_array(probe_entry* entry, int inc_counter, int save_80211k, int is_beacon, time_t expiry) { +probe_entry* insert_to_probe_array(probe_entry* entry, int is_local, int save_80211k, int is_beacon, time_t expiry) { dawnlog_debug_func("Entering..."); pthread_mutex_lock(&probe_array_mutex); - entry->time = expiry; + struct probe_entry_s** node_ref = &probe_set.first_probe; + struct probe_entry_s** skip_ref = &probe_set.first_probe_skip; - // TODO: Add a packed / unpacked wrapper pair? - probe_entry** existing_entry = probe_array_find_first_entry(entry->client_addr, entry->bssid_addr, true); + int cmp = 0; + while ((*skip_ref) != NULL) { + cmp = mac_compare_bb((*skip_ref)->client_addr, entry->client_addr); - if (((*existing_entry) != NULL) - && mac_is_equal_bb((*existing_entry)->client_addr, entry->client_addr) - && mac_is_equal_bb((*existing_entry)->bssid_addr, entry->bssid_addr)) { - (*existing_entry)->time = expiry; - if (inc_counter) - (*existing_entry)->counter++; + if (cmp == 0) + cmp = mac_compare_bb((*skip_ref)->bssid_addr, entry->bssid_addr); - if (entry->signal) - (*existing_entry)->signal = entry->signal; + if (cmp >= 0) { + break; + } + else { + node_ref = &((*skip_ref)->next_probe); + skip_ref = &((*skip_ref)->next_probe_skip); + } + } - if(entry->ht_capabilities) - (*existing_entry)->ht_capabilities = entry->ht_capabilities; + while ((*node_ref) != NULL) { + cmp = mac_compare_bb((*node_ref)->client_addr, entry->client_addr); - if(entry->vht_capabilities) - (*existing_entry)->vht_capabilities = entry->vht_capabilities; + if (cmp == 0) + cmp = mac_compare_bb((*node_ref)->bssid_addr, entry->bssid_addr); + + if (cmp >= 0) { + break; + } + else { + node_ref = &((*node_ref)->next_probe); + } + } + + if (*node_ref && cmp == 0) { + dawnlog_debug("Updating...\n"); + + if (!is_beacon) + { + if (is_local) + (*node_ref)->counter++; + + // Beacon reports don't have these fields, so only update them from probes + (*node_ref)->signal = entry->signal; + (*node_ref)->ht_capabilities = entry->ht_capabilities; + (*node_ref)->vht_capabilities = entry->vht_capabilities; + } + else + { + // FIXME: Equivalent to inserting BEACON based entry + (*node_ref)->counter = dawn_metric.min_probe_count; + } if (save_80211k && entry->rcpi != -1) - (*existing_entry)->rcpi = entry->rcpi; + (*node_ref)->rcpi = entry->rcpi; if (save_80211k && entry->rsni != -1) - (*existing_entry)->rsni = entry->rsni; + (*node_ref)->rsni = entry->rsni; - entry = *existing_entry; + entry = *node_ref; } else { dawnlog_debug("Adding...\n"); - if (inc_counter) + if (is_local && !is_beacon) entry->counter = 1; else entry->counter = 0; - entry->next_probe_skip = NULL; - entry->next_probe = *existing_entry; - *existing_entry = entry; - probe_entry_last++; + entry->next_probe = *node_ref; + *node_ref = entry; - // Try to keep skip list density stable - if ((probe_entry_last / DAWN_PROBE_SKIP_RATIO) > probe_skip_entry_last) + probe_set.node_count++; + + if (probe_set.node_count > (probe_set.skip_count * probe_set.skip_ratio)) { - insert_to_skip_array(entry); + probe_set.skip_count++; + + entry->next_probe_skip = *skip_ref; + *skip_ref = entry; } + else + { + entry->next_probe_skip = NULL; + } + + entry->time = expiry; } pthread_mutex_unlock(&probe_array_mutex); @@ -1280,12 +1232,29 @@ void remove_old_client_entries(time_t current_time, long long int threshold) { void remove_old_probe_entries(time_t current_time, long long int threshold) { dawnlog_debug_func("Entering..."); - probe_entry **i = &probe_set; + probe_entry** i = &(probe_set.first_probe); + probe_entry** s = &(probe_set.first_probe_skip); + while (*i != NULL ) { if (((*i)->time < current_time - threshold) && !is_connected((*i)->bssid_addr, (*i)->client_addr)) { - probe_array_unlink_next(i); + probe_entry* victim = *i; + + *i = victim->next_probe; + + if (*s == victim) + { + *s = victim->next_probe_skip; + } + + dawn_free(victim); + victim = NULL; } else { + if ((*i)->next_probe_skip != NULL) + { + s = &((*i)->next_probe_skip); + } + i = &((*i)->next_probe); } } diff --git a/src/test/test_storage.c b/src/test/test_storage.c index e3ae6fc..f3f1173 100644 --- a/src/test/test_storage.c +++ b/src/test/test_storage.c @@ -11,9 +11,9 @@ #include "test_storage.h" /*** Test Stub Functions - Called by SUT ***/ -void ubus_send_beacon_report(client *c, ap *a, int id) +void ubus_send_beacon_request(client *c, ap *a, int id) { - printf("send_beacon_report() was called...\n"); + printf("ubus_send_beacon_request() was called...\n"); } int send_set_probe(struct dawn_mac client_addr) @@ -213,32 +213,21 @@ static int array_auto_helper(int action, int i0, int i1) probe0->client_addr = this_mac; probe0->bssid_addr = this_mac; - insert_to_array(probe0, true, true, true, 0); // TODO: Check bool flags + insert_to_probe_array(probe0, true, true, true, 0); // TODO: Check bool flags } else if ((action & HELPER_ACTION_MASK) == HELPER_ACTION_STRESS) { probe0 = dawn_malloc(sizeof(probe_entry)); set_random_mac(probe0->client_addr.u8); set_random_mac(probe0->bssid_addr.u8); - insert_to_array(probe0, true, true, true, faketime); + insert_to_probe_array(probe0, true, true, true, faketime); remove_old_probe_entries(faketime, 10); time_moves_on(); } - else - { - probe0 = probe_array_get_entry(this_mac, this_mac); - if (probe0 == NULL) - { - printf("Can't find entry to delete!\n"); - } - else - { - probe_array_delete(probe0); - } + else if ((action & HELPER_ACTION_MASK) == HELPER_ACTION_DEL) { + probe_array_delete(this_mac, this_mac); } break; - - default: printf("HELPER error - which entity?\n"); ret = -1; @@ -385,15 +374,6 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) dawn_memory_audit(); } - else if (strcmp(*argv, "probe_sort") == 0) - { - args_required = 2; - if (curr_arg + args_required <= argc) - { - // sort_string is a datastorage.c global used for sorting probe entries - strcpy(sort_string, argv[1]); - } - } else if (strcmp(*argv, "faketime") == 0) { args_required = 2; @@ -823,7 +803,7 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) key_check = -1; // See if this entry already exists - pr0 = probe_array_get_entry(bmac, cmac); + pr0 = probe_array_get_entry(cmac, bmac); // If not, create and initialise it if (pr0 != NULL) @@ -855,7 +835,7 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) pr0->rcpi = 0; pr0->rsni = 0; - insert_to_array(pr0, true, true, true, pr0->time); + insert_to_probe_array(pr0, true, true, true, pr0->time); } } @@ -932,7 +912,7 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) hwaddr_aton(argv[2], client_mac.u8); hwaddr_aton(argv[1], bssid_mac.u8); - probe_entry *pr0 = probe_array_get_entry(bssid_mac, client_mac); + probe_entry *pr0 = probe_array_get_entry(client_mac, bssid_mac); if (pr0 == NULL ) { @@ -1075,7 +1055,6 @@ int main(int argc, char* argv[]) } else { - strcpy(sort_string, "bcfs"); init_mutex(); // Step past command name on args, ie argv[0] diff --git a/src/utils/dawn_uci.c b/src/utils/dawn_uci.c index 1b7e5cb..70e18c0 100644 --- a/src/utils/dawn_uci.c +++ b/src/utils/dawn_uci.c @@ -399,23 +399,6 @@ bool uci_get_dawn_hostapd_dir() { return false; } -bool uci_get_dawn_sort_order() { - dawnlog_debug_func("Entering..."); - - struct uci_element *e; - uci_foreach_element(&uci_pkg->sections, e) - { - struct uci_section *s = uci_to_section(e); - - if (strcmp(s->type, "ordering") == 0) { - const char* str = uci_lookup_option_string(uci_ctx, s, "sort_order"); - strncpy(sort_string, str, SORT_LENGTH); - return true; - } - } - return false; -} - int uci_reset() { dawnlog_debug_func("Entering..."); diff --git a/src/utils/msghandler.c b/src/utils/msghandler.c index 63c7a37..c5466c3 100644 --- a/src/utils/msghandler.c +++ b/src/utils/msghandler.c @@ -300,7 +300,7 @@ int handle_network_msg(char* msg) { if (strncmp(method, "probe", 5) == 0) { probe_entry *entry = parse_to_probe_req(data_buf.head); if (entry != NULL) { - if (entry != insert_to_array(entry, false, true, false, time(0))) // use 802.11k values + if (entry != insert_to_probe_array(entry, false, true, false, time(0))) // use 802.11k values { // insert found an existing entry, rather than linking in our new one dawn_free(entry); diff --git a/src/utils/ubus.c b/src/utils/ubus.c index 30675f5..38b7be3 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -214,7 +214,7 @@ bool subscriber_to_interface(const char *ifname); bool subscribe(struct ubus_context *ctx_local, struct hostapd_sock_entry *hostapd_entry); -int parse_to_beacon_rep(struct blob_attr *msg); +static probe_entry* parse_to_beacon_rep(struct blob_attr *msg); void ubus_set_nr(); @@ -264,7 +264,8 @@ int parse_to_client_req(struct blob_attr *msg, client_req_entry *client_req) { return 0; } -int parse_to_beacon_rep(struct blob_attr *msg) { +static probe_entry* parse_to_beacon_rep(struct blob_attr *msg) { + probe_entry* beacon_rep = NULL; struct blob_attr *tb[__BEACON_REP_MAX]; struct dawn_mac msg_bssid; struct dawn_mac msg_client; @@ -273,78 +274,49 @@ int parse_to_beacon_rep(struct blob_attr *msg) { blobmsg_parse(beacon_rep_policy, __BEACON_REP_MAX, tb, blob_data(msg), blob_len(msg)); - if(!tb[BEACON_REP_BSSID] || !tb[BEACON_REP_ADDR]) + if (!tb[BEACON_REP_BSSID] || + !tb[BEACON_REP_ADDR] || + hwaddr_aton(blobmsg_data(tb[BEACON_REP_BSSID]), msg_bssid.u8) || + hwaddr_aton(blobmsg_data(tb[BEACON_REP_ADDR]), msg_client.u8)) { - return -1; + dawnlog_warning("Parse of beacon report failed!\n"); } - - if (hwaddr_aton(blobmsg_data(tb[BEACON_REP_BSSID]), msg_bssid.u8)) - return UBUS_STATUS_INVALID_ARGUMENT; - - if(mac_is_null(msg_bssid.u8)) + else { - dawnlog_warning("Received NULL MAC! Client is strange!\n"); - return -1; - } + ap* ap_entry_rep = ap_array_get_ap(msg_bssid); - const uint8_t *ssid = (const uint8_t*)blobmsg_get_string(tb[BEACON_REP_SSID]); - ap *ap_entry_rep = ap_array_get_ap(msg_bssid); - - // no client from network!! - if (ap_entry_rep == NULL) { - return -1; //TODO: Check this - } - - if (hwaddr_aton(blobmsg_data(tb[BEACON_REP_ADDR]), msg_client.u8)) - return UBUS_STATUS_INVALID_ARGUMENT; - - int rcpi = blobmsg_get_u16(tb[BEACON_REP_RCPI]); - int rsni = blobmsg_get_u16(tb[BEACON_REP_RSNI]); - - - // HACKY WORKAROUND! - dawnlog_debug("Try update RCPI and RSNI for beacon report!\n"); - if(!probe_array_update_rcpi_rsni(msg_bssid, msg_client, rcpi, rsni, true)) - { - dawnlog_debug("Beacon: No Probe Entry Existing!\n"); - - probe_entry* beacon_rep = dawn_malloc(sizeof(probe_entry)); - probe_entry* beacon_rep_updated = NULL; - if (beacon_rep == NULL) - { - dawnlog_error("dawn_malloc of probe_entry failed!\n"); - return -1; - } - - beacon_rep->next_probe = NULL; - beacon_rep->bssid_addr = msg_bssid; - beacon_rep->client_addr = msg_client; - strncpy((char*)beacon_rep->ssid, (char*)ssid, SSID_MAX_LEN); - beacon_rep->ssid[SSID_MAX_LEN] = '\0'; - beacon_rep->counter = dawn_metric.min_probe_count; - hwaddr_aton(blobmsg_data(tb[BEACON_REP_ADDR]), beacon_rep->target_addr.u8); // TODO: What is this for? - beacon_rep->signal = 0; - beacon_rep->freq = ap_entry_rep->freq; - beacon_rep->rcpi = rcpi; - beacon_rep->rsni = rsni; - - beacon_rep->ht_capabilities = false; // that is very problematic!!! - beacon_rep->vht_capabilities = false; // that is very problematic!!! - dawnlog_debug("Inserting to array!\n"); - - // TODO: kept original code order here - send on network first to simplify? - beacon_rep_updated = insert_to_array(beacon_rep, false, false, true, time(0)); - if (beacon_rep != beacon_rep_updated) // use 802.11k values // TODO: Change 0 to false? - { - // insert found an existing entry, rather than linking in our new one - ubus_send_probe_via_network(beacon_rep_updated); - dawn_free(beacon_rep); - beacon_rep = NULL; + // no client from network!! + if (!ap_entry_rep) { + dawnlog_warning("No AP for beacon report entry!\n"); } else - ubus_send_probe_via_network(beacon_rep_updated); + { + beacon_rep = dawn_malloc(sizeof(probe_entry)); + if (beacon_rep == NULL) + { + dawnlog_error("dawn_malloc of beacon report failed!\n"); + } + else + { + beacon_rep->next_probe = NULL; + beacon_rep->bssid_addr = msg_bssid; + beacon_rep->client_addr = msg_client; + beacon_rep->counter = dawn_metric.min_probe_count; // TODO: Why is this? To allow a 802.11k client to meet proe count check immediately? + hwaddr_aton(blobmsg_data(tb[BEACON_REP_ADDR]), beacon_rep->target_addr.u8); // TODO: What is this for? + beacon_rep->freq = ap_entry_rep->freq; + beacon_rep->rcpi = blobmsg_get_u16(tb[BEACON_REP_RCPI]); + beacon_rep->rsni = blobmsg_get_u16(tb[BEACON_REP_RSNI]); + + // These fields, can't be set from a BEACON REPORT, so we ignore them later if updating an existing PROBE + // TODO: See if hostapd can send optional elements which might allow these to be set + beacon_rep->signal = 0; + beacon_rep->ht_capabilities = false; // that is very problematic!!! + beacon_rep->vht_capabilities = false; // that is very problematic!!! + } + } } - return 0; + + return beacon_rep; } int handle_auth_req(struct blob_attr* msg) { @@ -377,7 +349,7 @@ bool discard_entry = true; if (dawnlog_showing(DAWNLOG_DEBUG)) print_probe_array(); - probe_entry *tmp = probe_array_get_entry(auth_req->bssid_addr, auth_req->client_addr); + probe_entry *tmp = probe_array_get_entry(auth_req->client_addr, auth_req->bssid_addr); pthread_mutex_unlock(&probe_array_mutex); @@ -449,7 +421,7 @@ int discard_entry = true; if (dawnlog_showing(DAWNLOG_DEBUG)) print_probe_array(); - probe_entry *tmp = probe_array_get_entry(assoc_req->bssid_addr, assoc_req->client_addr); + probe_entry *tmp = probe_array_get_entry(assoc_req->client_addr, assoc_req->bssid_addr); pthread_mutex_unlock(&probe_array_mutex); @@ -496,11 +468,10 @@ int discard_entry = true; } static int handle_probe_req(struct blob_attr* msg) { - // MUSTDO: Untangle dawn_malloc() and linking of probe_entry - probe_entry* probe_req = parse_to_probe_req(msg); - dawnlog_debug_func("Entering..."); + // MUSTDO: Untangle dawn_malloc() and linking of probe_entry + probe_entry* probe_req = parse_to_probe_req(msg); if (probe_req == NULL) { @@ -509,7 +480,7 @@ static int handle_probe_req(struct blob_attr* msg) { } else { - probe_entry* probe_req_updated = insert_to_array(probe_req, true, true, false, time(0)); + probe_entry* probe_req_updated = insert_to_probe_array(probe_req, true, true, false, time(0)); // If insert finds an existing entry, rather than linking in our new one, // send new probe req because we want to stay synced. // If not, probe_req and probe_req_updated should be equivalent @@ -558,17 +529,48 @@ static int handle_probe_req(struct blob_attr* msg) { return WLAN_STATUS_SUCCESS; } -// FIXME: Seems to do nothing... static int handle_beacon_rep(struct blob_attr *msg) { dawnlog_debug_func("Entering..."); + int ret = UBUS_STATUS_INVALID_ARGUMENT; - if (parse_to_beacon_rep(msg) == 0) { - // dawnlog_debug("Inserting beacon Report!\n"); - // insert_to_array(beacon_rep, 1); - // dawnlog_debug("Sending via network!\n"); - // send_blob_attr_via_network(msg, "beacon-report"); + probe_entry* entry = parse_to_beacon_rep(msg); + + if (entry) + { + if (mac_is_null(entry->bssid_addr.u8)) + { + dawnlog_warning("Received NULL MAC! Client is strange!\n"); + dawn_free(entry); + } + else + { + // Update RxxI of current entry if it exists + pthread_mutex_lock(&probe_array_mutex); + + probe_entry* entry_updated = probe_array_update_rcpi_rsni(entry->client_addr, entry->bssid_addr, entry->rcpi, entry->rsni, true); + + pthread_mutex_unlock(&probe_array_mutex); + + if (entry_updated) + { + dawnlog_info("Local BEACON used to update RCPI and RSNI for client / BSSID = " MACSTR " / " MACSTR " \n", MAC2STR(entry->client_addr.u8), MAC2STR(entry->bssid_addr.u8)); + dawn_free(entry); + } + else + { + dawnlog_info("Local BEACON is for new client / BSSID = " MACSTR " / " MACSTR " \n", MAC2STR(entry->client_addr.u8), MAC2STR(entry->bssid_addr.u8)); + + // BEACON will never set RSSI, but may have RCPI and RSNI + entry = insert_to_probe_array(entry, false, false, true, time(0)); + + ubus_send_probe_via_network(entry); + + ret = 0; + } + } } - return 0; + + return ret; } @@ -944,7 +946,7 @@ static int get_mode_from_capability(int capability) { return -1; } -void ubus_send_beacon_report(client *c, ap *a, int id) +void ubus_send_beacon_request(client *c, ap *a, int id) { struct blob_buf b = {0}; dawnlog_debug_func("Entering..."); @@ -961,7 +963,7 @@ void ubus_send_beacon_report(client *c, ap *a, int id) blobmsg_add_u32(&b, "mode", get_mode_from_capability(c->rrm_enabled_capa)); blobmsg_add_string(&b, "ssid", (char*)a->ssid); - dawnlog_debug("Invoking beacon report!\n"); + dawnlog_debug("Invoking beacon request!\n"); ubus_invoke(ctx, id, "rrm_beacon_req", b.head, NULL, NULL, timeout * 1000); blob_buf_free(&b); dawn_unregmem(&b); @@ -976,13 +978,13 @@ void update_beacon_reports(struct uloop_timeout *t) { { return; } - dawnlog_debug("Sending beacon report!\n"); + dawnlog_debug("Sending beacon requests!\n"); struct hostapd_sock_entry *sub; list_for_each_entry(sub, &hostapd_sock_list, list) { if (sub->subscribed && (a = ap_array_get_ap(sub->bssid_addr))) { - dawnlog_debug("Sending beacon report Sub!\n"); - send_beacon_reports(a, sub->id); + dawnlog_debug("Sending beacon request Sub!\n"); + send_beacon_requests(a, sub->id); } } uloop_timeout_set(&beacon_reports_timer, timeout_config.update_beacon_reports * 1000); @@ -1326,7 +1328,6 @@ static int reload_config(struct ubus_context *ctx_local, struct ubus_object *obj dawn_metric = uci_get_dawn_metric(); timeout_config = uci_get_time_config(); uci_get_dawn_hostapd_dir(); - uci_get_dawn_sort_order(); if(timeout_config.update_beacon_reports) // allow setting timeout to 0 uloop_timeout_add(&beacon_reports_timer); // callback = update_beacon_reports @@ -1696,6 +1697,20 @@ int uci_send_via_network() return 0; } +// FIXME: Not sure if we need to create a NUL terminated string. Is unterminated length of 8 enough? +static void blobmsg_add_rrm_string(struct blob_buf* b, char* n, uint8_t caps) +{ + char* s = blobmsg_alloc_string_buffer(b, n, 9); + s[8] = '\0'; + for (int i = 7; i >= 0; i--) + { + // Treat string literal as char[] to get a mnemonic character for the capability + s[i] = (caps & 0x01) ? "?TAP??NL"[i] : '.'; + caps >>= 1; + } + blobmsg_add_string_buffer(b); +} + int build_hearing_map_sort_client(struct blob_buf *b) { dawnlog_debug_func("Entering..."); @@ -1714,7 +1729,7 @@ int build_hearing_map_sort_client(struct blob_buf *b) { // Scan AP list to find first of each SSID if (!same_ssid) { ssid_list = blobmsg_open_table(b, (char*)m->ssid); - probe_entry* i = probe_set; + probe_entry* i = probe_set.first_probe; while (i != NULL) { ap *ap_entry_i = ap_array_get_ap(i->bssid_addr); @@ -1830,34 +1845,38 @@ int build_network_overview(struct blob_buf *b) { blobmsg_add_string_buffer(b); // TODO: Could optimise this by exporting search func, but not a core process - client *k = client_set_bc; - while (k != NULL) { + client *k = *client_find_first_bc_entry(m->bssid_addr, dawn_mac_null, false); + while (k != NULL && mac_is_equal_bb(m->bssid_addr, k->bssid_addr)) { - if (mac_is_equal_bb(m->bssid_addr, k->bssid_addr)) { - sprintf(client_mac_buf, MACSTR, MAC2STR(k->client_addr.u8)); - client_list = blobmsg_open_table(b, client_mac_buf); + sprintf(client_mac_buf, MACSTR, MAC2STR(k->client_addr.u8)); + client_list = blobmsg_open_table(b, client_mac_buf); - if(strlen(k->signature) != 0) - { - char *s; - s = blobmsg_alloc_string_buffer(b, "signature", 1024); - sprintf(s, "%s", k->signature); - blobmsg_add_string_buffer(b); - } - blobmsg_add_u8(b, "ht", k->ht); - blobmsg_add_u8(b, "vht", k->vht); - //blobmsg_add_u32(b, "collision_count", ap_get_collision_count(m->collision_domain)); - - pthread_mutex_lock(&probe_array_mutex); - - probe_entry* n = probe_array_get_entry(k->bssid_addr, k->client_addr); - pthread_mutex_unlock(&probe_array_mutex); - - if (n != NULL) { - blobmsg_add_u32(b, "signal", n->signal); - } - blobmsg_close_table(b, client_list); + if (strlen(k->signature) != 0) + { + char* s; + s = blobmsg_alloc_string_buffer(b, "signature", 1024); + sprintf(s, "%s", k->signature); + blobmsg_add_string_buffer(b); } + blobmsg_add_u8(b, "ht", k->ht); + blobmsg_add_u8(b, "vht", k->vht); + + blobmsg_add_rrm_string(b, "rrm-caps", k->rrm_enabled_capa); + + pthread_mutex_lock(&probe_array_mutex); + probe_entry* n = probe_array_get_entry(k->client_addr, k->bssid_addr); + + if (n != NULL) { + { + blobmsg_add_u32(b, "signal", n->signal); + blobmsg_add_u32(b, "rcpi", n->rcpi); + blobmsg_add_u32(b, "rsni", n->rsni); + } + } + pthread_mutex_unlock(&probe_array_mutex); + + blobmsg_close_table(b, client_list); + k = k->next_entry_bc; } blobmsg_close_table(b, ap_list); @@ -1948,16 +1967,15 @@ void uloop_add_data_cbs() { uloop_timeout_add(&ap_timeout); // callback = remove_ap_array_cb } -// TODO: Move mutex handling to remove_??? function to make test harness simpler? -// Or not needed as test harness not threaded? void remove_probe_array_cb(struct uloop_timeout* t) { - dawnlog_debug_func("Entering..."); + dawnlog_debug_func("[Thread] : Removing old probe entries!\n"); pthread_mutex_lock(&probe_array_mutex); - dawnlog_debug("[Thread] : Removing old probe entries!\n"); remove_old_probe_entries(time(0), timeout_config.remove_probe); - dawnlog_debug("[Thread] : Removing old entries finished!\n"); pthread_mutex_unlock(&probe_array_mutex); + + dawnlog_debug("[Thread] : Removing old entries finished!\n"); + uloop_timeout_set(&probe_timeout, timeout_config.remove_probe * 1000); }