diff --git a/src/Makefile b/src/Makefile
index b4964b3fc672485d42678c438d8e8925a92e40ef..24642f6a2de239b5ab8b8a31e1209f2eb6e1446d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -7,7 +7,6 @@ OBJS = \
 	utils/liblist.o \
 	utils/utils.o \
 
-
 IPC_OBJS = \
 	ipc/comm.o \
 	ipc/worker.o \
@@ -19,6 +18,7 @@ AGENT_OBJS = \
 	core/agent_ubus.o \
 	core/agent.o \
 	core/agent_map.o \
+	core/agent_tlv_generator.o \
 	core/config.o \
 	core/main.o \
 	core/plugin.o
@@ -26,6 +26,7 @@ AGENT_OBJS = \
 LIBS = -lubus -lubox -ljson-c -lblobmsg_json -luci -lwifi-6 -leasy -pthread
 LIBS += -rdynamic -ldl
 LIBS += -lmaputils
+LIBS += -lwsc
 
 plugin_subdirs ?= $(wildcard plugins/*)
 plugin_sofile = $(wildcard $(d)/*.so)
@@ -36,13 +37,13 @@ plugin_files = $(foreach d, $(plugin_subdirs), $(plugin_sofile))
 
 all: $(EXECS) plugins utils/libeasyutils.so
 
-
 %.o: %.c
 	$(CC) $(CFLAGS) -c -o $@ $<
 
 mapagent: $(OBJS) $(IPC_OBJS) $(AGENT_OBJS)
 	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
 
+
 plugins:
 	@echo "$(plugin_subdirs)"
 	for i in $(plugin_subdirs); do [ -d $$i ] && $(MAKE) -C $$i all; done
diff --git a/src/agent.conf b/src/agent.conf
index 5779c0c589b218c5c88522a2ab87ffbe8aa85415..5d6f795baef2a2eaf8cd2d75752ab6a9a7ad4426 100644
--- a/src/agent.conf
+++ b/src/agent.conf
@@ -15,17 +15,20 @@ config fh-iface
 	option steer_legacy_reassoc_secs '30'
 	option steer_legacy_retry_secs '3600'
 	option assoc_ctrl_secs '30'
+	option band '2'
 
 config fh-iface
 	option ifname 'wl1'
 	option steer 'rssi bssload'
 	list exclude '00:11:22:33:44:55'
 	list exclude_btm '00:aa:bb:cc:dd:ee'
+	option band '5'
 
 #config bk-iface
 #	option ifname 'apclii0'
 #	option enabled '1'
 #	option onboarded '0'
+#	option disallow_bsta '1		# bitmap, 1 for disallow p1, 2 to disallow p2, 3 to disallow both (probably never applicable)
 
 config steer-param 'rssi'
 	option priority '0'
diff --git a/src/core/agent.c b/src/core/agent.c
index 9b44ff1bbb4501c513f930e5ba7a703b79f919d5..c3cae9a4de1d5f365e53d07e1dab88e0642c1099 100644
--- a/src/core/agent.c
+++ b/src/core/agent.c
@@ -29,6 +29,13 @@
 
 #include <pthread.h>
 
+#include <map1905/map2.h>
+#include <map1905/maputils.h>
+#include <easy/easy.h>
+#include <wifi.h>
+
+#include <wsc.h>
+
 #include "utils/utils.h"
 #include "map_module.h"
 #include "utils.h"
@@ -1400,7 +1407,7 @@ static int wifi_parse_frame(struct agent *a, struct json_object *frameobj)
 {
 	struct wifi_assoc_frame *new, *old;
 	struct sta *s;
-	char *assoc, *framestr;
+	const char *framestr;
 	uint8_t *frame;
 	int len;
 
@@ -1459,7 +1466,6 @@ static void wifi_iface_event_handler(void *c, struct blob_attr *msg)
 {
 	struct agent *a = (struct agent *)c;
 	const char *ifname, *event;
-	unsigned char mac[6];
 	struct json_object *jmsg, *data;
 	char *str;
 
@@ -1635,8 +1641,6 @@ static void wifi_radio_event_handler(void *c, struct blob_attr *msg)
 
 static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 {
-	struct agent *a = (struct agent *)c;
-	struct netif_fh *fh;
 	char encryption[32] = {0}, ifname[16] = {0}, ssid[33] = {0},
 			key[64] = {0};
 	struct blob_attr *tb[4];
@@ -1737,7 +1741,6 @@ static void ieee1905_cmdu_event_handler(void *c, struct blob_attr *msg)
 	if (tb[1])
 		mid = (uint16_t)blobmsg_get_u32(tb[1]);
 
-
 	if (tb[2])
 		strncpy(in_ifname, blobmsg_data(tb[2]), 15);
 
@@ -1761,9 +1764,9 @@ static void ieee1905_cmdu_event_handler(void *c, struct blob_attr *msg)
 		}
 
 		strtob(tlvstr, len, tlv);
+		free(tlvstr);
 	}
 
-
 #if 0
 	if (tb[4]) {
 		int rem;
@@ -1791,7 +1794,7 @@ static void ieee1905_cmdu_event_handler(void *c, struct blob_attr *msg)
 #endif
 
 	agent_handle_map_event(a, type, mid, in_ifname, srcmac, tlv, len);
-
+	free(tlv);
 }
 
 static void ubus_1905_event_handler(struct ubus_context *ctx,
@@ -2190,100 +2193,132 @@ static int run_agent(struct agent *a)
 	return 0;
 }
 
+static void parse_al_mac(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] = {
+		[0] = { .name = "ieee1905id", .type = BLOBMSG_TYPE_STRING },
+	};
+
+	blobmsg_parse(ieee_attrs, 1, tb, blob_data(msg), blob_len(msg));
+
+	if (tb[0]) {
+		char *mac;
+
+		mac = blobmsg_get_string(tb[0]);
+		hwaddr_aton(mac, a->al_mac);
+		dbg("almac = " MACFMT "\n", MAC2STR(a->al_mac));
+	}
+}
+
 static void parse_radio(struct ubus_request *req, int type,
 		struct blob_attr *msg)
 {
 	struct wifi_radio_element *re = (struct wifi_radio_element *)req->priv;
-	struct blob_attr *tb[7], *cur, *cur1;
-	int rem, j = 0, rem1, k = 0;
-	static const struct blobmsg_policy radio_attr[7] = {
+	struct blob_attr *tb[8];
+	static const struct blobmsg_policy radio_attr[8] = {
 		[0] = { .name = "isup", .type = BLOBMSG_TYPE_BOOL },
-		[1] = { .name = "noise", .type = BLOBMSG_TYPE_INT32 },
-		[2] = { .name = "rx_streams", .type = BLOBMSG_TYPE_INT8 },
-		[3] = { .name = "tx_streams", .type = BLOBMSG_TYPE_INT8 },
-		[4] = { .name = "supp_channels", .type = BLOBMSG_TYPE_ARRAY },
-		[5] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 },
-		[6] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }
+		[1] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
+		[2] = { .name = "noise", .type = BLOBMSG_TYPE_INT32 },
+		[3] = { .name = "rx_streams", .type = BLOBMSG_TYPE_INT8 },
+		[4] = { .name = "tx_streams", .type = BLOBMSG_TYPE_INT8 },
+		[5] = { .name = "supp_channels", .type = BLOBMSG_TYPE_ARRAY },
+		[6] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 },
+		[7] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 },
 	};
 
-	blobmsg_parse(radio_attr, 7, tb, blob_data(msg), blob_len(msg));
+	blobmsg_parse(radio_attr, 8, tb, blob_data(msg), blob_len(msg));
 
 	if (tb[0])
 		re->enabled = blobmsg_get_bool(tb[0]);
 
-	if (tb[1])
-		re->anpi = (int) blobmsg_get_u32(tb[1]); // no get int?
+	if (tb[1]) {
+		char *band;
+
+		band = blobmsg_get_string(tb[1]);
+		if (!strncmp(band, "2.4GHz", strlen("2.4GHz")))
+			re->band = BAND_2;
+		else if (!strncmp(band, "5GHz", strlen("5GHz")))
+			re->band = BAND_5;
+		else
+			re->band = BAND_UNKNOWN;
+	}
 
 	if (tb[2])
-		re->rx_streams = blobmsg_get_u8(tb[2]);
+		re->anpi = (int) blobmsg_get_u32(tb[2]); // no get int?
 
 	if (tb[3])
 		re->rx_streams = blobmsg_get_u8(tb[3]);
 
-	if (tb[4]) {
-		re->num_supp_opclass = blobmsg_check_array(tb[4], BLOBMSG_TYPE_TABLE);
+	if (tb[4])
+		re->rx_streams = blobmsg_get_u8(tb[4]);
+
+	if (tb[5]) {
+		int rem, rem1, i = 0;
+		struct blob_attr *cur;
+
+		re->num_supp_opclass = blobmsg_check_array(tb[5], BLOBMSG_TYPE_TABLE);
 		re->supp_opclass = calloc(re->num_supp_opclass, sizeof(*re->supp_opclass));
 		if (!re->supp_opclass) {
 			fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
 			return;
 		}
 
-		blobmsg_for_each_attr(cur, tb[4], rem) {
-			struct blob_attr *data[3];
+		blobmsg_for_each_attr(cur, tb[5], rem) {
+			struct blob_attr *data[3], *cur1;
 			static const struct blobmsg_policy supp_attrs[3] = {
 				[0] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 },
 				[1] = { .name = "txpower", .type = BLOBMSG_TYPE_INT32 },
 				[2] = { .name = "channels", .type = BLOBMSG_TYPE_ARRAY }
 			};
+			int k = 0;
 
-			k = 0;
 			if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
 				continue;
 
-			// for whatever reason it may continue parsing next object
-			if (!data[0] || !data[1] || j >= re->num_supp_opclass)
-				continue;
-
 			blobmsg_parse(supp_attrs, 3, data, blobmsg_data(cur),
-				blobmsg_data_len(cur));
-			if (data[0])
-				re->supp_opclass[j].id = (uint8_t) blobmsg_get_u32(data[0]);
+					blobmsg_data_len(cur));
+
+			if (!data[0] || !data[1] || i >= re->num_supp_opclass)
+				continue;
 
-			if (data[1])
-				re->supp_opclass[j].max_txpower = blobmsg_get_u32(data[1]);
+			re->supp_opclass[i].id = (uint8_t) blobmsg_get_u32(data[0]);
+			re->supp_opclass[i].max_txpower = (int8_t) blobmsg_get_u32(data[1]);
 
 			if (data[2])
-				re->supp_opclass[j].num_supported_channels = blobmsg_check_array(data[2], BLOBMSG_TYPE_INT32);
+				re->supp_opclass[i].num_supported_channels = blobmsg_check_array(data[2], BLOBMSG_TYPE_INT32);
 
-			re->supp_opclass[j].supp_chanlist = calloc(re->supp_opclass[j].num_supported_channels, sizeof(uint8_t));
-			if (!re->supp_opclass[j].supp_chanlist) {
+			re->supp_opclass[i].supp_chanlist = calloc(re->supp_opclass[i].num_supported_channels, sizeof(uint8_t));
+			if (!re->supp_opclass[i].supp_chanlist) {
 				fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
 				return;
 			}
 
-			blobmsg_for_each_attr(cur1, data[2], rem1) {
-				//struct blob_attr *data1;
-				re->supp_opclass[j].supp_chanlist[k++] = blobmsg_get_u32(cur1);
-			}
+			blobmsg_for_each_attr(cur1, data[2], rem1)
+				re->supp_opclass[i].supp_chanlist[k++] = blobmsg_get_u32(cur1);
 
-			re->supp_opclass[j].num_exclude_channels = 1;
-			if (re->supp_opclass[j].num_exclude_channels > 0) {
-				re->supp_opclass[j].exclude_chanlist =
-					(uint8_t *)calloc(re->supp_opclass[j].num_exclude_channels,
+			re->supp_opclass[i].num_exclude_channels = 1;
+			if (re->supp_opclass[i].num_exclude_channels > 0) {
+				re->supp_opclass[i].exclude_chanlist =
+						(uint8_t *)calloc(re->supp_opclass[i].num_exclude_channels,
 						sizeof(uint8_t));
-				if (re->supp_opclass[j].exclude_chanlist) {
-					 memcpy(re->supp_opclass[j].exclude_chanlist,
-						"\x5d",
-						re->supp_opclass[j].num_exclude_channels * sizeof(uint8_t));
+				if (re->supp_opclass[i].exclude_chanlist) {
+					memcpy(re->supp_opclass[i].exclude_chanlist,
+							"\x5d",
+							re->supp_opclass[i].num_exclude_channels * sizeof(uint8_t));
 				}
 			}
-			j++;
+			i++;
 		}
 	}
-	if (tb[5])
-		re->current_opclass = (uint8_t) blobmsg_get_u32(tb[5]);
+
 	if (tb[6])
-		re->current_channel = (uint8_t) blobmsg_get_u32(tb[6]);
+		re->current_opclass = (uint8_t) blobmsg_get_u32(tb[6]);
+
+	if (tb[7])
+		re->current_channel = (uint8_t) blobmsg_get_u32(tb[7]);
 }
 
 static void _enumerate_wifi_objects(struct ubus_request *req, int type,
@@ -2437,11 +2472,21 @@ static struct netif_bk *netif_alloc_bk(const char *ifname)
 	return n;
 }
 
-static void netif_free(const char *ifname)
+static void netif_free(struct netif_fh *n)
 {
+	list_del(&n->list);
+	free(n);
 	/* TODO? */
 }
 
+static void netif_free_all(struct agent *a)
+{
+	struct netif_fh *p, *tmp;
+
+	list_for_each_entry_safe(p, tmp, &a->fhlist, list)
+		netif_free(p);
+}
+
 const char *wifi_ifname_to_radio(struct agent *a, char *ifname)
 {
 	int i, j;
@@ -2465,7 +2510,7 @@ struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a,
 		char *ifname)
 {
 	int i;
-	char *radio;
+	const char *radio;
 
 	radio = wifi_ifname_to_radio(a, ifname);
 	if (!radio)
@@ -2488,10 +2533,9 @@ struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a,
 struct netif_fh *wifi_radio_to_ap(struct agent *a, const char *radio)
 {
 	struct netif_fh *p;
-	struct sta *s;
 
 	list_for_each_entry(p, &a->fhlist, list) {
-		char *fh_radio;
+		const char *fh_radio;
 
 		fh_radio = wifi_ifname_to_radio(a, p->name);
 		if (!fh_radio)
@@ -2576,14 +2620,13 @@ static void parse_ap(struct ubus_request *req, int type,
 	hwaddr_aton(bssid, fh->bssid);
 
 	if (tb[2]) {
-		struct blob_attr *data[2], *caps, *attr;
+		struct blob_attr *data[2];
 		static const struct blobmsg_policy cap_attr[2] = {
 			[0] = { .name = "dot11n", .type = BLOBMSG_TYPE_TABLE },
 			[1] = { .name = "dot11ac", .type = BLOBMSG_TYPE_TABLE }
 		};
-		int rv, rem;
 
-		rv = blobmsg_parse(cap_attr, 2, data, blobmsg_data(tb[2]),
+		blobmsg_parse(cap_attr, 2, data, blobmsg_data(tb[2]),
 				blobmsg_data_len(tb[2]));
 
 		if (data[0])
@@ -2610,6 +2653,15 @@ static int agent_init_interfaces(struct agent *a)
 	struct netif_fhcfg *f;
 	struct netif_bkcfg *b;
 	wifi_object_t wifi_obj;
+	uint32_t ieee1905_obj;
+
+	ieee1905_obj = ubus_get_object(a->ubus_ctx, "ieee1905");
+	if (ieee1905_obj != WIFI_OBJECT_INVALID) {
+		ubus_call_object(a, ieee1905_obj, "info", parse_al_mac, a);
+	} else {
+		warn("Object '%s' not present!\n");
+		return -1;
+	}
 
 	wifi_obj = ubus_get_object(a->ubus_ctx, "wifi");
 	if (wifi_obj != WIFI_OBJECT_INVALID) {
@@ -2786,6 +2838,16 @@ int agent_msgqueue_dispatcher(void *data)
 	return ret;
 }
 
+void clear_fhlist(struct agent *a)
+{
+	struct netif_fh *p, *tmp;
+
+	list_for_each_entry_safe(p, tmp,  &a->fhlist, list) {
+		list_del(&p->list);
+		free(p);
+	}
+}
+
 int start_agent(void)
 {
 	struct agent *w;
@@ -2830,14 +2892,14 @@ int start_agent(void)
 
 	ubus_add_uloop(ctx);
 
-	agent_config_reload(&w->cfg);
+	agent_config_init(&w->cfg);
+	//agent_config_reload(&w->cfg);
 	//agent_config_defaults(w, &w->cfg);
 #if 0
 	agent_config_reload("wifiagent", &w->cfg);
 	agent_config_reload("wireless", &w->cfg);
 	agent_config_dump(&w->cfg);
 #endif
-
 	get_registered_steer_rules();	/* TODO: return rule list and improve */
 
 	agent_init_interfaces(w);
@@ -2868,13 +2930,40 @@ int start_agent(void)
 	ubus_free(ctx);
 	uloop_done();
 	/* TODO: cleanups */
+	clear_fhlist(w);
 	free(w);
 
 	return 0;
 }
 
+void agent_free_radios(struct agent *a)
+{
+	int i;
+
+	for (i = 0; i < a->num_radios; i++) {
+		struct wifi_radio_element *re;
+		int j;
+
+		re = &a->radios[i];
+
+		for (j = 0; j < re->num_supp_opclass; j++)
+			free(re->supp_opclass[j].exclude_chanlist);
+
+		free(re->supp_opclass);
+
+		// theoretically should be allocated or NULL
+		if (re->autconfig.m1_frame)
+			free(re->autconfig.m1_frame);
+		if (re->autconfig.key) {
+			free(re->autconfig.key->key);
+			free(re->autconfig.key);
+		}
+	}
+}
+
 void stop_agent(struct agent *w)
 {
+
 	if (!w) {
 		warn("%s: (agent = NULL)\n", __func__);
 		exit(0);
@@ -2885,12 +2974,19 @@ void stop_agent(struct agent *w)
 	 */
 
 	//exit_dispatcher(w);
+
+	stop_test_logging();
 	worker_exit(&w->cmd_dispatcher);
 	ubus_unregister_event_handler(w->ubus_ctx, &w->wifi_evh);
 	ubus_unregister_event_handler(w->ubus_ctx, &w->ieee1905_evh);
-	agent_remove_object(w->ubus_ctx);
+	plugins_unload(&w->pluginlist);
+	agent_remove_object(w);
 	ubus_free(w->ubus_ctx);
 	uloop_done();
+	agent_config_clean(&w->cfg);
+	agent_free_radios(w);
+	clear_fhlist(w);
+	netif_free_all(w);
 	free(w);
 }
 
@@ -3756,7 +3852,6 @@ int wifiagent_process_cmd_async(struct ubus_context *ctx,
 		int cmd_id, char *cmd_data, int len)
 {
 	struct agent *a = this_agent;
-	int ret = 0;
 	struct msg *msg;
 
 	trace_cmd("Agent: Recvd CMD async %s payload_sz = %d\n",
diff --git a/src/core/agent.h b/src/core/agent.h
index 09902861221ed2f4f4b3dd10c21c96e82a1bdc6c..013c6d4dbb428e96b7726864963f2f2b7517b260 100644
--- a/src/core/agent.h
+++ b/src/core/agent.h
@@ -13,6 +13,10 @@
 #include <easy/easy.h>
 #include <wifi.h>
 
+// TODO: TODO: fixme: remove this include
+//#include <ieee1905/1905_tlvs.h>
+
+
 typedef char timestamp_t[32];
 
 typedef struct ip_address {
@@ -318,6 +322,7 @@ struct wifi_unassoc_sta_element {
 struct wifi_radio_element {
 	char name[16];
 	uint8_t macaddr[6];
+	enum wifi_band band;
 	bool enabled;
 	int anpi;
 	uint8_t total_utilization;   /** in %age, linearly scaled 0..255 */
@@ -345,6 +350,12 @@ struct wifi_radio_element {
 	struct wifi_bss_element *bsslist;
 	struct wifi_scanres_element *scanlist;
 	struct wifi_unassoc_sta_element *unassoc_stalist;
+
+	struct {
+		uint8_t *m1_frame;
+		uint16_t m1_size;
+		struct wsc_key *key;
+	} autconfig;
 };
 
 struct wifi_netdev {
@@ -358,6 +369,7 @@ struct wifi_netdev {
 /** struct agent - wifi agent */
 struct agent {
 	int debug;
+	uint8_t al_mac[6];
 	struct uloop_timeout heartbeat;
 	struct list_head fhlist;
 	struct list_head bklist;
@@ -412,6 +424,7 @@ extern void wifiagent_notify_event(struct agent *a, void *ev_type,
 #endif
 
 extern int plugins_load(int argc, char *argv[], struct list_head *plugins);
+extern int plugins_unload(struct list_head *plugins);
 
 struct netif_fh *wifi_radio_to_ap(struct agent *a, const char *radio);
 
diff --git a/src/core/agent_map.c b/src/core/agent_map.c
index 446634eeb00e816b744612988fb0b02d91a3f681..be223e5723987bd35b512f1bf4b216000a386c79 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -17,6 +17,12 @@
 #include <net/if_arp.h>
 #include <pthread.h>
 
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+#define TMP_WIFI_IFACE_MAX_NUM 16
+
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
@@ -29,6 +35,8 @@
 #include <libubus.h>
 
 
+#include <uci.h>
+
 #include "map_module.h"
 #include "utils.h"
 #include "debug.h"
@@ -39,10 +47,13 @@
 #include "msgqueue.h"
 #include "worker.h"
 #include "agent.h"
-
+//#include "platform_interfaces.h"
 
 #include <map1905/map2.h>
 #include <map1905/maputils.h>
+#include <wsc.h>
+
+#include "agent_tlv_generator.h"
 
 #define UBUS_TIMEOUT            1000
 
@@ -63,6 +74,21 @@ typedef int (*map_cmdu_sendfunc_t)(void *agent, struct cmdu_cstruct *cmdu);
 
 int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu);
 
+uint8_t *extract_tlv_by_type(struct cmdu_cstruct *cmdu, uint8_t tlv_type)
+{
+	uint8_t *tlv;
+	int i;
+
+	for (i = 0; i < cmdu->num_tlvs; i++) {
+		tlv = cmdu->tlvs[i];
+		if (*tlv == tlv_type)
+			return tlv;
+	}
+
+	return NULL;
+
+}
+
 /* lookup netif struct by bssid */
 static struct netif_fh *get_netif_by_bssid(struct agent *a, uint8_t *bssid)
 {
@@ -78,6 +104,76 @@ static struct netif_fh *get_netif_by_bssid(struct agent *a, uint8_t *bssid)
 	return NULL;
 }
 
+int build_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *rec_cmdu,
+		struct wifi_radio_element *radio, int idx)
+{
+	struct agent *a = (struct agent *) agent;
+	struct cmdu_cstruct *cmdu;
+	struct tlv_ap_radio_basic_cap *p;
+	struct tlv_profile2_ap_cap *p1;
+	struct tlv_ap_radio_adv_cap *p2;
+	struct tlv_wsc *p3;
+	int tlv_index = 0;
+	uint16_t len = 0;
+
+	cmdu = (struct cmdu_cstruct *)calloc(1, sizeof(struct cmdu_cstruct));
+	if (!cmdu) {
+		fprintf(stderr, "failed to malloc cmdu\n");
+		return -1;
+	}
+
+	memcpy(cmdu->origin, rec_cmdu->origin, 6);
+	cmdu->message_type = CMDU_TYPE_AP_AUTOCONFIGURATION_WSC;
+	cmdu->message_id = rec_cmdu->message_id;
+	strncpy(cmdu->intf_name, rec_cmdu->intf_name,
+			sizeof(cmdu->intf_name) - 1);
+
+	p = agent_gen_ap_radio_basic_cap(a, cmdu, idx);
+	if (!p)
+		goto fail_cmdu;
+	cmdu->num_tlvs++;
+
+	p1 = agent_gen_profile2_ap_cap(a, cmdu);
+	if (!p1)
+		goto fail_p;
+	cmdu->num_tlvs++;
+
+	p2 = agent_gen_ap_radio_adv_cap(a, cmdu, radio);
+	if (!p2)
+		goto fail_p1;
+	cmdu->num_tlvs++;
+
+	p3 = agent_gen_wsc(a, cmdu, radio);
+	if (!p3)
+		goto fail_p2;
+	cmdu->num_tlvs++;
+
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *));
+	if (!cmdu->tlvs)
+		goto fail_p3;
+
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p;
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p3;
+	// TODO: ff:ff:ff:ff:ff:ff = send to all agents
+
+	agent_send_cmdu(a, cmdu);
+	map_free_cmdu(cmdu);
+	return 0;
+fail_p3:
+	map_free_tlv_cstruct((uint8_t *) p3);
+fail_p2:
+	map_free_tlv_cstruct((uint8_t *) p2);
+fail_p1:
+	map_free_tlv_cstruct((uint8_t *) p1);
+fail_p:
+	map_free_tlv_cstruct((uint8_t *) p);
+fail_cmdu:
+	free(cmdu);
+	return -1;
+}
+
 int send_topology_notification(void *agent, struct cmdu_cstruct *cmdu)
 {
 	return 0;
@@ -249,154 +345,301 @@ int handle_topology_response(void *agent, struct cmdu_cstruct *cmdu)
 
 int handle_ap_autoconfig_search(void *agent, struct cmdu_cstruct *cmdu)
 {
-	trace("%s: --->\n", __func__);
+	trace("agent: %s: --->\n", __func__);
 	return 0;
 }
 
 int handle_ap_autoconfig_response(void *agent, struct cmdu_cstruct *cmdu)
 {
-	trace("%s: --->\n", __func__);
+	trace("agent: %s: --->\n", __func__);
+	struct agent *a = (struct agent *) agent;
+	struct wifi_radio_element *radio;
+	int i;
+
+	for (i = 0; i < a->num_radios; i++) {
+		radio = a->radios + i;
+		build_ap_autoconfig_wsc(a, cmdu, radio, i);
+	}
 	return 0;
 }
 
-int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
+static struct wifi_radio_element *wifi_get_radio_by_mac(struct agent *a,
+		uint8_t *hwaddr)
 {
-	trace("%s: --->\n", __func__);
-	return 0;
-}
+	struct wifi_radio_element *radio;
+	int i;
 
+	for (i = 0; i < a->num_radios; i++) {
+		radio = a->radios + i;
 
-int handle_1905_ack(void *agent, struct cmdu_cstruct *cmdu)
+		if (memcmp(radio->macaddr, hwaddr, 6))
+			continue;
+
+		return radio;
+	}
+
+	return NULL;
+}
+
+int wifi_teardown_iface(const char *ifname)
 {
-	trace("%s: --->\n", __func__);
+	config_del_iface("wireless", "wifi-iface", ifname);
+	config_del_iface("ieee1905", "wifi-iface", ifname);
+	config_del_iface("agent", "fh-iface", ifname);
+
 	return 0;
 }
 
-static void get_ap_vht_caps(struct agent *a,
-				struct tlv_ap_vht_cap *p, uint32_t radio_index)
+int wifi_teardown_map_ifaces_by_band(struct agent *a, enum wifi_band band)
 {
-	struct wifi_radio_element *radio = a->radios + radio_index;
-	struct netif_fh *fh;
+	struct netif_fhcfg *fh, *fh_tmp;
+	struct netif_bkcfg *bk, *bk_tmp;
 
-	trace("%s -----> parsing radio %s\n", __func__, radio->name);
+	list_for_each_entry_safe(fh, fh_tmp, &a->cfg.fhlist, list) {
+		if (fh->band != band)
+			continue;
 
-	fh = wifi_radio_to_ap(a, radio->name);
-	if (!fh)
-		return;
+		wifi_teardown_iface(fh->name);
+		clean_fh(fh);
+	}
 
-	memcpy(p->radio_id, radio->macaddr, 6);
-	memcpy(&p->vht_tx_mcs_supported, &fh->caps.mcs.vht_mcs_txmap, 2);
-	memcpy(&p->vht_rx_mcs_supported, &fh->caps.mcs.vht_mcs_rxmap, 2);
-	p->max_tx_streams_supported = (fh->tx_spatial_streams - 1);
-	p->max_rx_streams_supported = (fh->rx_spatial_streams - 1);
-	p->gi_80_support = fh->caps.vht[4] & (1 << 1) ? 1 : 0;
-	p->gi_160_support = fh->caps.vht[4] & (1 << 0) ? 1 : 0;
-	p->vht_8080_support = fh->caps.vht[5] & (1 << 7) ? 1 : 0;
-	p->vht_160_support = fh->caps.vht[5] & (1 << 6) ? 1 : 0;
-	p->su_beamformer_capable = fh->caps.vht[5] & (1 << 5) ? 1 : 0;
-	p->mu_beamformer_capable = fh->caps.vht[5] & (1 << 4) ? 1 : 0;
+	list_for_each_entry_safe(bk, bk_tmp, &a->cfg.bklist, list) {
+		if (bk->band != band)
+			continue;
+
+		wifi_teardown_iface(bk->name);
+		clean_bk(bk);
+	}
+
+	agent_config_reload(&a->cfg);
+
+	return 0;
 }
 
-static void get_ap_ht_caps(struct agent *a,
-				struct tlv_ap_ht_cap *p, uint32_t radio_index)
-{
-	struct wifi_radio_element *radio;
-	struct netif_fh *fh;
+/* return true if valid ifname is available */
+int check_wireless_ifname(struct agent *a, const char *device,
+		const char *ifname)
+{
+	enum {
+		W_IFNAME,
+		W_DEV,
+		NUM_POLICIES
+	};
+	const struct uci_parse_option opts[] = {
+		{ .name = "ifname", .type = UCI_TYPE_STRING },
+		{ .name = "device", .type = UCI_TYPE_STRING }
+	};
+	struct uci_option *tb[NUM_POLICIES];
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_element *e;
+	bool rv = false;
+	int num_ifs = 0;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return -1;
 
-	radio = a->radios + radio_index;
+	if (uci_load(ctx, "wireless", &pkg)) {
+		uci_free_context(ctx);
+		return -1;
+	}
 
-	trace("%s -----> parsing radio %s\n", __func__, radio->name);
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_section *s = uci_to_section(e);
 
-	fh = wifi_radio_to_ap(a, radio->name);
-	if (!fh)
-		return;
+		if (strncmp(s->type, "wifi-iface", strlen("wifi-iface")))
+			continue;
 
-	memcpy(p->radio_id, radio->macaddr, 6);
-	p->max_tx_streams_supported = (radio->tx_streams - 1) & 0xff;
-	p->max_rx_streams_supported = (radio->rx_streams - 1) & 0xff;
-	p->gi_20_support = fh->caps.ht & (1 << 3) ? 1 : 0;
-	p->gi_40_support = fh->caps.ht & (1 << 2) ? 1 : 0;
-	p->ht_40_support = fh->caps.ht & (1 << 1) ? 1 : 0;
+		uci_parse_section(s, opts, NUM_POLICIES, tb);
+
+		if (tb[W_DEV]) {
+			const char *cfg_dev;
+
+			cfg_dev = tb[W_DEV]->v.string;
+			if (!strncmp(cfg_dev, device, IFNAMSIZ))
+				num_ifs++;
+		}
+
+		/* TODO: should work with 16 instead of 4 */
+		if (num_ifs >= TMP_WIFI_IFACE_MAX_NUM) {
+			rv = true;
+			break;
+		}
+
+		if (tb[W_IFNAME]) {
+			char *cfg_ifname;
+
+			cfg_ifname = tb[W_IFNAME]->v.string;
+			if (!strncmp(cfg_ifname, ifname, IFNAMSIZ)) {
+				rv = true;
+				break;
+			}
+		}
+	}
+
+	uci_free_context(ctx);
+	return rv;
 }
 
-static void get_ap_radio_basic_cap(struct agent *a,
-					struct tlv_ap_radio_basic_cap *p,
-					uint32_t radio_index)
+/* return ifname buffer */
+char *wifi_gen_first_ifname(struct agent *a, char *device, char *ifname)
 {
-	uint32_t j;
-	struct wifi_radio_element *radio = a->radios + radio_index;
+	int i;
 
-	trace("%s -----> parsing radio %s\n", __func__, radio->name);
+	/* maximum number of interface per BSSID is currently 4
+	 * setting a higher number may cause segfault within libwsc.so,
+	 * caused by DH_free() from platform_cyrpto.c in
+	 * PLATFORM_COMPUTE_DH_SHARED_SECRET() (verified with i <= 8)
+	 */
+	/* TODO: should work with 16 instead of 4 */
+	for (i = 1; i <= TMP_WIFI_IFACE_MAX_NUM; i++) {
+		snprintf(ifname, IFNAMSIZ, "%s_%d", device, i);
+		if (!check_wireless_ifname(a, device, ifname))
+			return ifname;
+	}
 
-	memcpy(p->radio_id, radio->macaddr, 6);
-	p->max_bss_nr = 4; // Max BSS per Radio
-	p->operating_classes_nr = radio->num_supp_opclass;
+	return NULL;
+}
 
-	if (p->operating_classes_nr > 0)
-		p->operating_class = calloc(p->operating_classes_nr,
-				sizeof(*p->operating_class));
-	if (!p->operating_class) {
-		fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
-		p->operating_classes_nr = 0;
-		return;
-	}
+int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
+{
+	struct agent *a = (struct agent *) agent;
+	uint8_t bssid[6];
+	int i;
+	uint8_t *tlv = NULL;
+	struct wifi_radio_element *radio;
+	struct tlv_ap_radio_identifier *id_tlv;
+
+	trace("%s: --->\n", __func__);
+
+	id_tlv = (struct tlv_ap_radio_identifier *) extract_tlv_by_type(cmdu,
+			MAP_TLV_AP_RADIO_IDENTIFIER);
+	if (!id_tlv)
+		return -1;
+
+	memcpy(bssid, id_tlv->radio_id, 6);
+
+	radio = wifi_get_radio_by_mac(a, bssid);
+	if (!radio)
+		return -1;
+
+	wifi_teardown_map_ifaces_by_band(a, radio->band);
+
+	// need iterate every TLV_TYPE_WSC, may be multiple
+	for (i = 0; i < cmdu->num_tlvs; i++) {
+		tlv = cmdu->tlvs[i];
+		switch (*tlv) {
+		case TLV_TYPE_WSC: {
+			struct mdata out;
+			struct tlv_wsc *m2;
+			char ifname[IFNAMSIZ] = {0};
+			int rv;
+
+			m2 = (struct tlv_wsc *) tlv;
+
+			if (!wifi_gen_first_ifname(a, radio->name, ifname)) {
+				err("Failed to find valid interface name, "\
+						"probably maximum number of "\
+						"interfaces have been reached\n",
+						MACFMT "!\n", MAC2STR(bssid));
+				return -1;
+			}
 
-	for (j = 0; j < p->operating_classes_nr; j++) {
-		p->operating_class[j].op_class = radio->supp_opclass[j].id;
-		p->operating_class[j].max_tx_power = radio->supp_opclass[j].max_txpower;
-		p->operating_class[j].non_op_ch_nr = radio->supp_opclass[j].num_exclude_channels;
-		if (p->operating_class[j].non_op_ch_nr > 0) {
-			p->operating_class[j].channel =
-					(uint8_t *)calloc(p->operating_class[j].non_op_ch_nr,
-					sizeof(uint8_t));
-			if (p->operating_class[j].channel) {
-				memcpy(p->operating_class[j].channel, radio->supp_opclass[j].exclude_chanlist,
-						p->operating_class[j].non_op_ch_nr);
+			rv = wscProcessM2((void *) radio->autconfig.key,
+					radio->autconfig.m1_frame,
+					radio->autconfig.m1_size,
+					m2->wsc_frame,
+					m2->wsc_frame_size, &out, ifname);
+			if (!rv) {
+				err("Failed to process M2 target for interface"\
+						MACFMT "!\n", MAC2STR(bssid));
+				//wifi_teardown_iface(ifname);
+				wifi_teardown_map_ifaces_by_band(a, radio->band);
+				// Return rather than freeing because it may belong to an updated frame
+				return -1;
 			}
+
+			if (BIT(3, out.output.mapie)) {
+				err("MAP Extension had teardown bit set, "\
+						"tearing down all MAP interfaces"\
+						" for bssid" MACFMT "\n",
+						MAC2STR(bssid));
+				wifi_teardown_map_ifaces_by_band(a, radio->band);
+				goto teardown;
+			}
+
+			uci_apply_m2(ifname, out.output.ssid, out.output.bssid,
+					out.output.auth_types,
+					out.output.encryption_types,
+					out.output.network_key,
+					out.output.mapie, radio->band);
+
+			break;
+		}
+		default:
+			break;
+
 		}
 	}
+
+teardown:
+	// TODO: freeing from here risks freeing an updated frame
+	free(radio->autconfig.m1_frame);
+	free(radio->autconfig.key->key);
+	free(radio->autconfig.key);
+	radio->autconfig.key = NULL;
+	radio->autconfig.m1_frame = NULL;
+	return 0;
+}
+
+
+int handle_1905_ack(void *agent, struct cmdu_cstruct *cmdu)
+{
+	trace("agent: %s: --->\n", __func__);
+	return 0;
 }
 
 int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 {
-	trace("%s: --->\n", __func__);
+	trace("agent: %s: --->\n", __func__);
 	struct agent *a = (struct agent *) agent;
 	uint16_t tlv_index = 0;
 	uint32_t j;
-	struct cmdu_cstruct *cmdu_data;
+	struct cmdu_cstruct *cmdu;
+	struct tlv_ap_cap *p2;
 	int ret;
 
-	cmdu_data = (struct cmdu_cstruct *)calloc(1,
+	cmdu = (struct cmdu_cstruct *)calloc(1,
 			sizeof(struct cmdu_cstruct));
-	if (!cmdu_data) {
+	if (!cmdu) {
 		fprintf(stderr, "Out of memory!\n");
 		return -1;
 	}
 
-	cmdu_data->message_type = CMDU_AP_CAPABILITY_REPORT;
-	memcpy(cmdu_data->origin, rec_cmdu->origin, 6);
-	cmdu_data->message_id = rec_cmdu->message_id;
-	strcpy(cmdu_data->intf_name, rec_cmdu->intf_name);
+	cmdu->message_type = CMDU_AP_CAPABILITY_REPORT;
+	memcpy(cmdu->origin, rec_cmdu->origin, 6);
+	cmdu->message_id = rec_cmdu->message_id;
 
-	cmdu_data->num_tlvs = 3 * a->num_radios + 1; /* (Radio basic, HT, VHT capability per radio) */
-	cmdu_data->tlvs = (uint8_t **)calloc(cmdu_data->num_tlvs,
+	cmdu->num_tlvs = 3 * a->num_radios + 1; /* (Radio basic, HT, VHT capability per radio) */
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs,
 			sizeof(uint8_t *));
 
-	if (!cmdu_data->tlvs) {
-		map_free_cmdu(cmdu_data);
+	if (!cmdu->tlvs) {
+		map_free_cmdu(cmdu);
 		return -1;
 	}
 
 	/* AP basic Radio Capability TLV*/
 	for (j = 0; j < a->num_radios; j++) {
-		struct tlv_ap_radio_basic_cap *p =
-			(struct tlv_ap_radio_basic_cap *)calloc(1,
-					sizeof(struct tlv_ap_radio_basic_cap));
-		if (p) {
-			p->tlv_type = MAP_TLV_AP_RADIO_BASIC_CAPABILITIES;
-			get_ap_radio_basic_cap(a, p, j);
-			cmdu_data->tlvs[tlv_index++] = (uint8_t *)p;
-		}
+		struct tlv_ap_radio_basic_cap *p;
+
+		p = agent_gen_ap_radio_basic_cap(a, cmdu, j);
+		if (!p)
+			continue;
+		//cmdu->num_tlvs++;
+
+		cmdu->tlvs[tlv_index++] = (uint8_t *)p;
 	}
 	/* Collection Interval TLV*/
 /*	struct tlv_metric_collection_interval *p1 =
@@ -405,52 +648,52 @@ int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
  *	if (p1) {
  *		p1->tlv_type = MAP_TLV_METRIC_COLLECTION_INTERVAL;
  *		get_collection_interval(a, p1);
- *		cmdu_data->tlvs[tlv_index++] = (uint8_t *)p1;
+ *		cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
  *	}
  */
 
 	/* AP capability TLV */
-	struct tlv_ap_cap *p2 = (struct tlv_ap_cap *)calloc(1,
-			sizeof(struct tlv_ap_cap));
-	if (p2) {
-		p2->tlv_type = MAP_TLV_AP_CAPABILITY;
-		p2->op_ch_metric_reporting = 0;
-		p2->non_op_ch_metric_reporting = 0;
-		p2->agent_init_rcpi_steering = 0;
-		cmdu_data->tlvs[tlv_index++] = (uint8_t *)p2;
-	}
+	p2 = agent_gen_ap_caps(a, cmdu);
+	if (!p2)
+		return -1;
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+	//cmdu->num_tlvs++;
 
 	/* HT Capability */
 	for (j = 0; j < a->num_radios; j++) {
-		struct tlv_ap_ht_cap *p3 = (struct tlv_ap_ht_cap *)calloc(1,
-				sizeof(struct tlv_ap_ht_cap));
-		if (p3) {
-			p3->tlv_type = MAP_TLV_AP_HT_CAPABILITIES;
-			get_ap_ht_caps(a, p3, j);
-			cmdu_data->tlvs[tlv_index++] = (uint8_t *)p3;
-		}
+		struct tlv_ap_ht_cap *p3;
+
+		p3 = agent_gen_ap_ht_caps(a, cmdu, j);
+		if (!p3)
+			continue;
+		//cmdu->num_tlvs++;
+
+
+		cmdu->tlvs[tlv_index++] = (uint8_t *)p3;
 	}
 
 	/*VHT Capability */
 	for (j = 0; j < a->num_radios; j++) {
-		struct tlv_ap_vht_cap *p4 = (struct tlv_ap_vht_cap *)calloc(1,
-				sizeof(struct tlv_ap_vht_cap));
-		if (p4) {
-			p4->tlv_type = MAP_TLV_AP_VHT_CAPABILITIES;
-			get_ap_vht_caps(a, p4, j);
-			cmdu_data->tlvs[tlv_index++] = (uint8_t *)p4;
-		}
+		struct tlv_ap_vht_cap *p4;
+
+		p4 = agent_gen_ap_vht_caps(a, cmdu, j);
+		if (!p4)
+			continue;
+		//cmdu->num_tlvs++;
+
+
+		cmdu->tlvs[tlv_index++] = (uint8_t *)p4;
 	}
 
-	ret = agent_send_cmdu(a, cmdu_data);
-	map_free_cmdu(cmdu_data);
+	ret = agent_send_cmdu(a, cmdu);
+	map_free_cmdu(cmdu);
 
 	return ret;
 }
 
 int handle_map_policy_config(void *agent, struct cmdu_cstruct *cmdu)
 {
-	struct tlv *t;
+	//struct tlv *t;
 
 	trace("%s: --->\n", __func__);
 
@@ -945,8 +1188,8 @@ static const map_cmdu_handler_t i1905ftable[] = {
 	[0x02] = handle_topology_query,
 	[0x03] = handle_topology_response,
 	/* hole */
-	[0x07] = handle_ap_autoconfig_search,
-	/* [0x08] = handle_ap_autoconfig_response, */
+	/* [0x07] = handle_ap_autoconfig_search, */
+	[0x08] = handle_ap_autoconfig_response,
 	[0x09] = handle_ap_autoconfig_wsc,
 };
 
@@ -1149,14 +1392,14 @@ int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu)
 	struct blob_buf b = { 0 };
 	char dst_addr[18] = { 0 };
 	char *tlv_str = NULL;
-	uint8_t is_store_mid = 1;
 	uint8_t *ss = NULL;
 	uint16_t msgid = 0;
 	uint16_t len;
 	int ret = 0;
 	size_t i;
 	uint32_t id;
-	struct ieee1905_cmdu_msg *cmsg = NULL;
+	//uint8_t is_store_mid = 1;
+	//struct ieee1905_cmdu_msg *cmsg = NULL;
 
 	trace("|%s:%d| Entry\n", __func__, __LINE__);
 
@@ -1249,7 +1492,7 @@ int agent_handle_map_event(struct agent *a, uint16_t cmdutype, uint16_t mid,
 			   char *rxif, uint8_t *src, uint8_t *tlvs, int len)
 {
 	const map_cmdu_handler_t *f;
-	struct cmdu_cstruct *cmdu;
+	struct cmdu_cstruct *cmdu = NULL;
 	int ret = -1;
 	int idx;
 
@@ -1270,7 +1513,7 @@ int agent_handle_map_event(struct agent *a, uint16_t cmdutype, uint16_t mid,
 			ret = f[idx](a, cmdu);
 			map_free_cmdu(cmdu);
 		} else {
-			dbg("%s: map_build_cmdu() failed!\n");
+			dbg("agent: %s: map_build_cmdu() failed!\n", __func__);
 		}
 	}
 
diff --git a/src/core/agent_map.h b/src/core/agent_map.h
index fbb4881c7550eb13e80730de2b042b3dece44f67..a2f9b30d3ae0d02e0232f8335e069935df2c133f 100644
--- a/src/core/agent_map.h
+++ b/src/core/agent_map.h
@@ -8,8 +8,11 @@ extern bool is_cmdu_for_us(struct agent *a, uint16_t type);
 extern int agent_handle_map_cmd(struct agent *a, char *data, int len);
 
 extern int agent_handle_map_event(struct agent *a, uint16_t cmdutype,
-				  uint16_t mid, char *rxif, uint8_t *src,
-				  uint8_t *tlvs, int len);
+		uint16_t mid, char *rxif, uint8_t *src,
+		uint8_t *tlvs, int len);
+int build_ap_autoconfig_wsc(void *agent, uint8_t *hwaddr,
+		struct wifi_radio_element *radio, int idx);
+int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu);
 
 
 #endif /* AGENT_MAP_H */
diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c
new file mode 100644
index 0000000000000000000000000000000000000000..dfa28546b5816995d4c0aff716ebb5917354b7db
--- /dev/null
+++ b/src/core/agent_tlv_generator.c
@@ -0,0 +1,252 @@
+/*
+ * agent_tlv_generator.c - tlv building function
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: jakob.olsson@iopsys.eu
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <pthread.h>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <json-c/json.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 <map1905/map2.h>
+#include <map1905/maputils.h>
+#include <wsc.h>
+
+#include "map_module.h"
+#include "utils.h"
+#include "debug.h"
+#include "liblist.h"
+#include "steer_rules.h"
+#include "config.h"
+#include "comm.h"
+#include "msgqueue.h"
+#include "worker.h"
+#include "agent.h"
+//#include "platform_interfaces.h"
+#include "agent_tlv_generator.h"
+
+struct tlv_ap_ht_cap *agent_gen_ap_ht_caps(struct agent *a,
+		struct cmdu_cstruct *cmdu, uint32_t radio_index)
+{
+	struct tlv_ap_ht_cap *p;
+	struct wifi_radio_element *radio;
+	struct netif_fh *fh;
+
+	radio = a->radios + radio_index;
+
+	p = (struct tlv_ap_ht_cap *)calloc(1,
+			sizeof(struct tlv_ap_ht_cap));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_AP_HT_CAPABILITIES;
+
+	fh = wifi_radio_to_ap(a, radio->name);
+	if (!fh) {
+		free(p);
+		return NULL;
+	}
+
+	memcpy(p->radio_id, radio->macaddr, 6);
+	p->max_tx_streams_supported = (radio->tx_streams - 1) & 0xff;
+	p->max_rx_streams_supported = (radio->rx_streams - 1) & 0xff;
+	p->gi_20_support = fh->caps.ht & (1 << 3) ? 1 : 0;
+	p->gi_40_support = fh->caps.ht & (1 << 2) ? 1 : 0;
+	p->ht_40_support = fh->caps.ht & (1 << 1) ? 1 : 0;
+
+	return p;
+}
+
+struct tlv_ap_cap *agent_gen_ap_caps(struct agent *a,
+		struct cmdu_cstruct *cmdu)
+{
+	struct tlv_ap_cap *p;
+
+	p = (struct tlv_ap_cap *)calloc(1,
+			sizeof(struct tlv_ap_cap));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_AP_CAPABILITY;
+	p->op_ch_metric_reporting = 0;
+	p->non_op_ch_metric_reporting = 0;
+	p->agent_init_rcpi_steering = 0;
+
+	return p;
+}
+
+struct tlv_ap_radio_basic_cap *agent_gen_ap_radio_basic_cap(struct agent *a,
+		struct cmdu_cstruct *cmdu, uint32_t radio_index)
+{
+	uint32_t j;
+	struct wifi_radio_element *radio;
+	struct tlv_ap_radio_basic_cap *p;
+
+	radio = a->radios + radio_index;
+
+	p = (struct tlv_ap_radio_basic_cap *)calloc(1,
+			sizeof(struct tlv_ap_radio_basic_cap));
+
+	p->tlv_type = MAP_TLV_AP_RADIO_BASIC_CAPABILITIES;
+	memcpy(p->radio_id, radio->macaddr, 6);
+	p->max_bss_nr = 4; // Max BSS per Radio
+	p->operating_classes_nr = radio->num_supp_opclass;
+
+	if (p->operating_classes_nr > 0)
+		p->operating_class = calloc(p->operating_classes_nr,
+				sizeof(*p->operating_class));
+	if (!p->operating_class) {
+		fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
+		p->operating_classes_nr = 0;
+		return p;
+	}
+
+	for (j = 0; j < p->operating_classes_nr; j++) {
+		p->operating_class[j].op_class = radio->supp_opclass[j].id;
+		p->operating_class[j].max_tx_power = radio->supp_opclass[j].max_txpower;
+		p->operating_class[j].non_op_ch_nr = radio->supp_opclass[j].num_exclude_channels;
+		if (p->operating_class[j].non_op_ch_nr > 0) {
+			p->operating_class[j].channel =
+					(uint8_t *)calloc(p->operating_class[j].non_op_ch_nr,
+					sizeof(uint8_t));
+			if (p->operating_class[j].channel) {
+				memcpy(p->operating_class[j].channel, radio->supp_opclass[j].exclude_chanlist,
+						p->operating_class[j].non_op_ch_nr);
+			}
+		}
+	}
+
+	return p;
+}
+
+struct tlv_ap_vht_cap *agent_gen_ap_vht_caps(struct agent *a,
+		struct cmdu_cstruct *cmdu, uint32_t radio_index)
+{
+	struct tlv_ap_vht_cap *p;
+	struct wifi_radio_element *radio;
+	struct netif_fh *fh;
+
+	radio = a->radios + radio_index;
+
+	fh = wifi_radio_to_ap(a, radio->name);
+	if (!fh)
+		return NULL;
+
+	p = (struct tlv_ap_vht_cap *)calloc(1,
+			sizeof(struct tlv_ap_vht_cap));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_AP_VHT_CAPABILITIES;
+	memcpy(p->radio_id, radio->macaddr, 6);
+	memcpy(&p->vht_tx_mcs_supported, &fh->caps.mcs.vht_mcs_txmap, 2);
+	memcpy(&p->vht_rx_mcs_supported, &fh->caps.mcs.vht_mcs_rxmap, 2);
+	p->max_tx_streams_supported = (fh->tx_spatial_streams - 1);
+	p->max_rx_streams_supported = (fh->rx_spatial_streams - 1);
+	p->gi_80_support = fh->caps.vht[4] & (1 << 1) ? 1 : 0;
+	p->gi_160_support = fh->caps.vht[4] & (1 << 0) ? 1 : 0;
+	p->vht_8080_support = fh->caps.vht[5] & (1 << 7) ? 1 : 0;
+	p->vht_160_support = fh->caps.vht[5] & (1 << 6) ? 1 : 0;
+	p->su_beamformer_capable = fh->caps.vht[5] & (1 << 5) ? 1 : 0;
+	p->mu_beamformer_capable = fh->caps.vht[5] & (1 << 4) ? 1 : 0;
+
+	return p;
+}
+
+struct tlv_profile2_ap_cap *agent_gen_profile2_ap_cap(struct agent *a,
+		struct cmdu_cstruct *cmdu)
+{
+	struct tlv_profile2_ap_cap *p;
+
+	p = (struct tlv_profile2_ap_cap *)calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_PROFILE2_AP_CAPABILITY;
+	p->byte_counter = 0;
+	p->max_vids = (uint8_t)255;
+
+	return p;
+}
+
+struct tlv_ap_radio_adv_cap *agent_gen_ap_radio_adv_cap(struct agent *a,
+		struct cmdu_cstruct *cmdu, struct wifi_radio_element *radio)
+{
+	struct tlv_ap_radio_adv_cap *p;
+
+	p = (struct tlv_ap_radio_adv_cap *) calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_AP_RADIO_ADV_CAPABILITY;
+	memcpy(p->radio_id, radio->macaddr, 6);
+	p->combined_front_back = 0;
+	p->combined_p1_p2 = (a->cfg.profile == 0x02);
+
+	return p;
+}
+
+struct tlv_wsc *agent_gen_wsc(struct agent *a, struct cmdu_cstruct *cmdu,
+		struct wifi_radio_element *radio)
+{
+	struct tlv_wsc *p;
+	struct wsc_key *key;
+	int rv;
+	uint16_t len = 0;
+
+	p = (struct tlv_wsc *) calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = TLV_TYPE_WSC;
+
+	// TODO: auth_type uses dummy value (WPA2PSK)
+	// TODO: remove iface name from wscbuildm1 lib func
+	rv = wscBuildM1(radio->name, &p->wsc_frame, &len, &key, a->al_mac,
+			radio->band, 0x0020, 0);
+	if (!rv)
+		goto fail_p;
+
+	p->wsc_frame_size = len;
+	radio->autconfig.m1_size = len;
+
+	// discard previous frame if it has not been used
+	if (radio->autconfig.m1_frame)
+		free(radio->autconfig.m1_frame);
+	radio->autconfig.m1_frame = calloc(1, len);
+	if (!radio->autconfig.m1_frame)
+		goto fail_key;
+
+	memcpy(radio->autconfig.m1_frame, p->wsc_frame, len);
+	// discard previous key if it has not been used
+	if (radio->autconfig.key) {
+		free(radio->autconfig.key->key);
+		free(radio->autconfig.key);
+	}
+	radio->autconfig.key = key;
+
+	return p;
+fail_key:
+	free(key);
+fail_p:
+	map_free_tlv_cstruct((uint8_t *) p);
+	return NULL;
+}
\ No newline at end of file
diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c400bfdbc9fc003c4daac32db13e3713ea16a50
--- /dev/null
+++ b/src/core/agent_tlv_generator.h
@@ -0,0 +1,27 @@
+/*
+ * agent_tlv_generator.h - tlv building function declarations
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: jakob.olsson@iopsys.eu
+ *
+ */
+
+#ifndef CNTLR_TLV_GEN_H
+#define CNTLR_TLV_GEN_H
+
+struct tlv_ap_ht_cap *agent_gen_ap_ht_caps(struct agent *a,
+		struct cmdu_cstruct *cmdu, uint32_t radio_index);
+struct tlv_ap_cap *agent_gen_ap_caps(struct agent *a,
+		struct cmdu_cstruct *cmdu);
+struct tlv_ap_radio_basic_cap *agent_gen_ap_radio_basic_cap(struct agent *a,
+		struct cmdu_cstruct *cmdu, uint32_t radio_index);
+struct tlv_ap_vht_cap *agent_gen_ap_vht_caps(struct agent *a,
+		struct cmdu_cstruct *cmdu, uint32_t radio_index);
+struct tlv_profile2_ap_cap *agent_gen_profile2_ap_cap(struct agent *a,
+		struct cmdu_cstruct *cmdu);
+struct tlv_ap_radio_adv_cap *agent_gen_ap_radio_adv_cap(struct agent *a,
+		struct cmdu_cstruct *cmdu, struct wifi_radio_element *radio);
+struct tlv_wsc *agent_gen_wsc(struct agent *a, struct cmdu_cstruct *cmdu,
+		struct wifi_radio_element *radio);
+#endif
diff --git a/src/core/agent_ubus.c b/src/core/agent_ubus.c
index f36af1f56a4cdfb863f03f4cb6c168d01b6c76ee..c1e9c75ee5b095dbc123c0fe5636c69a28ffa789 100644
--- a/src/core/agent_ubus.c
+++ b/src/core/agent_ubus.c
@@ -16,6 +16,8 @@
 #include <libubus.h>
 #include <uci.h>
 
+#include <map1905/map2.h>
+#include <map1905/maputils.h>
 
 #include <easy/easy.h>
 #include <wifi.h>
@@ -92,7 +94,6 @@ static const struct blobmsg_policy cmd_params[_CMD_MAX] = {
 	[CMD_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING },
 };
 
-
 enum {
 	CFG_POLICY_AGENT,
 	CFG_POLICY_BSSID,
@@ -104,6 +105,17 @@ static const struct blobmsg_policy config_policy_params[__CFG_POLICY_MAX] = {
 	[CFG_POLICY_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
 };
 
+enum {
+	SEARCH_POLICY_AGENT,
+	SEARCH_POLICY_EGRESS,
+	__SEARCH_POLICY_MAX,
+};
+
+static const struct blobmsg_policy search_policy_params[__SEARCH_POLICY_MAX] = {
+	[SEARCH_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING },
+	[SEARCH_POLICY_EGRESS] = { .name = "egress", .type = BLOBMSG_TYPE_STRING }
+};
+
 static int steer_policy(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *req, const char *method,
 		      struct blob_attr *msg)
@@ -363,13 +375,9 @@ static int agent_config_ap(struct ubus_context *ctx, struct ubus_object *obj,
 	struct agent *a = container_of(obj, struct agent, obj);
 	struct blob_attr *tb[__CFG_POLICY_MAX];
 	char agent[18] = {0}, bssidstr[18] = {0};
-
+	struct wifi_radio_element *radio, *found = NULL;
 	uint8_t hwaddr[6] = {0}, bssid[6] = {0};
-	struct cmdu_cstruct *cmdu;
-	struct tlv_ap_radio_identifier *p = NULL;
-	struct tlv_default_8021q_settings *p1;
-	struct tlv_traffic_sep_policy *p2;
-	int i, tlv_index = 0;
+	int i;
 
 	blobmsg_parse(config_policy_params, __CFG_POLICY_MAX, tb,
 			blob_data(msg), blob_len(msg));
@@ -389,26 +397,121 @@ static int agent_config_ap(struct ubus_context *ctx, struct ubus_object *obj,
 	if (!hwaddr_aton(bssidstr, bssid))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
-	build_ap_autoconfig_wsc(a, hwaddr, bssid);
+	for (i = 0; i < a->num_radios; i++) {
+		radio = a->radios + i;
 
-	/*
-	else if (tb[CFG_POLICY_RADIO]) {
-		char radio[18] = {0};
-		struct netif_radio *r;
+		if (memcmp(radio->macaddr, bssid, 6))
+			continue;
+		found = radio;
+	}
+	if (!found)
+		return UBUS_STATUS_UNKNOWN_ERROR;
 
-		strncpy(radio, blobmsg_data(tb[CFG_POLICY_RADIO]),
-				sizeof(radio) - 1);
-		r = cntlr_radio_to_bssid(c, radio);
-		if (!r) {
-			free(cmdu);
-			return UBUS_STATUS_UNKNOWN_ERROR;
-		}
+	build_ap_autoconfig_wsc(a, hwaddr, radio, i);
+
+	return 0;
+}
+
+
+static int agent_ap_search(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct agent *a = container_of(obj, struct agent, obj);
+	struct blob_attr *tb[__SEARCH_POLICY_MAX];
+	struct cmdu_cstruct *cmdu;
+	struct tlv_supp_service *p = NULL;
+	struct tlv_searched_service *p1;
+	struct tlv_map_profile *p2;
+	int i, tlv_index = 0;
+
+	blobmsg_parse(config_policy_params, __SEARCH_POLICY_MAX, tb,
+			blob_data(msg), blob_len(msg));
+
+	// TODO: ff:ff:ff:ff:ff:ff = send to all agents
+	cmdu = (struct cmdu_cstruct *)calloc(1,	sizeof(struct cmdu_cstruct));
+	if (!cmdu) {
+		fprintf(stderr, "failed to malloc cmdu\n");
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
 
-		p = cntlr_gen_config_ap_tlv(c, cmdu, r->hwaddr);
+	if (tb[SEARCH_POLICY_AGENT]) {
+		char agent[18] = {0};
+
+		strncpy(agent, blobmsg_data(tb[SEARCH_POLICY_AGENT]),
+				sizeof(agent) - 1);
+		if (!hwaddr_aton(agent, cmdu->origin))
+			return UBUS_STATUS_UNKNOWN_ERROR;
 	}
-	*/
 
+	if (tb[SEARCH_POLICY_EGRESS])
+		strncpy(cmdu->intf_name, blobmsg_data(tb[SEARCH_POLICY_EGRESS]),
+				sizeof(cmdu->intf_name) - 1);
+	else
+		strncpy(cmdu->intf_name, "br-lan", sizeof(cmdu->intf_name) - 1);
+
+	cmdu->message_type = CMDU_TYPE_AP_AUTOCONFIGURATION_SEARCH;
+
+	p = calloc(1, sizeof(struct tlv_supp_service));
+	if (!p)
+		goto fail_cmdu;
+
+	cmdu->num_tlvs++;
+	p->tlv_type = MAP_TLV_SUPPORTED_SERVICE;
+	p->supported_services_list = 1;
+	p->supported_services = calloc(p->supported_services_list,
+			sizeof(*p->supported_services));
+	if (!p->supported_services)
+		goto fail_p;
+
+	for (i = 0; i < p->supported_services_list; i++)
+		p->supported_services[i].service = SUPPORTED_SERVICE_MULTIAP_AGENT;
+
+	p1 = calloc(1, sizeof(struct tlv_searched_service));
+	if (!p1)
+		goto fail_p;
+
+	cmdu->num_tlvs++;
+	p1->tlv_type = MAP_TLV_SEARCHED_SERVICE;
+	p1->searched_services_list = 1;
+	p1->service = calloc(p1->searched_services_list, sizeof(*p1->service));
+	if (!p1->service)
+		goto fail_p1;
+
+	for (i = 0; i < p->supported_services_list; i++)
+		p->supported_services[i].service = SEARCHED_SERVICE_MULTIAP_CONTROLLER;
+
+	p2 = calloc(1, sizeof(struct tlv_map_profile));
+	if (!p2)
+		goto fail_p1;
+
+	cmdu->num_tlvs++;
+	p2->tlv_type = MAP_TLV_MULTIAP_PROFILE;
+	p2->profile = 0x02;
+
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs,
+			sizeof(uint8_t *));
+
+	if (!cmdu->tlvs)
+		goto fail_p2;
+
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p;
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+
+	agent_send_cmdu(a, cmdu);
+	map_free_cmdu(cmdu);
 	return 0;
+
+fail_p2:
+	map_free_tlv_cstruct((uint8_t *) p2);
+fail_p1:
+	map_free_tlv_cstruct((uint8_t *) p1);
+fail_p:
+	map_free_tlv_cstruct((uint8_t *) p);
+fail_cmdu:
+	free(cmdu);
+	return UBUS_STATUS_UNKNOWN_ERROR;
 }
 
 int agent_publish_object(struct agent *a, const char *objname)
@@ -416,7 +519,8 @@ int agent_publish_object(struct agent *a, const char *objname)
 	struct ubus_object *obj;
 	struct ubus_object_type *obj_type;
 	struct ubus_method *obj_methods;
-	struct ubus_method m[7] = {
+	struct ubus_method m[8] = {
+		UBUS_METHOD("ap_search", agent_ap_search, search_policy_params),
 		UBUS_METHOD("config_ap", agent_config_ap, config_policy_params),
 		UBUS_METHOD("steer_policy", steer_policy, steer_policy_params),
 		UBUS_METHOD("steer", steer, steer_params),
@@ -505,8 +609,11 @@ int agent_publish_object(struct agent *a, const char *objname)
 
 void agent_remove_object(struct agent *a)
 {
-	if (a->ubus_ctx && a->obj.id != OBJECT_INVALID)
+	if (a->ubus_ctx && a->obj.id != OBJECT_INVALID) {
 		ubus_remove_object(a->ubus_ctx, &a->obj);
+		free(a->obj.type);
+		free((void *) a->obj.methods);
+	}
 }
 
 /*
diff --git a/src/core/config.c b/src/core/config.c
index c95fbe3908b7551ff2f58ce890a7f132f105eeac..a9c229fac82753dd428b8ad57e1478f534e2ba5a 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -32,6 +32,25 @@
 #include "worker.h"
 #include "agent.h"
 
+#define WPS_AUTH_OPEN          (0x0001)
+#define WPS_AUTH_WPAPSK        (0x0002)
+#define WPS_AUTH_SHARED        (0x0004)	/* deprecated */
+#define WPS_AUTH_WPA           (0x0008)
+#define WPS_AUTH_WPA2          (0x0010)
+#define WPS_AUTH_WPA2PSK       (0x0020)
+#define WPS_ENCR_NONE          (0x0001)
+#define WPS_ENCR_WEP           (0x0002)	/* deprecated */
+#define WPS_ENCR_TKIP          (0x0004)
+#define WPS_ENCR_AES           (0x0008)
+
+// UCI sections
+#define UCI_BK_AGENT "bk-iface"
+#define UCI_FH_AGENT "fh-iface"
+#define UCI_WLAN_IFACE "wifi-iface"
+#define UCI_WIRELESS "wireless"
+#define UCI_IEEE1905 "ieee1905"
+#define UCI_AGENT "agent"
+
 int verbose;
 
 static int set_value(struct uci_context *ctx, struct uci_package *pkg,
@@ -54,8 +73,8 @@ static int set_value(struct uci_context *ctx, struct uci_package *pkg,
 	return -1;
 }
 
-static struct uci_section *wifi_get_iface_section(struct uci_context *ctx,
-		struct uci_package *pkg, char *ifname)
+static struct uci_section *config_get_iface_section(struct uci_context *ctx,
+		struct uci_package *pkg, const char *type, const char *ifname)
 {
 
 	struct uci_element *e;
@@ -66,7 +85,7 @@ static struct uci_section *wifi_get_iface_section(struct uci_context *ctx,
 		const char *c_ifname;
 
 		section = uci_to_section(e);
-		if (strcmp(section->type, "wifi-iface"))
+		if (strcmp(section->type, type))
 			continue;
 
 		c_ifname = uci_lookup_option_string(ctx, section, "ifname");
@@ -77,12 +96,45 @@ static struct uci_section *wifi_get_iface_section(struct uci_context *ctx,
 	return NULL;
 }
 
+int config_del_iface(const char *config, const char *type, const char *ifname)
+{
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_section *section;
+	struct uci_ptr ptr = {0};
+	int rv = -1;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		goto out;
+
+	if (uci_load(ctx, config, &pkg) != UCI_OK) {
+		dbg("config file 'wireless' not found!\n");
+		goto out_uci;
+	}
+
+	section = config_get_iface_section(ctx, pkg, type, ifname);
+	if (!section)
+		goto out_pkg;
+
+	ptr.p = pkg;
+	ptr.s = section;
+
+	uci_delete(ctx, &ptr);
+	uci_commit(ctx, &pkg, false);
+out_pkg:
+	uci_unload(ctx, pkg);
+out_uci:
+	uci_free_context(ctx);
+out:
+	return rv;
+}
+
 int wifi_apply_iface_cfg(const char *ifname, const char *encryption,
 		const char *ssid, const char *key)
 {
 	struct uci_context *ctx;
 	struct uci_package *pkg;
-	struct uci_element *e;
 	struct uci_section *section;
 	int rv = -1;
 
@@ -95,7 +147,7 @@ int wifi_apply_iface_cfg(const char *ifname, const char *encryption,
 		goto out_uci;
 	}
 
-	section = wifi_get_iface_section(ctx, pkg, ifname);
+	section = config_get_iface_section(ctx, pkg, "wifi-iface", ifname);
 	if (!section)
 		goto out_pkg;
 
@@ -113,8 +165,468 @@ out:
 	return rv;
 }
 
+int config_add_section(const char *config, const char *type, const char *ifname)
+{
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_section *section;
+	struct uci_ptr ptr = {0};
+	int rv = -1;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		goto out;
+
+	if (uci_load(ctx, config, &pkg) != UCI_OK) {
+		dbg("config file '%s' not found!\n", config);
+		goto out_uci;
+	}
+
+	section = config_get_iface_section(ctx, pkg, type, ifname);
+	if (section)
+		goto out_pkg;
+
+	rv = uci_add_section(ctx, pkg, type, &section);
+	if (rv)
+		goto out_pkg;
+
+	rv = uci_save(ctx, pkg);
+	if (rv)
+		goto out_pkg;
+
+	ptr.value = ifname;
+	ptr.package = config;
+	ptr.section = section->e.name;
+	ptr.option = "ifname";
+	ptr.target = UCI_TYPE_OPTION;
+
+	uci_lookup_ptr(ctx, &ptr, NULL, false);
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+	uci_commit(ctx, &pkg, false);
+out_pkg:
+	uci_unload(ctx, pkg);
+out_uci:
+	uci_free_context(ctx);
+out:
+	return rv;
+}
+
+int config_add_default_wifi_iface(const char *config, const char *type,
+		const char *ifname, const char *device, const char *network,
+		const char *mode)
+{
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_section *section;
+	int rv = -1;
+
+	rv = config_add_section(config, type, ifname);
+	if (rv)
+		return -1;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		goto out;
+
+	if (uci_load(ctx, config, &pkg) != UCI_OK) {
+		dbg("config file 'wireless' not found!\n");
+		goto out_uci;
+	}
+
+	section = config_get_iface_section(ctx, pkg, type, ifname);
+	if (!section)
+		goto out_pkg;
+
+	set_value(ctx, pkg, section, "device", device, UCI_TYPE_STRING);
+	set_value(ctx, pkg, section, "network", network, UCI_TYPE_STRING);
+	//set_value(ctx, pkg, section, "mode", mode, UCI_TYPE_STRING);
+
+	uci_commit(ctx, &pkg, false);
+
+out_pkg:
+	uci_unload(ctx, pkg);
+out_uci:
+	uci_free_context(ctx);
+out:
+	return rv;
+}
+
+int config_add_default_agent_iface(const char *config, const char *type,
+		const char *ifname, enum wifi_band band)
+{
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_section *section;
+	int rv = -1;
+
+	rv = config_add_section(config, type, ifname);
+	if (rv)
+		return -1;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		goto out;
+
+	if (uci_load(ctx, config, &pkg) != UCI_OK) {
+		dbg("config file 'wireless' not found!\n");
+		goto out_uci;
+	}
+
+	section = config_get_iface_section(ctx, pkg, type, ifname);
+	if (!section)
+		goto out_pkg;
+
+	trace("band = %d\n", band);
+
+	if (band == BAND_5)
+		set_value(ctx, pkg, section, "band", "5", UCI_TYPE_STRING);
+	if (band == BAND_2)
+		set_value(ctx, pkg, section, "band", "2", UCI_TYPE_STRING);
+
+	uci_commit(ctx, &pkg, false);
+
+out_pkg:
+	uci_unload(ctx, pkg);
+out_uci:
+	uci_free_context(ctx);
+out:
+	return rv;
+}
+
+/* below functions are mostly taken from ieee1905d */
+static bool uci_check_wifi_iface(char *package_name, char *ifname,
+		char *section)
+{
+	bool ret;
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_element *e;
+
+	if (!package_name || !ifname)
+		return false;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return false;
+
+	if (uci_load(ctx, package_name, &pkg)) {
+		uci_free_context(ctx);
+		return false;
+	}
+
+	ret = false;
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_section *s = uci_to_section(e);
+
+		if (!strcmp(s->type, section)) {
+			struct uci_option *opt = uci_lookup_option(ctx, s,
+					"ifname");
+
+			if (!opt || opt->type != UCI_TYPE_STRING)
+				continue;
+			if (strcmp(opt->v.string, ifname) == 0) {
+				ret = true;
+				break;
+			}
+		}
+	}
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
+
+	return ret;
+}
+
+static bool uci_set_wireless_interface_option(char *package_name,
+		char *section_type, char *ifname, char *option, char *value)
+{
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_element *e;
+
+	if (!package_name || !ifname || !option || !value)
+		return false;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return false;
+
+	if (uci_load(ctx, package_name, &pkg)) {
+		uci_free_context(ctx);
+		return false;
+	}
+
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_section *s = uci_to_section(e);
+
+		if (!strcmp(s->type, section_type)) {
+			struct uci_option *opt = uci_lookup_option(ctx, s,
+					"ifname");
+
+			if (!opt || opt->type != UCI_TYPE_STRING)
+				continue;
+			if (strcmp(opt->v.string, ifname) == 0) {
+				struct uci_ptr ptr = {0};
+
+				ptr.value = value;
+				ptr.package = package_name;
+				ptr.section = s->e.name;
+				ptr.option = option;
+				ptr.target = UCI_TYPE_OPTION;
+				if (uci_lookup_ptr(ctx, &ptr, NULL, false) ||
+						!UCI_LOOKUP_COMPLETE)
+					break;
+				if (uci_set(ctx, &ptr) == UCI_OK)
+					uci_save(ctx, ptr.p);
+				break;
+			}
+		}
+	}
+	uci_commit(ctx, &pkg, false);
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
+	return false;
+}
+
+static bool get_encryption_value(uint16_t auth_type, uint16_t encryption_type,
+		char *encrypt_val, size_t elen)
+{
+	if (!encrypt_val)
+		return false;
+
+	if ((auth_type & WPS_AUTH_WPAPSK) && (auth_type & WPS_AUTH_WPA2PSK))
+		strncat(encrypt_val, "psk-mixed", elen);
+	else if ((auth_type & WPS_AUTH_WPA) && (auth_type & WPS_AUTH_WPA2))
+		strncat(encrypt_val, "wpa-mixed", elen);
+	else if (auth_type & WPS_AUTH_WPAPSK)
+		strncat(encrypt_val, "psk", elen);
+	else if (auth_type & WPS_AUTH_WPA2PSK)
+		strncat(encrypt_val, "psk2", elen);
+	else if (auth_type & WPS_AUTH_WPA)
+		strncat(encrypt_val, "wpa", elen);
+	else if (auth_type & WPS_AUTH_WPA2)
+		strncat(encrypt_val, "wpa2", elen);
+	else
+		return false;
+
+	//Check for the encryption type
+	if ((encryption_type & WPS_ENCR_TKIP) &&
+			(encryption_type & WPS_ENCR_AES))
+		strncat(encrypt_val, "+tkip+aes", elen);
+	else if (encryption_type & WPS_ENCR_TKIP)
+		strncat(encrypt_val, "+tkip", elen);
+	else if (encryption_type & WPS_ENCR_AES)
+		strncat(encrypt_val, "+aes", elen);
+
+	return true;
+}
+
+static bool uci_add_wireless_iface_sec(char *package_name, char *interface_name,
+		char *section_name)
+{
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_section *s;
+
+	if (!interface_name || !package_name)
+		return false;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return false;
+
+	if (uci_load(ctx, package_name, &pkg)) {
+		uci_free_context(ctx);
+		return false;
+	}
+
+	if (uci_add_section(ctx, pkg, section_name, &s) == UCI_OK) {
+		struct uci_ptr ptr = {0};
+
+		if (uci_save(ctx, pkg) != UCI_OK)
+			return false;
+
+		ptr.value = interface_name;
+		ptr.package = package_name;
+		ptr.section = s->e.name;
+		ptr.option = "ifname";
+		ptr.target = UCI_TYPE_OPTION;
+		uci_lookup_ptr(ctx, &ptr, NULL, false);
+
+		uci_set(ctx, &ptr);
+		uci_save(ctx, ptr.p);
+		uci_commit(ctx, &pkg, false);
+	}
+
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
+
+	return true;
+}
+
+static int ubus_call(const char *object, const char *method,
+		struct blob_buf *data, void *callback, void *cb_arg)
+{
+	uint32_t id;
+	struct ubus_context *ctx = ubus_connect(NULL);
+
+	if (!ctx) {
+		err("ubus_connect failed\n");
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	if (ubus_lookup_id(ctx, object, &id)) {
+		err("(%s) not present\n", object);
+		ubus_free(ctx);
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	// Invoke Ubus to get data from uspd
+	if (ubus_invoke(ctx, id, method, data->head, callback, cb_arg, 1000)) {
+		err("ubus call failed\n");
+		ubus_free(ctx);
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	ubus_free(ctx);
+	return UBUS_STATUS_OK;
+}
+
+static bool uci_reload_services(void)
+{
+	struct blob_buf bb;
+
+	memset(&bb, 0, sizeof(struct blob_buf));
+	blob_buf_init(&bb, 0);
+
+	info("## Reloading uci config\n");
+	if (!ubus_call("uci", "reload_config", &bb, NULL, NULL))
+		return true;
+
+	blob_buf_free(&bb);
+
+	return false;
+}
+
+int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
+		uint16_t auth_type, uint16_t encryption_type,
+		uint8_t *network_key, uint8_t mapie, uint8_t band)
+{
+	bool ret;
+	char auth_type_str[20] = {0};
+	char multiap_str[2] = {0};
+	uint8_t multi_ap = 0;
+	bool sta_mode;
+	char band_str[2] = {0};
+
+	dbg("Applying WSC configuration (%s):\n", interface_name);
+	dbg("  - SSID            : %s\n", ssid);
+	dbg("  - BSSID           : %02x:%02x:%02x:%02x:%02x:%02x\n",
+	     bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+	dbg("  - AUTH_TYPE       : 0x%04x\n", auth_type);
+	dbg("  - ENCRYPTION_TYPE : 0x%04x\n", encryption_type);
+	dbg("  - NETWORK_KEY     : %s\n", network_key);
+	dbg("  - MAPIE_EXTENSION : 0x%02x\n", mapie);
+
+	// if teardown bit is set, return
+	if (BIT(3, mapie))
+		return M2_PROCESS_TEARDOWN;
+
+	multi_ap |= (BIT(5, mapie) << 1);
+	multi_ap |= BIT(6, mapie);
+	sta_mode = BIT(7, mapie);
+
+	snprintf(multiap_str, sizeof(multiap_str), "%d", multi_ap);
+
+	if (!get_encryption_value(auth_type, encryption_type,
+			auth_type_str, 20)) {
+		info("Unsupported encryption or cipher received!!\n");
+		return M2_PROCESS_ERROR;
+	}
+
+	// Set uci in agent
+	ret = uci_check_wifi_iface(UCI_AGENT, interface_name,
+			(sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT));
+	if (!ret) {
+		ret = uci_add_wireless_iface_sec(UCI_AGENT, interface_name,
+				(sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT));
+		if (!ret)
+			return M2_PROCESS_ERROR;
+	}
+
+	printf("%s band = %d\n", __func__, band);
+
+	if (band == BAND_5)
+		strncpy(band_str, "5", 1);
+	else if (band == BAND_2)
+		strncpy(band_str, "2", 1);
+	else /* TODO: 60 */
+		return M2_PROCESS_ERROR;
+
+	uci_set_wireless_interface_option(UCI_AGENT,
+			(sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT),
+			interface_name, "band",
+			band_str);
+	if (sta_mode) {
+		char disallow_str[2] = {0};
+
+		snprintf(disallow_str, sizeof(disallow_str), "%d",
+				((mapie >> 2) & 0x03));
+		uci_set_wireless_interface_option(UCI_AGENT,
+				(sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT),
+				interface_name,
+				"disallow_bsta", disallow_str);
+	}
+
+	// Set uci in ieee1905
+	ret = uci_check_wifi_iface(UCI_IEEE1905, interface_name,
+			UCI_WLAN_IFACE);
+	if (!ret) {
+		ret = uci_add_wireless_iface_sec(UCI_IEEE1905, interface_name,
+				UCI_WLAN_IFACE);
+		if (!ret)
+			return M2_PROCESS_ERROR;
+	}
+
+	uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+			interface_name, "ssid", (char *) ssid);
+	uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+			interface_name, "key", (char *) network_key);
+	uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+			interface_name, "encryption", auth_type_str);
+	uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+			interface_name, "multi_ap", multiap_str);
+	uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+			interface_name, "mode", (sta_mode ? "sta" : "ap"));
+
+	// Set uci in wireless
+	ret = uci_check_wifi_iface(UCI_WIRELESS, interface_name,
+			UCI_WLAN_IFACE);
+	if (!ret) {
+		ret = uci_add_wireless_iface_sec(UCI_WIRELESS, interface_name,
+				UCI_WLAN_IFACE);
+		if (!ret)
+			return M2_PROCESS_ERROR;
+	}
+
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+			interface_name, "ssid", (char *) ssid);
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+			interface_name, "key", (char *) network_key);
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+			interface_name, "encryption", auth_type_str);
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+			interface_name, "multi_ap", multiap_str);
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+			interface_name, "mode", (sta_mode ? "sta" : "ap"));
+
+	uci_reload_services();
+	return M2_PROCESS_OK;
+}
+/* end of functions taken from ieee1905d */
+
 static struct netif_bkcfg *get_netif_bkcfg_by_name(struct agent_config *c,
-							const char *name)
+		const char *name)
 {
 	struct netif_bkcfg *p;
 
@@ -179,6 +691,29 @@ void stax_del_entry(struct list_head *h, char *sta_macstr)
 	}
 }
 
+static int clean_steer_btm_excl(struct netif_fhcfg *p)
+{
+	struct stax *n, *tmp;
+
+	list_for_each_entry_safe(n, tmp, &p->steer_btm_excludelist, list) {
+		list_del(&n->list);
+		free(n);
+	}
+
+	return 0;
+}
+static int clean_steer_excl(struct netif_fhcfg *p)
+{
+	struct stax *n, *tmp;
+
+	list_for_each_entry_safe(n, tmp, &p->steer_excludelist, list) {
+		list_del(&n->list);
+		free(n);
+	}
+
+	return 0;
+}
+
 void agent_config_dump(struct agent_config *cfg)
 {
 	struct netif_fhcfg *n;
@@ -314,6 +849,7 @@ struct netif_fhcfg *create_fronthaul_iface_config(struct agent_config *cfg,
 	new->steer_legacy_reassoc_secs = STEER_LEGACY_REASSOC_INT;
 	new->steer_legacy_retry_secs = STEER_LEGACY_RETRY_INT;
 	new->assoc_control_time = ASSOC_CONTROL_INT;
+	new->band = BAND_UNKNOWN;
 	INIT_LIST_HEAD(&new->steer_policylist);
 	/* nrules = get_registered_steer_rules(&pollist); */ /* TODO */
 	list_for_each_entry(r, &regd_steer_rules, list) {
@@ -352,7 +888,6 @@ struct netif_bkcfg *create_backhaul_iface_config(struct agent_config *cfg,
 							const char *ifname)
 {
 	struct netif_bkcfg *new;
-	struct steer_rule *r;
 
 	if (!cfg)
 		return NULL;
@@ -366,11 +901,12 @@ struct netif_bkcfg *create_backhaul_iface_config(struct agent_config *cfg,
 	snprintf(new->name, 16, "%s", ifname);
 	new->enabled = true;
 	new->onboarded = false;
+	new->band = BAND_UNKNOWN;
 
 	/* f->cfg = new; */
 	dbg("%s: %s netif_fh->cfg = %p\n", __func__, new->name, new);
 
-	list_add(&new->list, &cfg->fhlist);
+	list_add(&new->list, &cfg->bklist);
 
 	return new;
 }
@@ -590,7 +1126,7 @@ void register_config(struct config *c)
 }
 #endif
 
-static int cntlr_config_get_wifi_agent(struct agent_config *a,
+static int agent_config_get_wifi_agent(struct agent_config *a,
 						struct uci_section *s)
 {
 	enum {
@@ -623,17 +1159,19 @@ static int cntlr_config_get_wifi_agent(struct agent_config *a,
 	return 0;
 }
 
-static int cntlr_config_get_bk_iface(struct agent_config *a,
+static int agent_config_get_bk_iface(struct agent_config *a,
 						struct uci_section *s)
 {
 	enum {
 		BK_IFNAME,
+		BK_BAND,
 		BK_ENABLED,
 		BK_ONBOARDED,
 		NUM_POLICIES
 	};
 	const struct uci_parse_option opts[] = {
 		{ .name = "ifname", .type = UCI_TYPE_STRING },
+		{ .name = "band", .type = UCI_TYPE_STRING },
 		{ .name = "enabled", .type = UCI_TYPE_STRING },
 		{ .name = "onboarded", .type = UCI_TYPE_STRING }
 	};
@@ -667,14 +1205,24 @@ static int cntlr_config_get_bk_iface(struct agent_config *a,
 	if (tb[BK_ONBOARDED])
 		bk->onboarded = atoi(tb[BK_ONBOARDED]->v.string);
 
+	if (tb[BK_BAND]) {
+		int band = atoi(tb[BK_BAND]->v.string);
+
+		if (band == 2)
+			bk->band = BAND_2;
+		else if (band == 5)
+			bk->band = BAND_5;
+	}
+
 	return 0;
 }
 
-static int cntlr_config_get_fh_iface(struct agent_config *a,
+static int agent_config_get_fh_iface(struct agent_config *a,
 		struct uci_section *s)
 {
 	enum {
 		FH_IFNAME,
+		FH_BAND,
 		FH_STEER,
 		FH_EXCLUDE,
 		FH_EXCLUDE_BTM,
@@ -689,6 +1237,7 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
 	};
 	const struct uci_parse_option opts[] = {
 		{ .name = "ifname", .type = UCI_TYPE_STRING },
+		{ .name = "band", .type = UCI_TYPE_STRING },
 		{ .name = "steer", .type = UCI_TYPE_LIST },
 		{ .name = "exclude", .type = UCI_TYPE_LIST },
 		{ .name = "exclude_btm", .type = UCI_TYPE_LIST },
@@ -702,12 +1251,14 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
 	};
 	struct uci_option *tb[NUM_POLICIES];
 	struct netif_fhcfg *fh;
-	const char *ifname;
 
 	uci_parse_section(s, opts, NUM_POLICIES, tb);
 
 	if (tb[FH_IFNAME]) {
+		const char *ifname;
+
 		ifname = tb[FH_IFNAME]->v.string;
+
 		fh = get_netif_fhcfg_by_name(a, ifname);
 		if (!fh) {
 			fh = create_fronthaul_iface_config(a, ifname);
@@ -716,6 +1267,8 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
 				return -1;
 			}
 		} else {
+			clean_steer_btm_excl(fh);
+			clean_steer_excl(fh);
 			warn("Duplicate 'fh-iface %s' config!! ignore\n",
 					ifname);
 		}
@@ -724,6 +1277,15 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
 		return -1;
 	}
 
+	if (tb[FH_BAND]) {
+		int band = atoi(tb[FH_BAND]->v.string);
+
+		if (band == 2)
+			fh->band = BAND_2;
+		else if (band == 5)
+			fh->band = BAND_5;
+	}
+
 	if (tb[FH_STEER]) {
 		struct uci_element *xi;
 
@@ -793,8 +1355,8 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
 	return 0;
 }
 
-static int cntlr_config_get_steer_param(struct agent_config *a,
-						struct uci_section *s)
+static int agent_config_get_steer_param(struct agent_config *a,
+		struct uci_section *s)
 {
 	struct steer_rule *r;
 
@@ -818,9 +1380,6 @@ int agent_config_reload(struct agent_config *cfg)
 	cfg->enabled = false;
 	cfg->runfreq = AGENT_RUN_AUTO;
 
-	INIT_LIST_HEAD(&cfg->fhlist);
-	INIT_LIST_HEAD(&cfg->bklist);
-
 	ctx = uci_alloc_context();
 	if (!ctx)
 		return -1;
@@ -834,15 +1393,66 @@ int agent_config_reload(struct agent_config *cfg)
 		struct uci_section *s = uci_to_section(e);
 
 		if (!strcmp(s->type, "wifiagent"))
-			cntlr_config_get_wifi_agent(cfg, s);
+			agent_config_get_wifi_agent(cfg, s);
 		else if (!strcmp(s->type, "fh-iface"))
-			cntlr_config_get_fh_iface(cfg, s);
+			agent_config_get_fh_iface(cfg, s);
 		else if (!strcmp(s->type, "bk-iface"))
-			cntlr_config_get_bk_iface(cfg, s);
+			agent_config_get_bk_iface(cfg, s);
 		else if (!strcmp(s->type, "steer"))
-			cntlr_config_get_steer_param(cfg, s);
+			agent_config_get_steer_param(cfg, s);
 	}
 
 	uci_free_context(ctx);
 	return 0;
 }
+
+int agent_config_init(struct agent_config *cfg)
+{
+	INIT_LIST_HEAD(&cfg->fhlist);
+	INIT_LIST_HEAD(&cfg->bklist);
+
+	agent_config_reload(cfg);
+	return 0;
+}
+
+void clean_bk(struct netif_bkcfg *p)
+{
+	list_del(&p->list);
+	free(p);
+}
+
+int clean_all_bk(struct agent_config *cfg)
+{
+	struct netif_bkcfg *p, *tmp;
+
+	list_for_each_entry_safe(p, tmp, &cfg->bklist, list)
+		clean_bk(p);
+
+	return 0;
+}
+
+void clean_fh(struct netif_fhcfg *p)
+{
+	clean_steer_btm_excl(p);
+	clean_steer_excl(p);
+	list_del(&p->list);
+	free(p);
+}
+
+int clean_all_fh(struct agent_config *cfg)
+{
+	struct netif_fhcfg *p, *tmp;
+
+	list_for_each_entry_safe(p, tmp, &cfg->fhlist, list)
+		clean_fh(p);
+
+	return 0;
+}
+
+int agent_config_clean(struct agent_config *cfg)
+{
+	clean_all_fh(cfg);
+	clean_all_bk(cfg);
+
+	return 0;
+}
diff --git a/src/core/config.h b/src/core/config.h
index 211bb9e7424a7b28dfad076e3a6744c51b0cc890..566d2b99ab52dbbf8dedd545fe4bae9e92672709 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -10,6 +10,10 @@
 #ifndef CONFIG_H
 #define CONFIG_H
 
+// TODO: try to get rid of these
+#include <easy/easy.h>
+#include <wifi.h>
+
 #if 0
 enum steer_action {
 	STEER_DISABLE,     /** steer disallowed */
@@ -51,6 +55,7 @@ void stax_del_entry(struct list_head *h, char *sta_macstr);
  */
 struct netif_fhcfg {
 	char name[16];
+	enum wifi_band band;
 	bool enabled;
 	bool sta_steer_enabled;
 	bool assoc_control;
@@ -86,6 +91,7 @@ struct netif_fhcfg {
 
 struct netif_bkcfg {
 	char name[16];
+	enum wifi_band band;
 	bool enabled;
 	bool onboarded;
 	/* TODO: others as needed */
@@ -121,7 +127,16 @@ union config {
 
 struct agent;
 
+enum m2_process_status {
+	M2_PROCESS_OK,
+	M2_PROCESS_ERROR,
+	M2_PROCESS_TEARDOWN
+};
+
+
+int agent_config_init(struct agent_config *cfg);
 int agent_config_reload(struct agent_config *cfg);
+int agent_config_clean(struct agent_config *cfg);
 int agent_config_defaults(struct agent *a, struct agent_config *cfg);
 void agent_config_dump(struct agent_config *cfg);
 
@@ -138,5 +153,18 @@ int config_update2(const char *confname, struct agent_config *cfg,
 
 int wifi_apply_iface_cfg(const char *ifname, const char *encryption,
 		const char *ssid, const char *key);
-
+int config_del_iface(const char *config, const char *type, const char *ifname);
+int config_add_section(const char *config, const char *type, const char *ifname);
+int config_add_default_wifi_iface(const char *config, const char *type,
+		const char *ifname, const char *device, const char *network,
+		const char *mode);
+
+void clean_bk(struct netif_bkcfg *p);
+int clean_all_bk(struct agent_config *cfg);
+void clean_fh(struct netif_fhcfg *p);
+int clean_all_fh(struct agent_config *cfg);
+
+int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
+		uint16_t auth_type, uint16_t encryption_type,
+		uint8_t *network_key, uint8_t mapie, uint8_t band);
 #endif
diff --git a/src/utils/debug.c b/src/utils/debug.c
index a95e98d28ab569fe756fe3d4f80d42d87d9c85d7..77291aee5d0b61b67cb0a4a55f011e4fb1737569 100644
--- a/src/utils/debug.c
+++ b/src/utils/debug.c
@@ -221,5 +221,6 @@ void log_cmdu(int level, void *var)
 			continue;
 
 		log_test(level, btlv, len);
+		free(btlv);
 	}
 }
diff --git a/src/utils/utils.c b/src/utils/utils.c
index 3e720ea58eb503e177f66f7759fa96b16ba9ec50..62872845b3cde10d781029505b498b28114107d7 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -91,6 +91,7 @@ char *btostr(unsigned char *bytes, int len, char *str)
 	for (i = 0; i < len; i++)
 		sprintf(str + strlen(str), "%02x", bytes[i] & 0xff);
 
+
 	return str;
 }
 
diff --git a/src/utils/utils.h b/src/utils/utils.h
index 6b00df0f734eecd8dba6463f76019660f8d97dca..bdde468c60083796cb1c2353f404080f3b441fa1 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -10,6 +10,7 @@
 #ifndef UTILS_H
 #define UTILS_H
 
+#include <arpa/inet.h>
 #include <time.h>
 #include <stdbool.h>
 #include <json-c/json.h>
@@ -20,6 +21,7 @@
 
 #define hwaddr_hash(a)	(a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5])
 
+#define BIT(m, x)      ((x >> m) & 0x0001)
 
 bool match_oui0(unsigned char *oui, unsigned char *hwaddr, int ouis);
 unsigned char *hwaddr_aton(const char *macstr, unsigned char *mac);
@@ -47,7 +49,7 @@ unsigned char *strtob(char *str, int len, unsigned char *bytes);
 char *btostr(unsigned char *bytes, int len, char *str);
 
 /* utility wrappers over json-c functions */
-int json_get_bool(struct json_object *object, const char *key);
+bool json_get_bool(struct json_object *object, const char *key);
 int json_get_int(struct json_object *object, const char *key);
 const char *json_get_string(struct json_object *object, const char *key);