diff --git a/src/Makefile b/src/Makefile
index a027ddf1ed20c1fb9583d8a8d9a90e500a086207..a8910ba167c58f34bf3e038b98133c751f97554f 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -37,7 +37,8 @@ AGENT_OBJS = \
 	dppfrag.o \
 	dpphandler.o \
 	qos.o \
-	unasta.o
+	unasta.o \
+	mld.o
 
 ifneq (,$(findstring VENDOR_EXTENSION,$(CFLAGS)))
 AGENT_OBJS += extension.o
diff --git a/src/agent.c b/src/agent.c
index d518584a783218f25f400aea5627b05c23e5a69c..37eb8f29830a9ae629b23141970e96609167337e 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -59,6 +59,9 @@
 #include "qos.h"
 #endif
 #include "extension.h"
+#if (EASYMESH_VERSION >= 6)
+#include "mld.h"
+#endif
 #include "nl.h"
 #include "steer_rules.h"
 #include "timer_impl.h"
@@ -74,7 +77,6 @@ struct json_object;
 
 #define map_plugin	"ieee1905.map"
 
-#define IFACE_TIMEOUT 1
 #define BOOT_UP_SCAN_TIME	(0 * 1000)
 #define BOOT_UP_SCAN_ITV	(2 * 1000)
 #define BOOT_UP_SCAN_MAX_TRY 5
@@ -93,10 +95,6 @@ static int agent_req_btm_steer(struct agent *a, const char *ifname,
 		uint32_t validity_int);
 static void netif_free(struct netif_ap *ap);
 static void netif_reset(struct netif_ap *ap);
-#if (EASYMESH_VERSION >= 6)
-static void clear_apmld(struct netif_mld *mld);
-#endif
-void agent_clear_bsta_mld(struct agent *a);
 
 static void bsta_steer_cb(atimer_t *t)
 {
@@ -198,37 +196,7 @@ struct node *agent_add_node(struct agent *a, uint8_t *almac)
 	return n;
 }
 
-#if (EASYMESH_VERSION >= 6)
-bool wifi_is_affiliated_ap(struct agent *a, uint8_t *bssid)
-{
-	struct netif_ap *ap;
-
-	ap = agent_get_ap(a, bssid);
-	if (ap && ap->is_affiliated_ap)
-		return true;
-
-	return false;
-}
-
 
-bool agent_radio_support_ap_wifi7(struct wifi7_radio_capabilities *wifi7_caps)
-{
-	if (wifi7_caps->ap_str_support || wifi7_caps->ap_nstr_support ||
-		wifi7_caps->ap_emlsr_support || wifi7_caps->ap_emlmr_support)
-		return true;
-
-	return false;
-}
-
-bool agent_radio_support_bsta_wifi7(struct wifi7_radio_capabilities *wifi7_caps)
-{
-	if (wifi7_caps->bsta_str_support || wifi7_caps->bsta_nstr_support ||
-		wifi7_caps->bsta_emlsr_support || wifi7_caps->bsta_emlmr_support)
-		return true;
-
-	return false;
-}
-#endif
 struct wifi_radio_element *agent_get_radio_by_band(struct agent *a,
 						   enum wifi_band band)
 {
@@ -536,136 +504,8 @@ struct wifi_assoc_frame *wifi_get_frame(struct agent *a, uint8_t *macaddr)
 	return NULL;
 }
 
-#if (EASYMESH_VERSION >=6)
-struct netif_mld *agent_get_mld_by_ifname(struct agent *a, const char *ifname)
-{
-	struct netif_mld *mld = NULL;
-
-	list_for_each_entry(mld, &a->apmldlist, list) {
-		if (!strncmp(ifname, mld->ifname, sizeof(mld->ifname)))
-			return mld;
-	}
-
-	return NULL;
-}
-
-struct netif_mld *agent_alloc_mld(struct agent *a, const char *ifname)
-{
-	struct netif_mld *mld;
-
-	if (strlen(ifname) == 0) {
-		err("|%s:%d| MLD can not have empty ifname\n", __func__, __LINE__);
-		return NULL;
-	}
-
-	mld = calloc(1, sizeof(*mld));
-	if (!mld)
-		return NULL;
-
-	dbg("|%s:%d| allocated mld ifname:%s\n", __func__, __LINE__, ifname);
-
-	INIT_LIST_HEAD(&mld->stamldlist);
-
-	strncpy(mld->ifname, ifname, sizeof(mld->ifname));
-	list_add_tail(&mld->list, &a->apmldlist);
-	a->num_ap_mld++;
-
-	return mld;
-}
 
 
-bool agent_is_ap_in_mld(struct agent *a, struct netif_mld *mld,
-			     uint8_t *macaddr)
-{
-	int i;
-
-	for (i = 0; i < mld->num_affiliated_ap; i++) {
-		if (!memcmp(mld->affiliated_ap[i]->bssid, macaddr, 6))
-			return true;
-	}
-
-	return false;
-}
-
-bool agent_is_sta_in_sta_mld(struct agent *a, struct sta_mld *mld,
-			     uint8_t *macaddr)
-{
-	int i;
-
-	for (i = 0; i < mld->num_affiliated_sta; i++) {
-		if (!memcmp(mld->affiliated_sta[i]->macaddr, macaddr, 6))
-			return true;
-	}
-
-	return false;
-}
-
-
-bool agent_is_sta_in_bsta_mld(struct agent *a, struct bsta_mld *mld,
-			     uint8_t *macaddr)
-{
-	int i;
-
-	for (i = 0; i < mld->num_affiliated_bsta; i++) {
-		if (!memcmp(mld->affiliated_bsta[i]->macaddr, macaddr, 6))
-			return true;
-	}
-
-	return false;
-}
-
-
-struct sta_mld *agent_get_stamld(struct agent *a, uint8_t *macaddr)
-{
-	struct netif_mld *mld;
-
-	list_for_each_entry(mld, &a->apmldlist, list) {
-		struct sta_mld *s;
-
-		list_for_each_entry(s, &mld->stamldlist, list) {
-			if (!memcmp(macaddr, s->macaddr, 6))
-				return s;
-		}
-	}
-
-	return NULL;
-}
-
-struct sta_mld *agent_alloc_stamld(struct agent *a, struct netif_mld *mld,
-				    uint8_t *macaddr)
-{
-	struct sta_mld *s;
-
-	s = calloc(1, sizeof(*s));
-	if (!s)
-		return NULL;
-
-	trace("|%s:%d| allocate sta mac:"MACFMT"\n", __func__, __LINE__, MAC2STR(macaddr));
-	memcpy(s->macaddr, macaddr, 6);
-
-	list_add_tail(&s->list, &mld->stamldlist);
-
-	return s;
-}
-
-struct bsta_mld *agent_init_bstamld(struct agent *a, char *ifname,
-				     struct wifi7_radio_capabilities *caps)
-{
-	struct bsta_mld *bsta = &a->bstamld;
-
-	strncpy(bsta->ifname, ifname, sizeof(bsta->ifname));
-	dbg("|%s:%d| allocated bsta mld:%s\n", __func__, __LINE__, bsta->ifname);
-
-	bsta->str_enabled = caps->bsta_str_support;
-	bsta->nstr_enabled = caps->bsta_nstr_support;
-	bsta->emlsr_enabled = caps->bsta_emlsr_support;
-	bsta->emlmr_enabled = caps->bsta_emlmr_support;
-	a->has_bstamld = true;
-
-	return bsta;
-}
-#endif
-
 /* lookup netif_bk struct by device */
 struct netif_bk *agent_bsta_in_radio(struct agent *a,
 		const char *device)
@@ -1614,55 +1454,17 @@ static int cond_refresh_sta_neighbor_list(struct agent *a, struct sta *s)
 	return 0;
 }
 
-#if (EASYMESH_VERSION >= 6)
-static void mlsta_update_sta_mld(struct agent *a, struct netif_ap *ap,
-			struct wifi_mlsta *mlsta, struct sta *s)
-{
-	struct sta_mld *mld;
-	int num_sta = 0;
-
-	if (!ap || !mlsta)
-		return;
-
-	//err("|%s:%d| mldmac:"MACFMT" linkmac:"MACFMT"\n",
-	//    __func__, __LINE__,
-	//    MAC2STR(ap->mld->macaddr), MAC2STR(mlsta->macaddr));
-
-	mld = agent_get_stamld(a, mlsta->macaddr);
-	if (!mld) {
-		mld = agent_alloc_stamld(a, ap->mld, mlsta->macaddr);
-		if (!mld)
-			return;
-	}
-
-	memcpy(mld->bssid, mlsta->bssid, 6);
-	num_sta = mld->num_affiliated_sta;
-
-	s->mld = mld;
-	s->is_affiliated_sta = true;
-	s->mlo_link_id = mlsta->sta[0].mlo_link_id;
-
-	if (!agent_is_sta_in_sta_mld(a, mld, mlsta->sta[0].macaddr) &&
-		    num_sta < MAX_AFFILIATED_STA_LINKS_NUM) {
-		mld->affiliated_sta[num_sta] = s;
-		mld->num_affiliated_sta++;
-	}
 
-	//err("|%s:%d| num affiliated_sta:%d\n",
-	//    __func__, __LINE__,
-	//    mld->num_affiliated_sta);
-}
-#endif
 
 #define STA_STALE_STATS_CNT_MAX 60
 static void wifi_sta_periodic_run(atimer_t *t)
 {
 	struct sta *s = container_of(t, struct sta, sta_timer);
 	struct pref_neighbor *pref_nbr = NULL;
-	struct netif_ap *ap;
+	struct agent *a = s->agent;
 	struct wifi_sta sta = {};
+	struct netif_ap *ap;
 	unsigned int reason;
-	struct agent *a = s->agent;
 	int ret = 0;
 
 	ap = agent_get_ap(a, s->bssid);
@@ -1694,12 +1496,8 @@ static void wifi_sta_periodic_run(atimer_t *t)
 #if (EASYMESH_VERSION >= 6)
 	} else {
 		struct wifi_mlsta mlsta = {0};
-		uint8_t *mld_macaddr = NULL;
-
-		if (s->mld)
-			mld_macaddr = s->mld->macaddr;
 
-		ret = wifi_get_mld_station(ap, mld_macaddr, s->macaddr, &mlsta);
+		ret = wifi_get_mld_station(ap, s->mld_macaddr, s->macaddr, &mlsta);
 		if (ret)
 			goto rearm_periodic;
 
@@ -1713,17 +1511,11 @@ static void wifi_sta_periodic_run(atimer_t *t)
 			return;
 		}
 
+		if (mlsta.mlo_capable == true &&
+		    !hwaddr_is_zero(mlsta.sta[0].bssid))
+			stamld_update(a, ap, mlsta.macaddr, mlsta.bssid,
+				      mlsta.sta[0].mlo_link_id, s);
 
-		//err("%s: mac:"MACFMT" linkbssid:"MACFMT" mlo_link_id:%d\n",
-		//    __func__, MAC2STR(s->macaddr),
-		//    MAC2STR(mlsta.sta[0].bssid),
-		//    mlsta.sta[0].mlo_link_id);
-
-		if (mlsta.mlo_capable == true
-		    && !hwaddr_is_zero(mlsta.sta[0].bssid)
-		    && ap->mld) {
-			mlsta_update_sta_mld(a, ap, &mlsta, s);
-		}
 		update_sta_entry(a, ap, &(mlsta.sta[0]));
 	}
 #endif
@@ -1875,105 +1667,6 @@ static struct sta *wifi_add_sta(struct agent *a, const char *ifname,
 	return new;
 }
 
-#if (EASYMESH_VERSION >= 6)
-/* remove passed affiliated STA from mld */
-int wifi_sta_mld_del_sta(struct agent *a, struct sta *s)
-{
-	struct sta_mld *mld;
-	int i;
-
-	if (!s->mld)
-		return -1;
-
-	mld = s->mld;
-	for (i = 0; i < mld->num_affiliated_sta; i++) {
-		int j;
-
-		if (memcmp(mld->affiliated_sta[i]->macaddr, s->macaddr, 6))
-			continue;
-
-		for (j = (i + 1); j < mld->num_affiliated_sta; j++)
-			mld->affiliated_sta[j-1] = mld->affiliated_sta[j];
-
-		mld->affiliated_sta[j] = NULL;
-		mld->num_affiliated_sta--;
-	}
-
-	if (mld->num_affiliated_sta == 0) {
-		list_del(&mld->list);
-		free(mld);
-	}
-
-	return 0;
-}
-
-/* remove passed affiliated backhaul STA from mld */
-int wifi_sta_mld_del_bsta(struct agent *a, struct netif_bk *bk)
-{
-	struct bsta_mld *mld;
-	int i, j;
-
-	/* bk->mld may be NULL if bSTAMLD is not connected (Eth backhaul) */
-	if (!bk || bk->cfg->is_mld_netdev || !bk->mld)
-		return -1;
-
-	mld = bk->mld;
-	for (i = 0; i < mld->num_affiliated_bsta; i++) {
-		if (!memcmp(mld->affiliated_bsta[i]->macaddr, bk->macaddr, 6))
-			break;
-	}
-
-	if (i == mld->num_affiliated_bsta)
-		return -1;
-
-	for (j = (i + 1); j < mld->num_affiliated_bsta; j++)
-		mld->affiliated_bsta[j-1] = mld->affiliated_bsta[j];
-
-	mld->affiliated_bsta[j] = NULL;
-	mld->num_affiliated_bsta--;
-
-	bk->mld = NULL;
-	bk->is_affiliated_sta = false;
-
-	return 0;
-}
-
-/* remove passed affiliated AP from mld */
-static int wifi_mld_del_ap(struct netif_ap *ap)
-{
-	struct netif_mld *mld;
-	int i;
-
-	if (!ap->is_affiliated_ap)
-		return -1;
-
-	if (!ap->mld) {
-		warn("|%s:%d| MLD for given netif is not assigned!\n",
-		     __func__, __LINE__);
-		return -1;
-	}
-
-	mld = ap->mld;
-
-	for (i = 0; i < mld->num_affiliated_ap; i++) {
-		int j;
-
-		if (memcmp(mld->affiliated_ap[i]->bssid, ap->bssid, 6))
-			continue;
-
-		for (j = (i + 1); j < mld->num_affiliated_ap; j++)
-			mld->affiliated_ap[j-1] = mld->affiliated_ap[j];
-
-		mld->affiliated_ap[j] = NULL;
-		mld->num_affiliated_ap--;
-	}
-	ap->mld = NULL;
-	ap->is_affiliated_ap = false;
-
-	return 0;
-}
-#endif
-
 static int wifi_del_sta(struct agent *a, const char *ifname,
 		uint8_t *macaddr)
 {
@@ -2482,86 +2175,6 @@ static int wifi_process_rx_frame(struct agent *a, struct json_object *frameobj)
 	return -1;
 }
 
-#if (EASYMESH_VERSION >= 6)
-/* frame starting from payload, skipping header */
-int wifi_process_ml_ie(struct agent *a, struct sta_mld *stamld,
-		       uint8_t *assocframe, int framelen)
-{
-	uint8_t *ml;
-	uint8_t *ml_ctrl;
-	uint8_t type;
-	uint8_t presence_bmp[2];
-
-	bool linkid_info_present;
-	bool bss_param_chg_present;
-	bool medium_sync_present;
-	bool eml_caps_present;
-
-	bool mld_caps_ops_present;
-	uint8_t *common_info;
-	size_t pos;
-
-	ml = wifi_find_ie_ext(assocframe, framelen, IE_EXT_ML);
-	if (!ml) {
-		dbg("%s: frame did not include ML IE\n", __func__);
-		return -1;
-	}
-
-	ml_ctrl = ml + 3;
-	type = ml_ctrl[0] & 0x7;
-	presence_bmp[0] = (ml_ctrl[0] & 0xf0) >> 4;
-	presence_bmp[1] = ml_ctrl[1];
-
-	if (type != 0) {
-		dbg("%s: ML IE type non-zero\n", __func__);
-		return -1;
-	}
-
-	linkid_info_present = !!(presence_bmp[0] & 0x1);
-	bss_param_chg_present = !!(presence_bmp[0] & 0x2);
-	medium_sync_present = !!(presence_bmp[0] & 0x4);
-	eml_caps_present = !!(presence_bmp[0] & 0x8);
-
-	mld_caps_ops_present = !!(presence_bmp[1] & 0x1);
-	common_info = &ml_ctrl[2];
-	pos = 1;
-
-	pos += 6; /* skip apmld macaddr */
-
-	if (linkid_info_present)
-		pos += 1;
-
-	if (bss_param_chg_present)
-		pos += 1;
-
-	if (medium_sync_present)
-		pos += 2;
-
-	if (eml_caps_present) {
-		uint8_t *eml_caps = &common_info[pos];
-
-		stamld->emlsr_enabled = !!(eml_caps[0] & BIT(0)) ? true : false;
-		stamld->emlmr_enabled = !!(eml_caps[0] & BIT(7)) ? true : false;
-		pos += 2;
-	}
-
-	if (mld_caps_ops_present) {
-		uint8_t *mld_caps = &common_info[pos];
-		uint8_t max_simlinks = (mld_caps[0] & 0x0f);
-
-		pos += 2;
-		if (max_simlinks >= 1) {
-			stamld->nstr_enabled = false;
-			stamld->str_enabled = true;
-		} else {
-			stamld->nstr_enabled = true;
-			stamld->str_enabled = false;
-		}
-	}
-
-	return 0;
-}
-#endif
 
 /* generate a netif_ap with first available ifname on passed radio */
 struct netif_ap *agent_gen_netif_ap(struct agent *a, struct wifi_radio_element *re)
@@ -2657,6 +2270,7 @@ static uint16_t wifi_process_pvid_assoc_frame(struct agent *a, uint8_t *frame,
 }
 
 #define ASSOC_TIMEOUT	60
+/* TODO: add dedicated handler for each event type */
 static void wifi_sta_event_handler(void *c, struct blob_attr *msg)
 {
 	struct agent *a = (struct agent *)c;
@@ -2717,10 +2331,8 @@ static void wifi_sta_event_handler(void *c, struct blob_attr *msg)
 				return;
 
 			ap = agent_get_ap(a, bssid);
-			if (!ap) {
-				/* could also do link-id check here? */
+			if (!ap)
 				return;
-			}
 			strncpy(ifname,	ap->ifname, sizeof(ifname) - 1);
 		}
 #endif
@@ -2730,57 +2342,36 @@ static void wifi_sta_event_handler(void *c, struct blob_attr *msg)
 			s = wifi_add_sta(a, ifname, macaddr);
 		else
 			s = agent_get_sta(a, macaddr);
+#else
+		s = agent_get_sta(a, macaddr);
+#endif
 		if (!s) {
 			dbg("%s: Failed to add STA or STA has already disconnected\n", __func__);
 			return;
 		}
-#endif
-
 #if (EASYMESH_VERSION >= 6)
 		/* Affiliated STA MAC in-case of MLO client*/
-		if (add && data[2] && data[3] && data[4]) {
-			uint8_t linkid = 0;
-
-			linkid = (uint8_t) blobmsg_get_u32(data[4]);
-
-			if (ap && ap->mld) {
-				uint8_t mlo_bssid[6] = {0};
-				struct sta_mld *mld;
-				int num_sta = 0;
-
-				if (!hwaddr_aton(blobmsg_data(data[3]), mlo_macaddr))
-					return;
-				if (!hwaddr_aton(blobmsg_data(data[2]), mlo_bssid))
-					return;
-				mld = agent_get_stamld(a, mlo_macaddr);
-				if (!mld) {
-					mld = agent_alloc_stamld(a, ap->mld, mlo_macaddr);
-					if (!mld) {
-						err("%s: Failed to allocate MLD:"MACFMT"\n", __func__, MAC2STR(mlo_macaddr));
-						return;
-					}
-				}
+		if (ap && add && data[2] && data[3] && data[4]) {
+			uint8_t mlo_bssid[6] = {0};
+			uint8_t mlo_link_id = 0;
+			struct sta_mld *mld;
 
-				memcpy(mld->bssid, mlo_bssid, 6);
+			mlo_link_id = (uint8_t) blobmsg_get_u32(data[4]);
 
-				/* TODO: code is copy pasted from mlsta_update_sta_mld() */
-				num_sta = mld->num_affiliated_sta;
-
-				s->mld = mld;
-				s->is_affiliated_sta = true;
-				s->mlo_link_id = linkid;
+			if (!hwaddr_aton(blobmsg_data(data[3]), mlo_macaddr))
+				return;
+			if (!hwaddr_aton(blobmsg_data(data[2]), mlo_bssid))
+				return;
 
-				if (!agent_is_sta_in_sta_mld(a, mld, macaddr) &&
-					num_sta < MAX_AFFILIATED_STA_LINKS_NUM) {
-					mld->affiliated_sta[num_sta] = s;
-					mld->num_affiliated_sta++;
-				}
+			mld = stamld_update(a, ap, mlo_macaddr, mlo_bssid,
+					    mlo_link_id, s);
+			if (!mld)
+				return;
 
-				if (s->assoc_frame && s->assoc_frame->len > 4) {
-					wifi_process_ml_ie(a, mld,
-						s->assoc_frame->frame + 4,
-						s->assoc_frame->len - 4);
-				}
+			if (s->assoc_frame && s->assoc_frame->len > 4) {
+				wifi_process_ml_ie(a, mld,
+					s->assoc_frame->frame + 4,
+					s->assoc_frame->len - 4);
 			}
 		}
 #endif
@@ -4754,42 +4345,7 @@ static void wifi_bsta_event_handler(void *agent, struct blob_attr *msg)
 	}
 }
 
-#if (EASYMESH_VERSION >= 6)
-static void wifi_mld_event_handler(void *agent, struct blob_attr *msg)
-{
-	char ifname[16] = {0}, event[16] = {0};
-	struct agent *a = (struct agent *) agent;
-	struct blob_attr *tb[3];
-	static const struct blobmsg_policy ev_attr[3] = {
-		[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
-		[1] = { .name = "event", .type = BLOBMSG_TYPE_STRING },
-		[2] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
-	};
-	bool add, del;
-
-	blobmsg_parse(ev_attr, 3, tb, blob_data(msg), blob_len(msg));
 
-	if (!tb[0] || !tb[1])
-		return;
-
-	strncpy(ifname,	blobmsg_data(tb[0]), sizeof(ifname) - 1);
-	strncpy(event, blobmsg_data(tb[1]), sizeof(event) - 1);
-
-	add = !strcmp(event, "mlo-link-added");
-	del = !strcmp(event, "mlo-link-remove");
-
-	if (add) {
-		/* more actions */
-		timer_set(&a->init_ifaces_scheduler,
-			  IFACE_TIMEOUT * 1000);
-	} else if (del) {
-		/* more actions */
-		timer_set(&a->init_ifaces_scheduler,
-			  IFACE_TIMEOUT * 1000);
-	}
-}
-
-#endif
 
 #define ONBOARDING_TIMER 15
 static void wifi_wps_creds_event_handler(void *agent, struct blob_attr *msg)
@@ -4901,7 +4457,7 @@ static void agent_event_handler(struct ubus_context *ctx,
 #endif
 #endif
 #if (EASYMESH_VERSION >= 6)
-		{ "wifi.mld", wifi_mld_event_handler },
+		{ "wifi.mld", mld_event_handler },
 #endif
 	};
 
@@ -5679,7 +5235,7 @@ struct netif_ap *wifi_radio_to_ap(struct agent *a, struct wifi_radio_element *re
 	return NULL;
 }
 
-static void bk_toggle(struct agent *a, struct netif_bk *bk,
+void bk_toggle(struct agent *a, struct netif_bk *bk,
 		uint8_t *bssid, uint32_t freq)
 {
 	/* connect */
@@ -5891,325 +5447,6 @@ static void parse_ap_stats(struct ubus_request *req, int type,
 		bss->rx_bcast_bytes = blobmsg_get_u64(tb[5]);
 }
 
-#if (EASYMESH_VERSION >= 6)
-static int parse_affiliated_ap(struct ubus_request *req, int type,
-		struct blob_attr *msg)
-{
-	struct netif_ap *ap = (struct netif_ap *) req->priv;
-	static const struct blobmsg_policy ap_attr[] = {
-		[0] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
-		[1] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
-		[2] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 },
-		[3] = { .name = "ccfs0", .type = BLOBMSG_TYPE_INT32 },
-		[4] = { .name = "ccfs1", .type = BLOBMSG_TYPE_INT32 },
-		[5] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 },
-		[6] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
-		[7] = { .name = "security", .type = BLOBMSG_TYPE_STRING },
-		[8] = { .name = "encryption", .type = BLOBMSG_TYPE_STRING },
-		[9] = { .name = "standard", .type = BLOBMSG_TYPE_STRING },
-		[10] = { .name = "num_stations", .type = BLOBMSG_TYPE_INT32 },
-		[11] = { .name = "max_stations", .type = BLOBMSG_TYPE_INT32 },
-		[12] = { .name = "utilization", .type = BLOBMSG_TYPE_INT32 },
-		[13] = { .name = "adm_capacity", .type = BLOBMSG_TYPE_INT32 },
-		[14] = { .name = "hidden", .type = BLOBMSG_TYPE_BOOL },
-		[15] = { .name = "supp_security", .type = BLOBMSG_TYPE_ARRAY },
-		[16] = { .name = "capabilities", .type = BLOBMSG_TYPE_TABLE },
-	};
-	struct blob_attr *tb[ARRAY_SIZE(ap_attr)];
-	enum wifi_band band;
-
-	if (!ap)
-		return -1;
-
-	blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blobmsg_data(msg), blobmsg_data_len(msg));
-
-	if (!tb[0] || !tb[1] || !tb[6]) {
-		return -1;
-	}
-
-	band = wifi_bandstr_to_band(blobmsg_get_string(tb[1]));
-	if (band != ap->band)
-		return -1;
-
-	ap->linkid = blobmsg_get_u32(tb[0]);
-
-	hwaddr_aton(blobmsg_data(tb[6]), ap->bssid);
-	if (tb[2])
-		ap->channel = blobmsg_get_u32(tb[2]);
-
-	if (tb[5])
-		ap->bandwidth = blobmsg_get_u32(tb[5]);
-
-	if (tb[9])
-		strncpy(ap->standard, blobmsg_data(tb[9]), sizeof(ap->standard) - 1);
-
-	if (tb[10])
-		ap->num_sta = blobmsg_get_u32(tb[10]);
-
-	return 0;
-}
-
-static void parse_apmld(struct ubus_request *req, int type,
-		struct blob_attr *msg)
-{
-	static const struct blobmsg_policy ap_attr[] = {
-		[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
-		[1] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
-		[2] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING },
-		[3] = { .name = "mode", .type = BLOBMSG_TYPE_STRING },
-		[4] = { .name = "links", .type = BLOBMSG_TYPE_ARRAY },
-		[5] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
-	};
-	struct netif_ap *ap = (struct netif_ap *)req->priv;
-	struct blob_attr *tb[ARRAY_SIZE(ap_attr)];
-	struct agent *a = ap->agent;
-	struct netif_mld *mld;
-	const char *ifname;
-	const char *ssid;
-	uint8_t bssid[6] = {0};
-
-	blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blob_data(msg), blob_len(msg));
-
-	if (!tb[0] || !tb[1] || !tb[2] || !tb[3] || !tb[4] || !tb[5]) {
-		err("|%s:%d| missing some mandatory field!\n", __func__, __LINE__);
-		return;
-	}
-
-	ifname = blobmsg_get_string(tb[0]);
-	if (strlen(ifname) == 0)
-		return;
-
-	mld = agent_get_mld_by_ifname(a, ifname);
-	if (!mld) {
-		mld = agent_alloc_mld(a, ifname);
-		if (!mld) {
-			err("|%s:%d| failed to alloc MLD\n", __func__, __LINE__);
-			return;
-		}
-	}
-
-	if (!hwaddr_aton(blobmsg_data(tb[1]), mld->macaddr)) {
-		err("|%s:%d| MLD mac not valid\n", __func__, __LINE__);
-		return;
-	}
-
-	if (!hwaddr_aton(blobmsg_data(tb[5]), bssid)) {
-		err("|%s:%d| MLD BSSID not valid\n", __func__, __LINE__);
-		return;
-	}
-
-	/* In case of absence mld interface in the system, macaddres will be zero, use bssid */
-	if (hwaddr_is_zero(mld->macaddr) && !hwaddr_is_zero(bssid))
-		memcpy(mld->macaddr, bssid, 6);
-
-	ssid = blobmsg_get_string(tb[2]);
-	strncpy(mld->ssid, ssid, sizeof(mld->ssid));
-
-	if (tb[4]) {
-		struct blob_attr *link = NULL;
-		int rem_links = 0;
-
-		blobmsg_for_each_attr(link, tb[4], rem_links) {
-			struct wifi_radio_element *re = NULL;
-			struct wifi7_radio_capabilities *caps;
-			int num_ap = 0;
-			int ret;
-
-			if (blobmsg_type(link) != BLOBMSG_TYPE_TABLE) {
-				err("|%s:%d| link was not a table\n", __func__, __LINE__);
-				continue;
-			}
-
-			ret = parse_affiliated_ap(req, type, link);
-			if (ret)
-				continue;
-
-			strncpy(ap->mld_ifname, ifname, sizeof(ap->mld_ifname) - 1);
-			ap->is_affiliated_ap = true;
-			strncpy(ap->ssid, ssid, sizeof(ap->ssid));
-			ap->enabled = true;
-
-			num_ap = mld->num_affiliated_ap;
-			if (!agent_is_ap_in_mld(a, mld, ap->bssid) &&
-				num_ap < MAX_AFFILIATED_AP_LINKS_NUM) {
-				mld->affiliated_ap[num_ap] = ap;
-				mld->num_affiliated_ap++;
-			} else {
-				err("|%s:%d| link with bssid:"MACFMT" was already in the MLD (or num_ap too high:%d)\n", __func__, __LINE__, MAC2STR(ap->bssid), mld->num_affiliated_ap);
-			}
-
-			re = agent_get_radio_with_ifname(a, ap->ifname);
-			if (re) {
-				caps = &re->wifi7_caps;
-				if (caps) {
-					/* TODO: revisit: */
-					/* Enable based on capabilities */
-					if (caps->ap_str_support)
-						mld->ap_str_enabled = true;
-					if (caps->ap_nstr_support)
-						mld->ap_nstr_enabled = true;
-					if (caps->ap_emlsr_support)
-						mld->ap_emlsr_enabled = true;
-					if (caps->ap_emlmr_support)
-						mld->ap_emlmr_enabled = true;
-				}
-			}
-			ap->mld = mld;
-			break;
-		}
-
-		if (mld->num_affiliated_ap == 0) {
-			err("|%s:%d| no affiliated APs found in MLD, schedule reload\n", __func__, __LINE__);
-			timer_set(&a->init_ifaces_scheduler, IFACE_TIMEOUT * 1000);
-		}
-
-	}
-}
-
-static void parse_affiliated_bsta(struct agent *a, struct bsta_mld *mld,
-				 struct netif_bk *bk, int type,
-				 struct blob_attr *msg)
-{
-
-	struct blob_attr *link;
-	int rem_links;
-
-	/* mlo_links; */
-	blobmsg_for_each_attr(link, msg, rem_links) {
-		static const struct blobmsg_policy mlo_links[] = {
-			[0] = { .name = "mlo_link_id", .type = BLOBMSG_TYPE_INT32 },
-			[1] = {	.name = "macaddr", .type = BLOBMSG_TYPE_STRING },
-			[2] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
-			[3] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
-			[4] = { .name = "frequency", .type = BLOBMSG_TYPE_INT32 },
-		};
-		struct blob_attr *data[ARRAY_SIZE(mlo_links)];
-		uint8_t link_id;
-		int num_sta;
-		enum wifi_band band;
-
-		blobmsg_parse(mlo_links, ARRAY_SIZE(mlo_links), data,
-			blobmsg_data(msg), blobmsg_data_len(msg));
-
-		if (!data[0] || !data[1] || !data[2] || !data[3]) {
-			err("|%s:%d| missing mlo_links data for ifname:%s\n", __func__, __LINE__, bk->ifname);
-			continue;
-		}
-
-		link_id = (uint8_t) blobmsg_get_u32(data[0]);
-
-		band = wifi_bandstr_to_band(blobmsg_get_string(data[3]));
-		if (band != bk->cfg->band)
-			continue;
-
-		hwaddr_aton(blobmsg_data(data[1]), bk->macaddr);
-		hwaddr_aton(blobmsg_data(data[2]), bk->bssid);
-
-		num_sta = mld->num_affiliated_bsta;
-		bk->mld = mld;
-		bk->is_affiliated_sta = true;
-		bk->linkid = link_id;
-
-		if (!agent_is_sta_in_bsta_mld(a, mld, bk->macaddr) &&
-			num_sta < MAX_AFFILIATED_STA_LINKS_NUM) {
-			mld->affiliated_bsta[num_sta] = bk;
-			mld->num_affiliated_bsta++;
-		}
-
-		break;
-	}
-}
-
-void parse_bstamld(struct ubus_request *req, int type,
-		struct blob_attr *msg)
-{
-	static const struct blobmsg_policy ap_attr[] = {
-		[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
-		[1] = { .name = "status", .type = BLOBMSG_TYPE_STRING },
-		[2] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
-		[3] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
-		[4] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING },
-		[5] = { .name = "4addr", .type = BLOBMSG_TYPE_BOOL },
-		[6] = { .name = "mlo_links", .type = BLOBMSG_TYPE_ARRAY },
-	};
-	struct netif_bk *bk = (struct netif_bk *)req->priv;
-	struct blob_attr *tb[ARRAY_SIZE(ap_attr)];
-	struct wifi_radio_element *re;
-	struct agent *a = bk->agent;
-	uint8_t macaddr[6] = {0};
-	uint8_t bssid[6] = {0};
-	struct bsta_mld *mld = &a->bstamld;
-	const char *ifname;
-	const char *ssid = NULL;
-
-	blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blob_data(msg), blob_len(msg));
-
-	if (!tb[0] || !tb[1] || !tb[2] || !tb[5]) {
-		err("|%s:%d| missing some mandatory field(s)!\n", __func__, __LINE__);
-		return;
-	}
-
-	if (tb[4])
-		ssid = blobmsg_get_string(tb[4]);
-
-	if (!hwaddr_aton(blobmsg_data(tb[2]), macaddr)) {
-		err("|%s:%d| MAC not valid\n", __func__, __LINE__);
-		return;
-	}
-
-	if (tb[3] && !hwaddr_aton(blobmsg_data(tb[3]), bssid)) {
-		err("|%s:%d| MAC not valid\n", __func__, __LINE__);
-		return;
-	}
-
-	ifname = blobmsg_get_string(tb[0]);
-	re = agent_get_radio_with_ifname(a, bk->ifname);
-	if (!re) {
-		err("|%s:%d| could not find radio element\n", __func__,
-			__LINE__);
-		return;
-	}
-
-	mld = agent_init_bstamld(a, (char *)ifname, &re->wifi7_caps);
-	if (!mld) {
-		err("|%s:%d| failed to alloc bSTA MLD ifname:%s\n", __func__, __LINE__, ifname);
-		return;
-	}
-
-	memcpy(mld->macaddr, macaddr, 6);
-	memcpy(mld->bssid, bssid, 6);
-
-	if (bk->cfg->is_mld_netdev && !hwaddr_is_zero(bssid)) {
-		bk->mld = mld;
-		memcpy(bk->macaddr, macaddr, 6);
-		memcpy(bk->bssid, bssid, 6);
-	}
-
-	if (tb[6] && !bk->cfg->is_mld_netdev) {
-		struct blob_attr *link = NULL;
-		int rem_links = 0;
-
-		blobmsg_for_each_attr(link, tb[6], rem_links) {
-			if (blobmsg_type(link) != BLOBMSG_TYPE_TABLE) {
-				err("|%s:%d| link was not a table\n", __func__, __LINE__);
-				continue;
-			}
-
-			parse_affiliated_bsta(a, mld, bk, type, link);
-			strncpy(bk->mld_ifname, ifname, sizeof(bk->mld_ifname) - 1);
-			bk->is_affiliated_sta = true;
-			if (ssid)
-				strncpy(bk->ssid, ssid, sizeof(bk->ssid));
-			bk->enabled = true;
-			bk->mld = mld;
-		}
-	}
-
-	if (!bk->is_affiliated_sta || bk->cfg->is_mld_netdev)
-		bk_toggle(a, bk, bssid, 0);
-}
-#endif
-
 static void parse_ap(struct ubus_request *req, int type,
 		struct blob_attr *msg)
 {
@@ -6276,7 +5513,7 @@ static void parse_ap(struct ubus_request *req, int type,
 	}
 
 	if (tb[12])
-		ap->linkid = blobmsg_get_u32(tb[12]);
+		ap->mlo_link_id = blobmsg_get_u32(tb[12]);
 #endif
 
 	if (tb[13]) {
@@ -6518,7 +5755,7 @@ int agent_init_interfaces(struct agent *a)
 			ap->enabled = false;
 #if (EASYMESH_VERSIN >= 6)
 			if (ap->is_affiliated_ap)
-				wifi_mld_del_ap(ap);
+				mld_del_ap(a, ap);
 #endif
 		}
 	}
@@ -6585,7 +5822,7 @@ int agent_init_interfaces(struct agent *a)
 								 f->mld_id);
 			if (mldcred) {
 				snprintf(objname, 31, "wifi.apmld.%s", mldcred->ifname);
-				fn_parser = parse_apmld;
+				fn_parser = apmld_parse;
 				band = band_to_int(re->band);
 			}
 		}
@@ -6616,7 +5853,7 @@ int agent_init_interfaces(struct agent *a)
 
 		blob_buf_init(&bb, 0);
 #if (EASYMESH_VERSION >= 6)
-		if (band)
+		if (f->mld_id)
 			blobmsg_add_u32(&bb, "band", band);
 #endif
 		ubus_call_object_args(a, uobj_id, &bb, "stats", parse_ap_stats, bss);
@@ -6625,7 +5862,7 @@ int agent_init_interfaces(struct agent *a)
 	}
 
 	/** if AP is gone from config free it altogether
-	 *  if AP is disabled, cancel all timers/data
+	 *  if AP is disabled, cancel all timers and clear data
 	 */
 	list_for_each_entry(re, &a->radiolist, list) {
 		struct netif_ap *ap, *tmp;
@@ -6677,7 +5914,7 @@ int agent_init_interfaces(struct agent *a)
 								 b->mld_id);
 			if (mldcred) {
 				snprintf(objname, 31, "wifi.bstamld.%s", mldcred->ifname);
-				bk_parser = parse_bstamld;
+				bk_parser = bstamld_parse;
 			}
 		}
 #endif
@@ -6704,11 +5941,11 @@ int agent_init_interfaces(struct agent *a)
 	/* if an MLD is gone from config free it */
 	list_for_each_entry_safe(mld, tmp, &a->apmldlist, list) {
 		if (!agent_get_mld_credential_by_ifname(&a->cfg, mld->ifname))
-			clear_apmld(mld);
+			apmld_clean(a, mld);
 	}
 
 	if (a->has_bstamld) {
-		/* if bsta config has gone away free bstamld */
+		/* if bsta config has gone away clear bstamld */
 		if (!agent_get_bsta_mld_credential(&a->cfg))
 			agent_clear_bsta_mld(a);
 	}
@@ -7221,7 +6458,7 @@ void clear_sta(struct sta *s)
 	}
 #if (EASYMESH_VERSION >= 6)
 	if (s->is_affiliated_sta)
-		wifi_sta_mld_del_sta(s->agent, s);
+		mld_del_sta(s->agent, s);
 #endif
 	free(s);
 }
@@ -7277,7 +6514,7 @@ static void netif_reset(struct netif_ap *ap)
 
 #if (EASYMESH_VERSION >= 6)
 	if (ap->is_affiliated_ap)
-		wifi_mld_del_ap(ap);
+		mld_del_ap(ap->agent, ap);
 #endif
 }
 
@@ -7328,7 +6565,7 @@ void clear_bk(struct agent *a, struct netif_bk *bk)
 {
 #if (EASYMESH_VERSION >= 6)
 	if (bk->is_affiliated_sta)
-		wifi_sta_mld_del_bsta(a, bk);
+		mld_del_bsta(a, bk);
 #endif
 	memset(bk, 0, sizeof(*bk));
 }
@@ -7354,128 +6591,6 @@ void clear_wdslist(struct agent *a)
 	}
 }
 
-#if (EASYMESH_VERSION >= 6)
-
-void agent_clean_affiliated_sta_mld(struct sta_mld *mld)
-{
-	int i;
-
-	for (i = (mld->num_affiliated_sta - 1); i >= 0; i--) {
-		struct sta *s = mld->affiliated_sta[i];
-
-		if (!s)
-			continue;
-
-		s->mld = NULL;
-		s->is_affiliated_sta = false;
-		mld->affiliated_sta[i] = NULL;
-	}
-
-	mld->num_affiliated_sta = 0;
-}
-
-
-void agent_free_sta_mld(struct sta_mld *mld)
-{
-	agent_clean_affiliated_sta_mld(mld);
-
-	list_del(&mld->list);
-	free(mld);
-}
-
-/*
-void clear_stamldlist(struct agent *a)
-{
-	struct netif_mld *mld = NULL;
-
-	list_for_each_entry_safe(mld, tmp,  &a->apmldlist, list) {
-		struct sta_mld *smld = NULL, *tmp;
-
-		list_for_each_entry_safe(smld, tmp,  &mld->stamldlist, list)
-			agent_free_sta_mld(mld);
-	}
-}
-*/
-
-void agent_clean_affiliated_bsta_mld(struct bsta_mld *mld)
-{
-	int i;
-
-	for (i = 0; i < mld->num_affiliated_bsta; i++) {
-		struct netif_bk *bk = mld->affiliated_bsta[i];
-
-		if (!bk)
-			continue;
-
-		bk->mld = NULL;
-		bk->is_affiliated_sta = false;
-		mld->affiliated_bsta[i] = NULL;
-	}
-
-	mld->num_affiliated_bsta = 0;
-}
-
-
-void agent_clear_bsta_mld(struct agent *a)
-{
-	struct bsta_mld *mld = &a->bstamld;
-
-	agent_clean_affiliated_bsta_mld(mld);
-
-	a->has_bstamld = false;
-}
-
-void agent_clean_affiliated_ap_mld(struct netif_mld *mld)
-{
-	int i;
-
-	for (i = (mld->num_affiliated_ap - 1); i >= 0; i--) {
-		struct netif_ap *ap = mld->affiliated_ap[i];
-
-		if (!ap)
-			continue;
-
-		ap->mld = NULL;
-		ap->is_affiliated_ap = false;
-		mld->affiliated_ap[i] = NULL;
-	}
-
-	mld->num_affiliated_ap = 0;
-}
-
-
-void agent_free_ap_mld(struct netif_mld *mld)
-{
-	agent_clean_affiliated_ap_mld(mld);
-
-	list_del(&mld->list);
-	free(mld);
-}
-
-/* TODO: fix mld free funcs... too many and they are all different */
-
-static void clear_apmld(struct netif_mld *mld)
-{
-	struct sta_mld *smld = NULL, *stmp;
-
-	list_for_each_entry_safe(smld, stmp,  &mld->stamldlist, list)
-		agent_free_sta_mld(smld);
-
-	agent_free_ap_mld(mld);
-}
-
-void clear_apmldlist(struct agent *a)
-{
-	struct netif_mld *mld = NULL, *tmp;
-
-	list_for_each_entry_safe(mld, tmp,  &a->apmldlist, list) {
-		clear_apmld(mld);
-	}
-
-	a->num_ap_mld = 0;
-}
-#endif
-
 int agent_map_sub_cb(void *bus, void *priv, void *data)
 {
 	struct blob_attr *msg = (struct blob_attr *)data;
@@ -7855,7 +6970,7 @@ void run_agent(void)
 #endif
 #if (EASYMESH_VERSION >= 6)
 	agent_clear_bsta_mld(w);
-	clear_apmldlist(w);
+	apmld_free_all(w);
 #endif
 	ubus_unregister_event_handler(ctx, &w->evh);
 #ifdef VENDOR_EXTENSION
@@ -8046,7 +7161,6 @@ int wifiagent_get_status(struct ubus_context *ctx,
 {
 	struct agent *agent = this_agent;
 	struct wifi_radio_element *re;
-	struct netif_ap *p = NULL;
 	struct neighbor *n;
 	struct blob_buf bb;
 	void *a, *b, *c, *d, *t;
@@ -8056,6 +7170,8 @@ int wifiagent_get_status(struct ubus_context *ctx,
 
 	a = blobmsg_open_array(&bb, "radios");
 	list_for_each_entry(re, &agent->radiolist, list) {
+		struct netif_ap *ap = NULL;
+
 		t = blobmsg_open_table(&bb, "");
 		blobmsg_add_string(&bb, "name", re->name);
 		blobmsg_add_macaddr(&bb, "macaddr", re->macaddr);
@@ -8072,40 +7188,45 @@ int wifiagent_get_status(struct ubus_context *ctx,
 		blobmsg_close_table(&bb, b);
 
 		d = blobmsg_open_array(&bb, "fronthaul");
-		list_for_each_entry(p, &re->aplist, list) {
+		list_for_each_entry(ap, &re->aplist, list) {
 			struct sta *s;
 			void *tt;
 
-			if (!p->cfg)
+			if (!ap->cfg)
 				continue;
 
 			tt = blobmsg_open_table(&bb, "");
-			blobmsg_add_string(&bb, "name", p->ifname);
+			blobmsg_add_string(&bb, "name", ap->ifname);
 	#if (EASYMESH_VERSION >= 6)
-			blobmsg_add_u8(&bb, "is_affiliated_ap", p->is_affiliated_ap);
-			if (p->is_affiliated_ap && p->mld) {
-				blobmsg_add_string(&bb, "mld_ifname", p->mld->ifname);
-				blobmsg_add_u32(&bb, "mlo_linkid", p->linkid);
+			blobmsg_add_u8(&bb, "is_affiliated_ap", ap->is_affiliated_ap);
+			if (ap->is_affiliated_ap) {
+				struct netif_mld *apmld;
+
+				apmld = agent_get_apmld(a, ap->mld_macaddr);
+				if (apmld) {
+					blobmsg_add_string(&bb, "mld_ifname", apmld->ifname);
+					blobmsg_add_u32(&bb, "mlo_link_id", ap->mlo_link_id);
+				}
 			}
 	#endif
-			if (p->band == BAND_2)
+			if (ap->band == BAND_2)
 				blobmsg_add_string(&bb, "band", "2.4GHz");
-			else if (p->band == BAND_5)
+			else if (ap->band == BAND_5)
 				blobmsg_add_string(&bb, "band", "5GHz");
-			else if (p->band == BAND_6)
+			else if (ap->band == BAND_6)
 				blobmsg_add_string(&bb, "band", "6GHz");
 			else
 				blobmsg_add_string(&bb, "band", "Unknown");
 
-			blobmsg_add_u8(&bb, "enabled", p->enabled);
-			blobmsg_add_macaddr(&bb, "bssid", p->bssid);
-			blobmsg_add_string(&bb, "ssid", p->ssid);
-			blobmsg_add_u32(&bb, "channel", p->channel);
-			blobmsg_add_u32(&bb, "load", p->bssload);
-			blobmsg_add_u32(&bb, "num_sta", p->num_sta);
+			blobmsg_add_u8(&bb, "enabled", ap->enabled);
+			blobmsg_add_macaddr(&bb, "bssid", ap->bssid);
+			blobmsg_add_string(&bb, "ssid", ap->ssid);
+			blobmsg_add_u32(&bb, "channel", ap->channel);
+			blobmsg_add_u32(&bb, "load", ap->bssload);
+			blobmsg_add_u32(&bb, "num_sta", ap->num_sta);
 
 			b = blobmsg_open_array(&bb, "neighbor");
-			list_for_each_entry(n, &p->nbrlist, list) {
+			list_for_each_entry(n, &ap->nbrlist, list) {
 				void *ttt;
 
 				ttt = blobmsg_open_table(&bb, "");
@@ -8116,7 +7237,7 @@ int wifiagent_get_status(struct ubus_context *ctx,
 			blobmsg_close_array(&bb, b);
 
 			b = blobmsg_open_array(&bb, "stations");
-			list_for_each_entry(s, &p->stalist, list) {
+			list_for_each_entry(s, &ap->stalist, list) {
 				void *aa, *ttt, *tttt;
 				struct pref_neighbor *pn;
 
@@ -8124,10 +7245,15 @@ int wifiagent_get_status(struct ubus_context *ctx,
 				blobmsg_add_macaddr(&bb, "macaddr", s->macaddr);
 	#if (EASYMESH_VERSION >= 6)
 				blobmsg_add_u8(&bb, "is_affiliated_sta", s->is_affiliated_sta);
-				if (s->is_affiliated_sta && s->mld) {
-					blobmsg_add_macaddr(&bb, "mld_macaddr", s->mld->macaddr);
-					blobmsg_add_macaddr(&bb, "mld_bssid", s->mld->bssid);
-					blobmsg_add_u32(&bb, "mlo_linkid", s->mlo_link_id);
+				if (s->is_affiliated_sta) {
+					struct sta_mld *smld;
+
+					smld = agent_get_stamld(a, s->mld_macaddr);
+					if (smld) {
+						blobmsg_add_macaddr(&bb, "mld_macaddr", smld->macaddr);
+						blobmsg_add_macaddr(&bb, "mld_bssid", smld->bssid);
+						blobmsg_add_u32(&bb, "mlo_linkid", s->mlo_link_id);
+					}
 				}
 	#endif
 				/* blobmsg_add_u32(&bb, "conn_time", s->connected_ms / 1000); */
@@ -8202,15 +7328,15 @@ int wifiagent_get_status(struct ubus_context *ctx,
 
 		aa = blobmsg_open_array(&bb, "affiliated_ap");
 		for (i = 0; i < mld->num_affiliated_ap; i++) {
+			struct netif_ap *ap;
 			void *tt;
 
-			p = mld->affiliated_ap[i];
-
-			if (!p)
-				break;
+			ap = agent_get_ap(a, mld->affiliated_ap[i]);
+			if (!ap)
+				continue;
 
 			tt = blobmsg_open_table(&bb, "");
-			blobmsg_add_string(&bb, "ifname", p->ifname);
+			blobmsg_add_string(&bb, "ifname", ap->ifname);
 			blobmsg_close_table(&bb, tt);
 		}
 		blobmsg_close_array(&bb, aa);
@@ -8229,8 +7355,12 @@ int wifiagent_get_status(struct ubus_context *ctx,
 			for (i = 0; i < smld->num_affiliated_sta; i++) {
 				void *ttttt;
 				struct sta *s;
+
 				ttttt = blobmsg_open_table(&bb, "");
-				s = smld->affiliated_sta[i];
+				s = agent_get_sta(a, smld->affiliated_sta[i]);
+				if (!s)
+					continue;
+
 				blobmsg_add_macaddr(&bb, "macaddr", s->macaddr);
 				blobmsg_add_macaddr(&bb, "bssid", s->bssid);
 				blobmsg_add_u32(&bb, "linkid", s->mlo_link_id);
@@ -8262,10 +7392,9 @@ int wifiagent_get_status(struct ubus_context *ctx,
 			struct netif_bk *bk;
 			void *tt;
 
-			bk = agent->bstamld.affiliated_bsta[i];
-
+			bk = agent_get_bsta(a, agent->bstamld.affiliated_bsta[i]);
 			if (!bk)
-				break;
+				continue;
 
 			tt = blobmsg_open_table(&bb, "");
 			blobmsg_add_string(&bb, "ifname", bk->ifname);
diff --git a/src/agent.h b/src/agent.h
index 7953de5dac4880e37823bb9c793d274b8dd1dc24..8f9b458f142eed2c0f3b97c7e9d1abcac9cecab7 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -27,12 +27,15 @@
 #include "utils/allmac.h"
 #include "config.h"
 #include "nl.h"
+#include "mld.h"
+
 #include "wifi.h"
 #include "wifi_opclass.h"
 #include "wifi_scanresults.h"
 
 struct blob_attr;
 
+#define IFACE_TIMEOUT 1
 
 #ifndef EASYMESH_VENDOR_EXT_OUI_DEFAULT
 #define EASYMESH_VENDOR_EXT_OUI_DEFAULT		0xB456FA  /* IOPSYS OUI */
@@ -272,35 +275,6 @@ typedef uint32_t wifi_object_t;
 
 #define WIFI_OBJECT_INVALID	((uint32_t)-1)
 
-#if (EASYMESH_VERSION >= 6)
-/* multi-link device */
-struct netif_mld {
-	uint8_t id;
-	char ifname[16];
-	int channel;
-	int bandwidth;
-	uint8_t macaddr[6];
-	char ssid[33];
-	char standard[32];
-	char radio_name[16];
-	bool enabled;
-	bool torndown;
-
-	bool ap_str_enabled;
-	bool ap_nstr_enabled;
-	bool ap_emlsr_enabled;
-	bool ap_emlmr_enabled;
-
-	struct agent *agent;
-	struct list_head stamldlist;
-
-	int num_affiliated_ap;
-#define MAX_AFFILIATED_AP_LINKS_NUM 14
-	struct netif_ap *affiliated_ap[MAX_AFFILIATED_AP_LINKS_NUM];
-
-	struct list_head list;
-};
-#endif
 
 /* fronthaul wifi (ap) interface */
 struct netif_ap {
@@ -344,8 +318,8 @@ struct netif_ap {
 #if (EASYMESH_VERSION >= 6)
 	bool is_affiliated_ap;
 	char mld_ifname[16];
-	uint32_t linkid;
-	struct netif_mld *mld;
+	uint32_t mlo_link_id;
+	uint8_t mld_macaddr[6];
 #endif
 	struct wifi_bss_element bss;
 
@@ -377,9 +351,9 @@ struct netif_bk {
 #if (EASYMESH_VERSION >= 6)
 	bool is_affiliated_sta;
 	char mld_ifname[16];
-	uint32_t linkid;
-	struct bsta_mld *mld;
-	bool is_mld_netdev;
+	uint32_t mlo_link_id;
+	//struct bsta_mld *mld;
+	uint8_t mld_macaddr[6];
 #endif
 	/* enum netif_type iftype; */
 	struct agent *agent;
@@ -405,44 +379,6 @@ struct netif_bk {
 	uint8_t blacklist_bssid[16][6];
 };
 
-#if (EASYMESH_VERSION >= 6)
-
-// struct used for client MLO STAs and own MLO bSTAs
-struct sta_mld {
-#define MAX_AFFILIATED_STA_LINKS_NUM 14
-	uint8_t macaddr[6];
-	uint8_t bssid[6];
-
-	bool str_enabled;
-	bool nstr_enabled;
-	bool emlsr_enabled;
-	bool emlmr_enabled;
-
-	int num_affiliated_sta;
-	struct sta *affiliated_sta[MAX_AFFILIATED_STA_LINKS_NUM];
-
-	struct list_head list;
-};
-
-struct bsta_mld {
-#define MAX_AFFILIATED_BSTA_LINKS_NUM 14
-	uint8_t macaddr[6];
-	uint8_t bssid[6];
-	char ifname[16];
-
-	struct netif_bk bk;
-
-	bool str_enabled;
-	bool nstr_enabled;
-	bool emlsr_enabled;
-	bool emlmr_enabled;
-
-	int num_affiliated_bsta;
-	struct netif_bk *affiliated_bsta[MAX_AFFILIATED_BSTA_LINKS_NUM];
-
-	struct list_head list;
-};
-#endif
 
 struct sta {
 	uint8_t macaddr[6];
@@ -450,7 +386,8 @@ struct sta {
 #if (EASYMESH_VERSION >= 6)
 	bool is_affiliated_sta;
 	uint8_t mlo_link_id;
-	struct sta_mld *mld;
+	//struct sta_mld *mld;
+	uint8_t mld_macaddr[6];
 	uint8_t ruid[6];
 #endif
 	uint32_t caps;                  /** capability bitmap */
@@ -824,6 +761,29 @@ struct wifi_sta_steer_list {
 	uint8_t sta_mac[6];
 	uint8_t complete;
 };
+#if (EASYMESH_VERSION >= 6)
+/* TODO: FIXME!! MUST BE MOVED TO MLD.H  */
+struct bsta_mld {
+	uint8_t macaddr[6];
+	uint8_t bssid[6];
+	char ifname[16];
+
+	struct netif_bk bk;
+
+	bool str_enabled;
+	bool nstr_enabled;
+	bool emlsr_enabled;
+	bool emlmr_enabled;
+
+	int num_affiliated_bsta;
+	//struct netif_bk *affiliated_bsta[MAX_AFFILIATED_BSTA_LINKS_NUM];
+#define MAX_AFFILIATED_BSTA_LINKS_NUM 14
+	uint8_t affiliated_bsta[MAX_AFFILIATED_BSTA_LINKS_NUM][6];
+
+	struct list_head list;
+};
+
+#endif
 
 /** struct agent - wifi agent */
 struct agent {
@@ -1097,20 +1057,6 @@ void parse_bk(struct ubus_request *req, int type,
 int agent_radio_scanresults(struct agent *a, struct wifi_radio_element *re);
 int agent_init_interfaces(struct agent *a);
 int agent_switch_according_to_pref(struct agent *a);
-#if (EASYMESH_VERSION >= 6)
-bool wifi_is_affiliated_ap(struct agent *a, uint8_t *bssid);
-const char *wifi_ifname_to_mld(struct agent *a, char *ifname);
-bool agent_radio_support_ap_wifi7(struct wifi7_radio_capabilities *wifi7_caps);
-bool agent_radio_support_bsta_wifi7(struct wifi7_radio_capabilities *wifi7_caps);
-int wifi_sta_mld_del_bsta(struct agent *a, struct netif_bk *bk);
-void parse_bstamld(struct ubus_request *req, int type,
-		struct blob_attr *msg);
-struct sta_mld *agent_get_stamld(struct agent *a, uint8_t *macaddr);
-int wifi_sta_mld_del_sta(struct agent *a, struct sta *s);
-void agent_clean_affiliated_bsta_mld(struct bsta_mld *mld);
-void agent_free_bsta_mld(struct agent *a);
-void clear_apmldlist(struct agent *a);
-#endif
 struct sta *agent_get_sta(struct agent *a, uint8_t *mac);
 
 struct wifi_radio_element *agent_get_radio_by_band(struct agent *a,
@@ -1141,4 +1087,6 @@ void agent_pref_neighbor_to_nbr(struct pref_neighbor *pref_nbr_src,
 
 struct netif_ap *agent_gen_netif_ap(struct agent *a, struct wifi_radio_element *re);
 
+void bk_toggle(struct agent *a, struct netif_bk *bk,
+	       uint8_t *bssid, uint32_t freq);
 #endif /* AGENT_H */
diff --git a/src/agent_cmdu.c b/src/agent_cmdu.c
index de97f9ba2e68b37ff8e32b914ee7948fa88c4273..987a7166a65abf685902467fbb17bf034082f35f 100644
--- a/src/agent_cmdu.c
+++ b/src/agent_cmdu.c
@@ -30,6 +30,9 @@
 #include "agent_map.h"
 #include "agent_tlv.h"
 #include "config.h"
+#if (EASYMESH_VERSION >= 6)
+#include "mld.h"
+#endif
 #include "utils/1905_ubus.h"
 #include "utils/debug.h"
 #include "utils/utils.h"
@@ -327,7 +330,9 @@ struct cmdu_buff *agent_gen_ap_metrics_response(struct agent *a,
 				list_for_each_entry(smld, &mld->stamldlist, list) {
 
 					for (i = 0; i < smld->num_affiliated_sta; i++) {
-						s = smld->affiliated_sta[i];
+						s = agent_get_sta(a, smld->affiliated_sta[i]);
+						if (!s)
+							continue;
 
 						if (memcmp(s->bssid, bssid, 6))
 							continue;
@@ -351,14 +356,14 @@ struct cmdu_buff *agent_gen_ap_metrics_response(struct agent *a,
 						}
 
 						/* TODO: traffic stats are per-mld, today use first client statistics */
-						ret = agent_gen_assoc_sta_traffic_stats(a, frm, smld->macaddr, smld->affiliated_sta[0]);
+						ret = agent_gen_assoc_sta_traffic_stats(a, frm, smld->macaddr, s);
 						if (ret)
 							goto out;
 
 						if (rcfg->include_wifi6_sta_status &&
 						    a->cfg.map_profile > 2) {
 							/* TLV is sent only for SLO and MLD clients */
-							ret = agent_gen_assoc_wifi6_sta_status_report(a, frm, smld->affiliated_sta[0]);
+							ret = agent_gen_assoc_wifi6_sta_status_report(a, frm, s);
 							if (ret)
 								goto out;
 						}
@@ -1262,8 +1267,8 @@ struct cmdu_buff *agent_gen_topology_notification(struct agent *agent,
 	uint8_t origin[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x13};
 
 #if (EASYMESH_VERSION >= 6)
-	if (s->is_affiliated_sta && s->mld)
-		macaddr = s->mld->macaddr;
+	if (s->is_affiliated_sta)
+		macaddr = s->mld_macaddr;
 #endif
 
 	frm = cmdu_alloc_simple(CMDU_TYPE_TOPOLOGY_NOTIFICATION, &mid);
@@ -1309,14 +1314,22 @@ struct cmdu_buff *agent_gen_client_disassoc(struct agent *a,
 	memcpy(cmdu->origin, a->cntlr_almac, 6);
 
 #if (EASYMESH_VERSION >= 6)
-	if (s->is_affiliated_sta && s->mld) {
-		macaddr = s->mld->macaddr;
+	if (s->is_affiliated_sta) {
+		struct sta_mld *smld;
+
+		macaddr = s->mld_macaddr;
 		ret = agent_gen_affiliated_sta_metrics(a, cmdu, s);
 		if (ret)
 			goto error;
 
 		/* TODO: overwrite s as STA traffic are currently only available on first link */
-		s = s->mld->affiliated_sta[0];
+		smld = agent_get_stamld(a, s->mld_macaddr);
+		if (!smld)
+			goto error;
+
+		s = agent_get_sta(a, smld->affiliated_sta[0]);
+		if (!s)
+			goto error;
 	}
 
 #endif
@@ -1419,8 +1432,6 @@ struct cmdu_buff *agent_gen_topology_response(struct agent *a, uint8_t *origin,
 #if (EASYMESH_VERSION >= 6)
 		/* Backhaul STA Radio Capabilities TLV */
 		list_for_each_entry(re, &a->radiolist, list) {
-			agent_radio_support_bsta_wifi7(&re->wifi7_caps);
-
 			ret = agent_gen_bk_sta_radio_cap_tlv(a, resp, re);
 			if (ret)
 				goto error;
diff --git a/src/agent_map.c b/src/agent_map.c
index 01cf9efa6e868f7b47e44105a3d9a65cfa93d441..48fdd48ce72c2ea2a659b91ec574abedc4899167 100644
--- a/src/agent_map.c
+++ b/src/agent_map.c
@@ -60,6 +60,9 @@
 #include "qos.h"
 #endif
 #include "extension.h"
+#if (EASYMESH_VERSION >= 6)
+#include "mld.h"
+#endif
 #include "timer_impl.h"
 #include "unasta.h"
 #include "utils/1905_ubus.h"
@@ -1704,43 +1707,6 @@ int wifi_teardown_iface(const char *ifname)
 	return 0;
 }
 
-#if (EASYMESH_VERSION >= 6)
-int wifi_teardown_map_bsta_mld(struct agent *a, uint32_t band)
-{
-	struct wifi_radio_element *re;
-	char fmt[128] = {0};
-	const char *bandstr;
-
-	bandstr = band_to_str(band);
-	snprintf(fmt, sizeof(fmt), "teardown_bsta_mld %s", bandstr);
-	agent_exec_platform_scripts(fmt);
-
-	list_for_each_entry(re, &a->radiolist, list) {
-		if (!re->has_bsta || !re->bk.is_affiliated_sta)
-			continue;
-
-		if (!(re->bk.cfg->band & band))
-			continue;
-
-		re->bk.cfg->band &= ~band;
-
-		if (re->bk.cfg->band) {
-			break;
-		}
-
-#if 0
-		/* TODO: FIXME: proper MLD BSTA cleanup needed */
-		clean_bk(re->bk.cfg);
-		clear_bk(a, re->bk);
-		re->bk = NULL;
-#endif
-	}
-
-	agent_config_reload(a);
-	return 0;
-}
-#endif
-
 int wifi_teardown_map_ifaces_by_radio(struct agent *a, char *device)
 {
 	struct netif_apcfg *apcfg;
@@ -2240,36 +2206,6 @@ error_cleanup:
 
 #define RELOAD_TIMEOUT 5
 #if (EASYMESH_VERSION >= 6)
-static void mlo_update_id_in_configs(char *ifname, uint8_t mld_id)
-{
-	char mldname[16] = {0};
-	char idstr[4] = {0};
-
-	/* write empty string if mld id is not set */
-	if (mld_id) {
-		snprintf(idstr, sizeof(idstr), "%d", mld_id);
-		snprintf(mldname, sizeof(mldname), "mld%d", mld_id);
-	}
-
-	uci_set_wireless_interface_option("mapagent", "ap",
-				  "ifname", ifname,
-				  "mld_id", idstr);
-
-	uci_set_wireless_interface_option("wireless",
-				  "wifi-iface",
-				  "ifname", ifname,
-				  "mld", mldname);
-
-	uci_set_wireless_interface_option("mapagent", "ap",
-				  "ifname", ifname,
-				  "enabled", mld_id ? "1" : "0");
-
-	uci_set_wireless_interface_option("wireless",
-				  "wifi-iface",
-				  "ifname", ifname,
-				  "disabled", mld_id ? "0" : "1");
-}
-
 static int mlo_process_ap_mld_config(struct agent *a, uint8_t *tlv_data)
 {
 	trace("%s: --->\n", __func__);
@@ -2288,7 +2224,7 @@ static int mlo_process_ap_mld_config(struct agent *a, uint8_t *tlv_data)
 		if (apcfg->mld_id) {
 			struct netif_ap *ap;
 
-			mlo_update_id_in_configs(apcfg->name, 0);
+			mld_set_config_id(apcfg->name, 0);
 			apcfg->mld_id = 0;
 			ap = agent_get_ap_by_ifname(a, apcfg->name);
 			if (ap)
@@ -2444,7 +2380,7 @@ static int mlo_process_ap_mld_config(struct agent *a, uint8_t *tlv_data)
 				mld_complete = true;
 
 			/* Set mld_id/mld in ap/wifi-iface sections of cfg files */
-			mlo_update_id_in_configs(apcfg->name, id);
+			mld_set_config_id(apcfg->name, id);
 			apcfg->mld_id = id;
 		}
 	}
@@ -2498,7 +2434,7 @@ static int mlo_process_bsta_mld_config(struct agent *a, uint8_t *tlv_data)
 			continue;
 
 		if (!re->bk.cfg->is_mld_netdev && re->bk.is_affiliated_sta)
-			wifi_sta_mld_del_bsta(a, &re->bk);
+			mld_del_bsta(a, &re->bk);
 	}
 
 	num_affiliated_bstas = tlv_data[offset++];
@@ -2574,9 +2510,7 @@ static int mlo_process_bsta_mld_config(struct agent *a, uint8_t *tlv_data)
 	}
 	return 0;
 }
-#endif
 
-#if (EASYMESH_VERSION >= 6)
 static bool update_tlv_hash(struct agent *a, struct tlv *tv,
 			    uint8_t *sha256_out)
 {
@@ -2607,6 +2541,7 @@ error_cleanup:
 	return ret;
 }
 #endif
+
 int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu,
 			     struct node *n)
 {
@@ -2865,7 +2800,7 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu,
 		ret = mlo_process_bsta_mld_config(a,
 				tv[AP_AUTOCONFIGURATION_WSC_M2_BACKHAUL_STA_MLD_CONFIG_IDX][0]->data);
 		if (ret)
-			wifi_teardown_map_bsta_mld(a, radio->band);
+			bstamld_teardown_band(a, radio->band);
 		update_tlv_hash(a, tv[AP_AUTOCONFIGURATION_WSC_M2_BACKHAUL_STA_MLD_CONFIG_IDX][0],
 				a->bsta_mld_cfg_sha256);
 		a->reconfig_reason |= AGENT_RECONFIG_REASON_MLD_ID;
@@ -2873,7 +2808,7 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu,
 	} else {
 		dbg("%s: Missing BSTA MLD config TLV, teardown\n",
 		    __func__);
-		wifi_teardown_map_bsta_mld(a, radio->band);
+		bstamld_teardown_band(a, radio->band);
 	}
 #endif
 
@@ -6762,7 +6697,7 @@ int handle_bsta_mld_config_request(void *agent, struct cmdu_buff *cmdu, struct n
 		if (ret) {
 			uint32_t band_all = BAND_2 | BAND_5 | BAND_6;
 
-			wifi_teardown_map_bsta_mld(a, band_all);
+			bstamld_teardown_band(a, band_all);
 		} else {
 			/* re-do all MLD configuration in case TLV has changed */
 			dbg("%s: MLD configuration changed, schedule reconfig\n",
diff --git a/src/agent_tlv.c b/src/agent_tlv.c
index 85b421774c0e0181bb40ff70e5dbe80d134ce1fb..5c26b35c6deb7a41ada987b5d65fd4fcbc4896d1 100644
--- a/src/agent_tlv.c
+++ b/src/agent_tlv.c
@@ -33,6 +33,9 @@
 #include "agent_map.h"
 #include "config.h"
 #include "unasta.h"
+#if (EASYMESH_VERSION >= 6)
+#include "mld.h"
+#endif
 #include "utils/1905_ubus.h"
 #include "utils/debug.h"
 #include "utils/utils.h"
@@ -3667,12 +3670,16 @@ int agent_gen_assoc_client_tlv(struct agent *a, struct cmdu_buff *frm)
 			offset += 6;
 
 			if (smld->num_affiliated_sta > 0) {
-				/** conntime is not (yet) available for MLD dev
-				 *  use first affiliated STA conntime
-				 */
-				conntime = ((smld->affiliated_sta[0]->connected_ms / 1000) > 0xFFFF)
-					? 0xFFFF
-					: (smld->affiliated_sta[0]->connected_ms / 1000) & 0xFFFF;
+				struct sta *s;
+
+				s = agent_get_sta(a, smld->affiliated_sta[0]);
+				if (s) {
+					/** conntime is not (yet) available for MLD dev
+					 *  use first affiliated STA conntime
+					 */
+					conntime = ((s->connected_ms / 1000) > 0xFFFF)
+						? 0xFFFF : (s->connected_ms / 1000) & 0xFFFF;
+				}
 			}
 
 			/* conntime */
@@ -4224,8 +4231,8 @@ int agent_gen_assoc_wifi6_sta_status_report(struct agent *a,
 	data = (struct tlv_assoc_wifi6_sta_status_report *)t->data;
 	memcpy(data->macaddr, s->macaddr, 6);
 #if (EASYMESH_VERSION >= 6)
-	if (s->is_affiliated_sta && s->mld)
-		memcpy(data->macaddr, s->mld->macaddr, 6);
+	if (s->is_affiliated_sta)
+		memcpy(data->macaddr, s->mld_macaddr, 6);
 #endif
 	offset += sizeof(*data);
 	/* TODO:
@@ -4528,7 +4535,6 @@ int agent_gen_ap_mld_config(struct agent *a, struct cmdu_buff *frm)
 
 	list_for_each_entry(mld, &a->apmldlist, list) {
 		int ssid_len = strlen(mld->ssid);
-		struct netif_ap *ap = NULL;
 		int i;
 
 		/* AP MLD MAC Addr Valid */
@@ -4566,8 +4572,9 @@ int agent_gen_ap_mld_config(struct agent *a, struct cmdu_buff *frm)
 		t->data[offset++] = mld->num_affiliated_ap;
 		for (i = 0; i < mld->num_affiliated_ap; i++) {
 			struct wifi_radio_element *re = NULL;
-			ap = mld->affiliated_ap[i];
+			struct netif_ap *ap;
 
+			ap = agent_get_ap(a, mld->affiliated_ap[i]);
 			if (!ap || !ap->is_affiliated_ap)
 				continue;
 
@@ -4588,7 +4595,7 @@ int agent_gen_ap_mld_config(struct agent *a, struct cmdu_buff *frm)
 			offset += 6;
 
 			/* LinkID */
-			t->data[offset++] = ap->linkid;
+			t->data[offset++] = ap->mlo_link_id;
 
 			offset += 18; /* reserved */
 		}
@@ -4615,7 +4622,7 @@ int agent_gen_bsta_mld_config(struct agent *a, struct cmdu_buff *frm)
 	//struct mld_credential *mld = NULL;
 	int offset = 0;
 	uint8_t *num_aff_bstas;
-	struct bsta_mld *bsta = &a->bstamld;
+	struct bsta_mld *bstamld = &a->bstamld;
 	uint8_t valid_flag = BSTA_MLD_CONF_AFFILIATED_BSTA_MLD_ADDR_VALID;
 	int ret;
 
@@ -4638,28 +4645,28 @@ int agent_gen_bsta_mld_config(struct agent *a, struct cmdu_buff *frm)
 	data->flag = 0;
 
 	/* bSTA_MLD_MAC_Addr */
-	if (!hwaddr_is_zero(bsta->macaddr)) {
-		memcpy(&t->data[offset], bsta->macaddr, 6);
+	if (!hwaddr_is_zero(bstamld->macaddr)) {
+		memcpy(&t->data[offset], bstamld->macaddr, 6);
 		data->flag |= BSTA_MLD_CONF_BSTA_MLD_ADDR_VALID;
 	}
 	offset += 6;
 
 	/* AP_MLD_MAC_Addr */
 	/* "addr of the AP MLD to which the bSTA MLD is associated" */
-	if (!hwaddr_is_zero(bsta->bssid)) {
-		memcpy(&t->data[offset], bsta->bssid, 6);
+	if (!hwaddr_is_zero(bstamld->bssid)) {
+		memcpy(&t->data[offset], bstamld->bssid, 6);
 		data->flag |= BSTA_MLD_CONF_AP_MLD_ADDR_VALID;
 	}
 	offset += 6;
 
 	/* STR/NSTR/EMLSR/EMLMR */
-	if (bsta->str_enabled)
+	if (bstamld->str_enabled)
 		caps_flag |= BSTA_MLD_CONFIG_STR;
-	if (bsta->nstr_enabled)
+	if (bstamld->nstr_enabled)
 		caps_flag |= BSTA_MLD_CONFIG_NSTR;
-	if (bsta->emlsr_enabled)
+	if (bstamld->emlsr_enabled)
 		caps_flag |= BSTA_MLD_CONFIG_EMLSR;
-	if (bsta->emlmr_enabled)
+	if (bstamld->emlmr_enabled)
 		caps_flag |= BSTA_MLD_CONFIG_EMLMR;
 
 	data->flag2 = caps_flag;
@@ -4670,20 +4677,21 @@ int agent_gen_bsta_mld_config(struct agent *a, struct cmdu_buff *frm)
 
 	/* numAffiliatedbSTAs */
 	num_aff_bstas = &t->data[offset];
-	*num_aff_bstas = bsta->num_affiliated_bsta;
+	*num_aff_bstas = bstamld->num_affiliated_bsta;
 	offset++;
 
 	if (*num_aff_bstas) {
 		int i;
 
 		for (i = 0; i < *num_aff_bstas; i++) {
-			struct netif_bk *affsta = bsta->affiliated_bsta[i];
+			struct netif_bk *bsta;
 			struct wifi_radio_element *re;
 
-			if (!affsta->cfg)
+			bsta = agent_get_bsta(a, bstamld->affiliated_bsta[i]);
+			if (!bsta || !bsta->cfg)
 				continue;
 
-			re = agent_get_radio_by_band(a, affsta->cfg->band);
+			re = agent_get_radio_by_band(a, bsta->cfg->band);
 			if (!re)
 				continue;
 
@@ -4696,7 +4704,7 @@ int agent_gen_bsta_mld_config(struct agent *a, struct cmdu_buff *frm)
 			offset += 6;
 
 			/* Affilated_bSTA_MAC_Addr */
-			memcpy(&t->data[offset], affsta->macaddr, 6);
+			memcpy(&t->data[offset], bsta->macaddr, 6);
 			offset += 6;
 
 			/* reserved */
@@ -4795,7 +4803,7 @@ int agent_gen_affiliated_ap_metrics(struct agent *a, struct cmdu_buff *frm,
 	struct tlv *t;
 	int ret;
 
-	if (!wifi_is_affiliated_ap(a, bss->bssid))
+	if (!is_affiliated_ap(a, bss->bssid))
 		return 0;
 
 	t = cmdu_reserve_tlv(frm, sizeof(*data));
@@ -4899,7 +4907,11 @@ int agent_gen_associated_sta_mld_config(struct agent *a, struct cmdu_buff *frm,
 	offset += 1;
 
 	for (i = 0; i < mld->num_affiliated_sta; i++) {
-		struct sta *s = mld->affiliated_sta[i];
+		struct sta *s;
+
+		s = agent_get_sta(a, mld->affiliated_sta[i]);
+		if (!s)
+			continue;
 
 		memcpy(&t->data[offset], s->bssid, 6);
 		offset += 6;
diff --git a/src/backhaul.c b/src/backhaul.c
index f3d7a65f0d408e91bd583827f6594295b594ae4e..7683f1f7f504b0d367941e624aa9c996ff089b48 100644
--- a/src/backhaul.c
+++ b/src/backhaul.c
@@ -21,6 +21,9 @@
 #include "agent.h"
 #include "agent_ubus.h"
 #include "config.h"
+#if (EASYMESH_VERSION >= 6)
+#include "mld.h"
+#endif
 #include "timer.h"
 #include "utils/debug.h"
 #include "utils/utils.h"
@@ -532,9 +535,12 @@ void agent_check_bsta_connections(struct agent *a)
 
 
 #if (EASYMESH_VERSION >= 6)
-		if (bk->is_affiliated_sta) {
-			snprintf(objname, 31, "wifi.bstamld.%s", bk->mld->ifname);
-			cb = parse_bstamld;
+		if (bk->is_affiliated_sta && a->has_bstamld) {
+			struct bsta_mld *bstamld;
+
+			bstamld = &a->bstamld;
+			snprintf(objname, 31, "wifi.bstamld.%s", bstamld->ifname);
+			cb = bstamld_parse;
 		}
 
 		if (bk->cfg->is_mld_netdev)
diff --git a/src/mld.c b/src/mld.c
new file mode 100644
index 0000000000000000000000000000000000000000..864733c0bb753e63a35bef35837d4bd983a4c03c
--- /dev/null
+++ b/src/mld.c
@@ -0,0 +1,958 @@
+#if (EASYMESH_VERSION >= 6)
+
+
+#include "mld.h"
+
+#include "utils/debug.h"
+#include "utils/utils.h"
+#include "backhaul.h"
+#include "agent.h"
+
+struct sta_mld *stamld_update(struct agent *a, struct netif_ap *ap, uint8_t *mld_macaddr,
+		   uint8_t *mld_bssid, uint8_t mlo_link_id, struct sta *s)
+{
+	struct sta_mld *mld;
+	int ret;
+
+	mld = agent_get_stamld(a, mld_macaddr);
+	if (!mld) {
+		struct netif_mld *apmld;
+
+		apmld = agent_get_apmld(a, ap->mld_macaddr);
+		if (!apmld)
+			return NULL;
+
+		mld = agent_alloc_stamld(a, apmld, mld_macaddr);
+		if (!mld)
+			return NULL;
+	}
+
+	ret = mld_add_sta(a, mld, s->macaddr);
+	if (ret) {
+		dbg("%s: failed to add affiliated STA:"MACFMT" to STAMLD:"MACFMT"\n", __func__, MAC2STR(s->macaddr), MAC2STR(mld_macaddr));
+		return NULL;
+	}
+
+	memcpy(mld->bssid, mld_bssid, 6);
+
+	memcpy(s->mld_macaddr, mld->macaddr, 6);
+	s->is_affiliated_sta = true;
+	s->mlo_link_id = mlo_link_id;
+	return mld;
+}
+
+/* remove passed affiliated STA from mld */
+int mld_del_sta(struct agent *a, struct sta *s)
+{
+	struct sta_mld *mld;
+	int i;
+
+	mld = agent_get_stamld(a, s->mld_macaddr);
+	if (!mld)
+		return -1;
+
+	for (i = 0; i < mld->num_affiliated_sta; i++) {
+		if (memcmp(mld->affiliated_sta[i], s->macaddr, 6))
+			continue;
+
+		if (i < mld->num_affiliated_sta)
+			memcpy(mld->affiliated_sta[i], mld->affiliated_sta[i + 1], (mld->num_affiliated_sta - (i + 1)) * 6);
+
+		memset(mld->affiliated_sta[mld->num_affiliated_sta - 1], 0, 6);
+		mld->num_affiliated_sta--;
+		break;
+	}
+
+	if (mld->num_affiliated_sta == 0) {
+		list_del(&mld->list);
+		free(mld);
+	}
+
+	return 0;
+}
+
+/* remove passed affiliated backhaul STA from mld */
+int mld_del_bsta(struct agent *a, struct netif_bk *bk)
+{
+	struct bsta_mld *mld;
+	int i;
+
+	if (!a->has_bstamld || bk->cfg->is_mld_netdev)
+		return -1;
+
+	mld = &a->bstamld;
+	for (i = 0; i < mld->num_affiliated_bsta; i++) {
+		if (memcmp(mld->affiliated_bsta[i], bk->macaddr, 6))
+			continue;
+
+		if (i < mld->num_affiliated_bsta)
+			memcpy(mld->affiliated_bsta[i], mld->affiliated_bsta[i + 1], (mld->num_affiliated_bsta - (i + 1)) * 6);
+
+		memset(mld->affiliated_bsta[mld->num_affiliated_bsta - 1], 0, 6);
+		mld->num_affiliated_bsta--;
+	}
+
+	bk->is_affiliated_sta = false;
+	return 0;
+}
+
+/* remove passed affiliated AP from mld */
+int mld_del_ap(struct agent *a, struct netif_ap *ap)
+{
+	struct netif_mld *mld;
+	int i;
+
+	if (!ap->is_affiliated_ap)
+		return -1;
+
+	mld = agent_get_apmld(a, ap->mld_macaddr);
+	if (!mld)
+		return -1;
+
+	for (i = 0; i < mld->num_affiliated_ap; i++) {
+		if (memcmp(mld->affiliated_ap[i], ap->bssid, 6))
+			continue;
+
+		if (i < mld->num_affiliated_ap)
+			memcpy(mld->affiliated_ap[i], mld->affiliated_ap[i + 1], (mld->num_affiliated_ap - (i + 1)) * 6);
+
+		memset(mld->affiliated_ap[mld->num_affiliated_ap - 1], 0, 6);
+		mld->num_affiliated_ap--;
+	}
+
+	ap->is_affiliated_ap = false;
+	return 0;
+}
+
+/* frame starting from payload, skipping header */
+int wifi_process_ml_ie(struct agent *a, struct sta_mld *stamld,
+		       uint8_t *assocframe, int framelen)
+{
+	uint8_t *ml;
+	uint8_t *ml_ctrl;
+	uint8_t type;
+	uint8_t presence_bmp[2];
+
+	bool linkid_info_present;
+	bool bss_param_chg_present;
+	bool medium_sync_present;
+	bool eml_caps_present;
+
+	bool mld_caps_ops_present;
+	uint8_t *common_info;
+	size_t pos;
+
+	ml = wifi_find_ie_ext(assocframe, framelen, IE_EXT_ML);
+	if (!ml) {
+		dbg("%s: frame did not include ML IE\n", __func__);
+		return -1;
+	}
+
+	ml_ctrl = ml + 3;
+	type = ml_ctrl[0] & 0x7;
+	presence_bmp[0] = (ml_ctrl[0] & 0xf0) >> 4;
+	presence_bmp[1] = ml_ctrl[1];
+
+	if (type != 0) {
+		dbg("%s: ML IE type non-zero\n", __func__);
+		return -1;
+	}
+
+	linkid_info_present = !!(presence_bmp[0] & 0x1);
+	bss_param_chg_present = !!(presence_bmp[0] & 0x2);
+	medium_sync_present = !!(presence_bmp[0] & 0x4);
+	eml_caps_present = !!(presence_bmp[0] & 0x8);
+
+	mld_caps_ops_present = !!(presence_bmp[1] & 0x1);
+	common_info = &ml_ctrl[2];
+	pos = 1;
+
+	pos += 6; /* skip apmld macaddr */
+
+	if (linkid_info_present)
+		pos += 1;
+
+	if (bss_param_chg_present)
+		pos += 1;
+
+	if (medium_sync_present)
+		pos += 2;
+
+	if (eml_caps_present) {
+		uint8_t *eml_caps = &common_info[pos];
+
+		stamld->emlsr_enabled = !!(eml_caps[0] & BIT(0)) ? true : false;
+		stamld->emlmr_enabled = !!(eml_caps[0] & BIT(7)) ? true : false;
+		pos += 2;
+	}
+
+	if (mld_caps_ops_present) {
+		uint8_t *mld_caps = &common_info[pos];
+		uint8_t max_simlinks = (mld_caps[0] & 0x0f);
+
+		pos += 2;
+		if (max_simlinks >= 1) {
+			stamld->nstr_enabled = false;
+			stamld->str_enabled = true;
+		} else {
+			stamld->nstr_enabled = true;
+			stamld->str_enabled = false;
+		}
+	}
+
+	return 0;
+}
+
+void mld_event_handler(void *agent, struct blob_attr *msg)
+{
+	char ifname[16] = {0}, event[16] = {0};
+	struct agent *a = (struct agent *) agent;
+	struct blob_attr *tb[3];
+	static const struct blobmsg_policy ev_attr[3] = {
+		[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
+		[1] = { .name = "event", .type = BLOBMSG_TYPE_STRING },
+		[2] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
+	};
+	bool add, del;
+
+	blobmsg_parse(ev_attr, 3, tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[0] || !tb[1])
+		return;
+
+	strncpy(ifname,	blobmsg_data(tb[0]), sizeof(ifname) - 1);
+	strncpy(event, blobmsg_data(tb[1]), sizeof(event) - 1);
+
+	add = !strcmp(event, "mlo-link-added");
+	del = !strcmp(event, "mlo-link-remove");
+
+	if (add) {
+		/* more actions */
+		timer_set(&a->init_ifaces_scheduler,
+			  IFACE_TIMEOUT * 1000);
+	} else if (del) {
+		/* more actions */
+		timer_set(&a->init_ifaces_scheduler,
+			  IFACE_TIMEOUT * 1000);
+	}
+}
+
+int mld_parse_affiliated_ap(struct ubus_request *req, int type,
+		struct blob_attr *msg)
+{
+	struct netif_ap *ap = (struct netif_ap *) req->priv;
+	static const struct blobmsg_policy ap_attr[] = {
+		[0] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
+		[1] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
+		[2] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 },
+		[3] = { .name = "ccfs0", .type = BLOBMSG_TYPE_INT32 },
+		[4] = { .name = "ccfs1", .type = BLOBMSG_TYPE_INT32 },
+		[5] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 },
+		[6] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
+		[7] = { .name = "security", .type = BLOBMSG_TYPE_STRING },
+		[8] = { .name = "encryption", .type = BLOBMSG_TYPE_STRING },
+		[9] = { .name = "standard", .type = BLOBMSG_TYPE_STRING },
+		[10] = { .name = "num_stations", .type = BLOBMSG_TYPE_INT32 },
+		[11] = { .name = "max_stations", .type = BLOBMSG_TYPE_INT32 },
+		[12] = { .name = "utilization", .type = BLOBMSG_TYPE_INT32 },
+		[13] = { .name = "adm_capacity", .type = BLOBMSG_TYPE_INT32 },
+		[14] = { .name = "hidden", .type = BLOBMSG_TYPE_BOOL },
+		[15] = { .name = "supp_security", .type = BLOBMSG_TYPE_ARRAY },
+		[16] = { .name = "capabilities", .type = BLOBMSG_TYPE_TABLE },
+	};
+	struct blob_attr *tb[ARRAY_SIZE(ap_attr)];
+	enum wifi_band band;
+
+	if (!ap)
+		return -1;
+
+	blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blobmsg_data(msg), blobmsg_data_len(msg));
+
+	if (!tb[0] || !tb[1] || !tb[6]) {
+		return -1;
+	}
+
+	band = wifi_bandstr_to_band(blobmsg_get_string(tb[1]));
+	if (band != ap->band)
+		return -1;
+
+	ap->mlo_link_id = blobmsg_get_u32(tb[0]);
+
+	hwaddr_aton(blobmsg_data(tb[6]), ap->bssid);
+	if (tb[2])
+		ap->channel = blobmsg_get_u32(tb[2]);
+
+	if (tb[5])
+		ap->bandwidth = blobmsg_get_u32(tb[5]);
+
+	if (tb[9])
+		strncpy(ap->standard, blobmsg_data(tb[9]), sizeof(ap->standard) - 1);
+
+	if (tb[10])
+		ap->num_sta = blobmsg_get_u32(tb[10]);
+
+	return 0;
+}
+
+void apmld_parse(struct ubus_request *req, int type,
+		struct blob_attr *msg)
+{
+	static const struct blobmsg_policy ap_attr[] = {
+		[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
+		[1] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
+		[2] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING },
+		[3] = { .name = "mode", .type = BLOBMSG_TYPE_STRING },
+		[4] = { .name = "links", .type = BLOBMSG_TYPE_ARRAY },
+		[5] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
+	};
+	struct netif_ap *ap = (struct netif_ap *)req->priv;
+	struct blob_attr *tb[ARRAY_SIZE(ap_attr)];
+	struct agent *a = ap->agent;
+	struct netif_mld *mld;
+	const char *ifname;
+	const char *ssid;
+	uint8_t bssid[6] = {0};
+
+	blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[0] || !tb[1] || !tb[2] || !tb[3] || !tb[4] || !tb[5]) {
+		err("|%s:%d| missing some mandatory field!\n", __func__, __LINE__);
+		return;
+	}
+
+	ifname = blobmsg_get_string(tb[0]);
+	if (strlen(ifname) == 0)
+		return;
+
+	mld = agent_get_apmld_by_ifname(a, ifname);
+	if (!mld) {
+		mld = agent_alloc_apmld(a, ifname);
+		if (!mld) {
+			err("|%s:%d| failed to alloc MLD\n", __func__, __LINE__);
+			return;
+		}
+	}
+
+	if (!hwaddr_aton(blobmsg_data(tb[1]), mld->macaddr)) {
+		err("|%s:%d| MLD mac not valid\n", __func__, __LINE__);
+		return;
+	}
+
+	if (!hwaddr_aton(blobmsg_data(tb[5]), bssid)) {
+		err("|%s:%d| MLD BSSID not valid\n", __func__, __LINE__);
+		return;
+	}
+
+	/* In case of absence mld interface in the system, macaddres will be zero, use bssid */
+	if (hwaddr_is_zero(mld->macaddr) && !hwaddr_is_zero(bssid))
+		memcpy(mld->macaddr, bssid, 6);
+
+	ssid = blobmsg_get_string(tb[2]);
+	strncpy(mld->ssid, ssid, sizeof(mld->ssid));
+
+	if (tb[4]) {
+		struct blob_attr *link = NULL;
+		int rem_links = 0;
+
+		blobmsg_for_each_attr(link, tb[4], rem_links) {
+			struct wifi_radio_element *re = NULL;
+			struct wifi7_radio_capabilities *caps;
+			int num_ap = 0;
+			int ret;
+
+			if (blobmsg_type(link) != BLOBMSG_TYPE_TABLE) {
+				err("|%s:%d| link was not a table\n", __func__, __LINE__);
+				continue;
+			}
+
+			ret = mld_parse_affiliated_ap(req, type, link);
+			if (ret)
+				continue;
+
+			strncpy(ap->mld_ifname, ifname, sizeof(ap->mld_ifname) - 1);
+			memcpy(ap->mld_macaddr, mld->macaddr, 6);
+			ap->is_affiliated_ap = true;
+			strncpy(ap->ssid, ssid, sizeof(ap->ssid));
+			ap->enabled = true;
+
+			num_ap = mld->num_affiliated_ap;
+			if (!mld_contains_ap(a, mld, ap->bssid) &&
+			    num_ap < MAX_AFFILIATED_AP_LINKS_NUM) {
+				memcpy(mld->affiliated_ap[num_ap], ap->bssid, 6);
+				mld->num_affiliated_ap++;
+			} else {
+				err("|%s:%d| link with bssid:"MACFMT" was already in the MLD (or num_ap too high:%d)\n", __func__, __LINE__, MAC2STR(ap->bssid), mld->num_affiliated_ap);
+			}
+
+			re = agent_get_radio_with_ifname(a, ap->ifname);
+			if (re) {
+				caps = &re->wifi7_caps;
+				if (caps) {
+					/* TODO: revisit: */
+					/* Enable based on capabilities */
+					if (caps->ap_str_support)
+						mld->ap_str_enabled = true;
+					if (caps->ap_nstr_support)
+						mld->ap_nstr_enabled = true;
+					if (caps->ap_emlsr_support)
+						mld->ap_emlsr_enabled = true;
+					if (caps->ap_emlmr_support)
+						mld->ap_emlmr_enabled = true;
+				}
+			}
+			break;
+		}
+
+		if (mld->num_affiliated_ap == 0) {
+			err("|%s:%d| no affiliated APs found in MLD, schedule reload\n", __func__, __LINE__);
+			timer_set(&a->init_ifaces_scheduler, IFACE_TIMEOUT * 1000);
+		}
+
+	}
+}
+
+void mld_parse_affiliated_bsta(struct agent *a, struct bsta_mld *mld,
+				 struct netif_bk *bk, int type,
+				 struct blob_attr *msg)
+{
+
+	struct blob_attr *link;
+	int rem_links;
+
+	/* mlo_links; */
+	blobmsg_for_each_attr(link, msg, rem_links) {
+		static const struct blobmsg_policy mlo_links[] = {
+			[0] = { .name = "mlo_link_id", .type = BLOBMSG_TYPE_INT32 },
+			[1] = {	.name = "macaddr", .type = BLOBMSG_TYPE_STRING },
+			[2] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
+			[3] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
+			[4] = { .name = "frequency", .type = BLOBMSG_TYPE_INT32 },
+		};
+		struct blob_attr *data[ARRAY_SIZE(mlo_links)];
+		uint8_t link_id;
+		int num_sta;
+		enum wifi_band band;
+
+		blobmsg_parse(mlo_links, ARRAY_SIZE(mlo_links), data,
+			blobmsg_data(msg), blobmsg_data_len(msg));
+
+		if (!data[0] || !data[1] || !data[2] || !data[3]) {
+			err("|%s:%d| missing mlo_links data for ifname:%s\n", __func__, __LINE__, bk->ifname);
+			continue;
+		}
+
+		link_id = (uint8_t) blobmsg_get_u32(data[0]);
+
+		band = wifi_bandstr_to_band(blobmsg_get_string(data[3]));
+		if (band != bk->cfg->band)
+			continue;
+
+		hwaddr_aton(blobmsg_data(data[1]), bk->macaddr);
+		hwaddr_aton(blobmsg_data(data[2]), bk->bssid);
+
+		num_sta = mld->num_affiliated_bsta;
+		memcpy(bk->mld_macaddr, mld->macaddr, 6);
+		bk->is_affiliated_sta = true;
+		bk->mlo_link_id = link_id;
+
+		if (!mld_contains_bsta(a, mld, bk->macaddr) &&
+		    num_sta < MAX_AFFILIATED_STA_LINKS_NUM) {
+			memcpy(mld->affiliated_bsta[num_sta], bk->macaddr, 6);
+			mld->num_affiliated_bsta++;
+		}
+
+		break;
+	}
+}
+
+void bstamld_parse(struct ubus_request *req, int type,
+		struct blob_attr *msg)
+{
+	static const struct blobmsg_policy ap_attr[] = {
+		[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
+		[1] = { .name = "status", .type = BLOBMSG_TYPE_STRING },
+		[2] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
+		[3] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
+		[4] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING },
+		[5] = { .name = "4addr", .type = BLOBMSG_TYPE_BOOL },
+		[6] = { .name = "mlo_links", .type = BLOBMSG_TYPE_ARRAY },
+	};
+	struct netif_bk *bk = (struct netif_bk *)req->priv;
+	struct blob_attr *tb[ARRAY_SIZE(ap_attr)];
+	struct wifi_radio_element *re;
+	struct agent *a = bk->agent;
+	uint8_t macaddr[6] = {0};
+	uint8_t bssid[6] = {0};
+	struct bsta_mld *mld = &a->bstamld;
+	const char *ifname;
+	const char *ssid = NULL;
+
+	blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[0] || !tb[1] || !tb[2] || !tb[5]) {
+		err("|%s:%d| missing some mandatory field(s)!\n", __func__, __LINE__);
+		return;
+	}
+
+	if (tb[4])
+		ssid = blobmsg_get_string(tb[4]);
+
+	if (!hwaddr_aton(blobmsg_data(tb[2]), macaddr)) {
+		err("|%s:%d| MAC not valid\n", __func__, __LINE__);
+		return;
+	}
+
+	if (tb[3] && !hwaddr_aton(blobmsg_data(tb[3]), bssid)) {
+		err("|%s:%d| MAC not valid\n", __func__, __LINE__);
+		return;
+	}
+
+	ifname = blobmsg_get_string(tb[0]);
+	re = agent_get_radio_with_ifname(a, bk->ifname);
+	if (!re) {
+		err("|%s:%d| could not find radio element\n", __func__,
+			__LINE__);
+		return;
+	}
+
+	mld = agent_init_bstamld(a, (char *)ifname, &re->wifi7_caps);
+	if (!mld) {
+		err("|%s:%d| failed to alloc bSTA MLD ifname:%s\n", __func__, __LINE__, ifname);
+		return;
+	}
+
+	memcpy(mld->macaddr, macaddr, 6);
+	memcpy(mld->bssid, bssid, 6);
+
+	if (bk->cfg->is_mld_netdev && !hwaddr_is_zero(bssid)) {
+		memcpy(bk->mld_macaddr, mld->macaddr, 6);
+		memcpy(bk->macaddr, macaddr, 6);
+		memcpy(bk->bssid, bssid, 6);
+	}
+
+	if (tb[6] && !bk->cfg->is_mld_netdev) {
+		struct blob_attr *link = NULL;
+		int rem_links = 0;
+
+		blobmsg_for_each_attr(link, tb[6], rem_links) {
+			if (blobmsg_type(link) != BLOBMSG_TYPE_TABLE) {
+				err("|%s:%d| link was not a table\n", __func__, __LINE__);
+				continue;
+			}
+
+			mld_parse_affiliated_bsta(a, mld, bk, type, link);
+			strncpy(bk->mld_ifname, ifname, sizeof(bk->mld_ifname) - 1);
+			memcpy(bk->mld_macaddr, mld->macaddr, 6);
+			bk->is_affiliated_sta = true;
+			if (ssid)
+				strncpy(bk->ssid, ssid, sizeof(bk->ssid));
+			bk->enabled = true;
+		}
+	}
+
+	if (!bk->is_affiliated_sta || bk->cfg->is_mld_netdev)
+		bk_toggle(a, bk, bssid, 0);
+}
+
+struct netif_mld *agent_get_apmld(struct agent *a, uint8_t *macaddr)
+{
+	struct netif_mld *mld = NULL;
+
+	list_for_each_entry(mld, &a->apmldlist, list) {
+		if (!memcmp(macaddr, mld->macaddr, 6))
+			return mld;
+	}
+
+	return NULL;
+}
+
+struct netif_mld *agent_get_apmld_by_ifname(struct agent *a, const char *ifname)
+{
+	struct netif_mld *mld = NULL;
+
+	list_for_each_entry(mld, &a->apmldlist, list) {
+		if (!strncmp(ifname, mld->ifname, sizeof(mld->ifname)))
+			return mld;
+	}
+
+	return NULL;
+}
+
+struct netif_mld *agent_alloc_apmld(struct agent *a, const char *ifname)
+{
+	struct netif_mld *mld;
+
+	if (strlen(ifname) == 0) {
+		err("|%s:%d| MLD can not have empty ifname\n", __func__, __LINE__);
+		return NULL;
+	}
+
+	mld = calloc(1, sizeof(*mld));
+	if (!mld)
+		return NULL;
+
+	dbg("|%s:%d| allocated mld ifname:%s\n", __func__, __LINE__, ifname);
+
+	INIT_LIST_HEAD(&mld->stamldlist);
+
+	strncpy(mld->ifname, ifname, sizeof(mld->ifname));
+	list_add_tail(&mld->list, &a->apmldlist);
+	a->num_ap_mld++;
+
+	return mld;
+}
+
+int mld_add_ap(struct agent *a, struct netif_mld *mld,
+			     uint8_t *macaddr)
+{
+	int num_ap = mld->num_affiliated_ap;
+
+	if (mld_contains_ap(a, mld, macaddr))
+		return 0;
+
+	if (num_ap >= MAX_AFFILIATED_AP_LINKS_NUM)
+		return -1;
+
+	memcpy(mld->affiliated_ap[num_ap], macaddr, 6);
+	mld->num_affiliated_ap++;
+	return 0;
+}
+
+int mld_add_sta(struct agent *a, struct sta_mld *mld,
+			     uint8_t *macaddr)
+{
+	int num_sta = mld->num_affiliated_sta;
+
+	if (mld_contains_sta(a, mld, macaddr))
+		return 0;
+
+	if (num_sta >= MAX_AFFILIATED_STA_LINKS_NUM)
+		return -1;
+
+	memcpy(mld->affiliated_sta[num_sta], macaddr, 6);
+	mld->num_affiliated_sta++;
+	return 0;
+}
+
+
+int mld_add_bsta(struct agent *a, struct bsta_mld *mld,
+			     uint8_t *macaddr)
+{
+	int num_bsta = mld->num_affiliated_bsta;
+
+	if (mld_contains_bsta(a, mld, macaddr))
+		return 0;
+
+	if (num_bsta >= MAX_AFFILIATED_BSTA_LINKS_NUM)
+		return -1;
+
+	memcpy(mld->affiliated_bsta[num_bsta], macaddr, 6);
+	mld->num_affiliated_bsta++;
+	return 0;
+}
+
+
+
+bool mld_contains_ap(struct agent *a, struct netif_mld *mld,
+			     uint8_t *macaddr)
+{
+	int i;
+
+	for (i = 0; i < mld->num_affiliated_ap; i++) {
+		if (!memcmp(mld->affiliated_ap[i], macaddr, 6))
+			return true;
+	}
+
+	return false;
+}
+
+bool mld_contains_sta(struct agent *a, struct sta_mld *mld,
+			     uint8_t *macaddr)
+{
+	int i;
+
+	for (i = 0; i < mld->num_affiliated_sta; i++) {
+		if (!memcmp(mld->affiliated_sta[i], macaddr, 6))
+			return true;
+	}
+
+	return false;
+}
+
+
+bool mld_contains_bsta(struct agent *a, struct bsta_mld *mld,
+			     uint8_t *macaddr)
+{
+	int i;
+
+	for (i = 0; i < mld->num_affiliated_bsta; i++) {
+		if (!memcmp(mld->affiliated_bsta[i], macaddr, 6))
+			return true;
+	}
+
+	return false;
+}
+
+
+struct sta_mld *agent_get_stamld(struct agent *a, uint8_t *macaddr)
+{
+	struct netif_mld *mld;
+
+	list_for_each_entry(mld, &a->apmldlist, list) {
+		struct sta_mld *s;
+
+		list_for_each_entry(s, &mld->stamldlist, list) {
+			if (!memcmp(macaddr, s->macaddr, 6))
+				return s;
+		}
+	}
+
+	return NULL;
+}
+
+struct sta_mld *agent_alloc_stamld(struct agent *a, struct netif_mld *mld,
+				    uint8_t *macaddr)
+{
+	struct sta_mld *s;
+
+	s = calloc(1, sizeof(*s));
+	if (!s)
+		return NULL;
+
+	trace("|%s:%d| allocate sta mac:"MACFMT"\n", __func__, __LINE__, MAC2STR(macaddr));
+	memcpy(s->macaddr, macaddr, 6);
+
+	list_add_tail(&s->list, &mld->stamldlist);
+
+	return s;
+}
+
+struct bsta_mld *agent_init_bstamld(struct agent *a, char *ifname,
+				     struct wifi7_radio_capabilities *caps)
+{
+	struct bsta_mld *bsta = &a->bstamld;
+
+	strncpy(bsta->ifname, ifname, sizeof(bsta->ifname));
+	dbg("|%s:%d| allocated bsta mld:%s\n", __func__, __LINE__, bsta->ifname);
+
+	bsta->str_enabled = caps->bsta_str_support;
+	bsta->nstr_enabled = caps->bsta_nstr_support;
+	bsta->emlsr_enabled = caps->bsta_emlsr_support;
+	bsta->emlmr_enabled = caps->bsta_emlmr_support;
+	a->has_bstamld = true;
+
+	return bsta;
+}
+
+void stamld_clean(struct agent *a, struct sta_mld *mld)
+{
+	int i;
+
+	for (i = (mld->num_affiliated_sta - 1); i >= 0; i--) {
+		struct sta *s;
+
+		s = agent_get_sta(a, mld->affiliated_sta[i]);
+		if (!s)
+			continue;
+
+		memset(s->mld_macaddr, 0, 6);
+		s->is_affiliated_sta = false;
+		memset(mld->affiliated_sta[i], 0, 6);;
+	}
+
+	mld->num_affiliated_sta = 0;
+}
+
+
+void stamld_free(struct agent *a, struct sta_mld *mld)
+{
+	stamld_clean(a, mld);
+
+	list_del(&mld->list);
+	free(mld);
+}
+
+/*
+void clear_stamldlist(struct agent *a)
+{
+	struct netif_mld *mld = NULL;
+
+	list_for_each_entry_safe(mld, tmp,  &a->apmldlist, list) {
+		struct sta_mld *smld = NULL, *tmp;
+
+		list_for_each_entry_safe(smld, tmp,  &mld->stamldlist, list)
+			stamld_free(mld);
+	}
+}
+*/
+
+void bstamld_clean(struct agent *a, struct bsta_mld *mld)
+{
+	int i;
+
+	for (i = 0; i < mld->num_affiliated_bsta; i++) {
+		struct netif_bk *bk;
+
+		bk = agent_get_bsta(a, mld->affiliated_bsta[i]);
+		if (!bk)
+			continue;
+
+		memset(bk->mld_macaddr, 0, 6);
+		bk->is_affiliated_sta = false;
+		memset(mld->affiliated_bsta[i], 0, 6);
+	}
+
+	mld->num_affiliated_bsta = 0;
+}
+
+
+void agent_clear_bsta_mld(struct agent *a)
+{
+	struct bsta_mld *mld = &a->bstamld;
+
+	bstamld_clean(a, mld);
+
+	a->has_bstamld = false;
+}
+
+void apmld_clean(struct agent *a, struct netif_mld *mld)
+{
+	int i;
+
+	for (i = (mld->num_affiliated_ap - 1); i >= 0; i--) {
+		struct netif_ap *ap;
+
+		ap = agent_get_ap(a, mld->affiliated_ap[i]);
+		if (!ap)
+			continue;
+
+		memset(ap->mld_macaddr, 0, 6);
+		ap->is_affiliated_ap = false;
+		memset(mld->affiliated_ap[i], 0, 6);
+	}
+
+	mld->num_affiliated_ap = 0;
+}
+
+void apmld_free(struct agent *a, struct netif_mld *mld)
+{
+	struct sta_mld *smld = NULL, *stmp;
+
+	list_for_each_entry_safe(smld, stmp,  &mld->stamldlist, list)
+		stamld_free(a, smld);
+
+	apmld_clean(a, mld);
+
+	list_del(&mld->list);
+	free(mld);
+}
+
+void apmld_free_all(struct agent *a)
+{
+	struct netif_mld *mld = NULL, *tmp;
+
+	list_for_each_entry_safe(mld, tmp,  &a->apmldlist, list) {
+		apmld_free(a, mld);
+	}
+
+	a->num_ap_mld = 0;
+}
+
+bool is_affiliated_ap(struct agent *a, uint8_t *bssid)
+{
+	struct netif_ap *ap;
+
+	ap = agent_get_ap(a, bssid);
+	if (ap && ap->is_affiliated_ap)
+		return true;
+
+	return false;
+}
+
+
+bool agent_radio_support_ap_mlo(struct wifi7_radio_capabilities *wifi7_caps)
+{
+	if (wifi7_caps->ap_str_support || wifi7_caps->ap_nstr_support ||
+		wifi7_caps->ap_emlsr_support || wifi7_caps->ap_emlmr_support)
+		return true;
+
+	return false;
+}
+
+bool agent_radio_support_bsta_mlo(struct wifi7_radio_capabilities *wifi7_caps)
+{
+	if (wifi7_caps->bsta_str_support || wifi7_caps->bsta_nstr_support ||
+		wifi7_caps->bsta_emlsr_support || wifi7_caps->bsta_emlmr_support)
+		return true;
+
+	return false;
+}
+
+
+int bstamld_teardown_band(struct agent *a, uint32_t band)
+{
+	struct wifi_radio_element *re;
+	char fmt[128] = {0};
+	const char *bandstr;
+
+	bandstr = band_to_str(band);
+	snprintf(fmt, sizeof(fmt), "teardown_bsta_mld %s", bandstr);
+	agent_exec_platform_scripts(fmt);
+
+	list_for_each_entry(re, &a->radiolist, list) {
+		if (!re->has_bsta || !re->bk.is_affiliated_sta)
+			continue;
+
+		if (!(re->bk.cfg->band & band))
+			continue;
+
+		re->bk.cfg->band &= ~band;
+
+		if (re->bk.cfg->band) {
+			break;
+		}
+
+#if 0
+		/* TODO: FIXME: proper MLD BSTA cleanup needed */
+		clean_bk(re->bk.cfg);
+		clear_bk(a, re->bk);
+		re->bk = NULL;
+#endif
+	}
+
+	agent_config_reload(a);
+	return 0;
+}
+
+void mld_set_config_id(char *ifname, uint8_t mld_id)
+{
+	char mldname[16] = {0};
+	char idstr[4] = {0};
+
+	/* write empty string if mld id is not set */
+	if (mld_id) {
+		snprintf(idstr, sizeof(idstr), "%d", mld_id);
+		snprintf(mldname, sizeof(mldname), "mld%d", mld_id);
+	}
+
+	uci_set_wireless_interface_option("mapagent", "ap",
+				  "ifname", ifname,
+				  "mld_id", idstr);
+
+	uci_set_wireless_interface_option("wireless",
+				  "wifi-iface",
+				  "ifname", ifname,
+				  "mld", mldname);
+
+	uci_set_wireless_interface_option("mapagent", "ap",
+				  "ifname", ifname,
+				  "enabled", mld_id ? "1" : "0");
+
+	uci_set_wireless_interface_option("wireless",
+				  "wifi-iface",
+				  "ifname", ifname,
+				  "disabled", mld_id ? "0" : "1");
+}
+
+
+#endif
\ No newline at end of file
diff --git a/src/mld.h b/src/mld.h
new file mode 100644
index 0000000000000000000000000000000000000000..da04fb78652b7dd8f3f8647cdcd068f363fd2780
--- /dev/null
+++ b/src/mld.h
@@ -0,0 +1,120 @@
+#ifndef MLD_H
+#define MLD_H
+#if (EASYMESH_VERSION >= 6)
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <libubox/blobmsg.h>
+#include <libubox/list.h>
+#include <libubus.h>
+#include <easy/easy.h>
+#include <wifiutils.h>
+
+struct wifi7_radio_capabilities;
+struct netif_bk;
+struct netif_ap;
+struct bsta_mld;
+struct sta;
+
+/* multi-link device */
+struct netif_mld {
+	uint8_t id;
+	char ifname[16];
+	int channel;
+	int bandwidth;
+	uint8_t macaddr[6];
+	char ssid[33];
+	char standard[32];
+	char radio_name[16];
+	bool enabled;
+	bool torndown;
+
+	bool ap_str_enabled;
+	bool ap_nstr_enabled;
+	bool ap_emlsr_enabled;
+	bool ap_emlmr_enabled;
+
+	struct agent *agent;
+	struct list_head stamldlist;
+
+	int num_affiliated_ap;
+#define MAX_AFFILIATED_AP_LINKS_NUM 14
+        uint8_t affiliated_ap[MAX_AFFILIATED_AP_LINKS_NUM][6];
+
+	struct list_head list;
+};
+
+
+// struct used for client MLO STAs and own MLO bSTAs
+struct sta_mld {
+	uint8_t macaddr[6];
+	uint8_t bssid[6];
+
+	bool str_enabled;
+	bool nstr_enabled;
+	bool emlsr_enabled;
+	bool emlmr_enabled;
+
+	int num_affiliated_sta;
+#define MAX_AFFILIATED_STA_LINKS_NUM 14
+        uint8_t affiliated_sta[MAX_AFFILIATED_STA_LINKS_NUM][6];
+
+	struct list_head list;
+};
+
+
+struct sta_mld *stamld_update(struct agent *a, struct netif_ap *ap,
+			      uint8_t *mld_macaddr, uint8_t *mld_bssid,
+			      uint8_t mlo_link_id, struct sta *s);
+int mld_add_ap(struct agent *a, struct netif_mld *mld,
+				uint8_t *macaddr);
+int mld_add_sta(struct agent *a, struct sta_mld *mld,
+				uint8_t *macaddr);
+int mld_add_bsta(struct agent *a, struct bsta_mld *mld,
+				uint8_t *macaddr);
+int mld_del_sta(struct agent *a, struct sta *s);
+int mld_del_bsta(struct agent *a, struct netif_bk *bk);
+int mld_del_ap(struct agent *a, struct netif_ap *ap);
+int wifi_process_ml_ie(struct agent *a, struct sta_mld *stamld,
+                       uint8_t *assocframe, int framelen);
+void mld_event_handler(void *agent, struct blob_attr *msg);
+int mld_parse_affiliated_ap(struct ubus_request *req, int type,
+		struct blob_attr *msg);
+void apmld_parse(struct ubus_request *req, int type,
+		struct blob_attr *msg);
+void mld_parse_affiliated_bsta(struct agent *a, struct bsta_mld *mld,
+				 struct netif_bk *bk, int type,
+				 struct blob_attr *msg);
+void bstamld_parse(struct ubus_request *req, int type,
+		struct blob_attr *msg);
+struct netif_mld *agent_get_apmld(struct agent *a, uint8_t *macaddr);
+struct netif_mld *agent_get_apmld_by_ifname(struct agent *a, const char *ifname);
+struct netif_mld *agent_alloc_apmld(struct agent *a, const char *ifname);
+bool mld_contains_ap(struct agent *a, struct netif_mld *mld,
+                        uint8_t *macaddr);
+bool mld_contains_sta(struct agent *a, struct sta_mld *mld,
+                        uint8_t *macaddr);
+bool mld_contains_bsta(struct agent *a, struct bsta_mld *mld,
+                        uint8_t *macaddr);
+struct sta_mld *agent_get_stamld(struct agent *a, uint8_t *macaddr);
+struct sta_mld *agent_alloc_stamld(struct agent *a, struct netif_mld *mld,
+                                uint8_t *macaddr);
+struct bsta_mld *agent_init_bstamld(struct agent *a, char *ifname,
+                                struct wifi7_radio_capabilities *caps);
+void stamld_clean(struct agent *a, struct sta_mld *mld);
+void stamld_free(struct agent *a, struct sta_mld *mld);
+void bstamld_clean(struct agent *a, struct bsta_mld *mld);
+void agent_clear_bsta_mld(struct agent *a);
+void apmld_clean(struct agent *a, struct netif_mld *mld);
+void apmld_free(struct agent *a, struct netif_mld *mld);
+void apmld_free_all(struct agent *a);
+void clear_apmldlist(struct agent *a);
+bool is_affiliated_ap(struct agent *a, uint8_t *bssid);
+bool agent_radio_support_ap_mlo(struct wifi7_radio_capabilities *wifi7_caps);
+bool agent_radio_support_bsta_mlo(struct wifi7_radio_capabilities *wifi7_caps);
+int bstamld_teardown_band(struct agent *a, uint32_t band);
+void mld_set_config_id(char *ifname, uint8_t mld_id);
+#endif
+#endif
diff --git a/src/wifi_ubus.c b/src/wifi_ubus.c
index 7248f59974bad0c7124d87b211cedc5b412c475b..d8c9702f2ec0f45daef7d351fc3970ff08148457 100644
--- a/src/wifi_ubus.c
+++ b/src/wifi_ubus.c
@@ -2137,7 +2137,6 @@ static int wifi_ubus_get_mld_sta_links(struct ubus_context *ubus_ctx, struct net
 		.status = -1,
 	};
 	struct blob_buf bb = {};
-	char mld_addr_str[18] = {};
 	char name[256] = {};
 	uint32_t id;
 	int ret;
@@ -2153,7 +2152,9 @@ static int wifi_ubus_get_mld_sta_links(struct ubus_context *ubus_ctx, struct net
 
 	blob_buf_init(&bb, 0);
 
-	if (mld_addr) {
+	if (mld_addr && !hwaddr_is_zero(mld_addr)) {
+		char mld_addr_str[18] = {};
+
 		hwaddr_ntoa(mld_addr, mld_addr_str);
 		blobmsg_add_string(&bb, "sta", mld_addr_str);
 		ctx.mld_macaddr = mld_addr;