diff --git a/src/agent.c b/src/agent.c index 2c97ce3ec9f6c3a28b2e0e24247558f7b26efd11..0feb2d219ccb9eae9f105ff9cab153ff27a038a5 100644 --- a/src/agent.c +++ b/src/agent.c @@ -1316,6 +1316,16 @@ static void wifi_sta_steer_timeout(atimer_t *t) timer_set(&s->sta_steer_timer, 1000); } +static void wifi_sta_steered_deauth(atimer_t *t) +{ + struct sta *s = container_of(t, struct sta, sta_steer_deauth_timer); + struct netif_ap *vif = s->vif; + + warn("%s: Disconnect station: " MACFMT " from interface: %s with reson:%i\n", + __func__, MAC2STR(s->macaddr), vif->name, WIFI_REASON_BSS_TRANSITION_DISASSOC); + wifi_disconnect_sta(vif->name, s->macaddr, WIFI_REASON_BSS_TRANSITION_DISASSOC); +} + static int cond_refresh_sta_neighbor_list(struct agent *a, struct sta *s) { struct netif_ap *vif = s->vif; @@ -1514,6 +1524,11 @@ static int wifi_add_sta(struct agent *a, const char *vif, timer_set(&sptr->sta_finalize_timer, ifptr->cfg->steer_legacy_retry_secs * 1000); } + /* In case station is already on stalist, cancel steered station + * deauthentication timer if it is stil runnning. + */ + if (timer_pending(&sptr->sta_steer_deauth_timer)) + timer_del(&sptr->sta_steer_deauth_timer); return 0; } } @@ -1531,6 +1546,7 @@ static int wifi_add_sta(struct agent *a, const char *vif, timer_init(&new->sta_bcn_req_timer, wifi_sta_bcn_req); timer_init(&new->sta_steer_timer, wifi_sta_steer_timeout); timer_init(&new->sta_finalize_timer, wifi_sta_finalize); + timer_init(&new->sta_steer_deauth_timer, wifi_sta_steered_deauth); timestamp_update(&new->last_update); INIT_LIST_HEAD(&new->sta_nbrlist); INIT_LIST_HEAD(&new->pref_nbrlist); @@ -1581,6 +1597,7 @@ static int wifi_del_sta(struct agent *a, const char *vif, timer_del(&s->sta_steer_timer); timer_del(&s->sta_bcn_req_timer); timer_del(&s->sta_timer); + timer_del(&s->sta_steer_deauth_timer); list_del(&s->list); list_flush(&s->pref_nbrlist, struct pref_neighbor, list); list_flush(&s->sta_nbrlist, struct sta_neighbor, list); @@ -2367,7 +2384,37 @@ static void wifi_sta_event_handler(void *c, struct blob_attr *msg) trace("%s: btm-resp for "MACFMT" status %d\n", __func__, MAC2STR(mac), status); - if (status) { + /* Generally after successful steering station is disassociated from source BSSID, + * but sometimes it happens that station is not disassociated from source BSSID + * and is associated to targed BSSID at the same time. To avoid that situation + * we start timer here to disconnect wifi station when it left on source BSSID. + * When driver removes station after successful steer then timer will never end + * because it will be deleted together with station, but when timer hits timeout + * then it means station was not disconnected and funtion wifi_sta_steered_deauth + * will do this. + */ + if (!status) { + struct netif_ap *p = NULL; + struct sta *s = NULL; + + list_for_each_entry(p, &a->aplist, list) { + if (!strcmp(p->name, ifname)) { + break; + } + } + + if (!p) { + warn("%s: Unable to find iface %s\n", __func__, ifname); + return; + } + + list_for_each_entry(s, &p->stalist, list) { + if (!memcmp(s->macaddr, mac, 6)) { + timer_set(&s->sta_steer_deauth_timer, STA_STEERED_DEAUTH_INTERVAL * 1000); + break; + } + } + } else { /* TODO: * update reject counter and retry steer later */ diff --git a/src/agent.h b/src/agent.h index 31eb2092dd3c0cc550a7fe8b7fa0734371eae339..1a083c07313f10a78da872e1badf985557ea5215 100644 --- a/src/agent.h +++ b/src/agent.h @@ -149,6 +149,7 @@ struct wifi_assoc_frame { #define STA_NBR_REFRESH_CNT 120 /** x5 = 10 mins in auto */ #define STA_NBR_LIST_INTERVAL 2000 /** fetch bcn rpt after 2 secs of requesting*/ #define STA_NBR_AGEOUT_INTERVAL 10000 /** sta bcnreport is dynamic; expires quickly */ +#define STA_STEERED_DEAUTH_INTERVAL 10 /** 10 sec after successful sterring sta will be cleaned up */ typedef struct cntlr_preflist { int num; @@ -213,6 +214,7 @@ struct sta { uint32_t steer_opportunity_tmo; /** steer op timeout in msec */ struct timespec steer_opportunity; /** steer opportunity time window */ atimer_t sta_steer_timer; /** steer opportunity timer */ + atimer_t sta_steer_deauth_timer; /** time to deauth sta left after successful ster */ atimer_t sta_finalize_timer; /** for sta cleanup */ int ref; /** ref counting purpose */ bool legacy_steered; /** legacy steered */