diff --git a/src/agent.c b/src/agent.c
index 05826265f05c4328cdc9ffc181c275b190c4d5b0..182c91837a01bd44a573d93a0787afa88b15b2c3 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -127,9 +127,16 @@ out:
 	bk->bsta_steer.cmdu = NULL;
 }
 
+static pthread_t nl_thread;
+
 static void agent_sighandler(int sig)
 {
-	uloop_end();
+	pthread_t self = pthread_self();
+
+	if (nl_thread == self)
+		ts_need_reconfig = true;
+	else
+		uloop_end();
 }
 
 int agent_exec_platform_scripts(char *arg)
@@ -2948,14 +2955,14 @@ static void agent_detect_loop(struct agent *a, int secs)
 /* Check if Primary VLAN is set on bSTA in assoc IE */
 static void agent_check_ts(struct agent *a, struct netif_bk *bk, char *ifname)
 {
+#if 0 /* Not used at present */
 	char buf[64] = {0};
-
 	if (Cmd(buf, sizeof(buf), "/lib/wifi/multiap ts primary get %s", ifname)) {
 		err("|%s:%d| Unable to fetch Primary VID info from system",
 		    __func__, __LINE__);
 	}
 
-	if (atoi(buf) && a && a->cfg.ts_enabled) {
+	if (atoi(buf) && a) {
 		if (!(a->cfg.pcfg)) {
 			a->cfg.pcfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg));
 			if (!(a->cfg.pcfg)) {
@@ -2964,10 +2971,14 @@ static void agent_check_ts(struct agent *a, struct netif_bk *bk, char *ifname)
 				return;
 			}
 		}
+
+		pthread_mutex_lock(&a->nl_mutex);
 		a->cfg.pcfg->pvid = atoi(buf);
-		a->ts.requested = 1;
-		agent_apply_traffic_separation(a);
+		pthread_mutex_unlock(&a->nl_mutex);
+
+		/* TODO save pvid in the config file */
 	}
+#endif
 }
 
 char *agent_get_backhaul_ifname(char *ifname)
@@ -3611,37 +3622,6 @@ static void parse_i1905_info(struct ubus_request *req, int type,
 		hwaddr_aton(mac, a->almac);
 		dbg("almac = " MACFMT "\n", MAC2STR(a->almac));
 	}
-
-
-	if (tb[1] && a->cfg.ts_enabled) {
-		struct blob_attr *cur;
-		int rem;
-
-		blobmsg_for_each_attr(cur, tb[1], rem) {
-			struct blob_attr *data[1];
-			static const struct blobmsg_policy intf_attrs[1] = {
-				[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }
-			};
-			char *ifname;
-			char fmt[64] = {0};
-
-			if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
-				continue;
-
-			blobmsg_parse(intf_attrs, 1, data, blobmsg_data(cur),
-					blobmsg_data_len(cur));
-
-			if (!data[0])
-				continue;
-
-			ifname = blobmsg_get_string(data[0]);
-			if (!ifname)
-				continue;
-
-			snprintf(fmt, sizeof(fmt), "ts multicast %s", ifname);
-			agent_exec_platform_scripts(fmt);
-		}
-	}
 }
 
 static void uobj_add_event_handler(void *agent, struct blob_attr *msg)
@@ -3949,7 +3929,7 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 {
 	char encryption[32] = {0}, ifname[16] = {0}, ssid[33] = {0},
 			key[65] = {0};
-	uint16_t vlan = 0;
+	//uint16_t vlan = 0;
 	struct blob_attr *tb[5];
 	struct wifi_radio_element *radio;
 	struct agent *a = (struct agent *) c;
@@ -3972,9 +3952,6 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 	strncpy(encryption, blobmsg_data(tb[1]), sizeof(encryption) - 1);
 	strncpy(ssid, blobmsg_data(tb[2]), sizeof(ssid) - 1);
 	strncpy(key, blobmsg_data(tb[3]), sizeof(key) - 1);
-	if (tb[4])
-		vlan = (uint16_t) blobmsg_get_u16(tb[4]);
-
 	bk = find_bkhaul_by_ifname(a, ifname);
 	if (!bk)
 		return;
@@ -4009,7 +3986,12 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 
 	uloop_timeout_set(&a->onboarding_scheduler, timeout * 1000);
 
-	if (vlan && bk->agent && bk->agent->cfg.ts_enabled) {
+#if 0 /* Not used at present */
+	vlan = 0;
+	if (tb[4])
+		vlan = (uint16_t) blobmsg_get_u16(tb[4]);
+
+	if (vlan && bk->agent) {
 		if (!(a->cfg.pcfg)) {
 			a->cfg.pcfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg));
 			if (!(a->cfg.pcfg)) {
@@ -4018,10 +4000,13 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 				return;
 			}
 		}
+		pthread_mutex_lock(&a->nl_mutex);
 		bk->agent->cfg.pcfg->pvid = vlan;
-		bk->agent->ts.requested = 1;
+		pthread_mutex_unlock(&a->nl_mutex);
+
 		agent_apply_traffic_separation(bk->agent);
 	}
+#endif
 }
 
 static void agent_event_handler(struct ubus_context *ctx,
@@ -4859,6 +4844,7 @@ static void _enumerate_wifi_objects(struct ubus_request *req, int type,
 		/* clears radio apcfg states */
 		agent_free_radios(a);
 		clear_fhlist(a);
+		clear_bklist(a);
 		a->num_radios = len;
 	}
 
@@ -5496,8 +5482,10 @@ int agent_init_interfaces(struct agent *a)
 			fn->cfg = f;
 			fn->agent = a;
 			strncpy(fn->radio_name, radio_name, IFNAMSIZ-1);
-			fn->vid = TS_VID_INVALID;
+
+			pthread_mutex_lock(&a->nl_mutex);
 			list_add(&fn->list, &a->fhlist);
+			pthread_mutex_unlock(&a->nl_mutex);
 		}
 
 		snprintf(r_objname, 31, "wifi.radio.%s", radio_name);
@@ -5535,19 +5523,14 @@ int agent_init_interfaces(struct agent *a)
 		char r_objname[32] = {0};
 		char objname[32] = {0};
 
+
 		bn = find_bkhaul_by_ifname(a, b->name);
 		if (!bn) {
 			bn = netif_alloc_bk(b->name);
 			if (bn) {
-				if (a->cfg.ts_enabled) {
-					char tsfmt[64] = {0};
-					//FIXME: add primary VID
-					snprintf(tsfmt, sizeof(tsfmt), "ts create bh %s 1 2",
-						 b->name);
-					dbg("%s %d ts-fmt = %s\n", __func__, __LINE__, tsfmt);
-					agent_exec_platform_scripts(tsfmt);
-				}
+				pthread_mutex_lock(&a->nl_mutex);
 				list_add(&bn->list, &a->bklist);
+				pthread_mutex_unlock(&a->nl_mutex);
 			}
 		}
 
@@ -5576,7 +5559,6 @@ int agent_init_interfaces(struct agent *a)
 			bn->radio = r_wobj;
 			bn->cfg = b;
 			bn->agent = a;
-			bn->vid = TS_VID_INVALID;
 
 			ubus_call_object(a, wobj, "status", parse_bk, bn);
 			if (bn->connected)
@@ -5604,7 +5586,7 @@ int agent_init_interfaces(struct agent *a)
 	agent_config_reload(&a->cfg);
 
 	agent_init_interfaces_post_actions(a);
-
+	agent_apply_traffic_separation(a);
 	return 0;
 }
 
@@ -5619,17 +5601,12 @@ static void agent_enable_fhs_cb(struct uloop_timeout *t)
 
 static void agent_init_ifaces_cb(struct uloop_timeout *t)
 {
-	trace("%s: --->\n", __func__);
-
 	struct agent *a = container_of(t, struct agent, init_ifaces_scheduler);
 
 	if (!a)
 		return;
 
 	agent_init_interfaces(a);
-
-	if (a->cfg.ts_enabled && a->ts.requested)
-		agent_apply_traffic_separation(a);
 }
 
 
@@ -5647,11 +5624,6 @@ static void agent_reload_wireless(struct uloop_timeout *t)
 
 	agent_exec_platform_scripts("sync_credentials");
 	uci_reload_services("wireless");
-
-	if (a->cfg.ts_enabled && a->ts.requested) {
-		agent_apply_traffic_separation(a);
-	} else if (a->cfg.ts_enabled && a->ts.active)
-		agent_disable_traffic_separation(a);
 }
 
 /* send the steering compled message this function also resets the value of
@@ -5870,7 +5842,7 @@ void clear_restrict_stalist(struct netif_fh *p)
 	}
 }
 
-static void netif_free(struct netif_fh *n)
+static void netif_free(struct agent *a, struct netif_fh *n)
 {
 	/* clear stalist */
 	clear_stalist(n);
@@ -5888,7 +5860,10 @@ static void netif_free(struct netif_fh *n)
 	uloop_timeout_cancel(&n->util_threshold_timer);
 	uloop_timeout_cancel(&n->una_sta_meas_timer);
 
+	pthread_mutex_lock(&a->nl_mutex);
 	list_del(&n->list);
+	pthread_mutex_unlock(&a->nl_mutex);
+
 	free(n);
 }
 
@@ -5897,10 +5872,23 @@ void clear_fhlist(struct agent *a)
 	struct netif_fh *p, *tmp;
 
 	list_for_each_entry_safe(p, tmp, &a->fhlist, list) {
-		netif_free(p);
+		netif_free(a, p);
 	}
 }
 
+void clear_bklist(struct agent *a)
+{
+	struct netif_bk *p, *tmp;
+
+	list_for_each_entry_safe(p, tmp,  &a->bklist, list) {
+		pthread_mutex_lock(&a->nl_mutex);
+		list_del(&p->list);
+		pthread_mutex_unlock(&a->nl_mutex);
+		free(p);
+	}
+}
+
+
 int agent_map_sub_cb(void *bus, void *priv, void *data)
 {
 	struct blob_attr *msg = (struct blob_attr *)data;
@@ -6059,7 +6047,6 @@ void run_agent(void)
 {
 	struct agent *w;
 	struct ubus_context *ctx;
-	pthread_t tid[1];
 
 	set_sighandler(SIGHUP, agent_sighandler);
 	set_sighandler(SIGPIPE, SIG_IGN);
@@ -6071,6 +6058,7 @@ void run_agent(void)
 	this_agent = w;
 	dbg("Starting wifi_agent... (&agent = %p)\n", w);
 
+	pthread_mutex_init(&w->nl_mutex, NULL);
 	agent_init_defaults(w);
 
 	cmdu_ackq_init(&w->cmdu_ack_q);
@@ -6097,23 +6085,26 @@ void run_agent(void)
 
 	//agent_config_get_ethwan(w->ethwan);
 	//memcpy(w->cntlr_almac, w->cfg.cntlr_almac, 6);
+
 	if (w->cfg.brcm_setup) {
 		int ret;
 
-		/* TODO: memory management of thread on cleaup */
-		ret = pthread_create(&(tid[0]), NULL, (void *)&nl_loop, w);
+		ret = pthread_create(&w->nl_thread, NULL, (void *)&nl_loop, w);
 		if (ret) {
 			fprintf(stderr, "Failed to create thread\n");
+			free(w);
 			return;
 		}
 
-		pthread_detach(tid[0]);
+		nl_thread = w->nl_thread;
 	}
 
 	//agent_config_dump(&w->cfg);
 
 	get_registered_steer_rules();	/* TODO: return rule list and improve */
 
+	//agent_switch_according_to_pref(w); /*switch to the channel according to the prefrence*/
+
 	ubus_register_event_handler(ctx, &w->evh, "ethport");
 	ubus_register_event_handler(ctx, &w->evh, "wifi.*");
 	ubus_register_event_handler(ctx, &w->evh, "wps_credentials");
@@ -6149,19 +6140,26 @@ void run_agent(void)
 
 	agent_subscribe_for_cmdus(w);
 
-	/* TODO: can probably be removed */
-	if (w->cfg.ts_enabled)
-		agent_exec_platform_scripts("ts multicast lei_lan");
-
 	uloop_run();
 
 /* out_and_exit: */
+	if (w->cfg.brcm_setup) {
+		void *res;
+
+		pthread_cancel(w->nl_thread);
+		pthread_join(w->nl_thread, &res);
+		if (res != PTHREAD_CANCELED)
+			warn("Fail to cancel nl thread\n");
+	}
+
 	map_unsubscribe(w->ubus_ctx, w->subscriber);
 	agent_free_radios(w);
 	agent_remove_object(w);
 	agent_config_clean(&w->cfg);
 	cmdu_ackq_free(&w->cmdu_ack_q);
 	clear_fhlist(w);
+	clear_bklist(w);
+	pthread_mutex_destroy(&w->nl_mutex);
 	ubus_unregister_event_handler(ctx, &w->evh);
 	plugins_unload(&w->pluginlist);
 	uloop_done();
diff --git a/src/agent.h b/src/agent.h
index 72306725f15a64c4cb147bfc9cb37a2e9c002c73..6a662b5cbd18fea4b9ef87f3ad79ff345a5dfec0 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -16,6 +16,7 @@
 #include <timer_impl.h>
 #include <cmdu_ackq.h>
 #include <map_module.h>
+#include <linux/if_bridge.h>
 
 // TODO: TODO: fixme: remove this include
 //#include <ieee1905/1905_tlvs.h>
@@ -268,9 +269,6 @@ struct netif_fh {
 
 	/* previous channel utilization threshold value */
 	uint8_t prev_util;
-
-	/* traffic separation */
-	unsigned int vid;
 };
 
 /* backhaul wifi (sta) interface */
@@ -295,9 +293,6 @@ struct netif_bk {
 		struct cmdu_buff *cmdu;
 	} bsta_steer;
 	struct uloop_timeout connect_timer;
-
-	/* traffic separation */
-	unsigned int vid;
 };
 
 #if 0
@@ -649,13 +644,9 @@ struct agent {
 	struct uloop_timeout fh_disable_timer;
 #endif /* AGENT_ISLAND_PREVENTION */
 
-	/* traffic separation */
-	struct {
-//		bool enabled;		// config option to enable/disable feature
-		bool requested;		// triggered by condition according to spec
-//		bool setup;		// TS subsystem separation prepared
-		bool active;		// current status
-	} ts;
+	/* traffic separation and netlink events */
+	pthread_t nl_thread;
+	pthread_mutex_t nl_mutex;
 
 	/* dynamic backhaul */
 	struct uloop_timeout upgrade_backhaul_scheduler;
@@ -735,6 +726,7 @@ void agent_disable_local_cntlr(struct agent *a);
 void wifiagent_log_cntlrinfo(struct agent *a);
 void agent_free_radios(struct agent *a);
 void clear_fhlist(struct agent *a);
+void clear_bklist(struct agent *a);
 int agent_init_interfaces(struct agent *a);
 struct sta *find_sta_by_mac(struct agent *a, const unsigned char *mac);
 int agent_switch_according_to_pref(struct agent *a);
diff --git a/src/agent_map.c b/src/agent_map.c
index 43de2a00d23649e6adeaee87a94b0a3135419e45..56083dccc0c5cf25a8b4c6caa9d282fe3c05c745 100644
--- a/src/agent_map.c
+++ b/src/agent_map.c
@@ -903,14 +903,6 @@ int handle_ap_autoconfig_search(void *agent, struct cmdu_buff *rx_cmdu)
 		return -1;
 	}
 
-	if (memcmp(aladdr_origin, a->almac, 6) && a->cfg.ts_enabled) {
-		char cmd[64] = {0};
-
-		snprintf(cmd, sizeof(cmd), "ts unicast " MACFMT " %s",
-				MAC2STR(aladdr_origin), "lei_lan");
-		agent_exec_platform_scripts(cmd);
-	}
-
 	/* Discard autoconfig search in case it's been sent by ourself */
 	for (i = 0; i < a->num_radios; i++) {
 		if (a->radios[i].mid == cmdu_get_mid(rx_cmdu)) {
@@ -1425,63 +1417,13 @@ static inline bool is_vid_valid(unsigned int vid)
 	return (vid < TS_VID_INVALID) && (vid > 0);
 }
 
-static void agent_ts_setup_eths(struct agent *a,  struct agent_config *cfg,
-		struct policy_cfg *c)
-{
-	struct netif_fh *fh = NULL;
-	char cmd[128] = {0};
-	char vids[64] = {0};
-	char *vids_buf = vids;
-	int vids_len = sizeof(vids) - 1;
-	int len;
-
-	bool have_vids = false;
-	/* secondary networks vlan id's*/
-	list_for_each_entry(fh, &a->fhlist, list) {
-		char vid_str[8] = {0};
-
-		if (!is_vid_valid(fh->vid))
-			continue;
-		if (fh->vid == c->pvid)
-			continue;
-
-		/* TODO keep table of secondary vids from config */
-
-		snprintf(vid_str, sizeof(vid_str) - 1, " %u ", fh->vid);
-		if (strstr(vids, vid_str))
-			continue;
-
-		len = snprintf(vids_buf, vids_len, "%s", vid_str);
-		if (len < 0) {
-			err("Fail to add secondary vlan id");
-			break;
-		}
-
-		vids_buf += len;
-		vids_len -= len;
-
-		have_vids = true;
-	}
-
-	if (!have_vids)
-		return;
-
-	snprintf(cmd, sizeof(cmd), "ts create eths %u %s %s",
-		 c->pvid, cfg->al_bridge, vids);
-	agent_exec_platform_scripts(cmd);
-}
-
 /* Set up Traffic Separation rules */
 int agent_apply_traffic_separation(struct agent *a)
 {
-	trace("%s: --->\n", __func__);
 	struct agent_config *cfg;
 	struct policy_cfg *c;
-	struct netif_fh *fh;
-	struct netif_bk *bk;
-	bool diff = false;
-	char cmd[128] = {0};
-	bool dhcp_reload = false;
+
+	trace("%s: --->\n", __func__);
 
 	if (!a)
 		return -1;
@@ -1498,179 +1440,16 @@ int agent_apply_traffic_separation(struct agent *a)
 		return -1;
 	}
 
-	/* Fronthaul */
-	list_for_each_entry(fh, &a->fhlist, list) {
-		if (fh->cfg->multi_ap == 2) {
-			/* FH BSS */
-			unsigned int new_vid =
-				fh->cfg->vid ? fh->cfg->vid : c->pvid;
-			if (fh->vid == new_vid)		/* no change */
-				continue;
-			diff = true;
-
-			if (is_vid_valid(fh->vid)) {
-				/* existing vlan has changed */
-				/* TODO: less interruption if vlan filters are
-				 * just modified instead of recreated */
-				snprintf(cmd, sizeof(cmd), "ts delete %s",
-					 fh->name);
-				agent_exec_platform_scripts(cmd);
-				trace("%s: VID changed for FH BSS: %s\n",
-				      __func__, cmd);
-			}
-
-			snprintf(cmd, sizeof(cmd), "ts create fh %s %u %s",
-				 fh->name, new_vid, cfg->al_bridge);
-			agent_exec_platform_scripts(cmd);
-
-			if (is_local_cntlr_running() && new_vid != c->pvid) {
-				snprintf(cmd, sizeof(cmd), "ts create dhcp %u", new_vid);
-				agent_exec_platform_scripts(cmd);
-				dhcp_reload = true;
-			}
-
-			fh->vid = new_vid;
-		} else if (fh->cfg->multi_ap == 3) {
-			// TODO: Mixed FH/BH
-		}
-	}
-
-	/* Backhaul */
-	// TODO: Profile needs to be for BH, not Agent - for now always assume 2
-	list_for_each_entry(bk, &a->bklist, list) {
-		/* BH STA */
-		if (bk->vid == c->pvid)		/* no change */
-			continue;
-		diff = true;
-
-		if (is_vid_valid(bk->vid)) {
-			/* existing vlan has changed */
-			/* TODO: less interruption if vlan filters are
-			 * just modified instead of recreated */
-			snprintf(cmd, sizeof(cmd), "ts delete %s",
-				 bk->name);
-			agent_exec_platform_scripts(cmd);
-			trace("%s: VID changed for BH STA: %s\n", __func__, cmd);
-		}
-
-		snprintf(cmd, sizeof(cmd), "ts create bh %s %u %s %s",
-			 bk->name, c->pvid, "2", cfg->al_bridge);
-//			 cfg->profile == MULTIAP_PROFILE_2 ? "2" : "1");
-		agent_exec_platform_scripts(cmd);
-		bk->vid = c->pvid;
-		trace("%s: applying TS for BH STA: %s\n", __func__, cmd);
-	}
-
-	list_for_each_entry(fh, &a->fhlist, list) {
-		if (fh->cfg->multi_ap == 1) {
-			/* BH BSS */
-			if (fh->vid == c->pvid)		/* no change */
-				continue;
-			diff = true;
-
-			if (is_vid_valid(fh->vid)) {
-				/* existing vlan has changed */
-				/* TODO: less interruption if vlan filters are
-				 * just modified instead of recreated */
-				snprintf(cmd, sizeof(cmd), "ts delete %s",
-					 fh->name);
-				agent_exec_platform_scripts(cmd);
-				trace("%s: VID changed for BH BSS: %s\n",
-				      __func__, cmd);
-			}
-
-			snprintf(cmd, sizeof(cmd), "ts create bh %s %u %s",
-				 fh->name, c->pvid, "2");
-			agent_exec_platform_scripts(cmd);
-			fh->vid = c->pvid;
-			trace("%s: applying TS for BH BSS: %s\n", __func__, cmd);
-		} else if (fh->cfg->multi_ap == 3) {
-			// TODO: Mixed FH/BH
-		}
-	}
-
-	if (!diff && a->ts.active)
+	if (c->pvid == 0)
 		return 0;
 
-	/* Logical Ethernet Interface */
-	/* Note: setup of LEI is already handled by init script */
-	snprintf(cmd, sizeof(cmd), "ts create lei %u %u %s %s",
-		 c->pvid, c->pcp_default, cfg->al_bridge, "br-lan");
-	agent_exec_platform_scripts(cmd);
-
-	agent_ts_setup_eths(a, cfg, c);
-
-	a->ts.active = true;
-
-	snprintf(cmd, sizeof(cmd), "ts reload %s" , dhcp_reload ? "1" : "");
-	agent_exec_platform_scripts(cmd);
-
-#if 0	// Not needed for now, maybe never?
-	if (cfg->brcm_setup) {
-		/* special case to handle wds interface */
-		int i, num, max = 32;
-		char if_list[max][16];
-
-		if (br_get_iflist(cfg->al_bridge, &num, if_list)) {
-			trace("Failed to check bridge affiliation\n");
-			return -1;
-		}
-		max = (num < max) ? num : max;
-		for (i = 0; i < max; i++) {
-			if (strstr(if_list[i], "wds") &&
-			    !strstr(if_list[i], "vlan")) {
-				/* trigger nl hook */
-				trace("%s: applying TS for %s\n", __func__,
-				      if_list[i]);
-				br_delif(cfg->al_bridge, if_list[i]);
-			}
-		}
-	}
-#endif
-
-	return 0;
-}
-
-int agent_disable_traffic_separation(struct agent *a)
-{
-	trace("%s: --->\n", __func__);
-	struct netif_fh *fh = NULL;
-	struct netif_bk *bk = NULL;
-	char cmd[64] = {0};
-
-	/* go through all (fh) SSIDs and remove any vid found */
-	/* remove all existing vlans */
-
-	/* TODO: remove dual bridge */
-
-	/* Fronthaul */
-	list_for_each_entry(fh, &a->fhlist, list) {
-		if (is_vid_valid(fh->vid)) {
-			snprintf(cmd, sizeof(cmd), "ts delete %s", fh->name);
-			agent_exec_platform_scripts(cmd);
-			fh->vid = TS_VID_INVALID;
-		}
+	if (!is_vid_valid(c->pvid)) {
+		warn("Invalid primary vlan id %u", c->pvid);
+		return -1;
 	}
 
-	/* Backhaul */
-	list_for_each_entry(bk, &a->bklist, list) {
-		if (is_vid_valid(bk->vid)) {
-			snprintf(cmd, sizeof(cmd), "ts delete %s", bk->name);
-			agent_exec_platform_scripts(cmd);
-			bk->vid = TS_VID_INVALID;
-		}
-	}
-
-	/* Ethernet */
-	/* We might end without lei interface connected to br-map
-	 * bridge. Enabling / disabling TS should be addressed
-	 * properly , for now don't delete LEI */
-#if 0
-	snprintf(cmd, sizeof(cmd), "ts delete %s", VLAN_IFACE);
-	agent_exec_platform_scripts(cmd);
-#endif
-
-	a->ts.active = false;
+	dbg("wakeup nl_thread\n");
+	pthread_kill(a->nl_thread, SIGHUP);
 
 	return 0;
 }
@@ -1818,19 +1597,9 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
 	if (tv[1][0]) {
 		struct tlv_traffic_sep_policy *tlv = (struct tlv_traffic_sep_policy *) tv[1][0]->data;
 
-		agent_fill_traffic_sep_policy(a, tlv);
-
 		dbg("|%s:%d| TS policy received\n", __func__, __LINE__);
 
-		if (a->cfg.ts_enabled && tlv->num_ssid > 0)
-			a->ts.requested = true;
-		else
-			a->ts.requested = false;
-
-		dbg("|%s:%d| TS status:\n", __func__, __LINE__);
-		dbg("\tenabled: %d\n", a->cfg.ts_enabled);
-		dbg("\trequested: %d\n", a->ts.requested);
-		dbg("\tactive: %d\n", a->ts.active);
+		agent_fill_traffic_sep_policy(a, tlv);
 	}
 
 	dbg("|%s:%d| radio (%s) was configured! Apply heartbeat for this radio\n",
@@ -2482,19 +2251,8 @@ int handle_map_policy_config(void *agent, struct cmdu_buff *cmdu)
 		struct tlv_traffic_sep_policy *p =
 			(struct tlv_traffic_sep_policy *)tv[3][0]->data;
 
-		agent_fill_traffic_sep_policy(a, p);
-
 		dbg("|%s:%d| TS policy received\n", __func__, __LINE__);
-
-		if (a->cfg.ts_enabled && p->num_ssid > 0)
-			a->ts.requested = true;
-		else
-			a->ts.requested = false;
-
-		dbg("|%s:%d| TS status:\n", __func__, __LINE__);
-		dbg("\tenabled: %d\n", a->cfg.ts_enabled);
-		dbg("\trequested: %d\n", a->ts.requested);
-		dbg("\tactive: %d\n", a->ts.active);
+		agent_fill_traffic_sep_policy(a, p);
 	}
 
 	if (tv[4][0]) {
@@ -2533,10 +2291,7 @@ int handle_map_policy_config(void *agent, struct cmdu_buff *cmdu)
 
 	agent_process_policy_config(a);
 
-	if (a->cfg.ts_enabled && a->ts.requested) {
-		agent_apply_traffic_separation(a);
-	} else if (a->cfg.ts_enabled && a->ts.active)
-		agent_disable_traffic_separation(a);
+	agent_apply_traffic_separation(a);
 
 	return 0;
 }
diff --git a/src/agent_tlv.c b/src/agent_tlv.c
index 941f855421757ce7c8253d319d79e1a20bc960e7..e0459a66cb7182eb887c29cf151b73328967910b 100644
--- a/src/agent_tlv.c
+++ b/src/agent_tlv.c
@@ -2282,6 +2282,8 @@ int agent_fill_8021q_setting(struct agent *a,
 		uci_save(ctx, pkg);
 	}
 
+	dbg("Received Primary VID %u\n", BUF_GET_BE16(p->pvid));
+
 	memset(buf, 0, sizeof(buf));
 	snprintf(buf, sizeof(buf) - 1, "%s.%s.pvid=%d",
 			pkg->e.name, s->e.name,
diff --git a/src/config.c b/src/config.c
index 76cb2b9f9c7156a89d2dc05644f272ac61698ab0..45c2e54b4b86c5e4947fe4320289c18746ff9b5a 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1812,7 +1812,6 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 		A_AL_BRIDGE,
 		A_NETDEV,
 		A_IFPREFIX,
-		A_TS,
 		A_RESEND_NUM,
 		A_DYN_CNTLR_SYNC,
 		A_ISL_PREV,
@@ -1829,7 +1828,6 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 		{ .name = "al_bridge", .type = UCI_TYPE_STRING },
 		{ .name = "netdev", .type = UCI_TYPE_STRING },
 		{ .name = "ifprefix", .type = UCI_TYPE_STRING },
-		{ .name = "vlan_segregation", .type = UCI_TYPE_STRING },
 		{ .name = "resend_num", .type = UCI_TYPE_STRING },
 		{ .name = "dyn_cntlr_sync", .type = UCI_TYPE_STRING },
 		{ .name = "island_prevention", .type = UCI_TYPE_STRING },
@@ -1884,9 +1882,6 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 				sizeof(a->netdev) - 1);
 	}
 
-	if (tb[A_TS])
-		a->ts_enabled = atoi(tb[A_TS]->v.string);
-
 	if (tb[A_RESEND_NUM]) {
 		const char *val = tb[A_RESEND_NUM]->v.string;
 
@@ -2992,8 +2987,6 @@ int agent_config_init(struct agent *a, struct agent_config *cfg)
 	INIT_LIST_HEAD(&cfg->bklist);
 	INIT_LIST_HEAD(&cfg->radiolist);
 
-	cfg->ts_enabled = 0;
-
 	agent_config_prepare(cfg);
 	agent_config_reload(cfg);
 
diff --git a/src/config.h b/src/config.h
index c753722a252785141bf37ac78263b7d6ed41d7bf..2e1625c2f4e4e0ebe960480531aebac9143fc18a 100644
--- a/src/config.h
+++ b/src/config.h
@@ -190,7 +190,6 @@ struct agent_config {
 	uint8_t profile;
 	bool brcm_setup;
 	bool configured;
-	bool ts_enabled;
 	bool dyn_cntlr_sync;
 	int resend_num;
 	uint8_t cntlr_almac[6];
diff --git a/src/nl.c b/src/nl.c
index 5916fa5ea664476fb622fde5555a6097a4cc37fe..75d73781e82d990d7df0074298ed0d9ed84ad646 100644
--- a/src/nl.c
+++ b/src/nl.c
@@ -4,20 +4,18 @@
 #include <net/if.h>
 #include <uci.h>
 #include <string.h>
+#include <pthread.h>
 
 #include <netlink/netlink.h>
 #include <netlink/route/rtnl.h>
 #include <netlink/socket.h>
 #include <netlink/msg.h>
 
+#include <linux/if_bridge.h>
+
 #include <sys/ioctl.h>
 #include <net/if.h>
 
-#include <libubox/blobmsg.h>
-#include <libubox/blobmsg_json.h>
-#include <libubox/uloop.h>
-#include <libubox/ustream.h>
-#include <libubox/utils.h>
 #include <libubus.h>
 
 #include <easy/easy.h>
@@ -27,6 +25,397 @@
 #include "config.h"
 #include "agent.h"
 
+#define dbg(...) fprintf(stderr, __VA_ARGS__)
+#define warn(...) fprintf(stderr, __VA_ARGS__)
+
+#define TS_IFACE_MAX_NUM (2*WIFI_IFACE_MAX_NUM)
+#define MAX_VIDS (WIFI_IFACE_MAX_NUM - 4)
+
+static struct nl_sock *nl_main_sk;
+static struct nl_sock *nl_bridge_sk;
+static struct nl_cb *nl_bridge_cb;
+
+static bool ts_bridge_dump_done;
+static bool ts_check_vlan_settings;
+bool ts_need_reconfig;
+
+struct ts_iface {
+	char name[IFNAMSIZ];
+	uint16_t vid;
+	int ifi_index;
+	struct bridge_vlan_info cur_vinfo[MAX_VIDS];
+	bool is_bsta;
+};
+
+static struct ts_iface ts_iface_array[TS_IFACE_MAX_NUM];
+static uint16_t ts_primary_vid;
+
+static uint16_t ts_all_vids[MAX_VIDS];
+static unsigned int ts_num_vids = 0;
+
+static bool ts_is_our_vid(uint16_t vid)
+{
+	int i;
+
+	for (i = 0; i < ts_num_vids; i++) {
+		if (ts_all_vids[i] == vid)
+			return true;
+	}
+
+	return false;
+}
+
+static struct ts_iface *ts_find_iface(const char *ifname)
+{
+	int i;
+
+	for (i = 0; i < TS_IFACE_MAX_NUM; i++) {
+		if (strncmp(ts_iface_array[i].name, ifname , 16) == 0)
+			return &ts_iface_array[i];
+	}
+
+	return NULL;
+}
+
+static struct ts_iface *ts_configure_iface(const char *ifname, uint16_t vid)
+{
+	struct ts_iface *tsif;
+	int i;
+
+	for (i = 0; i < TS_IFACE_MAX_NUM; i++) {
+		tsif = &ts_iface_array[i];
+		if (tsif->name[0] == '\0') {
+			strncpy(tsif->name, ifname, IFNAMSIZ);
+			ts_check_vlan_settings = true;
+			break;
+		}
+
+		if (strncmp(tsif->name, ifname, IFNAMSIZ) == 0)
+			break;
+	}
+
+	if (i >= TS_IFACE_MAX_NUM) {
+		warn("Number of TS interfaces too small\n");
+		return NULL;
+	}
+
+	if (tsif->vid != vid) {
+		tsif->vid = vid;
+		ts_check_vlan_settings = true;
+	}
+
+	if (vid != 0 && !ts_is_our_vid(tsif->vid)) {
+		if (ts_num_vids < MAX_VIDS)
+			ts_all_vids[ts_num_vids++] = tsif->vid;
+		else
+			warn("Too many vids\n");
+	}
+
+	return tsif;
+}
+
+static void tsif_check_attr(struct ts_iface *tsif, struct rtattr *attr)
+{
+	struct bridge_vlan_info *vinfo;
+	struct rtattr *cur;
+	int rem = RTA_PAYLOAD(attr);
+	int i;
+
+	for (cur = RTA_DATA(attr); RTA_OK(cur, rem); cur = RTA_NEXT(cur, rem)) {
+		if (cur->rta_type != IFLA_BRIDGE_VLAN_INFO)
+			continue;
+
+		vinfo = RTA_DATA(cur);
+
+		dbg("%s %s vid %d flags %0x\n", __func__, tsif->name, vinfo->vid, vinfo->flags);
+
+		for (i = 0; i < MAX_VIDS; i++) {
+			if (tsif->cur_vinfo[i].vid == 0) {
+				tsif->cur_vinfo[i] = *vinfo;
+				break;
+			}
+		}
+
+		if (i >= MAX_VIDS)
+			warn("%s cur_vinfo array too small\n", tsif->name);
+	}
+}
+
+static int ts_nl_get_cb(struct nl_msg *msg, void *arg)
+{
+	struct nlmsghdr *nh = nlmsg_hdr(msg);
+	struct ifinfomsg *ifi = NLMSG_DATA(nh);
+	struct rtattr *attr;
+	struct ts_iface *tsif;
+	char name[16];
+	char *ifname;
+	int rem;
+
+	if (!nh || !ifi)
+		return NL_SKIP;
+
+	dbg("%s family %u index %u\n", __func__, ifi->ifi_family, ifi->ifi_index);
+
+	if (nh->nlmsg_type != RTM_NEWLINK)
+		return NL_SKIP;
+
+	if (ifi->ifi_family != AF_BRIDGE)
+		return NL_SKIP;
+
+	ifname = if_indextoname(ifi->ifi_index, name);
+	if (!ifname) {
+		ts_bridge_dump_done = true;
+		return NL_STOP;
+	}
+
+	tsif = ts_find_iface(ifname);
+	if (!tsif)
+		return NL_SKIP;
+
+	attr = IFLA_RTA(ifi);
+	rem = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
+	while (RTA_OK(attr, rem)) {
+		if (attr->rta_type == IFLA_AF_SPEC)
+			tsif_check_attr(tsif, attr);
+
+		attr = RTA_NEXT(attr, rem);
+	}
+
+	tsif->ifi_index = ifi->ifi_index;
+
+	return NL_SKIP;
+}
+
+static int ts_nl_finish_cb(struct nl_msg *msg, void *arg)
+{
+	dbg("%s\n", __func__);
+
+	ts_bridge_dump_done = true;
+
+	return NL_STOP;
+}
+
+static int ts_nl_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
+{
+	/* TODO print error */
+	dbg("%s\n", __func__);
+
+	ts_bridge_dump_done = true;
+
+	return NL_STOP;
+}
+
+void ts_read_bridge_vlan(const char *br_name)
+{
+	static struct ifinfomsg ifi = {
+		.ifi_family = AF_BRIDGE
+	};
+	static struct rtattr ext_req = {
+		.rta_type = IFLA_EXT_MASK,
+		.rta_len = RTA_LENGTH(sizeof(uint32_t)),
+	};
+	uint32_t filter = RTEXT_FILTER_BRVLAN;
+	struct nl_msg *nlmsg;
+	int ret;
+
+	/* TODO check if this works when there are more than one bridge */
+	ifi.ifi_index = if_nametoindex(br_name);
+	if (ifi.ifi_index <= 0)
+		return;
+
+
+	nlmsg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_DUMP);
+	if (!nlmsg)
+		return;
+
+	dbg("%s START\n", __func__);
+
+	ret = nlmsg_append(nlmsg, &ifi, sizeof(ifi), 0);
+	ret |= nlmsg_append(nlmsg, &ext_req, sizeof(ext_req), NLMSG_ALIGNTO);
+	ret |= nlmsg_append(nlmsg, &filter, sizeof(filter), 0);
+
+	if (ret)
+		goto free;
+
+	ts_bridge_dump_done = false;
+
+	if (nl_send_auto_complete(nl_bridge_sk, nlmsg) < 0)
+		ts_bridge_dump_done = true;
+
+	while (!ts_bridge_dump_done)
+		nl_recvmsgs(nl_bridge_sk, nl_bridge_cb);
+free:
+	nlmsg_free(nlmsg);
+
+	dbg("%s END\n", __func__);
+}
+
+static int send_bridge_vlan_info(int nlmsg_type, struct ifinfomsg *ifi, struct bridge_vlan_info *vinfo, int n)
+{
+	struct nl_msg *nlmsg;
+	struct nlattr *attr;
+	int ret = -1;
+	int i;
+
+	nlmsg = nlmsg_alloc_simple(nlmsg_type, NLM_F_REQUEST);
+	if (!nlmsg)
+		return -1;
+
+	nlmsg_append(nlmsg, ifi, sizeof(*ifi), 0);
+
+	attr = nla_nest_start(nlmsg, IFLA_AF_SPEC);
+	if (!attr)
+		goto err;
+
+	for (i = 0; i < n; i++)
+		nla_put(nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo[i]), &vinfo[i]);
+
+	nla_nest_end(nlmsg, attr);
+
+	ret = nl_send_auto_complete(nl_main_sk, nlmsg);
+
+err:
+	nlmsg_free(nlmsg);
+
+	return ret < 0 ? ret : 0;
+}
+
+static void ts_set_iface_vlan(struct ts_iface *tsif)
+{
+	const uint16_t prim_flags = BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED;
+	struct ifinfomsg ifi = { .ifi_family = PF_BRIDGE };
+	struct bridge_vlan_info add_vinfo[MAX_VIDS];
+	struct bridge_vlan_info del_vinfo[MAX_VIDS];
+	int n_del, n_add;
+	int i, ret;
+	bool has_vid;
+
+	ifi.ifi_index = tsif->ifi_index;
+	if (ifi.ifi_index <= 0) {
+		warn("Wrong index %d for %s\n", tsif->ifi_index, tsif->name);
+		return;
+	}
+
+	n_del = 0;
+	n_add = 0;
+
+	if (tsif->vid) {
+		/* Fronthaul */
+		has_vid = false;
+		for (i = 0; i < MAX_VIDS; i++) {
+			if (tsif->cur_vinfo[i].vid == 0)
+				break;
+
+			if (tsif->cur_vinfo[i].vid != tsif->vid)
+				del_vinfo[n_del++] = tsif->cur_vinfo[i];
+			else if (tsif->cur_vinfo[i].flags == prim_flags)
+				has_vid = true;
+		}
+
+		if (!has_vid) {
+			add_vinfo[0].vid = tsif->vid;
+			add_vinfo[0].flags = prim_flags;
+			n_add = 1;
+		}
+	} else {
+		/* Backhaul */
+		for (i = 0; i < MAX_VIDS; i++) {
+			if (tsif->cur_vinfo[i].vid == 0)
+				break;
+
+			if (!ts_is_our_vid(tsif->cur_vinfo[i].vid))
+				del_vinfo[n_del++] = tsif->cur_vinfo[i];
+		}
+
+		for (i = 0; i < ts_num_vids; i++) {
+			add_vinfo[i].vid = ts_all_vids[i];
+#if 0
+			/* if we want primary vid to be send untagged
+			 * similar like for eth interfaces, but this
+			 * is not MultiAP spec compliant.
+			 */
+			if (add_vinfo[i].vid == ts_primary_vid)
+				add_vinfo[i].flags = prim_flags;
+			else
+#endif
+			add_vinfo[i].flags = 0;
+		}
+		n_add = i;
+	}
+
+	if (n_add == 0 && n_del == 0)
+		return;
+
+	dbg("add %d del %d vids for %s iface %s %d\n", n_add, n_del,
+	    tsif->vid ? "fronthaul" : "backhaul", tsif->name, tsif->ifi_index);
+
+	if (n_add > 0) {
+		ret = send_bridge_vlan_info(RTM_SETLINK, &ifi, add_vinfo, n_add);
+		if (ret < 0)
+			warn("Failed to add vlan info for %s\n", tsif->name);
+	}
+
+	if (n_del > 0) {
+		ret = send_bridge_vlan_info(RTM_DELLINK, &ifi, del_vinfo, n_del);
+		if (ret < 0)
+			warn("Failed to remove vlan info %s\n", tsif->name);
+	}
+}
+
+static void ts_set_system(void)
+{
+	char buf[16] = {0};
+	uint16_t vid;
+	int i;
+
+	if (ts_primary_vid == 0)
+		return;
+
+	for (i = 0; i < ts_num_vids; i++) {
+		vid = ts_all_vids[i];
+		warn("/lib/wifi/multiap ts create %u\n",vid);
+		Cmd(buf, sizeof(buf), "/lib/wifi/multiap ts create %u", vid);
+	}
+
+	warn("/lib/wifi/multiap ts reload\n");
+	Cmd(buf, sizeof(buf), "/lib/wifi/multiap ts reload");
+}
+
+static void ts_check_ifi(struct ifinfomsg *ifi, const char *ifname)
+{
+	struct ts_iface *tsif;
+
+
+	if (ts_primary_vid == 0)
+		return;
+
+/*
+	if (ifi->ifi_family == AF_BRIDGE)
+		return;
+*/
+
+	if (!(ifi->ifi_flags & IFF_UP))
+		return;
+
+	tsif = ts_find_iface(ifname);
+	if (tsif) {
+		ts_check_vlan_settings = true;
+		dbg("found %s tsif %p ifi_index %d\n", ifname, tsif, tsif->ifi_index);
+		return;
+	}
+
+	if (!strstr(ifname, "wds"))
+		return;
+
+	tsif = ts_configure_iface(ifname, 0);
+	if (tsif) {
+		tsif->ifi_index = ifi->ifi_index;
+		ts_check_vlan_settings = true;
+		dbg("added %s tsif %p ifi_index %d\n", ifname, tsif, tsif->ifi_index);
+	} else {
+		warn("Fail to add %s interface to ts array\n", ifname);
+	}
+}
 
 int if_updown(const char *ifname, bool up)
 {
@@ -63,9 +452,11 @@ int if_updown(const char *ifname, bool up)
 	return 0;
 }
 
-static int func(struct nl_msg *msg, void *arg)
+static int nl_main_cb(struct nl_msg *msg, void *arg)
 {
 	struct nlmsghdr *nlh = nlmsg_hdr(msg);
+	struct agent *a = (struct agent *) arg;
+	const char *bridge = a->cfg.al_bridge;
 
 	switch (nlh->nlmsg_type) {
 	case RTM_GETLINK:
@@ -74,41 +465,30 @@ static int func(struct nl_msg *msg, void *arg)
 		{
 			struct ifinfomsg *ifi;
 			char ifname[16] = {0};
-			struct agent *a = (struct agent *) arg;
-			char *bridge = a->cfg.al_bridge;
 			int ret;
 
 			ifi = NLMSG_DATA(nlh);
 
-			if_indextoname(ifi->ifi_index, ifname);
-
-			//printf("ifname = %s  ifindex = %d  status = %s  action = %s\n",
-			//       ifname,
-			//       ifi->ifi_index,
-			//       !!(ifi->ifi_flags & IFF_UP) ? "up" : "down",
-			//       nlh->nlmsg_type == RTM_GETLINK ? "RTM_GETLINK" :
-			//       nlh->nlmsg_type == RTM_NEWLINK ? "RTM_NEWLINK" :
-			//       "RTM_DELLINK");
-
-			//if (!(ifi->ifi_flags & IFF_UP))
-			//	break;
+			if (if_indextoname(ifi->ifi_index, ifname) == NULL)
+				break;
 
-			if (!strstr(ifname, "wds"))
+			fprintf(stderr, "ifname = %s  ifindex = %d family = %u status = %s  action = %s\n",
+			       ifname,
+			       ifi->ifi_index,
+			       ifi->ifi_family,
+			       !!(ifi->ifi_flags & IFF_UP) ? "up" : "down",
+			       nlh->nlmsg_type == RTM_GETLINK ? "RTM_GETLINK" :
+			       nlh->nlmsg_type == RTM_NEWLINK ? "RTM_NEWLINK" :
+			       "RTM_DELLINK");
+
+/*
+			if (!(ifi->ifi_flags & IFF_UP))
 				break;
+*/
+			ts_check_ifi(ifi, ifname);
 
-#if 0			// Not needed for now, maybe never?
-			// TODO: find a better place to do this
-			if (a->ts.active && !strstr(ifname, "vlan")) {
-				char buf[32] = { 0 };
-				snprintf(buf, 32, "%s_vlan", ifname);
-				if (if_isbridge_interface(buf) == -1){
-					// create tagged wds
-					runCmd("/lib/wifi/multiap ts create bh %s %d 2",
-					       ifname, a->cfg.pcfg->pvid );
-				}
+			if (!strstr(ifname, "wds"))
 				break;
-			}
-#endif
 
 			if (if_isbridge_interface(ifname)) {
 				int i, num, max = 32;
@@ -132,8 +512,7 @@ static int func(struct nl_msg *msg, void *arg)
 					break;
 			}
 
-			printf("Adding interface %s to bridge %s!\n", ifname,
-			       bridge);
+			printf("Adding interface %s to bridge %s!\n", ifname, bridge);
 
 			/* add wds iface to bridge */
 			ret = br_addif(bridge, ifname);
@@ -157,24 +536,181 @@ static int func(struct nl_msg *msg, void *arg)
 	return 0;
 }
 
+static inline bool is_vid_valid(unsigned int vid)
+{
+#if 0
+	dbg("%s: vid %u\n", __func__,  vid);
+
+	if (vid > TS_VID_INVALID)
+		abort();
+#endif
+	return (vid < TS_VID_INVALID) && (vid > 0);
+}
+
+static void ts_configure(struct agent *a)
+{
+	struct netif_fh *fh;
+	struct netif_bk *bk;
+	struct ts_iface *tsif;
+	uint16_t vid;
+	char buf[16];
+
+	/* TODO remove interfaces */
+
+	pthread_mutex_lock(&a->nl_mutex);
+
+	if (is_vid_valid(a->cfg.pcfg->pvid)) {
+		ts_primary_vid = a->cfg.pcfg->pvid;
+		snprintf(buf, sizeof(buf), "%u", ts_primary_vid);
+		setenv("PRIMARY_VID", buf, 1);
+	}
+
+	if (ts_primary_vid == 0)
+		goto out;
+
+	/* Fronthaul */
+	list_for_each_entry(fh, &a->fhlist, list) {
+		dbg("FH name %s multi_ap %d\n", fh->name, fh->cfg->multi_ap);
+		// TODO? Mixed FH/BH
+		if (fh->cfg->multi_ap != 2)
+			continue;
+
+		vid = fh->cfg->vid;
+		if (!is_vid_valid(vid))
+			vid = a->cfg.pcfg->pvid;
+
+		ts_configure_iface(fh->name, vid);
+	}
+
+	/* Backhaul stations */
+	list_for_each_entry(bk, &a->bklist, list) {
+		dbg("BK name %s\n", bk->name);
+
+		tsif = ts_configure_iface(bk->name, 0);
+		if (tsif)
+			tsif->is_bsta = true;
+	}
+
+out:
+	pthread_mutex_unlock(&a->nl_mutex);
+}
+
+int init_bridge_nl_sock(void)
+{
+	nl_bridge_sk = nl_socket_alloc();
+	if (!nl_bridge_sk)
+		return -1;
+
+	nl_bridge_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!nl_bridge_cb) {
+		nl_socket_free(nl_bridge_sk);
+		return -1;
+	}
+
+	nl_connect(nl_bridge_sk, NETLINK_ROUTE);
+	nl_socket_add_memberships(nl_bridge_sk, RTNLGRP_LINK, 0);
+
+	nl_cb_set(nl_bridge_cb, NL_CB_VALID, NL_CB_CUSTOM, ts_nl_get_cb, NULL);
+	nl_cb_set(nl_bridge_cb, NL_CB_FINISH, NL_CB_CUSTOM, ts_nl_finish_cb, NULL);
+	nl_cb_set(nl_bridge_cb, NL_CB_ACK, NL_CB_CUSTOM, ts_nl_finish_cb, NULL);
+	nl_cb_err(nl_bridge_cb, NL_CB_CUSTOM, ts_nl_error_cb, NULL);
+
+	return 0;
+}
+
+int init_main_nl_sock(struct agent *agent)
+{
+	nl_main_sk = nl_socket_alloc();
+	if (!nl_main_sk)
+		return -1;
+
+	nl_socket_disable_seq_check(nl_main_sk);
+	nl_socket_modify_cb(nl_main_sk, NL_CB_VALID, NL_CB_CUSTOM, nl_main_cb, agent);
+
+	nl_connect(nl_main_sk, NETLINK_ROUTE);
+	nl_socket_add_memberships(nl_main_sk, RTNLGRP_LINK, 0);
+	nl_rtgen_request(nl_main_sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
+
+	return 0;
+}
+
 int nl_loop(void *arg)
 {
-	struct nl_sock *sk;
+	struct agent *agent = arg;
+	char *bridge = agent->cfg.al_bridge;
+	struct pollfd fds[1];
+	int ret, i;
+
+	setenv("AL_BRIDGE", bridge, 1);
+
+	ret = init_bridge_nl_sock();
+	if (ret)
+		return -1;
+
+	ret = init_main_nl_sock(agent);
+	if (ret)
+		return -1;
+
+	fds[0].fd = nl_socket_get_fd(nl_main_sk);
+	fds[0].events = POLLIN;
+
+	for (;;) {
+		ts_check_vlan_settings = false;
+
+		dbg("Start polling ...\n");
+
+		ret = poll(fds, 1, -1);
+
+		dbg("End polling with %d ret %08x revents\n", ret , fds[0].revents);
+
+		if (fds[0].revents) {
+			ret = nl_recvmsgs_default(nl_main_sk);
+			fprintf(stderr, "nl_recvmsgs_default ret %d\n", ret);
+		}
+
+		if (ts_need_reconfig) {
+			ts_configure(agent);
+			ts_need_reconfig = false;
 
-	sk = nl_socket_alloc();
-	if (!sk)
-		return 1;
+			ts_set_system();
+		}
 
-	nl_socket_disable_seq_check(sk);
+		if (ts_check_vlan_settings) {
+			dbg("Reading bridge %s vlan config\n", bridge);
+			for (i = 0; i < TS_IFACE_MAX_NUM; i++) {
+				ts_iface_array[i].cur_vinfo[0].vid = 0;
+				ts_iface_array[i].ifi_index = 0;
+			}
+			ts_read_bridge_vlan(bridge);
+
+			for (i = 0; i < TS_IFACE_MAX_NUM; i++) {
+				struct ts_iface *tsif = &ts_iface_array[i];
+
+				if (tsif->name[0] == '\0')
+					break;
 
-	nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, func, arg);
+				dbg("checking vlan settings for %s tsif %p index %d\n",
+				    tsif->name, tsif, tsif->ifi_index);
 
-	nl_connect(sk, NETLINK_ROUTE);
-	nl_socket_add_memberships(sk, RTNLGRP_LINK, 0);
-	nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
+				/* Add to the bridge if not added already and if not backhaul sta,
+				 * bsta bridging is done by dynamically by other entities.
+				 */
+				if (ts_iface_array[i].ifi_index <= 0 && !tsif->is_bsta) {
+					ret = br_addif(bridge, tsif->name);
+					dbg("(re)added %s interface to %s with status %d\n",
+					    tsif->name, bridge, ret);
 
-	for (;;)
-		nl_recvmsgs_default(sk);
+					ts_iface_array[i].ifi_index = if_nametoindex(tsif->name);
+					dbg("get %s index %d\n", tsif->name, tsif->ifi_index);
+
+				}
+
+				if (ts_iface_array[i].ifi_index <= 0)
+					continue;
+				ts_set_iface_vlan(&ts_iface_array[i]);
+			}
+		}
+	}
 
 	return 0;
 }
diff --git a/src/nl.h b/src/nl.h
index 5815516dca58433d50de7f1513202fafb49ef384..c9b981ff2111a7328baf6dd17d9089a263882ba4 100644
--- a/src/nl.h
+++ b/src/nl.h
@@ -3,4 +3,6 @@
 
 int nl_loop(void);
 
+extern bool ts_need_reconfig;
+
 #endif /* MAPAGENT_NL_H */