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);