From be767b0aee4abf3b1eb40f4d2d756249e0db23cf Mon Sep 17 00:00:00 2001 From: Eneas U de Queiroz Date: Wed, 4 Aug 2021 09:11:06 -0300 Subject: [PATCH] datastorage: use signal strength as a metric This adds a few options to use the signal strength as a metric, band dependent: - rssi_weight: every db of signal increases the score by this much. - rssi_center: if the signal is stronger than this, the score becomes positive; below this, it is negative. - initial_score: since we are capping negative scores, it may be beneficial to have a positive base score to offset a possible negative signal value. This is replacing the 'freq' metric. To avoid a single-digit RSSI increase resulting in a kick, we add a global threshold value to act as a buffer: - kicking_threshold: a candidate AP must have a score larger than that of the current AP plus the value here. The kicking_threshold also applies when assembling the list of roaming neighbors we send with the "wnm_disassoc_imminent" command. Signed-off-by: Eneas U de Queiroz --- src/include/datastorage.h | 7 ++-- src/storage/datastorage.c | 75 ++++++++++++++++++++++++++++----------- src/test/test_storage.c | 6 ++-- src/utils/dawn_uci.c | 7 ++-- src/utils/msghandler.c | 21 +++++++++-- src/utils/ubus.c | 5 ++- 6 files changed, 89 insertions(+), 32 deletions(-) diff --git a/src/include/datastorage.h b/src/include/datastorage.h index 6c52e8e..5e10491 100644 --- a/src/include/datastorage.h +++ b/src/include/datastorage.h @@ -55,7 +55,7 @@ int get_band(int freq); // TODO: Define a proper version string #ifndef DAWN_CONFIG_VERSION -#define DAWN_CONFIG_VERSION "2" +#define DAWN_CONFIG_VERSION "3" #endif // Band definitions @@ -90,11 +90,13 @@ struct probe_metric_s { int chan_util_avg_period; int set_hostapd_nr; int kicking; + int kicking_threshold; int duration; int rrm_mode_mask; int rrm_mode_order[__RRM_BEACON_RQST_MODE_MAX]; // Per-band Configuration + int initial_score[__DAWN_BAND_MAX]; // eval_probe_metric()() int ap_weight[__DAWN_BAND_MAX]; // TODO: Never evaluated? int ht_support[__DAWN_BAND_MAX]; // eval_probe_metric()() int vht_support[__DAWN_BAND_MAX]; // eval_probe_metric()() @@ -102,13 +104,14 @@ struct probe_metric_s { int no_vht_support[__DAWN_BAND_MAX]; // eval_probe_metric()() int rssi[__DAWN_BAND_MAX]; // eval_probe_metric()() int low_rssi[__DAWN_BAND_MAX]; // eval_probe_metric()() - int freq[__DAWN_BAND_MAX]; // eval_probe_metric()() int chan_util[__DAWN_BAND_MAX]; // eval_probe_metric()() int max_chan_util[__DAWN_BAND_MAX]; // eval_probe_metric()() int rssi_val[__DAWN_BAND_MAX]; // eval_probe_metric()() int low_rssi_val[__DAWN_BAND_MAX]; // eval_probe_metric()() int chan_util_val[__DAWN_BAND_MAX]; // eval_probe_metric()() int max_chan_util_val[__DAWN_BAND_MAX]; // eval_probe_metric()() + int rssi_weight[__DAWN_BAND_MAX]; // eval_probe_metric()() + int rssi_center[__DAWN_BAND_MAX]; // eval_probe_metric()() struct mac_entry_s* neighbors[__DAWN_BAND_MAX]; // ap_get_nr() }; diff --git a/src/storage/datastorage.c b/src/storage/datastorage.c index 338e930..dc71ad7 100644 --- a/src/storage/datastorage.c +++ b/src/storage/datastorage.c @@ -434,12 +434,11 @@ int eval_probe_metric(struct probe_entry_s* probe_entry, ap* ap_entry) { int band, score = 0; // TODO: Should RCPI be used here as well? - // TODO: Should this be more scaled? Should -63dB on current and -77dB on other both score 0 if low / high are -80db and -60dB? - // TODO: That then lets device capabilites dominate score - making them more important than RSSI difference of 14dB. band = get_band(probe_entry->freq); - score = dawn_metric.freq[band]; + score = dawn_metric.initial_score[band]; score += probe_entry->signal >= dawn_metric.rssi_val[band] ? dawn_metric.rssi[band] : 0; score += probe_entry->signal <= dawn_metric.low_rssi_val[band] ? dawn_metric.low_rssi[band] : 0; + score += (probe_entry->signal - dawn_metric.rssi_center[band]) * dawn_metric.rssi_weight[band]; // check if ap entry is available if (ap_entry != NULL) { @@ -504,15 +503,14 @@ static int compare_station_count(ap* ap_entry_own, ap* ap_entry_to_compare, stru return 0; } -static struct kicking_nr *insert_kicking_nr(struct kicking_nr *nr_list, char *nr, int score) { - struct kicking_nr *new_entry; +static struct kicking_nr *find_position(struct kicking_nr *nrlist, int score) { + struct kicking_nr *ret = NULL; - if (!(new_entry = dawn_malloc(sizeof (struct kicking_nr)))) - return NULL; - strncpy(new_entry->nr, nr, NEIGHBOR_REPORT_LEN); - new_entry->score = score; - new_entry->next = nr_list; - return new_entry; + while (nrlist && nrlist->score < score) { + ret = nrlist; + nrlist = nrlist->next; + } + return ret; } static void remove_kicking_nr_list(struct kicking_nr *nr_list) { @@ -525,6 +523,40 @@ static void remove_kicking_nr_list(struct kicking_nr *nr_list) { } } +static struct kicking_nr *prune_kicking_nr_list(struct kicking_nr *nr_list, int min_score) { + struct kicking_nr *next; + + while (nr_list && nr_list->score <= min_score) { + 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 (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; + } + return head; +} + int better_ap_available(ap *kicking_ap, struct dawn_mac client_mac, struct kicking_nr **neighbor_report) { // This remains set to the current AP of client for rest of function @@ -577,7 +609,7 @@ int better_ap_available(ap *kicking_ap, struct dawn_mac client_mac, struct kicki int score_to_compare = eval_probe_metric(i, candidate_ap); // Find better score... - if (score_to_compare > max_score) { + if (score_to_compare > max_score + (kick ? 0 : dawn_metric.kicking_threshold)) { if(neighbor_report == NULL) { fprintf(stderr,"Neighbor-Report is NULL!\n"); @@ -586,15 +618,14 @@ int better_ap_available(ap *kicking_ap, struct dawn_mac client_mac, struct kicki kick = 1; - // instead of returning we create a neighbor report list... - remove_kicking_nr_list(*neighbor_report); - *neighbor_report = insert_kicking_nr(NULL, candidate_ap->neighbor_report, score_to_compare); + // instead of returning we add the ap to the neighbor report list, pruning it first... + *neighbor_report = insert_kicking_nr(*neighbor_report, candidate_ap->neighbor_report, score_to_compare, true); max_score = score_to_compare; } // if ap have same value but station count is different... // TODO: Is absolute number meaningful when AP have diffeent capacity? - else if (dawn_metric.use_station_count > 0 && score_to_compare == max_score ) { + else if (dawn_metric.use_station_count > 0 && score_to_compare >= max_score ) { int compare = compare_station_count(kicking_ap, candidate_ap, client_mac); if (compare > 0) { @@ -605,15 +636,17 @@ int better_ap_available(ap *kicking_ap, struct dawn_mac client_mac, struct kicki } kick = 1; - remove_kicking_nr_list(*neighbor_report); - *neighbor_report = insert_kicking_nr(NULL, candidate_ap->neighbor_report, score_to_compare); + *neighbor_report = insert_kicking_nr(*neighbor_report, candidate_ap->neighbor_report, + score_to_compare, true); } else if (compare == 0 && kick) { - *neighbor_report = insert_kicking_nr(*neighbor_report, candidate_ap->neighbor_report, score_to_compare); + *neighbor_report = insert_kicking_nr(*neighbor_report, candidate_ap->neighbor_report, + score_to_compare, false); } } - else if (score_to_compare == max_score && kick) { - *neighbor_report = insert_kicking_nr(*neighbor_report, candidate_ap->neighbor_report, score_to_compare); + else if (score_to_compare >= max_score && kick) { + *neighbor_report = insert_kicking_nr(*neighbor_report, candidate_ap->neighbor_report, + score_to_compare, false); } i = i->next_probe; diff --git a/src/test/test_storage.c b/src/test/test_storage.c index 484b343..2812c8b 100644 --- a/src/test/test_storage.c +++ b/src/test/test_storage.c @@ -654,8 +654,8 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) dawn_metric.rssi[1] = 10; // Sum component dawn_metric.low_rssi[0] = -500; // Sum component dawn_metric.low_rssi[1] = -500; // Sum component - dawn_metric.freq[0] = 0; // Sum component - dawn_metric.freq[1] = 100; // Sum component + dawn_metric.initial_score[0] = 0; // Sum component + dawn_metric.initial_score[1] = 100; // Sum component dawn_metric.chan_util[0] = 0; // Sum component dawn_metric.chan_util[1] = 0; // Sum component dawn_metric.max_chan_util[0] = -500; // Sum component @@ -697,7 +697,7 @@ static int consume_actions(int argc, char* argv[], int harness_verbosity) else if (!strncmp(fn, "no_vht_support=", 15)) load_int_band(dawn_metric.no_vht_support, fn + 15); else if (!strncmp(fn, "rssi=", 5)) load_int_band(dawn_metric.rssi, fn + 5); else if (!strncmp(fn, "low_rssi=", 9)) load_int_band(dawn_metric.low_rssi, fn + 9); - else if (!strncmp(fn, "freq=", 5)) load_int(&dawn_metric.freq[1], fn + 5); + else if (!strncmp(fn, "freq=", 5)) load_int(&dawn_metric.initial_score[1], fn + 5); else if (!strncmp(fn, "chan_util=", 10)) load_int_band(dawn_metric.chan_util, fn + 10); else if (!strncmp(fn, "max_chan_util=", 14)) load_int_band(dawn_metric.max_chan_util, fn + 14); else if (!strncmp(fn, "rssi_val=", 9)) load_int_band(dawn_metric.rssi_val, fn + 9); diff --git a/src/utils/dawn_uci.c b/src/utils/dawn_uci.c index 890a9a1..d887215 100644 --- a/src/utils/dawn_uci.c +++ b/src/utils/dawn_uci.c @@ -244,7 +244,7 @@ struct probe_metric_s uci_get_dawn_metric() { .no_vht_support = { 0, 0 }, .rssi = { 10, 10 }, .rssi_val = { -60, -60 }, - .freq = { 0, 100 }, + .initial_score = { 0, 100 }, .chan_util = { 0, 0 }, .max_chan_util = { -500, -500 }, .chan_util_val = { 140, 140 }, @@ -267,6 +267,7 @@ struct probe_metric_s uci_get_dawn_metric() { if (global_s) { // True global configuration DAWN_SET_CONFIG_INT(ret, global_s, kicking); + DAWN_SET_CONFIG_INT(ret, global_s, kicking_threshold); DAWN_SET_CONFIG_INT(ret, global_s, min_probe_count); DAWN_SET_CONFIG_INT(ret, global_s, use_station_count); DAWN_SET_CONFIG_INT(ret, global_s, eval_auth_req); @@ -291,6 +292,7 @@ struct probe_metric_s uci_get_dawn_metric() { ret.neighbors[band] = uci_lookup_mac_list(neighbors ? : global_neighbors); } + DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, initial_score); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, ap_weight); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, ht_support); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, vht_support); @@ -298,13 +300,14 @@ struct probe_metric_s uci_get_dawn_metric() { DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, no_vht_support); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, rssi); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, rssi_val); - DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, freq); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, chan_util); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, max_chan_util); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, chan_util_val); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, max_chan_util_val); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, low_rssi); DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, low_rssi_val); + DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, rssi_weight); + DAWN_SET_BANDS_CONFIG_INT(ret, global_s, band_s, rssi_center); return ret; } diff --git a/src/utils/msghandler.c b/src/utils/msghandler.c index 2f370d1..37307ca 100644 --- a/src/utils/msghandler.c +++ b/src/utils/msghandler.c @@ -580,6 +580,7 @@ enum { UCI_EVAL_AUTH_REQ, UCI_EVAL_ASSOC_REQ, UCI_KICKING, + UCI_KICKING_THRESHOLD, UCI_DENY_AUTH_REASON, UCI_DENY_ASSOC_REASON, UCI_USE_DRIVER_RECOG, @@ -594,7 +595,7 @@ enum { enum { UCI_BAND, - UCI_FREQ, + UCI_INITIAL_SCORE, UCI_AP_WEIGHT, UCI_HT_SUPPORT, UCI_VHT_SUPPORT, @@ -608,6 +609,8 @@ enum { UCI_LOW_RSSI_VAL, UCI_CHAN_UTIL_VAL, UCI_MAX_CHAN_UTIL_VAL, + UCI_RSSI_WEIGHT, + UCI_RSSI_CENTER, __UCI_BAND_METRIC_MAX }; @@ -639,6 +642,7 @@ static const struct blobmsg_policy uci_metric_policy[__UCI_METRIC_MAX] = { [UCI_EVAL_AUTH_REQ] = {.name = "eval_auth_req", .type = BLOBMSG_TYPE_INT32}, [UCI_EVAL_ASSOC_REQ] = {.name = "eval_assoc_req", .type = BLOBMSG_TYPE_INT32}, [UCI_KICKING] = {.name = "kicking", .type = BLOBMSG_TYPE_INT32}, + [UCI_KICKING_THRESHOLD] = {.name = "kicking_threshold", .type = BLOBMSG_TYPE_INT32}, [UCI_DENY_AUTH_REASON] = {.name = "deny_auth_reason", .type = BLOBMSG_TYPE_INT32}, [UCI_DENY_ASSOC_REASON] = {.name = "deny_assoc_reason", .type = BLOBMSG_TYPE_INT32}, [UCI_USE_DRIVER_RECOG] = {.name = "use_driver_recog", .type = BLOBMSG_TYPE_INT32}, @@ -651,7 +655,7 @@ static const struct blobmsg_policy uci_metric_policy[__UCI_METRIC_MAX] = { }; static const struct blobmsg_policy uci_band_metric_policy[__UCI_METRIC_MAX] = { - [UCI_FREQ] = {.name = "freq", .type = BLOBMSG_TYPE_INT32}, + [UCI_INITIAL_SCORE] = {.name = "initial_score", .type = BLOBMSG_TYPE_INT32}, [UCI_HT_SUPPORT] = {.name = "ht_support", .type = BLOBMSG_TYPE_INT32}, [UCI_VHT_SUPPORT] = {.name = "vht_support", .type = BLOBMSG_TYPE_INT32}, [UCI_NO_HT_SUPPORT] = {.name = "no_ht_support", .type = BLOBMSG_TYPE_INT32}, @@ -664,6 +668,8 @@ static const struct blobmsg_policy uci_band_metric_policy[__UCI_METRIC_MAX] = { [UCI_MAX_CHAN_UTIL] = {.name = "max_chan_util", .type = BLOBMSG_TYPE_INT32}, [UCI_CHAN_UTIL_VAL] = {.name = "chan_util_val", .type = BLOBMSG_TYPE_INT32}, [UCI_MAX_CHAN_UTIL_VAL] = {.name = "max_chan_util_val", .type = BLOBMSG_TYPE_INT32}, + [UCI_RSSI_WEIGHT] = {.name = "rssi_weight", .type = BLOBMSG_TYPE_INT32}, + [UCI_RSSI_CENTER] = {.name = "rssi_center", .type = BLOBMSG_TYPE_INT32}, }; static const struct blobmsg_policy uci_times_policy[__UCI_TIMES_MAX] = { @@ -723,6 +729,9 @@ static int handle_uci_config(struct blob_attr* msg) { sprintf(cmd_buffer, "dawn.global.kicking=%d", blobmsg_get_u32(tb_metric[UCI_KICKING])); uci_set_network(cmd_buffer); + sprintf(cmd_buffer, "dawn.global.kicking_threshold=%d", blobmsg_get_u32(tb_metric[UCI_KICKING_THRESHOLD])); + uci_set_network(cmd_buffer); + sprintf(cmd_buffer, "dawn.global.deny_auth_reason=%d", blobmsg_get_u32(tb_metric[UCI_DENY_AUTH_REASON])); uci_set_network(cmd_buffer); @@ -770,7 +779,7 @@ static int handle_uci_config(struct blob_attr* msg) { sprintf(cmd_buffer, "dawn.%s=metric", band_name); uci_set_network(cmd_buffer); - sprintf(cmd_buffer, "dawn.%s.freq=%d", band_name, blobmsg_get_u32(tb_band_metric[UCI_FREQ])); + sprintf(cmd_buffer, "dawn.%s.initial_score=%d", band_name, blobmsg_get_u32(tb_band_metric[UCI_INITIAL_SCORE])); uci_set_network(cmd_buffer); sprintf(cmd_buffer, "dawn.%s.ht_support=%d", band_name, blobmsg_get_u32(tb_band_metric[UCI_HT_SUPPORT])); @@ -808,6 +817,12 @@ static int handle_uci_config(struct blob_attr* msg) { sprintf(cmd_buffer, "dawn.%s.max_chan_util_val=%d", band_name, blobmsg_get_u32(tb_band_metric[UCI_MAX_CHAN_UTIL_VAL])); uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.%s.rssi_weight=%d", band_name, blobmsg_get_u32(tb_band_metric[UCI_RSSI_WEIGHT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.%s.rssi_center=%d", band_name, blobmsg_get_u32(tb_band_metric[UCI_RSSI_CENTER])); + uci_set_network(cmd_buffer); } struct blob_attr* tb_times[__UCI_TIMES_MAX]; diff --git a/src/utils/ubus.c b/src/utils/ubus.c index 59e8679..28d8d92 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -1448,6 +1448,7 @@ int uci_send_via_network() blobmsg_add_u32(&b, "eval_auth_req", dawn_metric.eval_auth_req); blobmsg_add_u32(&b, "eval_assoc_req", dawn_metric.eval_assoc_req); blobmsg_add_u32(&b, "kicking", dawn_metric.kicking); + blobmsg_add_u32(&b, "kicking_threshold", dawn_metric.kicking_threshold); blobmsg_add_u32(&b, "deny_auth_reason", dawn_metric.deny_auth_reason); blobmsg_add_u32(&b, "deny_assoc_reason", dawn_metric.deny_assoc_reason); blobmsg_add_u32(&b, "use_driver_recog", dawn_metric.use_driver_recog); @@ -1460,6 +1461,7 @@ int uci_send_via_network() for (int band=0; band < __DAWN_BAND_MAX; band++) { band_entry = blobmsg_open_table(&b, band_config_name[band]); + blobmsg_add_u32(&b, "initial_score", dawn_metric.initial_score[band]); blobmsg_add_u32(&b, "ap_weight", dawn_metric.ap_weight[band]); blobmsg_add_u32(&b, "ht_support", dawn_metric.ht_support[band]); blobmsg_add_u32(&b, "vht_support", dawn_metric.vht_support[band]); @@ -1469,11 +1471,12 @@ int uci_send_via_network() blobmsg_add_u32(&b, "rssi_val", dawn_metric.rssi_val[band]); blobmsg_add_u32(&b, "low_rssi", dawn_metric.low_rssi[band]); blobmsg_add_u32(&b, "low_rssi_val", dawn_metric.low_rssi_val[band]); - blobmsg_add_u32(&b, "freq", dawn_metric.freq[band]); blobmsg_add_u32(&b, "chan_util", dawn_metric.chan_util[band]); blobmsg_add_u32(&b, "max_chan_util", dawn_metric.max_chan_util[band]); blobmsg_add_u32(&b, "chan_util_val", dawn_metric.chan_util_val[band]); blobmsg_add_u32(&b, "max_chan_util_val", dawn_metric.max_chan_util_val[band]); + blobmsg_add_u32(&b, "rssi_weight", dawn_metric.rssi_weight[band]); + blobmsg_add_u32(&b, "rssi_center", dawn_metric.rssi_center[band]); blobmsg_close_table(&b, band_entry); } blobmsg_close_table(&b, band_table);