diff --git a/docs/README-Traffic_Separation.md b/docs/README-Traffic_Separation.md
new file mode 100644
index 0000000000000000000000000000000000000000..13743426d3241d3086c71ec957ad21d84b804e2e
--- /dev/null
+++ b/docs/README-Traffic_Separation.md
@@ -0,0 +1,259 @@
+# Traffic Separation
+
+## Overview
+
+This README documents important aspects regarding application of the Traffic Separation feature in map-agent.
+
+## Design
+
+When Traffic Separation is in effect, traffic is to be isolated from eachother using different vlans.
+The functionality for this is specified in Multi-AP Spec 2.0 ch 19, which is the base for this implementation.
+The specification defines 3 differing kinds of interfaces towards the Multi-AP subsystem.
+- Fronthaul (FH) - used to connect a client STA
+- Backhaul (BH) - used to connect to another AP
+- Logical Ethernet Interface (LEI) - used to interface between the Multi-AP subsystem and the rest of the node (including CPU and ethernet)  
+
+### Multi-AP subsystem separation
+
+According to the specification the Multi-AP subsystem shall be a layer 2 device separate from the rest of the node features.
+To fulfill this, we separate all Multi-AP Traffic Separation features into a separate bridge, which contains the FH and BH interfaces as well as a LEI interface towards the rest of the node (represented by another bridge).
+
+```
+       No Traffic Separation                                   Traffic Separation
+                                                                                    ┌───┐  ┌───┐
+                                                                                 ┌──┤Tag├──┤FH │
+                                                                                 │  └───┘  └───┘
+          Agent/Controller                            bSTA                       │
+             ┌─────┐         ┌───┐                   ┌───┐  ┌───┐    ┌───────┐   │  ┌───┐  ┌───┐
+             │ CPU │    ┌────┤FH │                   │BH ├──┤Tag├────┤bridge ├───┼──┤Tag├──┤FH │
+             └──┬──┘    │    └───┘                   └───┘  └───┘    └───┬───┘   │  └───┘  └───┘
+ bSTA           │       │                                                │       │
+┌───┐       ┌───┴───┐   │    ┌───┐                                     ┌─┴─┐     │  ┌───┐  ┌───┐
+│BH ├───────┤bridge ├───┼────┤FH │                                     │Tag│     └──┤Tag├──┤BH │
+└───┘       └┬─────┬┘   │    └───┘                                     └─┬─┘        └───┘  └───┘
+             │     │    │                                                │                  bBSS
+           ┌─┴─┐ ┌─┴─┐  │    ┌───┐                                     ┌─┴─┐
+           │Eth│ │Eth│  └────┤BH │                                     │LEI│
+           └───┘ └───┘       └───┘                                     └─┬─┘
+                              bBSS                                       │       Agent/Controller
+                                                                     ┌───┴───┐      ┌─────┐
+                                                                     │bridge ├──────┤ CPU │
+                                                                     └┬─────┬┘      └─────┘
+                                                                      │     │
+                                                                    ┌─┴─┐ ┌─┴─┐
+                                                                    │Eth│ │Eth│
+                                                                    └───┘ └───┘
+```
+This setup is done in map-agent init script (**/etc/init.d/mapagent**), provided that the feature is enabled in Map Agent config.
+The LEI interface is implemented with a linux *veth* device pair.
+
+### Vlan tagging
+
+To apply vlan tagging the Broadcom vlanctl kernel module is used. This sets up tagging devices connected to the specified interfaces.
+These tagging devices apply filter rules and tagging actions similar to iptables/ebtables functionality.
+The "real" interfaces is enslaved to the tagging device, which in turn is enslaved to the bridge.
+
+## Implementation
+
+### Vlan tagging
+
+Vlan tagging is handled in a platform specific script (**/lib/wifi/multiap**) which is used to create tagging devices and apply tagging rules according to the specification.
+Some examples of use:
+```
+/lib/wifi/multiap ts create fh wl0 10			# create a tagging device for FH iface wl0 with vlan id 10
+/lib/wifi/multiap ts create bh wl2 1 2 			# create a tagging device for BH iface wl2 with vlan 1 and profile 2
+/lib/wifi/multiap ts create eth lei 1 3	br-map br-lan	# create a tagging device for LEI iface lei with vlan 1, default pcp 3, Multi-AP bridge "br-map" and local bridge "br-lan"
+/lib/wifi/multiap ts populate eth lei 10		# apply LEI specific rules for Secondary Network with vlan id 10 on iface lei
+/lib/wifi/multiap ts delete wl0				# remove tagging device for iface wl0
+```
+
+### Map Agent
+
+In order for a Map Agent to apply vlan tagging on the *Primary Network*, it must receive a **Default 802.1Q Settings TLV** containing the Primary Vlan ID.
+This can be received in any of three ways:
+- in a **AP-Autoconfiguration WSC** message
+- in a **Multi-AP Policy Config Request** message
+- as a Multi-AP IE subelement in **(Re-)Association Response** frames
+
+To apply tagging on *Secondary Networks*, it must receive a **Traffic Separation Policy TLV** containing at least one SSID to Vlan ID mapping.
+This can be received in either of:
+- a **AP-Autoconfiguration WSC** message
+- a **Multi-AP Policy Config Request** message
+
+If the Traffic Separation feature is enabled in the Map Agent, it will monitor these trigger conditions and apply the tagging rules using the script when any of the trigger conditions is fulfilled.
+
+## Configuration
+
+### Map Agent
+
+To enable the Traffic Separation feature:
+```
+config agent 'agent'
+	...
+	option vlan_segregation '1'
+```
+After Map Agent is restarted, the Traffic Separation setup will be done (and the *al_bridge* option will have been updated).
+NOTE: This needs to be set on each Map Agent separately.
+
+### Map Controller
+
+The configuration governing the Traffic Separation (vlan tag numbering) comes from the Map Controller.
+
+Primary Vlan ID and Default PCP value is currently set per agent:
+```
+config agent-policy
+        option agent_id 'ee:6c:9a:79:fc:4e'
+        option band '5'
+        option pvid '1'
+        option pcp_default '2'
+```
+Each bss specifies which Vlan ID it belongs to:
+```
+config bss
+        option band '5'
+        option ssid 'MAP-EC6C9A79FC4E-5GHz'
+        option encryption 'sae-mixed'
+        option vlan '1'
+        option multi_ap '2'
+        option key 'FPaY-7teN-hTHa-pgdT'
+
+config bss
+        option band '2'
+        option ssid 'MAP-EC6C9A79FC4E-2.4GHz'
+        option encryption 'sae-mixed'
+        option vlan '1'
+        option multi_ap '2'
+        option key 'FPaY-7teN-hTHa-pgdT'
+
+config bss
+        option band '5'
+        option ssid 'My-Guest-Network'
+        option encryption 'sae-mixed'
+        option vlan '10'
+        option multi_ap '2'
+        option key 'FPaY-7teN-hTHa-pgdT'
+
+config bss
+        option band '5'
+        option ssid 'Another-Guest-Network'
+        option encryption 'sae-mixed'
+        option vlan '20'
+        option multi_ap '2'
+        option key 'FPaY-7teN-hTHa-pgdT'
+```
+Each Vlan needs to be separately declared in its own section:
+```
+config vlan 'lan'
+        option network 'lan'
+        option id '1'
+
+config vlan 'guest'
+        option network 'lan'
+        option id '10'
+
+config vlan
+        option network 'lan'
+        option id '20'
+```
+*Note: This part is likely to be removed*
+
+### ieee1905d
+
+The ieee1905d config specifies which bridge ieee1905 packets are expected to be received on. This should point to the CPU bridge, which is the default (br-lan).
+
+### Bridge <-> wl MAC conflict
+
+If no wl base MAC is specified in nvram parameters, bridge and wl macs will end up in conflict in the multi-bridge environment.
+This can be mitigated by setting a wl MAC base in */data/.kernel_nvram.setting* that will not conflict with any bridge MAC.
+An example:
+```
+root@iopsys:~# grep -i mac /data/.kernel_nvram.setting
+1:macaddr=ec:6c:9a:79:fc:60
+2:macaddr=ec:6c:9a:79:fc:70
+root@iopsys:~# ip l sh br-lan
+21: br-lan: <BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
+    link/ether ec:6c:9a:79:fc:4f brd ff:ff:ff:ff:ff:ff
+```
+
+## Other issues worth noting
+
+### ebtables
+
+In the dual bridge setup, ieee1905 packets are expected to be forwarded to the local bridge. This requires an ACCEPT rule in ebtables. In order for ieee1905d service to pick up the packets, it requires a DROP rule in ebtables.
+These rules are set up by ieee1905d and mapagent automatically.
+
+### EAPOL and the ASSOC-IE
+
+hostapd manages the BSS side of a wifi connection and wpa_supplicant manages the STA side of a wifi connection.
+For a STA to connect to a BSS a 4-way handshake needs to take place. This is achieved using EAPOL traffic between wpa_supplicant and hostapd.
+According to specification, EAPOL traffic over a backhaul is to be tagged with the primary Vlan ID when Traffic Separation is in effect.
+To avoid the need to modify these services to use tag devices for rx/tx, Broadcom wifi driver has included a feature to enable tagging of EAPOL in driver.
+To use this feature one needs to set the bBSS and bSTA interfaces to Profile 2 and set a Primary Vlan ID on the bBSS.
+This will trigger wifi driver to tag EAPOL using PVID, and also make PVID available from the driver on the bSTA side.
+
+For any BH iface we can then do:
+```
+wl vlan_mode 0 &> /dev/null                             # make sure this is OFF, else driver won't handle vlan
+wl -i $iface down &> /dev/null
+wl -i $iface map_profile $profile &> /dev/null          # only has effect on profile 2
+wl -i $iface map_8021q_settings $vid &> /dev/null       # can only be set on bBSS (read-only on bSTA)
+wl -i $iface up &> /dev/null
+
+```
+This is also used to enable tagging on a repeater connecting to a AP that already has tagging enabled as it can fetch the PVID from the driver after association.
+
+#### Simplified Backhaul
+
+Since the tagging of EAPOL is handled by the driver, and since we currently only support Profile 2 BH, we may simplify our solution by removing the tagging devices from the BH devices (since this is in effect a no-op).
+
+### Secondary networks
+
+The specification makes clear that Secondary traffic going out on the Logical Ethernet Interface should retain its tag, while Primary traffic is to be untagged.
+The specification also makes clear that traffic originating from outside the Multi-AP network is to be tagged or untagged prior to entering the Multi-AP network.
+The implementation of this is left outside of the scope of the specification.
+The implication is that any services that are to be made available to Secondary networks, (such as DHCP etc), are to be tagged prior to entering the Multi-AP network.
+Also, any traffic between a Secondary network and WAN will need to be tagged/untagged outside of the scope of the Multi-AP network.
+
+#### DHCP
+
+To provide DHCP service on secondary networks, we create **sink** devices (in practice, a bridge) connected to the lan bridge for each Secondary network. These will do untagging of Secondary VIDs for the benefit of the DHCP service running on the **sink** device. The return traffic is then re-tagged with the Secondary VID and forwarded back to the Multi-AP network.
+
+```
+                                            ┌───┐  ┌───┐
+                                         ┌──┤Tag├──┤FH │
+                                         │  └───┘  └───┘
+              bSTA                       │
+             ┌───┐  ┌───┐    ┌───────┐   │  ┌───┐  ┌───┐
+             │BH ├──┤Tag├────┤bridge ├───┼──┤Tag├──┤FH │
+             └───┘  └───┘    └───┬───┘   │  └───┘  └───┘
+                                 │       │
+                               ┌─┴─┐     │  ┌───┐  ┌───┐
+                               │Tag│     └──┤Tag├──┤BH │
+                               └─┬─┘        └───┘  └───┘
+                                 │                  bBSS
+                               ┌─┴─┐
+            DHCP               │LEI│
+          ┌──────┐  ┌───┐      └─┬─┘
+          │ sink ├──┤Tag├─┐      │       Agent/Controller
+          └──────┘  └───┘ │  ┌───┴───┐      ┌─────┐
+                          ├──┤bridge ├──────┤ CPU │
+          ┌──────┐  ┌───┐ │  └┬─────┬┘      └─────┘
+          │ sink ├──┤Tag├─┘   │     │
+          └──────┘  └───┘   ┌─┴─┐ ┌─┴─┐
+                            │Eth│ │Eth│
+                            └───┘ └───┘
+```
+
+#### WAN
+
+The above **sink** device can also be used to access WAN via NAT. If this interface is added to the *lan* zone of the firewall rules, it will get NATed just like *lan* traffic.
+```
+config zone
+        option name 'lan'
+        list network 'lan'
+        list network 'sink'
+        option input 'ACCEPT'
+        option output 'ACCEPT'
+        option forward 'ACCEPT'
+```
+This is added automatically when Secondary networks are getting set up.
diff --git a/src/agent.c b/src/agent.c
index 9c34e37f7ccd91c4f953611cce06036b31073cc2..0542183be81c68d1fbcc91780314fa697889fbbd 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -2378,6 +2378,11 @@ static void wifi_radio_event_handler(void *c, struct blob_attr *msg)
 			clear_fhlist(agent);
 			/* completely re-init data */
 			agent_init_interfaces(agent);
+			if (agent->cfg.ts_enabled && agent->ts.requested)
+				agent_apply_traffic_separation(agent);
+		} else if (!strcmp(event, "ap-disabled")) {
+			if (agent->cfg.ts_enabled && agent->ts.active)
+				agent_disable_traffic_separation(agent);
 		}
 	}
 
@@ -2482,6 +2487,31 @@ static void agent_detect_loop(struct agent *a, int secs)
 }
 #endif
 
+/* 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)
+{
+	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 (!(a->cfg.pcfg)) {
+			a->cfg.pcfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg));
+			if (!(a->cfg.pcfg)) {
+				err("%s:%d - memory allocation failed\n",
+				    __func__, __LINE__);
+				return;
+			}
+		}
+		a->cfg.pcfg->pvid = atoi(buf);
+		a->ts.requested = 1;
+		agent_apply_traffic_separation(a);
+	}
+}
+
 static bool is_bsta_global_disable(void)
 {
 	return !access("/tmp/map.agent.bsta_global_disable", F_OK);
@@ -2862,6 +2892,8 @@ static void wifi_bsta_event_handler(void *agent, struct blob_attr *msg)
 		strncpy(bssid_str, blobmsg_data(data[0]),
 				sizeof(bssid_str) - 1);
 
+		agent_check_ts(a, bk, bk->name);
+
 		hwaddr_aton(bssid_str, bssid);
 
 		wifi_bsta_connect(a, bk, bssid);
@@ -2883,21 +2915,23 @@ 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};
-	struct blob_attr *tb[4];
+	uint16_t vlan = 0;
+	struct blob_attr *tb[5];
 	struct wifi_radio_element *radio;
 	struct agent *a = (struct agent *) c;
-	static const struct blobmsg_policy ap_attr[4] = {
+	static const struct blobmsg_policy ap_attr[5] = {
 		[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
 		[1] = { .name = "encryption", .type = BLOBMSG_TYPE_STRING },
 		[2] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING },
 		[3] = { .name = "key", .type = BLOBMSG_TYPE_STRING },
+		[4] = { .name = "vlan_id", .type = BLOBMSG_TYPE_INT32 },
 	};
 	int ret;
 	struct netif_bk *bk, *p;
 	int timeout = 0;
 	char seconds_str[64] = {0};
 
-	blobmsg_parse(ap_attr, 4, tb, blob_data(msg), blob_len(msg));
+	blobmsg_parse(ap_attr, 5, tb, blob_data(msg), blob_len(msg));
 
 	if (!tb[0] || !tb[1] || !tb[2] || !tb[3])
 		return;
@@ -2906,6 +2940,8 @@ 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)
@@ -2939,6 +2975,12 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 			radio->name, "onboarded", "1");
 
 	uloop_timeout_set(&a->onboarding_scheduler, timeout * 1000);
+
+	if (vlan && bk->agent && bk->agent->cfg.ts_enabled) {
+		bk->agent->cfg.pcfg->pvid = vlan;
+		bk->agent->ts.requested = 1;
+		agent_apply_traffic_separation(bk->agent);
+	}
 }
 
 static void agent_event_handler(struct ubus_context *ctx,
@@ -3425,16 +3467,17 @@ static int run_agent(struct agent *a)
 }
 #endif
 
-static void parse_almac(struct ubus_request *req, int type,
+static void parse_i1905_info(struct ubus_request *req, int type,
 		struct blob_attr *msg)
 {
 	struct agent *a = (struct agent *)req->priv;
-	struct blob_attr *tb[1];
-	static const struct blobmsg_policy ieee_attrs[1] = {
+	struct blob_attr *tb[2];
+	static const struct blobmsg_policy ieee_attrs[2] = {
 		[0] = { .name = "ieee1905id", .type = BLOBMSG_TYPE_STRING },
+		[1] = { .name = "interface", .type = BLOBMSG_TYPE_ARRAY }
 	};
 
-	blobmsg_parse(ieee_attrs, 1, tb, blob_data(msg), blob_len(msg));
+	blobmsg_parse(ieee_attrs, 2, tb, blob_data(msg), blob_len(msg));
 
 	if (tb[0]) {
 		char *mac;
@@ -3443,6 +3486,36 @@ static void parse_almac(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 parse_radio(struct ubus_request *req, int type,
@@ -4272,7 +4345,7 @@ int agent_init_interfaces(struct agent *a)
 	if (ret)
 		return -1;
 
-	ubus_call_object(a, ieee1905_obj, "info", parse_almac, a);
+	ubus_call_object(a, ieee1905_obj, "info", parse_i1905_info, a);
 
 	wifi_obj = ubus_get_object(a->ubus_ctx, "wifi");
 	if (wifi_obj != WIFI_OBJECT_INVALID) {
@@ -4334,6 +4407,7 @@ 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;
 			list_add(&fn->list, &a->fhlist);
 
 			ubus_call_object(a, wobj, "status", parse_ap, fn);
@@ -4382,8 +4456,17 @@ int agent_init_interfaces(struct agent *a)
 		bn = find_bkhaul_by_ifname(a, b->name);
 		if (!bn) {
 			bn = netif_alloc_bk(b->name);
-			if (bn)
+			if (bn) {
+
+				if (a->cfg.ts_enabled) {
+					char fmt[64] = {0};
+
+					snprintf(fmt, sizeof(fmt), "ts create bh %s 1 2", b->name);
+					dbg("%s %d fmt = %s\n", __func__, __LINE__, fmt);
+					agent_exec_platform_scripts(fmt);
+				}
 				list_add(&bn->list, &a->bklist);
+			}
 		}
 
 		if (bn) {
@@ -4391,6 +4474,7 @@ 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);
 		}
@@ -4429,14 +4513,20 @@ static void agent_periodic_run(struct uloop_timeout *t)
 	}
 }
 
+#define RELOAD_TIMEOUT 10
+
 static void agent_reload_wireless(struct uloop_timeout *t)
 {
+	trace("%s: --->\n", __func__);
 	struct agent *a = container_of(t, struct agent, reload_scheduler);
 
-	UNUSED(a);
-
 	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
@@ -4886,8 +4976,7 @@ int start_agent(void)
 		int ret;
 
 		/* TODO: memory management of thread on cleaup */
-		ret = pthread_create(&(tid[0]), NULL, (void *)&nl_loop,
-				w->cfg.al_bridge);
+		ret = pthread_create(&(tid[0]), NULL, (void *)&nl_loop, w);
 		if (ret) {
 			fprintf(stderr, "Failed to create thread\n");
 			return -1;
@@ -4928,6 +5017,10 @@ int start_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: */
diff --git a/src/agent.h b/src/agent.h
index 78fcfbaa50996d4ab71ffc1a1f2102c6e52c43f9..9bd2ac8b4b67ab49a7feffa88049091f025f725c 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -184,6 +184,8 @@ struct wifi_caps_element {
 	struct wifi_mcs mcs;
 };
 
+#define TS_VID_INVALID 0x0FFF
+
 /* fronthaul wifi (ap) interface */
 struct netif_fh {
 	char name[16];
@@ -225,6 +227,9 @@ struct netif_fh {
 
 	/* previous channel utilization threshold value */
 	uint8_t prev_util;
+
+	/* traffic separation */
+	unsigned int vid;
 };
 
 /* backhaul wifi (sta) interface */
@@ -250,6 +255,9 @@ struct netif_bk {
 		struct cmdu_buff *cmdu;
 	} bsta_steer;
 	struct uloop_timeout connect_timer;
+
+	/* traffic separation */
+	unsigned int vid;
 };
 
 #if 0
@@ -547,6 +555,14 @@ struct agent {
 
 	/* STA Metrics Reporting RCPI Threshold timer */
 	struct uloop_timeout rcpi_threshold_timer;
+
+	/* 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;
 };
 
 struct netif_bk *find_bkhaul_by_bssid(struct agent *a, uint8_t *bssid);
diff --git a/src/agent_map.c b/src/agent_map.c
index ca3155a9b34d80d1ea3448320533dd58c517013d..82d5f6edee5ec56d0bad35019f0df3663e91384f 100644
--- a/src/agent_map.c
+++ b/src/agent_map.c
@@ -598,6 +598,14 @@ 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 ACS 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)) {
@@ -1092,7 +1100,230 @@ void agent_autoconfig_event(struct agent *a, char *radio, char *status,
 
 }
 
+/* TODO: vlan bridge and logical ethernet interface names hardcoded for now */
+#define VLAN_BRIDGE "map"
+#define VLAN_IFACE  "lei"
+#if 0	// handled by init script now
+/* Set up Multi-AP subsystem separation */
+int agent_prepare_traffic_separation(struct agent *a)
+{
+	trace("%s: --->\n", __func__);
+	struct netif_fh *fh;
+	struct netif_bk *bk;
+
+	a->ts.setup = true;
+
+	/* TODO: streamline for efficiency */
+
+	if (uci_set_bridge("network", VLAN_BRIDGE, "static", NULL)) {
+		info("Error seting up bridge for Traffic Separation!\n");
+		return -1;
+	}
+	dbg("|%s:%d| bridge \"%s\" added => reloading network config\n",
+	    __func__, __LINE__, VLAN_BRIDGE);
+
+	list_for_each_entry(fh, &a->fhlist, list) {
+		uci_set_wireless_interface_option("wireless", "wifi-iface",
+						  "ifname", fh->name,
+						  "network", VLAN_BRIDGE);
+	}
+	list_for_each_entry(bk, &a->bklist, list) {
+		uci_set_wireless_interface_option("wireless", "wifi-iface",
+						  "ifname", bk->name,
+						  "network", VLAN_BRIDGE);
+	}
+	dbg("|%s:%d| wifi interfaces moved to bridge \"%s\" => reloading wireless config\n",
+	    __func__, __LINE__, VLAN_BRIDGE);
+
+	uci_reload_services("network");
+
+	return 0;
+}
+#endif
+
+/* Set up Traffic Separation rules */
+int agent_apply_traffic_separation(struct agent *a)
+{
+	trace("%s: --->\n", __func__);
+	struct agent_config *cfg = &a->cfg;
+	struct policy_cfg *c = cfg->pcfg;
+	struct netif_fh *fh;
+	struct netif_bk *bk;
+	char cmd[64] = {0};
+
+	if (!a || !cfg || !c) {
+		err("%s:%d - missing configuration!\n", __func__, __LINE__);
+		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;
+
+			if (fh->vid != TS_VID_INVALID) {
+				/* 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",
+				 fh->name, new_vid);
+			agent_exec_platform_scripts(cmd);
+
+			snprintf(cmd, sizeof(cmd), "ts create dhcp %u", new_vid);
+			agent_exec_platform_scripts(cmd);
+			fh->vid = new_vid;
+			trace("%s: applying TS for FH BSS: %s\n", __func__, cmd);
+		} 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;
+
+		if (bk->vid != TS_VID_INVALID) {
+			/* 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",
+			 bk->name, c->pvid, "2");
+//			 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;
+
+			if (fh->vid != TS_VID_INVALID) {
+				/* 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
+		}
+	}
+
+	/* Logical Ethernet Interface */
+	/* Note: setup of LEI is already handled by init script */
+	snprintf(cmd, sizeof(cmd), "ts create eth %s %u %u %s %s",
+		 VLAN_IFACE, c->pvid, c->pcp_default, cfg->al_bridge, "br-lan");
+	agent_exec_platform_scripts(cmd);
+
+	list_for_each_entry(fh, &cfg->fhlist, list) {
+		if (fh->vid) {
+			/* secondary networks */
+			snprintf(cmd, sizeof(cmd), "ts populate eth %s %u",
+				 VLAN_IFACE, fh->vid);
+			agent_exec_platform_scripts(cmd);
+		}
+	}
+
+	a->ts.active = true;
+
+#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;
+	struct netif_bk *bk;
+	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 (fh->vid != TS_VID_INVALID) {
+			snprintf(cmd, sizeof(cmd), "ts delete %s", fh->name);
+			agent_exec_platform_scripts(cmd);
+			fh->vid = TS_VID_INVALID;
+		}
+	}
+
+	/* Backhaul */
+	list_for_each_entry(bk, &a->bklist, list) {
+		if (bk->vid != TS_VID_INVALID) {
+			snprintf(cmd, sizeof(cmd), "ts delete %s", bk->name);
+			agent_exec_platform_scripts(cmd);
+			bk->vid = TS_VID_INVALID;
+		}
+	}
+
+	/* Ethernet */
+	snprintf(cmd, sizeof(cmd), "ts delete %s", VLAN_IFACE);
+	agent_exec_platform_scripts(cmd);
+
+	a->ts.active = false;
+
+	return 0;
+}
+
 #define RELOAD_TIMEOUT 5
+
 int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
 {
 	struct agent *a = (struct agent *) agent;
@@ -1105,11 +1336,10 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
 	uint8_t bssid[6];
 	//struct tlv *tlv = NULL;
 	struct wifi_radio_element *radio;
-	//struct tlv_traffic_sep_policy *traffic_sep;
+
 	struct tlv *tv[4][16] = {0};
 	int ret = 0, num = 0;
 
-
 	trace("%s: --->\n", __func__);
 
 	if (memcmp(rx_cmdu->origin, a->cntlr_almac, 6)) {
@@ -1119,11 +1349,18 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
 	}
 
 
+
 	ret = cmdu_parse_tlvs(rx_cmdu, tv, a_policy, 4);
 
-	if (!tv[0][0] || !tv[1][0] || !tv[2][0] || !tv[3][0])
+	if (!tv[2][0] || !tv[3][0])
 		return -1;
 
+	if (tv[0][0]) {
+		struct tlv_default_8021q_settings *tlv = tv[0][0]->data;
+		//uci_apply_default_8021q_settings(tlv);
+		agent_fill_8021q_setting(a, tlv);
+	}
+
 	memcpy(bssid, tv[2][0]->data, 6);
 
 	radio = wifi_get_radio_by_mac(a, bssid);
@@ -1229,7 +1466,28 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
 		num++;
 	}
 
-	uci_apply_traffic_sep((struct tlv_traffic_sep_policy *)tv[1][0]->data);
+	if (tv[1][0]) {
+		//uci_clear_traffic_sep(&a->cfg);
+		//uci_apply_traffic_sep((struct tlv_traffic_sep_policy *)tv[1][0]->data);
+	}
+	if (tv[1][0]) {
+		struct tlv_traffic_sep_policy *tlv = 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);
+	}
+
 	dbg("|%s:%d| radio (%s) was configured! Apply heartbeat for this radio\n",
 				__func__, __LINE__, radio->name);
 	agent_exec_platform_scripts("write_credentials");
@@ -1237,6 +1495,8 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
 	agent_link_ap_to_cfg(a);
 	radio->state = ACS_HEARTBEAT;
 	agent_autoconfig_event(a, radio->name, "success", "completed");
+
+	//uci_apply_wps_credentials(&a->cfg, radio->band);
 teardown:
 	// TODO: freeing from here risks freeing an updated frame
 	agent_free_wsc_data(&radio->autconfig);
@@ -1717,14 +1977,26 @@ int handle_map_policy_config(void *agent, struct cmdu_buff *cmdu)
 		struct tlv_default_8021q_settings *p =
 			(struct tlv_default_8021q_settings *)tv[2][0]->data;
 
-		agent_fill_8021q_setting(a, p, ctx, pkg);
+		agent_fill_8021q_setting(a, p);
 	}
 
 	if (tv[3][0]) {
 		struct tlv_traffic_sep_policy *p =
 			(struct tlv_traffic_sep_policy *)tv[3][0]->data;
 
-		agent_fill_traffic_sep_policy(a, p, ctx, pkg);
+		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);
 	}
 
 	if (tv[4][0]) {
@@ -1763,6 +2035,11 @@ 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);
+
 	return 0;
 }
 
diff --git a/src/agent_map.h b/src/agent_map.h
index 650bf44315f87423d4e8652f058de9fe23fb1620..e4094935e512ae891434b536afc8a20ac1637aab 100644
--- a/src/agent_map.h
+++ b/src/agent_map.h
@@ -33,4 +33,8 @@ int send_beacon_metrics_response(void *agent, uint8_t *sta_addr,
 int send_sta_steer_complete(void *agent, uint8_t *origin, const char *intf_name);
 uint16_t agent_send_cmdu_unish(struct agent *a, struct cmdu_buff *cmdu);
 
+//int agent_prepare_traffic_separation(struct agent *a);
+int agent_apply_traffic_separation(struct agent *a);
+int agent_disable_traffic_separation(struct agent *a);
+
 #endif /* AGENT_MAP_H */
diff --git a/src/agent_tlv.c b/src/agent_tlv.c
index 0012405da9512e6e504456866f80b71b48075e26..090365008c01ec71e4321ac92fb4646a53b3132a 100644
--- a/src/agent_tlv.c
+++ b/src/agent_tlv.c
@@ -2190,8 +2190,7 @@ int agent_fill_metric_report_policy(struct agent *a,
 }
 
 int agent_fill_8021q_setting(struct agent *a,
-		struct tlv_default_8021q_settings *p, struct uci_context *ctx,
-		struct uci_package *pkg)
+		struct tlv_default_8021q_settings *p)
 {
 	int ret;
 	struct uci_element *e;
@@ -2199,6 +2198,17 @@ int agent_fill_8021q_setting(struct agent *a,
 	char buf[64] = {0};
 	struct uci_section *s;
 	bool is_section_found = false;
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return -1;
+
+	if (uci_load(ctx, "mapagent", &pkg)) {
+		uci_free_context(ctx);
+		return -1;
+	}
 
 	uci_foreach_element(&pkg->sections, e) {
 		s = uci_to_section(e);
@@ -2240,12 +2250,13 @@ int agent_fill_8021q_setting(struct agent *a,
 	uci_set(ctx, &ptr);
 	uci_save(ctx, ptr.p);
 
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
 	return 0;
 }
 
 int agent_fill_traffic_sep_policy(struct agent *a,
-		struct tlv_traffic_sep_policy *p, struct uci_context *ctx,
-		struct uci_package *pkg)
+		struct tlv_traffic_sep_policy *p)
 {
 	int ret, i;
 	int offset = 0;
@@ -2254,6 +2265,17 @@ int agent_fill_traffic_sep_policy(struct agent *a,
 	struct uci_element *e;
 	struct uci_ptr ptr;
 	char buf[64];
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return -1;
+
+	if (uci_load(ctx, "mapagent", &pkg)) {
+		uci_free_context(ctx);
+		return -1;
+	}
 
 	num_ssid = data[offset++];
 	for (i = 0; i < num_ssid; i++) {
@@ -2305,6 +2327,8 @@ int agent_fill_traffic_sep_policy(struct agent *a,
 		}
 	}
 
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
 	return 0;
 }
 
diff --git a/src/agent_tlv.h b/src/agent_tlv.h
index 4d1c90916efd5d1875cc4d0c0987f320e803979e..3647eebf935bc0073555589970a5d21076d64e47 100644
--- a/src/agent_tlv.h
+++ b/src/agent_tlv.h
@@ -158,11 +158,9 @@ int agent_fill_metric_report_policy(struct agent *a,
 		struct tlv_metric_report_policy *p,
 		struct uci_context *ctx, struct uci_package *pkg);
 int agent_fill_8021q_setting(struct agent *a,
-		struct tlv_default_8021q_settings *p,
-		struct uci_context *ctx, struct uci_package *pkg);
+		struct tlv_default_8021q_settings *p);
 int agent_fill_traffic_sep_policy(struct agent *a,
-		struct tlv_traffic_sep_policy *p,
-		struct uci_context *ctx, struct uci_package *pkg);
+		struct tlv_traffic_sep_policy *p);
 int agent_fill_ch_scan_rep_policy(struct agent *a,
 		struct tlv_channel_scan_report_policy *p,
 		struct uci_context *ctx, struct uci_package *pkg);
diff --git a/src/config.c b/src/config.c
index 97bdc1d74e56d4dc739aef9151172deda76b60f8..b151f4c14bc51ead2e4dca446ed508dabd3d8eb8 100644
--- a/src/config.c
+++ b/src/config.c
@@ -67,6 +67,7 @@
 #define UCI_WIRELESS "wireless"
 #define UCI_IEEE1905 "ieee1905"
 #define UCI_AGENT "mapagent"
+#define UCI_POLICY "policy"
 
 char *replace_char(char *str, char find, char replace)
 {
@@ -842,6 +843,105 @@ int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band)
 }
 #endif
 
+/* duplicate implementation
+ * use
+ * agent_fill_8021q_setting
+ * and
+ * agent_fill_traffic_sep_policy
+ */
+#if 0
+int uci_apply_default_8021q_settings(struct tlv_default_8021q_settings *tlv)
+{
+	struct uci_context *ctx = NULL;
+	struct uci_package *pkg;
+	struct uci_element *e;
+	struct uci_section *section = NULL;
+	int rv;
+	char buf[16] = {0};
+
+	pkg = uci_load_pkg(&ctx, UCI_AGENT);
+	if (!pkg)
+		return -1;
+
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_section *s = uci_to_section(e);
+		if (strcmp(s->type, UCI_POLICY))
+			continue;
+
+		/* There is only one policy section */
+		section = s;
+		break;
+	}
+	if (!section) {
+		rv = uci_add_section(ctx, pkg, UCI_POLICY, &section);
+		if (rv)
+			goto out_pkg;
+	}
+
+	dbg("Applying Default 802.1Q Settings:\n");
+	dbg("  - VID             : %u\n", tlv->pvid);
+	dbg("  - PCP             : %u\n", tlv->pcp);
+
+	snprintf(buf, sizeof(buf), "%u", tlv->pvid);
+	set_value(ctx, pkg, section, "pvid", buf, UCI_TYPE_STRING);
+	snprintf(buf, sizeof(buf), "%u", tlv->pcp);
+	set_value(ctx, pkg, section, "pcp_default", buf, UCI_TYPE_STRING);
+
+	rv = uci_save(ctx, pkg);
+	if (rv)
+		goto out_pkg;
+
+	uci_commit(ctx, &pkg, false);
+out_pkg:
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
+	return 0;
+}
+
+int uci_clear_traffic_sep(struct agent_config *cfg)
+{
+	struct uci_context *ctx = NULL;
+	struct uci_package *pkg;
+	struct uci_element *e;
+	struct uci_section *section = NULL;
+	struct uci_option *option = NULL;
+	struct uci_ptr ptr = {0};
+	struct netif_fhcfg *fh;
+
+	/* TODO: do we need this considering wifi_teardown_map_ifaces_by_radio? */
+	dbg("Clearing previous TS VIDs\n");
+
+	/* remove from cfg */
+	list_for_each_entry(fh, &cfg->fhlist, list) {
+		fh->vid = 0;	/* Note: 0 is reserved for FH */
+	}
+
+	/* remove from uci */
+	pkg = uci_load_pkg(&ctx, UCI_AGENT);
+	if (!pkg)
+		return -1;
+
+	uci_foreach_element(&pkg->sections, e) {
+		section = uci_to_section(e);
+		if (strcmp(section->type, UCI_FH_AGENT))
+			continue;
+
+		option = uci_lookup_option(ctx, section, "vid");
+
+		if (option) {
+			ptr.p = pkg;
+			ptr.s = section;
+			ptr.option = option;
+
+			uci_delete(ctx, &ptr);
+		}
+	}
+
+	uci_commit(ctx, &pkg, false);
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
+	return 0;
+}
 
 /*
  * Will only be successful if uci_apply_m2 is done prior, or interfaces already
@@ -853,6 +953,9 @@ void uci_apply_traffic_sep(struct tlv_traffic_sep_policy *tlv)
 	uint8_t *ptr;
 
 	ptr = (uint8_t *)tlv;
+
+	/* TODO: error handling - valid vid range is 0x0003->0x0FFE */
+
 	ptr++;
 	for (i = 0; i < tlv->num_ssid; i++) {
 		char ssid[33] = {0};
@@ -871,6 +974,7 @@ void uci_apply_traffic_sep(struct tlv_traffic_sep_policy *tlv)
 				"ssid",	ssid, "vid", vid);
 	}
 }
+#endif
 
 /* TODO: batch the changes arther than commit oneby one */
 int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
@@ -886,7 +990,10 @@ int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
 	int mfp = 0;
 	/* step past br- prefix if present*/
 
+	bridge = cfg->al_bridge;
+#if 0
 	bridge = bridge_buf;
+#endif
 	if (!strncmp("br-", bridge, 3))
 		bridge += 3;
 
@@ -900,7 +1007,9 @@ int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
 
 	memcpy(ssid, out->ssid, out->ssidlen);
 	memcpy(network_key, out->key, out->keylen);
+#if 0
 	memcpy(bridge, exts->bridge, 15);
+#endif
 
 	inet_ntop(AF_INET, &exts->br_ip, ipaddr_str, INET_ADDRSTRLEN);
 
@@ -933,12 +1042,13 @@ int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
 		info("Unsupported encryption or cipher received!!\n");
 		return M2_PROCESS_ERROR;
 	}
-
+#if 0
 	ret = uci_set_bridge("network", bridge, exts->proto, ipaddr_str);
 	if (ret) {
 		info("Error seting up bridge from M2!\n");
 		return M2_PROCESS_ERROR;
 	}
+#endif
 
 	// Set uci in agent
 	ret = uci_check_wifi_iface(UCI_AGENT, interface_name,
@@ -1523,6 +1633,7 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 		A_NETDEV,
 		A_RCPI_THRESHOLD,
 		A_REPORT_RCPI_THRESHOLD,
+		A_TS,
 		NUM_POLICIES
 	};
 	const struct uci_parse_option opts[] = {
@@ -1538,6 +1649,7 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 		{ .name = "netdev", .type = UCI_TYPE_STRING },
 		{ .name = "rcpi_threshold", .type = UCI_TYPE_STRING },
 		{ .name = "report_rcpi_threshold", .type = UCI_TYPE_STRING },
+		{ .name = "vlan_segregation", .type = UCI_TYPE_STRING },
 	};
 	struct uci_option *tb[NUM_POLICIES];
 
@@ -1613,6 +1725,9 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 	else
 		a->report_rcpi_threshold = 130;
 
+	if (tb[A_TS])
+		a->ts_enabled = atoi(tb[A_TS]->v.string);
+
 	return 0;
 }
 
@@ -1874,6 +1989,7 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		FH_INCLUDE_STA_STATS,
 		FH_INCLUDE_STA_METRIC,
 		FH_ENABLED,
+		FH_VID,
 		FH_MULTI_AP,
 		NUM_POLICIES,
 	};
@@ -1899,6 +2015,7 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		{ .name = "include_sta_stats", .type = UCI_TYPE_STRING },
 		{ .name = "include_sta_metric", .type = UCI_TYPE_STRING },
 		{ .name = "enabled", .type = UCI_TYPE_STRING },
+		{ .name = "vid", .type = UCI_TYPE_STRING },
 		{ .name = "multi_ap", .type = UCI_TYPE_STRING }
 	};
 	struct uci_option *tb[NUM_POLICIES];
@@ -2034,6 +2151,9 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 	if (tb[FH_ENABLED])
 		fh->enabled = atoi(tb[FH_ENABLED]->v.string);
 
+	if (tb[FH_VID])
+		fh->vid = atoi(tb[FH_VID]->v.string);
+
 	if (tb[FH_MULTI_AP])
 		fh->multi_ap = atoi(tb[FH_MULTI_AP]->v.string);
 
@@ -2488,6 +2608,8 @@ int agent_config_init(struct agent *a, struct agent_config *cfg)
 	INIT_LIST_HEAD(&cfg->steer_excludelist);
 	INIT_LIST_HEAD(&cfg->steer_btm_excludelist);
 
+	cfg->ts_enabled = 0;
+
 	agent_config_prepare(cfg);
 	agent_config_reload(cfg);
 
@@ -2670,7 +2792,7 @@ int uci_set_bridge(char *config, char *bridge, char *proto, char *ipaddress)
 
 	alias = ifname + 3;
 
-	pkg = uci_load_pkg(&ctx, "network");
+	pkg = uci_load_pkg(&ctx, config);
 	if (!pkg)
 		return -1;
 
@@ -2699,7 +2821,7 @@ int uci_set_bridge(char *config, char *bridge, char *proto, char *ipaddress)
 	set_value(ctx, pkg, section, "is_lan", "1", UCI_TYPE_STRING);
 	if (strlen(proto))
 		set_value(ctx, pkg, section, "proto", proto, UCI_TYPE_STRING);
-	if (!strcmp(proto, "static")) {
+	if (!strcmp(proto, "static") && ipaddress) {
 		set_value(ctx, pkg, section, "ipaddr", ipaddress,
 				UCI_TYPE_STRING);
 		set_value(ctx, pkg, section, "netmask", "255.255.255.0",
diff --git a/src/config.h b/src/config.h
index ea6c428895699a276e215fc0727aa0ae92e1cf75..7c6015fd46bad90ca3721679394fc2e83ace742f 100644
--- a/src/config.h
+++ b/src/config.h
@@ -113,7 +113,8 @@ struct netif_fhcfg {
 	bool include_sta_metric;
 
 	struct list_head list;  /* link to next netif_config */
-	uint8_t multi_ap; /* this option is 1 fh 2 bh 3 both */
+	uint8_t multi_ap;	/* this option is 1 fh 2 bh 3 both */
+	unsigned int vid;	/* traffic separation vlan id */
 };
 
 struct netif_bkcfg {
@@ -187,6 +188,7 @@ struct agent_config {
 	uint8_t profile;
 	bool brcm_setup;
 	bool configured;
+	bool ts_enabled;
 	uint8_t cntlr_almac[6];
 	char al_bridge[16];
 	char netdev[16];
@@ -289,6 +291,8 @@ int uci_add_dhcp(char *interface);
 int uci_add_fw(struct agent_config *cfg, char *interface);
 void config_disable_bstas(struct agent_config *cfg);
 int config_disable_bsta(struct netif_bkcfg *bk);
+int uci_apply_default_8021q_settings(struct tlv_default_8021q_settings *tlv);
+int uci_clear_traffic_sep(struct agent_config *cfg);
 void uci_apply_traffic_sep(struct tlv_traffic_sep_policy *tlv);
 int wifi_set_opclass_preference(char *radio_name, uint32_t opclass_id,
 	uint32_t preference, uint32_t *channel_list, int channel_num);
diff --git a/src/nl.c b/src/nl.c
index f5f840d723897bdf2a3637f076a78ce1d104e5fe..c7fc476c1895e4bc0a0b3cb9c83b1af72e25b6f2 100644
--- a/src/nl.c
+++ b/src/nl.c
@@ -22,8 +22,8 @@
 
 #include <easy/easy.h>
 
-#define UCI_WIRELESS "wireless"
-#define UCI_WLAN_IFACE "wifi-iface"
+#include "config.h"
+#include "agent.h"
 
 
 int if_updown(const char *ifname, bool up)
@@ -72,17 +72,21 @@ static int func(struct nl_msg *msg, void *arg)
 		{
 			struct ifinfomsg *ifi;
 			char ifname[16] = {0};
-			char *bridge = (char *) arg;
+			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\n",
-			//	ifname,
-			//	ifi->ifi_index,
-			//	!!(ifi->ifi_flags & IFF_UP) ? "up" : "down");
+			//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;
@@ -90,18 +94,50 @@ static int func(struct nl_msg *msg, void *arg)
 			if (!strstr(ifname, "wds"))
 				break;
 
-			if (if_isbridge_interface(ifname)) {
-				printf("Interface %s is already a part of a bridge\n", 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 );
+				}
 				break;
 			}
+#endif
+
+			if (if_isbridge_interface(ifname)) {
+				int i, num, max = 32;
+				char if_list[max][16];
+				bool found = false;
+
+				if (br_get_iflist(bridge, &num, if_list)) {
+					printf("Failed to check bridge affiliation\n");
+					break;
+				}
+				max = (num < max) ? num : max;
+				for (i = 0; i < max; i++) {
+					if (!strncmp(ifname, if_list[i], 15)) {
+						printf("Interface %s is already a part of bridge\n",
+						       ifname);
+						found = true;
+						break;
+					}
+				}
+				if (found)
+					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);
 			if (!ret)
-				printf("Successfully added interface %s to " \
-						"bridge %s\n", ifname, bridge);
+				printf("Successfully added interface %s to bridge %s\n",
+				       ifname, bridge);
 
 			/* bring up wds interface */
 			//ret = if_setflags(ifname, IFF_UP);