diff --git a/src/cntlr.c b/src/cntlr.c index c0f6f7cce879bbec9be3150414c872d18a5ae04d..03b1c3e6c755a0acbc98e13d6bb4485a1ad3f4bf 100644 --- a/src/cntlr.c +++ b/src/cntlr.c @@ -231,6 +231,23 @@ struct node *cntlr_find_node_with_bssid(struct controller *c, uint8_t *bssid) return NULL; } +/* returns first found node with given STA MAC on its stalist */ +struct node *cntlr_find_node_with_sta(struct controller *c, uint8_t *stamacaddr) +{ + struct node *n = NULL; + + list_for_each_entry(n, &c->nodelist, list) { + struct sta *e = NULL; + + list_for_each_entry(e, &n->stalist, list) { + if (!memcmp(e->macaddr, stamacaddr, 6)) + return n; + } + } + + return NULL; +} + #if (EASYMESH_VERSION >= 6) bool cntlr_radio_support_ap_wifi7(struct wifi7_radio_capabilities *wifi7_caps) { @@ -482,31 +499,84 @@ void cntlr_bcn_metrics_timer_cb(atimer_t *t) } } -void node_add_sta(struct node *n, struct sta *s) +static void cntlr_freeze_sta(struct controller *c, struct sta *s) +{ + timer_del(&s->bcn_metrics_timer); + timer_del(&s->btm_req_timer); + timer_del(&s->stale_sta_timer); + + sta_free_assoc_frame(s); + sta_free_bcn_metrics(s); + cntlr_clean_bcnreqlist_sta(c, s); +} + +static void cntlr_remove_sta(struct controller *c, struct sta *s) +{ + struct node *n = NULL; + + do { + n = cntlr_find_node_with_sta(c, s->macaddr); + if (n) + node_del_sta(n, s); + } while (n); + + cntlr_freeze_sta(c, s); + cntlr_del_sta(c->sta_table, s); +} + +void cntlr_stale_sta_timer_cb(atimer_t *t) +{ + trace("%s: --->\n", __func__); + + struct sta *s = container_of(t, struct sta, stale_sta_timer); + struct controller *c = s->cntlr; + time_t curr_time; + + if (!c) + return; + + if (WARN_ON(s->state == STA_ASSOCIATED || !s->disassoc_time)) { + /* should never happen */ + return; + } + + time(&curr_time); + if ((curr_time - s->disassoc_time) >= c->cfg.stale_sta_timeout) { + cntlr_dbg(LOG_STA, "%s: Delete STA " MACFMT " after %ds of disassociation\n", + __func__, MAC2STR(s->macaddr), c->cfg.stale_sta_timeout); + cntlr_remove_sta(c, s); + } +} + +int node_add_sta(struct node *n, struct sta *s) { if (WARN_ON(node_find_sta(n, s->macaddr))) { cntlr_dbg(LOG_STA, "%s: Warn! STA " MACFMT " already in node " MACFMT"\n", __func__, MAC2STR(s->macaddr), MAC2STR(n->almacaddr)); - return; + return -1; } memcpy(s->agent_almacaddr, n->almacaddr, 6); list_add(&s->list, &n->stalist); n->sta_count++; + + return 0; } -void node_del_sta(struct node *n, struct sta *s) +int node_del_sta(struct node *n, struct sta *s) { if (WARN_ON(!node_find_sta(n, s->macaddr))) { cntlr_dbg(LOG_STA, "%s: Warn! STA " MACFMT " not in node " MACFMT"\n", __func__, MAC2STR(s->macaddr), MAC2STR(n->almacaddr)); - return; + return -1; } list_del(&s->list); n->sta_count--; + + return 0; } struct sta *node_find_sta(struct node *n, uint8_t *macaddr) @@ -535,23 +605,6 @@ struct unassoc_sta_metrics *cntlr_find_usta_metric(struct controller *c, return NULL; } -static void cntlr_freeze_sta(struct controller *c, struct sta *s) -{ - timer_del(&s->bcn_metrics_timer); - timer_del(&s->btm_req_timer); - - sta_free_assoc_frame(s); - sta_free_bcn_metrics(s); - cntlr_clean_bcnreqlist_sta(c, s); -} - -static void cntlr_remove_sta(struct controller *c, struct node *n, struct sta *s) -{ - cntlr_freeze_sta(c, s); - node_del_sta(n, s); - cntlr_del_sta(c->sta_table, s->macaddr); -} - struct cmdu_buff *cntlr_query_sta_metric(struct controller *c, struct sta *s) { if (!c || !s) @@ -875,7 +928,7 @@ static void node_clean_stalist(struct controller *c, struct node *n) return; list_for_each_entry_safe(s, tmp, &n->stalist, list) { - cntlr_remove_sta(c, n, s); + node_del_sta(n, s); } if (WARN_ON(n->sta_count != 0)) { @@ -890,6 +943,27 @@ static void cntlr_clean_mac_hashtable(struct controller *c) mactable_flush(c->mac_table); } +static void cntlr_clean_all_sta(struct controller *c) +{ + struct hlist_node *tmp = NULL; + int i; + + for (i = 0; i < MAC_HASHTABLE_SIZE; i++) { + struct sta *s = NULL; + + if (hlist_empty(&c->sta_table[i])) + continue; + + hlist_for_each_entry_safe(s, tmp, &c->sta_table[i], hlist) { + hlist_del(&s->hlist, &c->sta_table[i]); + cntlr_freeze_sta(c, s); + cntlr_free_sta(s); + } + } + + c->num_sta = 0; +} + static void cntlr_clean_nodelist(struct controller *c) { struct node *n = NULL, *tmp; @@ -1708,34 +1782,6 @@ static void cntlr_event_handler(struct ubus_context *ctx, free(str); } -//FIXME: move to history -static void cntlr_remove_stale_sta(struct controller *c) -{ - struct node *n = NULL; - time_t curr_time; - - if (!c) - return; - - time(&curr_time); - list_for_each_entry(n, &c->nodelist, list) { - struct sta *s = NULL, *tmp; - - list_for_each_entry_safe(s, tmp, &n->stalist, list) { - if (s->state != STA_ASSOCIATED && s->disassoc_time != 0) { - if ((curr_time - s->disassoc_time) >= c->cfg.stale_sta_timeout) { - cntlr_dbg(LOG_STA, - "%s: Delete STA " MACFMT " after %ds of disassociation\n", - __func__, MAC2STR(s->macaddr), - c->cfg.stale_sta_timeout); - - cntlr_remove_sta(c, n, s); - } - } - } - } -} - static void cntlr_periodic_run(atimer_t *t) { struct controller *c = container_of(t, struct controller, heartbeat); @@ -1762,7 +1808,6 @@ static void cntlr_periodic_run(atimer_t *t) } #endif cntlr_ageout_nodes(c); - cntlr_remove_stale_sta(c); timer_set(&c->heartbeat, 1 * 1000); } @@ -1916,6 +1961,7 @@ out_exit: cntlr_clean_bcnreqlist(c); cntlr_clean_linklist(c); cntlr_clean_nodelist(c); + cntlr_clean_all_sta(c); free_topology(&c->topology); ubus_unregister_event_handler(ctx, &c->evh); cntlr_remove_object(c); diff --git a/src/cntlr.h b/src/cntlr.h index bdbf67292a861b7ea2755e4a1fb468ad6068da52..7382fd2076db657c663683a9e30fb7b198656e0a 100644 --- a/src/cntlr.h +++ b/src/cntlr.h @@ -367,6 +367,7 @@ struct node *cntlr_add_node(struct controller *c, uint8_t *almacaddr); struct node *cntlr_alloc_node(struct controller *c, uint8_t *almacaddr); struct node *cntlr_find_node(struct controller *c, uint8_t *almacaddr); struct node *cntlr_find_node_with_bssid(struct controller *c, uint8_t *bssid); +struct node *cntlr_find_node_with_sta(struct controller *c, uint8_t *stamacaddr); struct netif_link *cntlr_alloc_link(struct controller *c, uint8_t *upstream, uint8_t *downstream); @@ -413,8 +414,8 @@ int cntlr_sync_dyn_controller_config(struct controller *c, uint8_t *agent); void cntrl_send_max_wifi_bh_hops_policy(struct controller *c); -void node_add_sta(struct node *n, struct sta *s); -void node_del_sta(struct node *n, struct sta *s); +int node_add_sta(struct node *n, struct sta *s); +int node_del_sta(struct node *n, struct sta *s); struct sta *node_find_sta(struct node *n, uint8_t *sta_macaddr); int cntlr_register_steer_module(struct controller *c, const char *name); diff --git a/src/cntlr_map.c b/src/cntlr_map.c index 4a537ddb2b9cc73145f996cb7a351734e59976b4..2fb3c8515dca80ed1dcf6a42a4eb18f8345145d0 100644 --- a/src/cntlr_map.c +++ b/src/cntlr_map.c @@ -170,6 +170,17 @@ int handle_topology_discovery(void *cntlr, struct cmdu_buff *cmdu, return 0; } +static void cntlr_send_client_caps_query(struct controller *c, struct sta *s) +{ + struct cmdu_buff *txcmdu; + + txcmdu = cntlr_gen_client_caps_query(c, c->almacaddr, s->macaddr, s->bssid); + if (txcmdu) { + send_cmdu(c, txcmdu); + cmdu_free(txcmdu); + } +} + int handle_topology_notification(void *cntlr, struct cmdu_buff *cmdu, struct node *n) { @@ -228,87 +239,74 @@ int handle_topology_notification(void *cntlr, struct cmdu_buff *cmdu, return 0; } - bsta_iface = cntlr_find_iface_type(c, ev->macaddr, MAC_ENTRY_BSTA); - s = cntlr_find_sta(c->sta_table, ev->macaddr); - if (associated) { - struct node *old_n = NULL; - - if (!s) { - struct cmdu_buff *txcmdu; - - s = cntlr_add_sta(c, c->sta_table, ev->macaddr); - if (!s) { - cntlr_dbg(LOG_STA, "%s: failed to add STA " MACFMT "\n", - __func__, MAC2STR(ev->macaddr)); - return -1; - } - + if (s) { + if (associated) { time(&s->assoc_time); - s->state = STA_ASSOCIATED; + timer_del(&s->stale_sta_timer); memcpy(s->bssid, ev->bssid, 6); - node_add_sta(n, s); + s->state = STA_ASSOCIATED; - txcmdu = cntlr_gen_client_caps_query(c, c->almacaddr, s->macaddr, s->bssid); - if (txcmdu) { - send_cmdu(c, txcmdu); - cmdu_free(txcmdu); + if (memcmp(s->agent_almacaddr, n->almacaddr, 6)) { + /* associated to a new node - remove from the old one */ + struct node *old_n = NULL; + + old_n = cntlr_find_node(c, s->agent_almacaddr); + if (old_n) + node_del_sta(old_n, s); } - goto inform_steer_plugins; - } + node_add_sta(n, s); - /* remove sta from old-node and add to new-node */ - old_n = cntlr_find_node(c, s->agent_almacaddr); - if (old_n) { - if (node_find_sta(old_n, s->macaddr)) { + cntlr_send_client_caps_query(c, s); + } else { + if (!memcmp(s->agent_almacaddr, n->almacaddr, 6)) { + /* disassociated from current node */ time(&s->disassoc_time); + timer_set(&s->stale_sta_timer, c->cfg.stale_sta_timeout); + //memset(s->bssid, 0, sizeof(s->bssid)); s->state = STA_DISCONNECTED; - node_del_sta(old_n, s); } - } - if (!node_find_sta(n, ev->macaddr)) { - struct cmdu_buff *txcmdu; + node_del_sta(n, s); + } + } else { /* unknown sta */ + if (associated) { + s = cntlr_add_sta(c, c->sta_table, ev->macaddr); + if (!s) { + cntlr_dbg(LOG_STA, "%s: failed to add STA " MACFMT "\n", + __func__, MAC2STR(ev->macaddr)); + return -1; + } time(&s->assoc_time); - s->state = STA_ASSOCIATED; memcpy(s->bssid, ev->bssid, 6); + s->state = STA_ASSOCIATED; + node_add_sta(n, s); - txcmdu = cntlr_gen_client_caps_query(c, c->almacaddr, s->macaddr, s->bssid); - if (txcmdu) { - send_cmdu(c, txcmdu); - cmdu_free(txcmdu); - } - } - } else { - if (!s) { + cntlr_send_client_caps_query(c, s); + } else { cntlr_dbg(LOG_STA, "Ignore unknown STA " MACFMT " disassoc event\n", MAC2STR(ev->macaddr)); return 0; } - - if (node_find_sta(n, ev->macaddr)) { - time(&s->disassoc_time); - s->state = STA_DISCONNECTED; - node_del_sta(n, s); - } } + bsta_iface = cntlr_find_iface_type(c, ev->macaddr, MAC_ENTRY_BSTA); s->is_bsta = bsta_iface || bh ? true : false; cntlr_info(LOG_STA, "%s: STA " MACFMT " %s Node " MACFMT"\n", __func__, MAC2STR(s->macaddr), s->state == STA_ASSOCIATED ? "associated to" : "disconnected from", MAC2STR(s->agent_almacaddr)); - } -inform_steer_plugins: - if (s) { cntlr_update_sta_steer_data(c, s); + } + if (s) { + /* Inform steering plugins */ c->inform_cmdu_type = CMDU_TYPE_TOPOLOGY_NOTIFICATION; c->inform_sta_num = 1; memset(c->inform_stalist, 0, sizeof(c->inform_stalist)); @@ -634,18 +632,21 @@ int handle_topology_response(void *cntlr, struct cmdu_buff *cmdu, struct node *n s->de_sta->conn_time = conntime; s->state = conntime != 0 ? STA_ASSOCIATED : STA_DISCONNECTED; if (old_state != STA_ASSOCIATED && s->state == STA_ASSOCIATED) { - struct cmdu_buff *txcmdu; - + if (!hwaddr_is_zero(s->agent_almacaddr) && + memcmp(s->agent_almacaddr, n->almacaddr, 6)) { + /* associated to a new node - remove from the old one */ + struct node *old_n = NULL; + + old_n = cntlr_find_node(c, s->agent_almacaddr); + if (old_n) + node_del_sta(old_n, s); + } node_add_sta(n, s); time(&s->assoc_time); - txcmdu = cntlr_gen_client_caps_query(c, - c->almacaddr, - s->macaddr, - s->bssid); - if (txcmdu) { - send_cmdu(c, txcmdu); - cmdu_free(txcmdu); - } + if (timer_pending(&s->stale_sta_timer)) + timer_del(&s->stale_sta_timer); + + cntlr_send_client_caps_query(c, s); } else if (old_state != STA_DISCONNECTED && s->state == STA_DISCONNECTED) { node_del_sta(n, s); time(&s->disassoc_time); diff --git a/src/sta.c b/src/sta.c index f3e37013625cd87b235cb473189876e75d5efa54..afb91e68c113d7d973bdf7ed4b7c943d51e9d25d 100644 --- a/src/sta.c +++ b/src/sta.c @@ -23,6 +23,7 @@ extern void cntlr_bcn_metrics_timer_cb(atimer_t *t); extern void cntlr_btm_req_timer_cb(atimer_t *t); +extern void cntlr_stale_sta_timer_cb(atimer_t *t); struct sta *cntlr_find_sta(struct hlist_head *table, uint8_t *macaddr) { @@ -53,6 +54,7 @@ static struct sta *sta_alloc(uint8_t *macaddr) memcpy(s->macaddr, macaddr, 6); timer_init(&s->bcn_metrics_timer, cntlr_bcn_metrics_timer_cb); timer_init(&s->btm_req_timer, cntlr_btm_req_timer_cb); + timer_init(&s->stale_sta_timer, cntlr_stale_sta_timer_cb); time(&s->lookup_time); s->de_sta = (struct wifi_sta_element *)(s + 1); @@ -101,9 +103,9 @@ struct sta *cntlr_add_sta(void *cntlr, struct hlist_head *table, uint8_t *macadd if (least_used_sta) { cntlr_dbg(LOG_STA, "%s: remove least used STA " MACFMT - " to add new STA " MACFMT "\n", __func__, - MAC2STR(least_used_sta->de_sta->macaddr), - MAC2STR(macaddr)); + " to add new STA " MACFMT "\n", __func__, + MAC2STR(least_used_sta->de_sta->macaddr), + MAC2STR(macaddr)); node_remove_sta(c, n, least_used_sta); } else { @@ -112,6 +114,10 @@ struct sta *cntlr_add_sta(void *cntlr, struct hlist_head *table, uint8_t *macadd } } #endif + if (WARN_ON(hwaddr_is_zero(macaddr))) { + /* should never happen */ + return NULL; + } s = sta_alloc(macaddr); if (!s) @@ -125,24 +131,39 @@ struct sta *cntlr_add_sta(void *cntlr, struct hlist_head *table, uint8_t *macadd return s; } -void cntlr_del_sta(struct hlist_head *table, uint8_t *macaddr) +void cntlr_del_sta_hash(struct hlist_head *table, uint8_t *macaddr) { + int idx; struct hlist_node *tmp = NULL; struct sta *s = NULL; - int idx; + bool found = false; idx = sta_hash(macaddr); - if (hlist_empty(&table[idx])) - return; - - hlist_for_each_entry_safe(s, tmp, &table[idx], hlist) { - if (!memcmp(s->macaddr, macaddr, 6)) { - hlist_del(&s->hlist, &table[idx]); - s->cntlr = NULL; - sta_free(s); - return; + if (!hlist_empty(&table[idx])) { + hlist_for_each_entry_safe(s, tmp, &table[idx], hlist) { + if (!memcmp(s->macaddr, macaddr, 6)) { + hlist_del(&s->hlist, &table[idx]); + found = true; + } } } + + if (!found) { + cntlr_warn(LOG_STA, "%s: STA " MACFMT " not found in table\n", + __func__, MAC2STR(macaddr)); + } +} + +void cntlr_free_sta(struct sta *del) +{ + del->cntlr = NULL; + sta_free(del); +} + +void cntlr_del_sta(struct hlist_head *table, struct sta *del) +{ + cntlr_del_sta_hash(table, del->macaddr); + cntlr_free_sta(del); } int sta_link_metrics_process(struct sta *s) diff --git a/src/sta.h b/src/sta.h index 244691f1dba31cca5ae5530c5e73143ca7e81dc8..06a25e9b566db9ac43a53b5bba449f536afbc13d 100644 --- a/src/sta.h +++ b/src/sta.h @@ -48,6 +48,7 @@ struct sta { time_t assoc_time; time_t disassoc_time; uint16_t disassoc_reason; + atimer_t stale_sta_timer; struct wifi_sta_element *de_sta; @@ -73,7 +74,9 @@ struct sta { struct sta *cntlr_find_sta(struct hlist_head *table, uint8_t *macaddr); struct sta *cntlr_add_sta(void *cntlr, struct hlist_head *table, uint8_t *macaddr); -void cntlr_del_sta(struct hlist_head *table, uint8_t *macaddr); +void cntlr_free_sta(struct sta *s); +void cntlr_del_sta_hash(struct hlist_head *table, uint8_t *macaddr); +void cntlr_del_sta(struct hlist_head *table, struct sta *del); int sta_link_metrics_process(struct sta *s); void sta_free_bcn_metrics(struct sta *s);