mirror of
https://github.com/berlin-open-wireless-lab/DAWN.git
synced 2025-03-09 15:40:12 +00:00
datastorage/ubus: Add "soft" kicking algorithm
In addition to scored "hard" kick for all clients (inc. legacy), add a "soft" kick for 802.11v aware clients by always asking them to move if below threshold RSSI, but with no mandatory disassociation. [cleanup commit message] Signed-off-by: Nick Hainke <vincent@systemli.org>
This commit is contained in:
parent
d37a768766
commit
359dd085aa
4 changed files with 138 additions and 30 deletions
|
@ -133,6 +133,16 @@ int send_set_probe(struct dawn_mac client_addr);
|
||||||
*/
|
*/
|
||||||
int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, int threshold, uint32_t duration);
|
int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, int threshold, uint32_t duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to ask a client to move to another AP, but not enforce it.
|
||||||
|
* @param id
|
||||||
|
* @param client_addr
|
||||||
|
* @param dest_ap
|
||||||
|
* @param duration
|
||||||
|
* @return - 0 = asynchronous (client has been told to remove itself, and caller should manage arrays); 1 = synchronous (caller should assume arrays are updated)
|
||||||
|
*/
|
||||||
|
int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, uint32_t duration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send control message to all hosts to add the mac to a don't control list.
|
* Send control message to all hosts to add the mac to a don't control list.
|
||||||
* @param client_addr
|
* @param client_addr
|
||||||
|
|
|
@ -479,11 +479,11 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) {
|
||||||
// Seach for BSSID
|
// Seach for BSSID
|
||||||
client *j = *client_find_first_bc_entry(kicking_ap->bssid_addr, dawn_mac_null, false);
|
client *j = *client_find_first_bc_entry(kicking_ap->bssid_addr, dawn_mac_null, false);
|
||||||
|
|
||||||
// Go through clients
|
// Go through clients: only kick one each time (not sure why, was in original algorithm...)
|
||||||
while (j != NULL && mac_is_equal_bb(j->bssid_addr, kicking_ap->bssid_addr)) {
|
while (kicked_clients == 0 && j != NULL && mac_is_equal_bb(j->bssid_addr, kicking_ap->bssid_addr)) {
|
||||||
struct kicking_nr *kick_nr_list = NULL;
|
struct kicking_nr *kick_nr_list = NULL;
|
||||||
|
|
||||||
int do_kick = 0;
|
int kick_type = 0;
|
||||||
int own_score = 0;
|
int own_score = 0;
|
||||||
|
|
||||||
if (mac_find_entry(j->client_addr)) {
|
if (mac_find_entry(j->client_addr)) {
|
||||||
|
@ -492,29 +492,54 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) {
|
||||||
else {
|
else {
|
||||||
dawn_mutex_require(&probe_array_mutex);
|
dawn_mutex_require(&probe_array_mutex);
|
||||||
probe_entry* own_probe = probe_array_get_entry(j->client_addr, kicking_ap->bssid_addr);
|
probe_entry* own_probe = probe_array_get_entry(j->client_addr, kicking_ap->bssid_addr);
|
||||||
|
|
||||||
if (own_probe == NULL) {
|
if (own_probe == NULL) {
|
||||||
// no entry for own ap - may happen if DAWN is started after client has connected, and then "sleeps" so sends no BEACON / PROBE
|
// no entry for own ap - may happen if DAWN is started after client has connected, and then "sleeps" so sends no BEACON / PROBE
|
||||||
dawnlog_info("Current AP " MACSTR " for client " MACSTR " not found in probe array!\n", MAC2STR(kicking_ap->bssid_addr.u8), MAC2STR(j->client_addr.u8));
|
dawnlog_info("Current AP " MACSTR " for client " MACSTR " not found in probe array!\n", MAC2STR(kicking_ap->bssid_addr.u8), MAC2STR(j->client_addr.u8));
|
||||||
print_probe_array();
|
print_probe_array();
|
||||||
|
|
||||||
|
// TODO: Work out a way to handle clients that are reluctant to share a probe / beacon that doesn't become DoS for them
|
||||||
|
// do_kick = -1;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
if ((kick_type == 0) && own_probe && (dawn_metric.kicking & 1) == 1) {
|
||||||
own_score = eval_probe_metric(own_probe, kicking_ap);
|
own_score = eval_probe_metric(own_probe, kicking_ap);
|
||||||
dawnlog_trace("Current AP score = %d for:\n", own_score);
|
dawnlog_trace("Current AP score = %d for:\n", own_score);
|
||||||
print_probe_entry(DAWNLOG_TRACE, own_probe);
|
print_probe_entry(DAWNLOG_TRACE, own_probe);
|
||||||
|
|
||||||
do_kick = better_ap_available(kicking_ap, own_probe, own_score, &kick_nr_list);
|
kick_type = better_ap_available(kicking_ap, own_probe, own_score, &kick_nr_list);
|
||||||
|
|
||||||
|
// If we found any candidates by evaluating PROBEs (even if too low to kick to) add the highest scoring one to local AP NR set
|
||||||
|
if (kick_type != 0 && 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((kick_type == 0) && own_probe && (dawn_metric.kicking & 2) == 2) {
|
||||||
|
int band = get_band(own_probe->freq);
|
||||||
|
|
||||||
|
if (own_probe->signal < dawn_metric.rssi_center[band])
|
||||||
|
{
|
||||||
|
dawnlog_info("Client " MACSTR ": Low asolute RSSI - proposing other APs\n", MAC2STR(j->client_addr.u8));
|
||||||
|
dawn_mutex_require(&ap_array_mutex);
|
||||||
|
|
||||||
|
// FIXME: Using all AP is OK for a small network, but should ideally use the local-to-current-AP set
|
||||||
|
for (ap* candidate_ap = ap_set; candidate_ap != NULL; candidate_ap = candidate_ap->next_ap) {
|
||||||
|
// Check is same SSID< but is not the current AP
|
||||||
|
if (candidate_ap != kicking_ap && strcmp((char*)kicking_ap->ssid, (char*)candidate_ap->ssid) == 0) {
|
||||||
|
insert_kicking_nr_by_bssid(&kick_nr_list, candidate_ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kick_type = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// better ap available
|
||||||
if (do_kick > 0) {
|
if (kick_type > 0) {
|
||||||
|
|
||||||
// kick after algorithm decided to kick several times
|
// kick after algorithm decided to kick several times
|
||||||
// + rssi is changing a lot
|
// + rssi is changing a lot
|
||||||
|
@ -562,28 +587,31 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) {
|
||||||
// don't deauth station? <- deauth is better!
|
// don't deauth station? <- deauth is better!
|
||||||
// maybe we can use handovers...
|
// maybe we can use handovers...
|
||||||
//del_client_interface(id, client_array[j].client_addr, NO_MORE_STAS, 1, 1000);
|
//del_client_interface(id, client_array[j].client_addr, NO_MORE_STAS, 1, 1000);
|
||||||
int sync_kick = wnm_disassoc_imminent(id, j->client_addr, kick_nr_list, own_score + dawn_metric.kicking_threshold, 12);
|
if (kick_type == 1)
|
||||||
|
|
||||||
// Synchronous kick is a test harness feature to indicate arrays have been updated, so don't change further
|
|
||||||
if (sync_kick)
|
|
||||||
{
|
{
|
||||||
kicked_clients++;
|
int sync_kick = wnm_disassoc_imminent(id, j->client_addr, kick_nr_list, own_score + dawn_metric.kicking_threshold, 12);
|
||||||
|
|
||||||
|
if (!sync_kick)
|
||||||
|
{
|
||||||
|
client_array_delete(j, false);
|
||||||
|
|
||||||
|
// don't delete clients in a row. use update function again...
|
||||||
|
// -> chan_util update, ...
|
||||||
|
//FIXME: Why / 4?
|
||||||
|
add_client_update_timer(timeout_config.update_client * 1000 / 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client_array_delete(j, false);
|
bss_transition_request(id, j->client_addr, kick_nr_list, 12);
|
||||||
|
|
||||||
// don't delete clients in a row. use update function again...
|
|
||||||
// -> chan_util update, ...
|
|
||||||
//FIXME: Why / 4?
|
|
||||||
add_client_update_timer(timeout_config.update_client * 1000 / 4);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kicked_clients++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (do_kick == -1) {
|
else if (kick_type == -1) {
|
||||||
// FIXME: Causes clients to be kicked until first probe is received, which is a bit brutal for pre-802.11k clients.
|
// FIXME: Causes clients to be kicked until first probe is received, which is a bit brutal for pre-802.11k clients.
|
||||||
dawnlog_info("Client " MACSTR ": No Information about client. Force reconnect:\n", MAC2STR(j->client_addr.u8));
|
dawnlog_info("Client " MACSTR ": No Information about client. Force reconnect:\n", MAC2STR(j->client_addr.u8));
|
||||||
print_client_entry(DAWNLOG_TRACE, j);
|
print_client_entry(DAWNLOG_TRACE, j);
|
||||||
|
@ -605,6 +633,7 @@ int kick_clients(struct dawn_mac bssid_mac, uint32_t id) {
|
||||||
if (dawn_metric.set_hostapd_nr == 2)
|
if (dawn_metric.set_hostapd_nr == 2)
|
||||||
ubus_set_nr_from_clients(ap_nr_list);
|
ubus_set_nr_from_clients(ap_nr_list);
|
||||||
|
|
||||||
|
// FIXME: Consider retaining this so it can be used for kick type 2 - low absolute RSSI
|
||||||
remove_kicking_nr_list(ap_nr_list);
|
remove_kicking_nr_list(ap_nr_list);
|
||||||
ap_nr_list = NULL;
|
ap_nr_list = NULL;
|
||||||
|
|
||||||
|
@ -634,7 +663,7 @@ void update_iw_info(struct dawn_mac bssid_mac) {
|
||||||
iee80211_calculate_expected_throughput_mbit(get_expected_throughput_iwinfo(j->client_addr)));
|
iee80211_calculate_expected_throughput_mbit(get_expected_throughput_iwinfo(j->client_addr)));
|
||||||
|
|
||||||
if (rssi != INT_MIN) {
|
if (rssi != INT_MIN) {
|
||||||
if (!probe_array_update_rssi(j->client_addr, j->bssid_addr, rssi, true)) {
|
if (probe_array_update_rssi(j->client_addr, j->bssid_addr, rssi, true) == NULL) {
|
||||||
dawnlog_info("Failed to update rssi!\n");
|
dawnlog_info("Failed to update rssi!\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -795,6 +824,7 @@ probe_entry* probe_array_update_rssi(struct dawn_mac client_addr, struct dawn_ma
|
||||||
|
|
||||||
dawn_mutex_require(&probe_array_mutex);
|
dawn_mutex_require(&probe_array_mutex);
|
||||||
probe_entry* probe_req_new = dawn_malloc(sizeof(probe_entry));
|
probe_entry* probe_req_new = dawn_malloc(sizeof(probe_entry));
|
||||||
|
probe_entry* probe_req_updated = NULL;
|
||||||
|
|
||||||
if (probe_req_new) {
|
if (probe_req_new) {
|
||||||
// Fields we will update
|
// Fields we will update
|
||||||
|
@ -812,7 +842,7 @@ probe_entry* probe_array_update_rssi(struct dawn_mac client_addr, struct dawn_ma
|
||||||
probe_req_new->next_probe = NULL;
|
probe_req_new->next_probe = NULL;
|
||||||
probe_req_new->next_probe_skip = NULL;
|
probe_req_new->next_probe_skip = NULL;
|
||||||
|
|
||||||
probe_entry* probe_req_updated = insert_to_probe_array(probe_req_new, false, false, false, time(0));
|
probe_req_updated = insert_to_probe_array(probe_req_new, false, false, false, time(0));
|
||||||
if (probe_req_new != probe_req_updated)
|
if (probe_req_new != probe_req_updated)
|
||||||
{
|
{
|
||||||
dawnlog_info("RSSI PROBE used to update client / BSSID = " MACSTR " / " MACSTR " \n", MAC2STR(probe_req_updated->client_addr.u8), MAC2STR(probe_req_updated->bssid_addr.u8));
|
dawnlog_info("RSSI PROBE used to update client / BSSID = " MACSTR " / " MACSTR " \n", MAC2STR(probe_req_updated->client_addr.u8), MAC2STR(probe_req_updated->bssid_addr.u8));
|
||||||
|
@ -829,7 +859,7 @@ probe_entry* probe_array_update_rssi(struct dawn_mac client_addr, struct dawn_ma
|
||||||
ubus_send_probe_via_network(probe_req_updated, false);
|
ubus_send_probe_via_network(probe_req_updated, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return probe_req_new;
|
return probe_req_updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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)
|
||||||
|
|
|
@ -34,6 +34,34 @@ int send_set_probe(struct dawn_mac client_addr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, uint32_t duration)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
printf("bss_transition_request() was called...\n");
|
||||||
|
|
||||||
|
if (neighbor_list != NULL)
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
// Use it to keep the results the same as before
|
||||||
|
while (neighbor_list && neighbor_list->next)
|
||||||
|
neighbor_list = neighbor_list->next;
|
||||||
|
for (int n = 0; n < ETH_ALEN; 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_ap->neighbor_report));
|
||||||
|
|
||||||
|
// Tell caller not to change the arrays any further
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, int threshold, uint32_t duration)
|
int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, int threshold, uint32_t duration)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
|
@ -1149,6 +1149,46 @@ void del_client_interface(uint32_t id, const struct dawn_mac client_addr, uint32
|
||||||
dawn_unregmem(&b);
|
dawn_unregmem(&b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bss_transition_request(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, uint32_t duration) {
|
||||||
|
struct hostapd_sock_entry* sub;
|
||||||
|
struct blob_buf b = { 0 };
|
||||||
|
|
||||||
|
dawnlog_debug_func("Entering...");
|
||||||
|
|
||||||
|
blob_buf_init(&b, 0);
|
||||||
|
dawn_regmem(&b);
|
||||||
|
blobmsg_add_macaddr(&b, "addr", client_addr);
|
||||||
|
blobmsg_add_u32(&b, "disassociation_timer", duration);
|
||||||
|
blobmsg_add_u32(&b, "validity_period", duration);
|
||||||
|
blobmsg_add_u8(&b, "abridged", 1); // prefer aps in neighborlist
|
||||||
|
blobmsg_add_u8(&b, "disassociation_imminent", 0); // Just a friendly request - no disassociation
|
||||||
|
|
||||||
|
void* nbs = blobmsg_open_array(&b, "neighbors");
|
||||||
|
|
||||||
|
// Add the first N AP
|
||||||
|
int neighbors_added = 0;
|
||||||
|
while (neighbors_added < dawn_metric.disassoc_nr_length && neighbor_list != NULL) {
|
||||||
|
dawnlog_info("BSS TRANSITION NEIGHBOR " NR_MACSTR "\n", NR_MAC2STR(neighbor_list->nr_ap->neighbor_report));
|
||||||
|
blobmsg_add_string(&b, NULL, neighbor_list->nr_ap->neighbor_report);
|
||||||
|
neighbor_list = neighbor_list->next;
|
||||||
|
neighbors_added++;
|
||||||
|
}
|
||||||
|
|
||||||
|
blobmsg_close_array(&b, nbs);
|
||||||
|
list_for_each_entry(sub, &hostapd_sock_list, list)
|
||||||
|
{
|
||||||
|
if (sub->subscribed) {
|
||||||
|
int timeout = 1; //TDO: Maybe ID is wrong?! OR CHECK HERE ID
|
||||||
|
ubus_invoke(ctx, id, "bss_transition_request", b.head, NULL, NULL, timeout * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blob_buf_free(&b);
|
||||||
|
dawn_unregmem(&b);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, int threshold, uint32_t duration) {
|
int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct kicking_nr* neighbor_list, int threshold, uint32_t duration) {
|
||||||
struct hostapd_sock_entry *sub;
|
struct hostapd_sock_entry *sub;
|
||||||
struct blob_buf b = {0};
|
struct blob_buf b = {0};
|
||||||
|
@ -1168,7 +1208,7 @@ int wnm_disassoc_imminent(uint32_t id, const struct dawn_mac client_addr, struct
|
||||||
// Add the first N AP that reach threshold, where list order id high->low score
|
// Add the first N AP that reach threshold, where list order id high->low score
|
||||||
int neighbors_added = 0;
|
int neighbors_added = 0;
|
||||||
while(neighbors_added < dawn_metric.disassoc_nr_length && neighbor_list != NULL && neighbor_list->score >= threshold) {
|
while(neighbors_added < dawn_metric.disassoc_nr_length && neighbor_list != NULL && neighbor_list->score >= threshold) {
|
||||||
dawnlog_info("BSS TRANSITION NEIGHBOR " NR_MACSTR ", Score=%d\n", NR_MAC2STR(neighbor_list->nr_ap->neighbor_report), neighbor_list->score);
|
dawnlog_info("WNM DISASSOC 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);
|
blobmsg_add_string(&b, NULL, neighbor_list->nr_ap->neighbor_report);
|
||||||
neighbor_list = neighbor_list->next;
|
neighbor_list = neighbor_list->next;
|
||||||
neighbors_added++;
|
neighbors_added++;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue