From e229d97da9bee400a828744fba73b681a73d8779 Mon Sep 17 00:00:00 2001
From: Jakob Olsson <jakob.olsson@iopsys.eu>
Date: Wed, 2 Dec 2020 16:27:28 +0100
Subject: [PATCH] map-agent: Multi-AP Onboarding (Section 5) and AP-Autoconfig
 support (Section 7.1)

---
 src/Makefile                    |   3 +
 src/agent.conf                  |   4 +-
 src/core/agent.c                | 406 ++++++++++++++++++++++------
 src/core/agent.h                |  31 ++-
 src/core/agent_cmdu_generator.c | 162 +++++++++++
 src/core/agent_cmdu_generator.h |  16 ++
 src/core/agent_map.c            | 459 ++++++++++++++++++++------------
 src/core/agent_map.h            |   1 +
 src/core/agent_tlv_generator.c  |  79 +++++-
 src/core/agent_tlv_generator.h  |   5 +
 src/core/agent_ubus.c           | 144 +++-------
 src/core/config.c               | 368 ++++++++++++++++---------
 src/core/config.h               |  24 +-
 src/utils/brcm_nl.c             | 109 ++++++++
 src/utils/brcm_nl.h             |   6 +
 src/utils/debug.c               |   1 -
 src/utils/utils.c               |  24 ++
 src/utils/utils.h               |   1 +
 18 files changed, 1333 insertions(+), 510 deletions(-)
 create mode 100644 src/core/agent_cmdu_generator.c
 create mode 100644 src/core/agent_cmdu_generator.h
 create mode 100644 src/utils/brcm_nl.c
 create mode 100644 src/utils/brcm_nl.h

diff --git a/src/Makefile b/src/Makefile
index 24642f6a2..dc001c4fc 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,6 +5,7 @@ CFLAGS+= -g -Wall
 OBJS = \
 	utils/debug.o \
 	utils/liblist.o \
+	utils/brcm_nl.o \
 	utils/utils.o \
 
 IPC_OBJS = \
@@ -19,11 +20,13 @@ AGENT_OBJS = \
 	core/agent.o \
 	core/agent_map.o \
 	core/agent_tlv_generator.o \
+	core/agent_cmdu_generator.o \
 	core/config.o \
 	core/main.o \
 	core/plugin.o
 
 LIBS = -lubus -lubox -ljson-c -lblobmsg_json -luci -lwifi-6 -leasy -pthread
+LIBS += -I/usr/include/libnl3 -lnl-3 -lnl-route-3
 LIBS += -rdynamic -ldl
 LIBS += -lmaputils
 LIBS += -lwsc
diff --git a/src/agent.conf b/src/agent.conf
index 5d6f795ba..8edf1b0d1 100644
--- a/src/agent.conf
+++ b/src/agent.conf
@@ -1,10 +1,11 @@
-config wifiagent
+config agent agent
 	option enabled '1'
 	option debug '6'
 	option profile '2'
 
 config fh-iface
 	option ifname 'wl0'
+	option device 'wl0'
 	option steer 'rssi bssload'
 	list exclude '00:11:22:33:44:55'
 	list exclude_btm '00:aa:bb:cc:dd:ee'
@@ -19,6 +20,7 @@ config fh-iface
 
 config fh-iface
 	option ifname 'wl1'
+	option device 'wl1'
 	option steer 'rssi bssload'
 	list exclude '00:11:22:33:44:55'
 	list exclude_btm '00:aa:bb:cc:dd:ee'
diff --git a/src/core/agent.c b/src/core/agent.c
index 32e63dae0..ada6ba07b 100644
--- a/src/core/agent.c
+++ b/src/core/agent.c
@@ -27,6 +27,9 @@
 #include <sys/ioctl.h>
 #include <net/if_arp.h>
 
+#include <netinet/in.h>
+#include <net/if.h>
+
 #include <pthread.h>
 
 #include <map1905/map2.h>
@@ -53,6 +56,9 @@
 #include "agent_ubus.h"
 #include "agent_map.h"
 #include "plugin.h"
+#include "agent_cmdu_generator.h"
+#include "brcm_nl.h"
+
 
 static struct agent *this_agent;
 static int signal_pending;
@@ -92,6 +98,48 @@ static void agent_sighandler(int sig)
 	signal_pending = sig;
 }
 
+
+const char *wifi_ifname_to_radio(struct agent *a, char *ifname)
+{
+	int i, j;
+	const char *ret;
+
+	for (i = 0; i < WIFI_DEVICE_MAX_NUM; i++) {
+		for (j = 0; j < WIFI_IFACE_MAX_NUM; j++) {
+			if (a->ifs[i].iface[j].name &&
+				a->ifs[i].iface[j].name[0] != '\0' &&
+				!strncmp(a->ifs[i].iface[j].name, ifname, 15)) {
+
+				ret = a->ifs[i].radio;
+				return ret;
+			}
+		}
+	}
+	return NULL;
+}
+
+struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a,
+		char *ifname)
+{
+	int i;
+	const char *radio;
+
+	radio = wifi_ifname_to_radio(a, ifname);
+	if (!radio)
+		return NULL;
+
+	for (i = 0; i < WIFI_DEVICE_MAX_NUM; i++) {
+		if (a->radios[i].name &&
+			a->radios[i].name[0] != '\0' &&
+			!strncmp(a->radios[i].name, radio, 15)) {
+
+			return &a->radios[i];
+		}
+	}
+
+	return NULL;
+}
+
 static void wifiagent_log_steer(struct agent *a,
 				unsigned char *stamac,
 				char *vifname,
@@ -1405,7 +1453,7 @@ out:
 static void wifi_sta_event_handler(void *c, struct blob_attr *msg)
 {
 	struct agent *a = (struct agent *)c;
-	const char ifname[16] = {0}, event[16] = {0};
+	char ifname[16] = {0}, event[16] = {0};
 	struct blob_attr *tb[3];
 	static const struct blobmsg_policy ev_attr[3] = {
 		[0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
@@ -1431,7 +1479,7 @@ static void wifi_sta_event_handler(void *c, struct blob_attr *msg)
 			[0] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
 			[1] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
 		};
-		const char mac_str[18] = {0}, bssid_str[18] = {0};
+		char mac_str[18] = {0}, bssid_str[18] = {0};
 		uint8_t mac[6] = {0}, bssid[6] = {0};
 
 		blobmsg_parse(data_attr, 2, data, blobmsg_data(tb[2]),
@@ -1461,7 +1509,7 @@ static void wifi_sta_event_handler(void *c, struct blob_attr *msg)
 			[1] = { .name = "target_bssid", .type = BLOBMSG_TYPE_STRING },
 			[2] = { .name = "status", .type = BLOBMSG_TYPE_STRING },
 		};
-		const char mac_str[18] = {0}, bssid_str[18] = {0};
+		char mac_str[18] = {0}, bssid_str[18] = {0};
 		uint8_t mac[6] = {0}, bssid[6] = {0};
 		int status;
 
@@ -1499,7 +1547,7 @@ static void wifi_sta_event_handler(void *c, struct blob_attr *msg)
 		static const struct blobmsg_policy data_attr[1] = {
 			[0] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
 		};
-		const char mac_str[18] = {0};
+		char mac_str[18] = {0};
 		uint8_t mac[6] = {0};
 		struct sta *s;
 
@@ -1541,7 +1589,7 @@ static int wifi_parse_frame(struct agent *a, struct json_object *frameobj)
 	if (!frame)
 		return -1;
 
-	if (!strtob(framestr, len, frame))
+	if (!strtob((char *)framestr, len, frame))
 		goto out_frame;
 
 	new = calloc(1, sizeof(*new));
@@ -1756,6 +1804,95 @@ static void wifi_radio_event_handler(void *c, struct blob_attr *msg)
 	dbg("%s: Unhandled!!! TODO\n", __func__);
 }
 
+static int wifi_mod_bridge(struct agent *a, char *ifname, char *action)
+{
+	char bridge[16] = {0};
+	char cmd[256] = {0};
+	struct blob_buf bb = {0};
+	int ret;
+	uint32_t id;
+
+	if (!uci_get_bridge(ifname, bridge))
+		return -1;
+
+	/* add wds iface to bridge */
+
+	snprintf(cmd, sizeof(cmd), "network.interface.%s", bridge);
+
+	trace("%s interface %s to bridge %s using netifd API\n",
+			(!strcmp(action, "add") ? "Adding" : "Deleting"),
+			ifname, bridge);
+
+	blob_buf_init(&bb, 0);
+
+	blobmsg_add_string(&bb, "name", ifname);
+
+	id = ubus_get_object(a->ubus_ctx, cmd);
+	snprintf(cmd, sizeof(cmd), "%s_device", action);
+	ret = ubus_invoke(a->ubus_ctx, id, cmd, bb.head,
+			NULL, NULL, 3 * 1000);
+
+	blob_buf_free(&bb);
+	return ret;
+}
+
+
+static int if_setip(const char *name, uint32_t ipaddr)
+{
+	int fd;
+	struct ifreq ifr;
+	struct sockaddr_in sin;
+
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (fd == -1)
+		return -1;
+
+	strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+	memset(&sin, 0, sizeof(struct sockaddr));
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = ipaddr;
+
+	memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
+	if (ioctl(fd, SIOCSIFADDR, &ifr) < 0)
+		return -1;
+
+	return 0;
+}
+
+static void agent_add_to_bridge(struct agent *a, char *ifname)
+{
+	struct ip_address addrs[32] = {0};
+	int no_addrs = 32;
+	char buf[256] = {0};
+
+	if (if_isbridge_interface(ifname) > 0)
+		return;
+
+	trace("|%s:%d| Triggering dhcp on %s\n", __func__, __LINE__,
+			ifname);
+
+	/* TODO: can we figure a better solution for chrCmd? */
+	chrCmd(buf, sizeof(buf),
+			"timeout 2 udhcpc -i %s > /dev/null 2>&1",
+			ifname);
+
+	if_getaddrs(ifname, addrs, &no_addrs);
+
+	dbg("|%s:%d| no_addrs: %d\n", __func__, __LINE__, no_addrs);
+
+	if (no_addrs > 0) {
+		trace("|%s:%d| first ip addr: %s\n", __func__, __LINE__,
+				inet_ntoa(addrs[0].addr.ip4));
+		trace("|%s:%d| Attempting to add interface (%s) "\
+				" to the bridge\n", __func__, __LINE__,
+				ifname);
+		wifi_mod_bridge(a, ifname, "add");
+
+		if_setip(ifname, 0);
+	}
+}
+
 static void wifi_bsta_event_handler(void *c, struct blob_attr *msg)
 {
 	char ifname[16] = {0}, event[16] = {0}, bssid_str[18] = {0};
@@ -1770,15 +1907,24 @@ static void wifi_bsta_event_handler(void *c, struct blob_attr *msg)
 	struct tlv_backhaul_steer_resp *p;
 	uint8_t bssid[6] = {0};
 	struct cmdu_cstruct *cmdu;
+	bool add, del;
 
 	blobmsg_parse(ev_attr, 3, tb, blob_data(msg), blob_len(msg));
 
 	if (!tb[0] || !tb[1] || !tb[2])
 		return;
 
+
 	strncpy(ifname,	blobmsg_data(tb[0]), sizeof(ifname) - 1);
 	strncpy(event, blobmsg_data(tb[1]), sizeof(event) - 1);
 
+	bk = find_bkhaul_by_ifname(a, ifname);
+	if (!bk)
+		return;
+
+	add = !strcmp(event, "connected");
+	del = !strcmp(event, "disconnected");
+
 	if (tb[2]) {
 		struct blob_attr *data[1];
 		static const struct blobmsg_policy data_attr[1] = {
@@ -1792,9 +1938,23 @@ static void wifi_bsta_event_handler(void *c, struct blob_attr *msg)
 				sizeof(bssid_str) - 1);
 	}
 
-	bk = find_bkhaul_by_ifname(a, ifname);
-	if (!bk)
-		return;
+	if (add) {
+		struct cmdu_cstruct *autoconfig_cmdu;
+
+		bk->connected = true;
+		if (!a->configured) {
+			time(&a->autocfg);
+			uloop_timeout_set(&a->autocfg_dispatcher, 2 * 1000); // 2 seconds
+		} else {
+			trace("Autoconfig already completed, will not trigger" \
+					" again on bsta connection\n");
+			/* if (a->cfg.brcm_setup) */
+				agent_add_to_bridge(a, ifname);
+		}
+	} else if (del) {
+		bk->connected = false;
+		wifi_mod_bridge(a, ifname, "remove");
+	}
 
 	cmdu = bk->bsta_steer.cmdu;
 	if (!cmdu)
@@ -1807,6 +1967,11 @@ static void wifi_bsta_event_handler(void *c, struct blob_attr *msg)
 
 	hwaddr_aton(bssid_str, bssid);
 
+	/**
+	 * if event bssid and tlv target bssid differ, that means steering
+	 * failed, add an error TLV prior to sending response
+	 */
+	//TODO: move to if(add)?
 	if (memcmp(bssid, p->bssid, 6)) {
 		struct tlv_error_code *p1;
 		uint8_t **tlvs;
@@ -1844,12 +2009,15 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 	char encryption[32] = {0}, ifname[16] = {0}, ssid[33] = {0},
 			key[64] = {0};
 	struct blob_attr *tb[4];
+	struct wifi_radio_element *radio;
+	struct agent *a = (struct agent *) c;
 	static const struct blobmsg_policy ap_attr[4] = {
 		[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 },
 	};
+	int ret;
 
 	blobmsg_parse(ap_attr, 4, tb, blob_data(msg), blob_len(msg));
 
@@ -1862,6 +2030,25 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 	strncpy(key, blobmsg_data(tb[3]), sizeof(key) - 1);
 
 	wifi_apply_iface_cfg(ifname, encryption, ssid, key);
+
+	/* set agent section to onboarded */
+	ret = uci_check_wifi_iface("mapagent", ifname, "bk-iface");
+	if (!ret) {
+		ret = uci_add_wireless_iface_sec("mapagent", ifname,
+				"bk-iface");
+		if (!ret)
+			return;
+	}
+	uci_set_wireless_interface_option("mapagent", "bk-iface", ifname,
+			"onboarded", "1");
+
+	uci_reload_services();
+
+	radio = wifi_ifname_to_radio_element(a, ifname);
+	if (!radio)
+		return;
+
+	radio->onboarded = 1;
 }
 
 static void ubus_wifi_event_handler(struct ubus_context *ctx,
@@ -1999,9 +2186,9 @@ static void ieee1905_cmdu_event_handler(void *c, struct blob_attr *msg)
 }
 
 static void ubus_1905_event_handler(struct ubus_context *ctx,
-					struct ubus_event_handler *ev,
-					const char *type,
-					struct blob_attr *msg)
+		struct ubus_event_handler *ev,
+		const char *type,
+		struct blob_attr *msg)
 {
 	int i;
 	char *str;
@@ -2394,7 +2581,7 @@ static int run_agent(struct agent *a)
 	return 0;
 }
 
-static void parse_al_mac(struct ubus_request *req, int type,
+static void parse_almac(struct ubus_request *req, int type,
 		struct blob_attr *msg)
 {
 	struct agent *a = (struct agent *)req->priv;
@@ -2409,8 +2596,8 @@ static void parse_al_mac(struct ubus_request *req, int type,
 		char *mac;
 
 		mac = blobmsg_get_string(tb[0]);
-		hwaddr_aton(mac, a->al_mac);
-		dbg("almac = " MACFMT "\n", MAC2STR(a->al_mac));
+		hwaddr_aton(mac, a->almac);
+		dbg("almac = " MACFMT "\n", MAC2STR(a->almac));
 	}
 }
 
@@ -2418,8 +2605,8 @@ 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[10];
-	static const struct blobmsg_policy radio_attr[10] = {
+	struct blob_attr *tb[11];
+	static const struct blobmsg_policy radio_attr[11] = {
 		[0] = { .name = "isup", .type = BLOBMSG_TYPE_BOOL },
 		[1] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
 		[2] = { .name = "noise", .type = BLOBMSG_TYPE_INT32 },
@@ -2430,9 +2617,10 @@ static void parse_radio(struct ubus_request *req, int type,
 		[7] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 },
 		[8] = { .name = "regdomain", .type = BLOBMSG_TYPE_STRING },
 		[9] = { .name = "txpower", .type = BLOBMSG_TYPE_INT32 },
+		[10] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING },
 	};
 
-	blobmsg_parse(radio_attr, 10, tb, blob_data(msg), blob_len(msg));
+	blobmsg_parse(radio_attr, 11, tb, blob_data(msg), blob_len(msg));
 
 	if (tb[0])
 		re->enabled = blobmsg_get_bool(tb[0]);
@@ -2515,6 +2703,7 @@ static void parse_radio(struct ubus_request *req, int type,
 							re->supp_opclass[i].num_exclude_channels * sizeof(uint8_t));
 				}
 			}
+
 			i++;
 		}
 	}
@@ -2530,6 +2719,16 @@ static void parse_radio(struct ubus_request *req, int type,
 
 	if (tb[9])
 		re->current_txpower_percent = (uint8_t) blobmsg_get_u32(tb[9]);
+
+	if (tb[10]) {
+		// TODO: uncomment when radio mac is fixed in wifimngr
+		//char macaddr[18] = {0};
+
+		re->macaddr[5] = atoi(re->name+2);
+		//strncpy(macaddr, blobmsg_data(tb[10]), 17);
+		//if (!hwaddr_aton(macaddr, re->macaddr))
+		//	return;
+	}
 }
 
 static void _enumerate_wifi_objects(struct ubus_request *req, int type,
@@ -2699,47 +2898,6 @@ static void netif_free_all(struct agent *a)
 		netif_free(p);
 }
 
-const char *wifi_ifname_to_radio(struct agent *a, char *ifname)
-{
-	int i, j;
-	const char *ret;
-
-	for (i = 0; i < WIFI_DEVICE_MAX_NUM; i++) {
-		for (j = 0; j < WIFI_IFACE_MAX_NUM; j++) {
-			if (a->ifs[i].iface[j].name &&
-				a->ifs[i].iface[j].name[0] != '\0' &&
-				!strncmp(a->ifs[i].iface[j].name, ifname, 15)) {
-
-				ret = a->ifs[i].radio;
-				return ret;
-			}
-		}
-	}
-	return NULL;
-}
-
-struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a,
-		char *ifname)
-{
-	int i;
-	const char *radio;
-
-	radio = wifi_ifname_to_radio(a, ifname);
-	if (!radio)
-		return NULL;
-
-	for (i = 0; i < WIFI_DEVICE_MAX_NUM; i++) {
-		if (a->radios[i].name &&
-			a->radios[i].name[0] != '\0' &&
-			!strncmp(a->radios[i].name, radio, 15)) {
-
-			return &a->radios[i];
-		}
-	}
-
-	return NULL;
-}
-
 /* get first ap on the radio */
 // TODO: fixme: get base interface based on macaddr instead?
 struct netif_fh *wifi_radio_to_ap(struct agent *a, const char *radio)
@@ -2830,7 +2988,6 @@ static void parse_bk(struct ubus_request *req, int type,
 static void parse_ap(struct ubus_request *req, int type,
 		struct blob_attr *msg)
 {
-	struct wifi_radio_element *radio;
 	struct netif_fh *fh = (struct netif_fh *)req->priv;
 	char bssid[18] = { 0 }, ifname[16] = { 0 };
 	struct blob_attr *tb[4];
@@ -2850,7 +3007,8 @@ static void parse_ap(struct ubus_request *req, int type,
 	strncpy(fh->name, blobmsg_data(tb[0]), 15);
 
 	strncpy(bssid, blobmsg_data(tb[1]), 17);
-	hwaddr_aton(bssid, fh->bssid);
+	if (!hwaddr_aton(bssid, fh->bssid))
+		return;
 
 	fh->channel = blobmsg_get_u8(tb[2]);
 
@@ -2870,14 +3028,7 @@ static void parse_ap(struct ubus_request *req, int type,
 			parse_dot11ac(fh, data[1]);
 	}
 
-	if (!hwaddr_aton(bssid, fh->bssid))
-		return;
-
-	radio = wifi_ifname_to_radio_element(fh->agent, ifname);
-	if (!radio)
-		return;
 
-	memcpy(radio->macaddr, fh->bssid, 6);
 }
 
 /* Initialize netif_fh/bk structs from ubus wifi objects */
@@ -2891,7 +3042,7 @@ static int agent_init_interfaces(struct agent *a)
 
 	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);
+		ubus_call_object(a, ieee1905_obj, "info", parse_almac, a);
 	} else {
 		warn("Object '%s' not present!\n");
 		return -1;
@@ -2991,6 +3142,18 @@ static int agent_init_interfaces(struct agent *a)
 
 			ubus_call_object(a, wobj, "status", parse_bk, bn);
 		}
+
+		if (b->onboarded) {
+			struct wifi_radio_element *re;
+
+			re = wifi_ifname_to_radio_element(a, b->name);
+			if (!re)
+				continue;
+
+			re->onboarded = 1;
+			trace("radio (%s) has been onboarded\n", re->name);
+		}
+
 	}
 
 	return 0;
@@ -3034,6 +3197,54 @@ static void agent_steering_opp_timeout(struct uloop_timeout *t)
 	send_sta_steer_complete((void *)a, origin, ifname);
 }
 
+/* TODO: is it possible to pass private 'reason'? i.e. switch case (reason) */
+static void agent_dispatch_autoconfig(struct uloop_timeout *t)
+{
+	struct agent *a = container_of(t, struct agent, autocfg_dispatcher);
+	int diff;
+	time_t now;
+	struct netif_bk *bk;
+	int i;
+
+	time(&now);
+
+	trace("|%s:%d| Attempting to trigger AP-Autoconfig\n", __func__, __LINE__);
+
+	diff = difftime(now, a->autocfg);
+	dbg("|%s:%d| Time since AP-Auotconfig was triggered %d(s)\n", __func__, __LINE__, diff);
+	/* if more than 2 minutes has passed since triggered, stop */
+	if (a->configured && diff > 2 * 60) {
+		dbg("|%s:%d| Diff exceeds 2 minutes and agent is configured, "\
+				"will not retrigger\n", __func__, __LINE__);
+		return;
+	}
+
+	/* Only applicable for bSTA interfaces */
+	list_for_each_entry(bk, &a->bklist, list) {
+		if (!bk->connected)
+			continue;
+
+		agent_add_to_bridge(a, bk->name);
+	}
+
+	for (i = 0; i < a->num_radios; i++) {
+		struct cmdu_cstruct *cmdu;
+		struct wifi_radio_element *radio = &a->radios[i];
+
+		cmdu = agent_gen_ap_autoconfig_search(a, radio, NULL, 0x02);
+		if (!cmdu)
+			continue;
+
+		trace("|%s:%d| Sending Autoconfig Search for radio %s(%s)\n",
+				__func__, __LINE__, radio->name,
+				(radio->band == BAND_2 ? "2.4GHz" : "5GHz"));
+		agent_send_cmdu(a, cmdu);
+		map_free_cmdu(cmdu);
+	}
+
+	uloop_timeout_set(&a->autocfg_dispatcher, 15 * 1000);
+}
+
 static struct msg *agent_msg_enqueue(struct agent *a, int id,
 						char *data, int len)
 {
@@ -3103,8 +3314,11 @@ void clear_fhlist(struct agent *a)
 
 int start_agent(void)
 {
+	struct cmdu_cstruct *autoconfig_cmdu;
 	struct agent *w;
 	struct ubus_context *ctx;
+	pthread_t tid[1];
+	struct netif_fhcfg *f;
 
 	signal_pending = 0;
 	set_sighandler(SIGINT, agent_sighandler);
@@ -3146,6 +3360,20 @@ int start_agent(void)
 	ubus_add_uloop(ctx);
 
 	agent_config_init(&w->cfg);
+
+	memcpy(w->cntlr_almac, w->cfg.cntlr_almac, 6);
+	if (w->cfg.brcm_setup) {
+		int ret;
+
+		/* TODO: memory management of thread on cleaup */
+		ret = pthread_create(&(tid[0]), NULL, (void *)&brcm_nl_loop,
+				NULL);
+		if (ret) {
+			fprintf(stderr, "Failed to create thread\n");
+			return -1;
+		}
+	}
+
 	//agent_config_reload(&w->cfg);
 	//agent_config_defaults(w, &w->cfg);
 #if 0
@@ -3155,12 +3383,26 @@ int start_agent(void)
 #endif
 	get_registered_steer_rules();	/* TODO: return rule list and improve */
 
+	list_for_each_entry(f, &w->cfg.fhlist, list) {
+		for (;;) {
+			uint32_t flags;
+
+			if_getflags(f->name, &flags);
+			if (flags & IFF_UP)
+				break;
+
+			sleep(2);
+		}
+	}
+
 	agent_init_interfaces(w);
 
 	ubus_register_event_handler(ctx, &w->wifi_evh, "wifi.*");
 	ubus_register_event_handler(ctx, &w->wifi_evh, "wps_credentials");
 	ubus_register_event_handler(ctx, &w->ieee1905_evh, "ieee1905.*");
 
+	w->autocfg_dispatcher.cb = agent_dispatch_autoconfig;
+
 	w->heartbeat.cb = agent_periodic_run;
 	uloop_timeout_set(&w->heartbeat, 1 * 1000);
 
@@ -3177,6 +3419,12 @@ int start_agent(void)
 	w->sta_steerlist_count = 0;
 	w->sta_steer_req_timer.cb = agent_steering_opp_timeout;
 
+	autoconfig_cmdu = agent_gen_ap_autoconfig_search(w,
+			MULTICAST_ADDR_HEX, NULL, 0x02);
+	agent_add_cmdu(w, autoconfig_cmdu);
+	time(&w->autocfg);
+	uloop_timeout_set(&w->autocfg_dispatcher, 2 * 1000); // 2 seconds
+
 	uloop_run();
 
 /* out_and_exit: */
@@ -3194,6 +3442,18 @@ int start_agent(void)
 	return 0;
 }
 
+struct wsc_data *agent_free_wsc_data(struct wsc_data *wsc)
+{
+	if (wsc->m1_frame)
+		free(wsc->m1_frame);
+	if (wsc->key) {
+		free(wsc->key->key);
+		free(wsc->key);
+	}
+
+	return NULL;
+}
+
 void agent_free_radios(struct agent *a)
 {
 	int i;
@@ -3210,14 +3470,10 @@ void agent_free_radios(struct agent *a)
 		}
 
 		free(re->supp_opclass);
+		agent_free_wsc_data(&re->autconfig);
+		re->autconfig.key = NULL;
+		re->autconfig.m1_frame = NULL;
 
-		// 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);
-		}
 	}
 }
 
diff --git a/src/core/agent.h b/src/core/agent.h
index 8c10a5ac4..fc81cdd45 100644
--- a/src/core/agent.h
+++ b/src/core/agent.h
@@ -19,11 +19,6 @@
 #define MAX_STA 20
 typedef char timestamp_t[32];
 
-typedef struct ipaddress {
-	uint8_t ver;
-	uint8_t addr[16];
-} ipaddr_t;
-
 /* defined in agent/main.c */
 extern const char *ubus_socket;
 extern const char *pidfile;
@@ -193,6 +188,7 @@ struct netif_bk {
 	int channel;
 	unsigned char bssid[6];
 	char ssid[33];
+	bool connected;
 	struct netif_bkcfg *cfg;
 	/* enum netif_type iftype; */
 	struct list_head list;
@@ -261,7 +257,7 @@ struct wifi_sta_element {
 	uint32_t tx_errors;
 	uint32_t rx_errors;
 	uint32_t rtx_pkts;            /* total retransmitted packets */
-	ipaddr_t ipaddr;
+	struct ip_address ipaddr;
 	char hostname[128];
 	uint8_t num_bcn_reports;
 	uint8_t *bcn_reportlist;      /* list of beacon reports */
@@ -330,10 +326,17 @@ struct wifi_unassoc_sta_element {
 	uint8_t rssi;
 };
 
+struct wsc_data {
+	uint8_t *m1_frame;
+	uint16_t m1_size;
+	struct wsc_key *key;
+};
+
 struct wifi_radio_element {
 	char name[16];
 	uint8_t macaddr[6];
 	uint8_t country_code[2];
+	bool onboarded;
 	enum wifi_band band;
 	bool enabled;
 	int anpi;
@@ -365,11 +368,7 @@ struct wifi_radio_element {
 	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 wsc_data autconfig;
 };
 
 struct wifi_netdev {
@@ -385,11 +384,18 @@ struct wifi_sta_steer_list {
 	uint8_t complete;
 };
 
+#define CMDU_QUEUE_MAX 8
+
 /** struct agent - wifi agent */
 struct agent {
 	int debug;
-	uint8_t al_mac[6];
+	uint8_t almac[6];
+	uint8_t cntlr_almac[6];
 	struct uloop_timeout heartbeat;
+	bool configured;
+	time_t autocfg;
+	struct uloop_timeout autocfg_dispatcher;
+	struct cmdu_cstruct *cmdu_queue[CMDU_QUEUE_MAX];
 	struct list_head fhlist;
 	struct list_head bklist;
 	struct list_head framelist;
@@ -418,6 +424,7 @@ struct agent {
 };
 
 struct netif_bk *find_bkhaul_by_bssid(struct agent *a, uint8_t *bssid);
+struct wsc_data *agent_free_wsc_data(struct wsc_data *wsc);
 
 extern int start_agent(void);
 extern void stop_agent(struct agent *a);
diff --git a/src/core/agent_cmdu_generator.c b/src/core/agent_cmdu_generator.c
new file mode 100644
index 000000000..faa258700
--- /dev/null
+++ b/src/core/agent_cmdu_generator.c
@@ -0,0 +1,162 @@
+/*
+ * 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 <uci.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"
+#include "agent_cmdu_generator.h"
+
+struct cmdu_cstruct *agent_gen_ap_autoconfig_search(struct agent *a,
+		struct wifi_radio_element *radio, char *intf_name,
+		uint8_t profile)
+{
+	struct cmdu_cstruct *cmdu;
+	struct tlv_supp_service *p = NULL;
+	struct tlv_searched_service *p1;
+	struct tlv_map_profile *p2;
+	struct tlv_al_mac *p3;
+	struct tlv_autoconf_freq_band *p4;
+	struct tlv_searched_role *p5;
+	int i, tlv_index = 0;
+	uint8_t band = 0;
+
+	cmdu = (struct cmdu_cstruct *)calloc(1,	sizeof(struct cmdu_cstruct));
+	if (!cmdu) {
+		fprintf(stderr, "failed to malloc cmdu\n");
+		return NULL;
+	}
+
+	memcpy(cmdu->origin, "\x01\x80\xc2\x00\x00\x13", 6);
+	if (intf_name)
+		strncpy(cmdu->intf_name, intf_name,
+				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 = profile;
+
+	p3 = agent_gen_al_mac(a, a->almac);
+	if (!p3)
+		goto fail_p2;
+	cmdu->num_tlvs++;
+
+	band = wifi_band_to_ieee1905band(radio->band);
+
+	p4 = agent_gen_autoconf_freq_band(a, band);
+	if (!p4)
+		goto fail_p3;
+	cmdu->num_tlvs++;
+
+	p5 = agent_gen_searched_role(a, 0x00); /* registrar */
+	if (!p5)
+		goto fail_p4;
+	cmdu->num_tlvs++;
+
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs,
+			sizeof(uint8_t *));
+	if (!cmdu->tlvs)
+		goto fail_p5;
+
+	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;
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p4;
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p5;
+
+	return cmdu;
+fail_p5:
+	map_free_tlv_cstruct((uint8_t *) p5);
+fail_p4:
+	map_free_tlv_cstruct((uint8_t *) p4);
+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 NULL;
+}
diff --git a/src/core/agent_cmdu_generator.h b/src/core/agent_cmdu_generator.h
new file mode 100644
index 000000000..acf40545f
--- /dev/null
+++ b/src/core/agent_cmdu_generator.h
@@ -0,0 +1,16 @@
+/*
+ * agent_tlv_generator.h - tlv building function declarations
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: jakob.olsson@iopsys.eu
+ *
+ */
+
+#ifndef AGENT_CMDU_GEN_H
+#define AGENT_CMDU_GEN_H
+
+struct cmdu_cstruct *agent_gen_ap_autoconfig_search(struct agent *a,
+		struct wifi_radio_element *radio, char *intf_name,
+		uint8_t profile);
+#endif
diff --git a/src/core/agent_map.c b/src/core/agent_map.c
index f409ef2eb..691e3273e 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -126,7 +126,10 @@ int build_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *rec_cmdu,
 	struct tlv_ap_radio_adv_cap *p2;
 	struct tlv_wsc *p3;
 	int tlv_index = 0;
-	uint16_t len = 0;
+
+	/* don't trigger autoconfig for bSTA radios */
+	if (radio->onboarded)
+		return -1;
 
 	cmdu = (struct cmdu_cstruct *)calloc(1, sizeof(struct cmdu_cstruct));
 	if (!cmdu) {
@@ -525,12 +528,53 @@ int handle_ap_autoconfig_response(void *agent, struct cmdu_cstruct *cmdu)
 	trace("agent: %s: --->\n", __func__);
 	struct agent *a = (struct agent *) agent;
 	struct wifi_radio_element *radio;
+	struct tlv_supp_service *supp_serv;
+	struct tlv_supported_freq_band *supp_freq;
+	char mac_str[18] = {0};
+	bool cntlr = false;
 	int i;
 
+	supp_serv = (struct tlv_supp_service *) extract_tlv_by_type(cmdu,
+			MAP_TLV_SUPPORTED_SERVICE);
+	if (!supp_serv)
+		return -1;
+
+	for (i = 0; i < supp_serv->supported_services_list; i++) {
+		if (supp_serv->supported_services[i].service == SUPPORTED_SERVICE_MULTIAP_CONTROLLER) {
+			cntlr = true;
+			break;
+		}
+	}
+
+	if (!cntlr) {
+		trace("agent: Autoconfig response was not from controller\n");
+		return -1;
+	}
+
+	memcpy(a->cntlr_almac, cmdu->origin, 6);
+	if (!hwaddr_ntoa(a->cntlr_almac, mac_str))
+		return -1;
+
+	set_value_by_string("mapagent", "agent", "controller_mac", mac_str,
+			UCI_TYPE_STRING);
+	uloop_timeout_cancel(&a->autocfg_dispatcher);
+
+	supp_freq = (struct tlv_supported_freq_band *) extract_tlv_by_type(cmdu,
+			TLV_TYPE_SUPPORTED_FREQ_BAND);
+	if (!supp_freq)
+		return -1;
+
 	for (i = 0; i < a->num_radios; i++) {
+		uint8_t band;
+
 		radio = a->radios + i;
+		band = wifi_band_to_ieee1905band(radio->band);
+		if (band != supp_freq->freq_band)
+			continue;
+
 		build_ap_autoconfig_wsc(a, cmdu, radio, i);
 	}
+
 	return 0;
 }
 
@@ -555,12 +599,38 @@ static struct wifi_radio_element *wifi_get_radio_by_mac(struct agent *a,
 int wifi_teardown_iface(const char *ifname)
 {
 	config_del_iface("wireless", "wifi-iface", ifname);
-	config_del_iface("ieee1905", "wifi-iface", ifname);
-	config_del_iface("agent", "fh-iface", ifname);
+	//config_del_iface("ieee1905", "wifi-iface", ifname);
+	config_del_iface("mapagent", "fh-iface", ifname);
+	config_del_iface("mapagent", "bk-iface", ifname);
 
 	return 0;
 }
 
+int wifi_teardown_map_ifaces_by_radio(struct agent *a, char *device)
+{
+	struct netif_fhcfg *fh, *fh_tmp;
+	struct netif_bkcfg *bk, *bk_tmp;
+
+	list_for_each_entry_safe(fh, fh_tmp, &a->cfg.fhlist, list) {
+		if (strncmp(fh->device, device, sizeof(fh->device) - 1))
+			continue;
+
+		wifi_teardown_iface(fh->name);
+		clean_fh(fh);
+	}
+
+	list_for_each_entry_safe(bk, bk_tmp, &a->cfg.bklist, list) {
+		if (strncmp(bk->device, device, sizeof(bk->device) - 1))
+			continue;
+
+		wifi_teardown_iface(bk->name);
+		clean_bk(bk);
+	}
+
+	agent_config_reload(&a->cfg);
+	return 0;
+}
+
 int wifi_teardown_map_ifaces_by_band(struct agent *a, enum wifi_band band)
 {
 	struct netif_fhcfg *fh, *fh_tmp;
@@ -658,6 +728,8 @@ char *wifi_gen_first_ifname(struct agent *a, char *device, char *ifname)
 {
 	int i;
 
+	strncpy(ifname, device, IFNAMSIZ);
+
 	/* 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
@@ -665,9 +737,14 @@ char *wifi_gen_first_ifname(struct agent *a, char *device, char *ifname)
 	 */
 	/* 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;
+
+		snprintf(ifname, IFNAMSIZ, "%s%s%d",
+				device,
+				(a->cfg.brcm_setup ? "." : "_"),
+				i);
 	}
 
 	return NULL;
@@ -695,9 +772,10 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
 	if (!radio)
 		return -1;
 
-	wifi_teardown_map_ifaces_by_band(a, radio->band);
+	dbg("|%s:%d| found radio = %s\n", __func__, __LINE__, radio->name);
 
-	// need iterate every TLV_TYPE_WSC, may be multiple
+	wifi_teardown_map_ifaces_by_radio(a, radio->name);
+	/* iterate every TLV_TYPE_WSC, may be multiple */
 	for (i = 0; i < cmdu->num_tlvs; i++) {
 		tlv = cmdu->tlvs[i];
 		switch (*tlv) {
@@ -723,11 +801,14 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
 					m2->wsc_frame,
 					m2->wsc_frame_size, &out, ifname);
 			if (!rv) {
-				err("Failed to process M2 target for interface"\
+				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
+
+				wifi_teardown_map_ifaces_by_radio(a,
+						radio->name);
+				/* Return rather than freeing because it may
+				 * belong to an updated frame
+				 */
 				return -1;
 			}
 
@@ -736,16 +817,16 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
 						"tearing down all MAP interfaces"\
 						" for bssid" MACFMT "\n",
 						MAC2STR(bssid));
-				wifi_teardown_map_ifaces_by_band(a, radio->band);
+				wifi_teardown_map_ifaces_by_radio(a,
+						radio->name);
 				goto teardown;
 			}
 
-			uci_apply_m2(ifname, out.output.ssid, out.output.bssid,
+			uci_apply_m2(ifname, radio->name, out.output.ssid,
 					out.output.auth_types,
 					out.output.encryption_types,
 					out.output.network_key,
 					out.output.mapie, radio->band);
-
 			break;
 		}
 		default:
@@ -754,16 +835,32 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
 		}
 	}
 
+	a->configured = true;
+	agent_config_reload(&a->cfg);
+	uci_apply_wps_credentials(&a->cfg, radio->band);
 teardown:
 	// TODO: freeing from here risks freeing an updated frame
-	free(radio->autconfig.m1_frame);
-	free(radio->autconfig.key->key);
-	free(radio->autconfig.key);
+	agent_free_wsc_data(&radio->autconfig);
 	radio->autconfig.key = NULL;
 	radio->autconfig.m1_frame = NULL;
+	uci_reload_services();
 	return 0;
 }
 
+int handle_ap_autoconfig_renew(void *agent, struct cmdu_cstruct *cmdu)
+{
+	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_1905_ack(void *agent, struct cmdu_cstruct *cmdu)
 {
@@ -776,7 +873,7 @@ int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 	trace("agent: %s: --->\n", __func__);
 	struct agent *a = (struct agent *) agent;
 	uint16_t tlv_index = 0;
-	uint32_t j;
+	uint32_t i;
 	struct cmdu_cstruct *cmdu;
 	struct tlv_ap_cap *p2;
 	struct tlv_ch_scan_cap *p5;
@@ -795,6 +892,7 @@ int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 	cmdu->message_type = CMDU_AP_CAPABILITY_REPORT;
 	memcpy(cmdu->origin, rec_cmdu->origin, 6);
 	cmdu->message_id = rec_cmdu->message_id;
+	strcpy(cmdu->intf_name, rec_cmdu->intf_name);
 
 	cmdu->num_tlvs = 3 * a->num_radios + 1; /* (Radio basic, HT, VHT capability per radio) */
 
@@ -809,10 +907,10 @@ int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 	}
 
 	/* AP basic Radio Capability TLV*/
-	for (j = 0; j < a->num_radios; j++) {
+	for (i = 0; i < a->num_radios; i++) {
 		struct tlv_ap_radio_basic_cap *p;
 
-		p = agent_gen_ap_radio_basic_cap(a, cmdu, j);
+		p = agent_gen_ap_radio_basic_cap(a, cmdu, i);
 		if (!p)
 			continue;
 		//cmdu->num_tlvs++;
@@ -828,10 +926,10 @@ int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 	cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
 
 	/* HT Capability */
-	for (j = 0; j < a->num_radios; j++) {
+	for (i = 0; i < a->num_radios; i++) {
 		struct tlv_ap_ht_cap *p3;
 
-		p3 = agent_gen_ap_ht_caps(a, cmdu, j);
+		p3 = agent_gen_ap_ht_caps(a, cmdu, i);
 		if (!p3)
 			continue;
 		//cmdu->num_tlvs++;
@@ -841,10 +939,10 @@ int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 	}
 
 	/* VHT Capability */
-	for (j = 0; j < a->num_radios; j++) {
+	for (i = 0; i < a->num_radios; i++) {
 		struct tlv_ap_vht_cap *p4;
 
-		p4 = agent_gen_ap_vht_caps(a, cmdu, j);
+		p4 = agent_gen_ap_vht_caps(a, cmdu, i);
 		if (!p4)
 			continue;
 
@@ -1037,77 +1135,87 @@ int handle_channel_pref_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 	return ret;
 }
 
-int handle_channel_sel_request(void *agent, struct cmdu_cstruct *cmdu)
+int send_channel_sel_response(void *agent, struct cmdu_cstruct *rec_cmdu,
+		struct channel_response *channel_resp,
+		uint32_t channel_response_nr)
 {
 	trace("agent: %s: --->\n", __func__);
 	struct agent *a = (struct agent *) agent;
-	int ret = 0;
-	struct channel_response channel_resp[MAX_RADIO];
-	uint32_t channel_resp_nr = 0, match = 0, found = 0;
-	int i, j, k, l, m;
-	uint8_t *tlv = NULL;
-	struct wifi_radio_element *radio;
-	uint32_t pref_tlv_present = 0;
+	uint16_t tlv_index = 0;
+	uint32_t j, ret = 0;
+	struct cmdu_cstruct *cmdu_data;
 
-	//Here we first need to update the channel preference values
-	//from the channel selection request
-	//then send the CMDU for channel selection response
+	cmdu_data = (struct cmdu_cstruct *)calloc(1,
+		sizeof(struct cmdu_cstruct));
 
-	if (cmdu->num_tlvs != 0) {
-		for (i = 0; i < cmdu->num_tlvs; i++) {
-			tlv = (uint8_t *) cmdu->tlvs[i];
-			switch (*tlv) {
-			case MAP_TLV_CHANNEL_PREFERENCE:
-				{
-					struct tlv_channel_pref  *p =
-						(struct tlv_channel_pref *)tlv;
-					pref_tlv_present = 1;
+	if (!cmdu_data) {
+		fprintf(stderr, "Out of memory!\n");
+		return -1;
+	}
 
-					ret = agent_process_channel_pref_tlv
-						(agent, p, channel_resp,
-						&channel_resp_nr);
-				}
-			case MAP_TLV_TRANSMIT_POWER_LIMIT:
-				{
-					struct tlv_tx_power_limit  *p =
-						(struct tlv_tx_power_limit *)tlv;
+	cmdu_data->message_type = CMDU_CHANNEL_SELECTION_RESPONSE;
+	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);
 
-					trace("tlv radio_id: " MACFMT "\n",
-						MAC2STR(p->radio_id));
-					for (l = 0; l < a->num_radios; l++) {
-						radio = a->radios + l;
-						match = memcmp(radio->macaddr, p->radio_id, 6);
-						if (match == 0) {
-							//Here we set the
-							//transmit_power_limit of the radio
-							radio->transmit_power_limit =
-								p->tx_power_limit;
-							trace("transmit power %d\n",
-								p->tx_power_limit);
-							break;
-						}
-					}
-				}
-			default:
-				break;
-			}
-		}
-	}
+	cmdu_data->num_tlvs = 1 * channel_response_nr; /* (channel selection response) */
+	cmdu_data->tlvs = (uint8_t **)calloc(cmdu_data->num_tlvs,
+				sizeof(uint8_t *));
 
-	if (cmdu->num_tlvs == 0 || pref_tlv_present == 0) {
-		//Here the condition is that the
-		//channel selection request have no tlvs or only transmit power tlv
-		//so we need to set all the prefernce in all radios to max 15
-		agent_fill_radio_max_preference(agent,
-			channel_resp, &channel_resp_nr);
+	if (!cmdu_data->tlvs) {
+		map_free_cmdu(cmdu_data);
+		return -1;
 	}
 
-	ret = send_channel_sel_response(agent, cmdu,
-		channel_resp, channel_resp_nr);
+	/* Operating Channel Response TLV 17.2.16 */
+	for (j = 0; j < channel_response_nr; j++) {
+		struct tlv_ch_selection_resp *p = NULL;
+		/* Here we need to check that the radio
+		 *response is for the radio for which we get request
+		 */
+		p = agent_gen_operate_channel_response(a, rec_cmdu,
+			channel_resp[j].radio_id, channel_resp[j].response);
+		if (!p)
+			continue;
+		cmdu_data->tlvs[tlv_index++] = (uint8_t *)p;
+	}
+	ret = agent_send_cmdu(a, cmdu_data);
+	map_free_cmdu(cmdu_data);
 
+	/* TODO send a report message for each radio. This will be
+	 * sent not here but on receiving of the event when the
+	 * actually radio channel poreference have been changed
+	 */
+	send_oper_channel_report(agent, rec_cmdu);
 	return ret;
 }
 
+int agent_fill_radio_max_preference(void *agent,
+		struct channel_response *channel_resp,
+		uint32_t *channel_response_nr)
+{
+	trace("agent: %s: --->\n", __func__);
+	struct agent *a = (struct agent *) agent;
+	uint32_t j = 0, k = 0, l = 0;
+	struct wifi_radio_element *radio = NULL;
+
+	*channel_response_nr = a->num_radios;
+
+	for (j = 0; j < a->num_radios; j++) {
+		radio = a->radios + j;
+		memcpy(channel_resp[j].radio_id, radio->macaddr, 6);
+
+		for (k = 0; k < radio->num_supp_opclass; k++) {
+			for (l = 0; l < radio->supp_opclass[k].
+				num_supported_channels; l++)
+				radio->supp_opclass[k].supp_chanlist[l].pref =
+				0xff;
+		}
+		channel_resp[j].response = 0x00;
+	}
+	return 0;
+}
+
 int agent_process_channel_pref_tlv(void *agent, struct tlv_channel_pref  *p,
 		struct channel_response *channel_resp,
 		uint32_t *channel_resp_nr)
@@ -1116,44 +1224,46 @@ int agent_process_channel_pref_tlv(void *agent, struct tlv_channel_pref  *p,
 	struct agent *a = (struct agent *) agent;
 	int ret = 0;
 	uint32_t  match = 0, found = 0;
-	int i, j, k, l, m;
+	int j, l;
 	struct wifi_radio_element *radio;
-	uint32_t pref_tlv_present = 0;
 
-	trace("\tradio_id: " MACFMT "\n",
-		MAC2STR(p->radio_id));
+	trace("\tradio_id: " MACFMT "\n", MAC2STR(p->radio_id));
 	for (l = 0; l < a->num_radios; l++) {
 		radio = a->radios + l;
 		match = memcmp(radio->macaddr, p->radio_id, 6);
 		if (match == 0) {
 			found = 1;
 			memcpy(channel_resp[*channel_resp_nr].radio_id,
-				radio->macaddr, 6);
+					radio->macaddr, 6);
 			channel_resp[*channel_resp_nr].response = 0x00;
 			break;
 		}
 	}
 	if (found == 0) {
 		memcpy(channel_resp[*channel_resp_nr].radio_id,
-			p->radio_id, 6);
-		//Here response code is a Reserved code
-		//to decline the request
+				p->radio_id, 6);
+		/* Here response code is a Reserved code
+		 * to decline the request
+		 */
 		channel_resp[*channel_resp_nr].response = 0x04;
 		*channel_resp_nr = *channel_resp_nr + 1;
 		return ret;
 	}
-	trace("ch_preference_op_class_nr: %d\n",
-		p->ch_preference_op_class_nr);
+	trace("ch_preference_op_class_nr: %d\n", p->ch_preference_op_class_nr);
 
 	for (j = 0; j < p->ch_preference_op_class_nr; j++) {
-		//Here we need to search the operating class in the radio
+		/* Here we need to search the operating class in the radio */
 		for (l = 0; l < radio->num_supp_opclass; l++) {
 			if (radio->supp_opclass[l].id ==  p->op_class[j].op_class) {
-				//Here we reset all the channels preferences in the
-				//operating class as 15 highest prefernce
+				int k;
+
+				/* Here we reset all the channels preferences
+				 * in the operating class as 15 highest
+				 * preference
+				 */
 				trace("op_class : %d channel_nr %d\n",
-					p->op_class[j].op_class,
-					p->op_class[j].channel_nr);
+						p->op_class[j].op_class,
+						p->op_class[j].channel_nr);
 
 				for (k = 0; k <
 					radio->supp_opclass[l].num_supported_channels;
@@ -1162,11 +1272,13 @@ int agent_process_channel_pref_tlv(void *agent, struct tlv_channel_pref  *p,
 						supp_chanlist[k].pref = 0xff;
 
 				for (k = 0; k < p->op_class[j].channel_nr; k++) {
+					int m;
+
 					for (m = 0; m <
 						radio->supp_opclass[l].
 						num_supported_channels ; m++) {
 						trace("channel  %d\n",
-							p->op_class[j].channel_list[k]);
+								p->op_class[j].channel_list[k]);
 						if (p->op_class[j].channel_list[k] ==
 							radio->supp_opclass[l].
 							supp_chanlist[m].channel) {
@@ -1175,7 +1287,7 @@ int agent_process_channel_pref_tlv(void *agent, struct tlv_channel_pref  *p,
 								p->op_class[j].preference;
 
 							trace("channel pref is %d\n",
-								p->op_class[j].preference);
+									p->op_class[j].preference);
 						}
 					}
 				}
@@ -1187,82 +1299,78 @@ int agent_process_channel_pref_tlv(void *agent, struct tlv_channel_pref  *p,
 	return ret;
 }
 
-int agent_fill_radio_max_preference(void *agent,
-		struct channel_response *channel_resp,
-		uint32_t *channel_response_nr)
+int handle_channel_sel_request(void *agent, struct cmdu_cstruct *cmdu)
 {
 	trace("agent: %s: --->\n", __func__);
 	struct agent *a = (struct agent *) agent;
-	uint32_t j = 0, k = 0, l = 0;
-	struct wifi_radio_element *radio = NULL;
+	int ret = 0;
+	struct channel_response channel_resp[MAX_RADIO];
+	uint32_t channel_resp_nr = 0, match = 0;
+	int i;
+	uint8_t *tlv = NULL;
+	struct wifi_radio_element *radio;
+	uint32_t pref_tlv_present = 0;
 
-	*channel_response_nr = a->num_radios;
+	/* Here we first need to update the channel preference values
+	 * from the channel selection request
+	 * then send the CMDU for channel selection response
+	 */
+	if (cmdu->num_tlvs != 0) {
+		for (i = 0; i < cmdu->num_tlvs; i++) {
+			tlv = (uint8_t *) cmdu->tlvs[i];
+			switch (*tlv) {
+			case MAP_TLV_CHANNEL_PREFERENCE:
+				{
+					struct tlv_channel_pref  *p =
+						(struct tlv_channel_pref *)tlv;
+					pref_tlv_present = 1;
 
-	for (j = 0; j < a->num_radios; j++) {
-		radio = a->radios + j;
-		memcpy(channel_resp[j].radio_id, radio->macaddr, 6);
+					ret = agent_process_channel_pref_tlv
+						(agent, p, channel_resp,
+						&channel_resp_nr);
+				}
+			case MAP_TLV_TRANSMIT_POWER_LIMIT:
+				{
+					struct tlv_tx_power_limit  *p =
+						(struct tlv_tx_power_limit *)tlv;
+					int l;
 
-		for (k = 0; k < radio->num_supp_opclass; k++) {
-			for (l = 0; l < radio->supp_opclass[k].
-				num_supported_channels; l++)
-				radio->supp_opclass[k].supp_chanlist[l].pref =
-				0xff;
+					trace("tlv radio_id: " MACFMT "\n",
+						MAC2STR(p->radio_id));
+					for (l = 0; l < a->num_radios; l++) {
+						radio = a->radios + l;
+						match = memcmp(radio->macaddr, p->radio_id, 6);
+						if (match == 0) {
+							/* Here we set the
+							 * transmit_power_limit
+							 * of the radio
+							 */
+							radio->transmit_power_limit =
+								p->tx_power_limit;
+							trace("transmit power %d\n",
+								p->tx_power_limit);
+							break;
+						}
+					}
+				}
+			default:
+				break;
+			}
 		}
-		channel_resp[j].response = 0x00;
-	}
-	return 0;
-}
-
-int send_channel_sel_response(void *agent, struct cmdu_cstruct *rec_cmdu,
-		struct channel_response *channel_resp,
-		uint32_t channel_response_nr)
-{
-	trace("agent: %s: --->\n", __func__);
-	struct agent *a = (struct agent *) agent;
-	uint16_t tlv_index = 0;
-	uint32_t j, ret = 0;
-	struct cmdu_cstruct *cmdu_data;
-
-	cmdu_data = (struct cmdu_cstruct *)calloc(1,
-		sizeof(struct cmdu_cstruct));
-
-	if (!cmdu_data) {
-		fprintf(stderr, "Out of memory!\n");
-		return -1;
 	}
 
-	cmdu_data->message_type = CMDU_CHANNEL_SELECTION_RESPONSE;
-	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_data->num_tlvs = 1 * channel_response_nr; /* (channel selection response) */
-	cmdu_data->tlvs = (uint8_t **)calloc(cmdu_data->num_tlvs,
-				sizeof(uint8_t *));
-
-	if (!cmdu_data->tlvs) {
-		map_free_cmdu(cmdu_data);
-		return -1;
+	if (cmdu->num_tlvs == 0 || pref_tlv_present == 0) {
+		/* Here the condition is that the
+		 * channel selection request have no tlvs or only transmit power tlv
+		 * so we need to set all the prefernce in all radios to max 15
+		 */
+		agent_fill_radio_max_preference(agent,
+			channel_resp, &channel_resp_nr);
 	}
 
-	/* Operating Channel Response TLV 17.2.16 */
-	for (j = 0; j < channel_response_nr; j++) {
-		struct tlv_ch_selection_resp *p = NULL;
-		//Here we need to check that the radio
-		//response is for the radio for which we get request
-		p = agent_gen_operate_channel_response(a, rec_cmdu,
-			channel_resp[j].radio_id, channel_resp[j].response);
-		if (!p)
-			continue;
-		cmdu_data->tlvs[tlv_index++] = (uint8_t *)p;
-	}
-	ret = agent_send_cmdu(a, cmdu_data);
-	map_free_cmdu(cmdu_data);
+	ret = send_channel_sel_response(agent, cmdu,
+		channel_resp, channel_resp_nr);
 
-	//TODO send a report message for each radio. This will be
-	//sent not here but on receiving of the event when the
-	//actually radio channel poreference have been changed
-	send_oper_channel_report(agent, rec_cmdu);
 	return ret;
 }
 
@@ -1346,12 +1454,14 @@ int handle_sta_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 		goto send_cmdu;
 	}
 
-	// if bit is set, HT Control section is included and should be skipped
+	/* if bit is set, HT Control section is included and
+	 * should be skipped
+	 */
 	if (!(s->assoc_frame->frame[0] & 0x80))
 		offset += 4;
 
 	body = s->assoc_frame->frame + offset;
-	// subtract 4 from remaining len to not include FCS section
+	/* subtract 4 from remaining len to not include FCS section */
 	len = s->assoc_frame->len - offset - 4;
 
 	cmdu->num_tlvs--;
@@ -1360,7 +1470,7 @@ int handle_sta_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
 	if (!p1->frame_body)
 		goto fail_cmdu;
 
-	// first byte annotates length of frame
+	/* first byte annotates length of frame */
 	*(p1->frame_body) = (1 + len);
 
 	memcpy(p1->frame_body + 1, body, len);
@@ -1934,7 +2044,6 @@ int handle_backhaul_sta_steer_request(void *agent,
 	struct tlv_backhaul_steer_req *req;
 	struct cmdu_cstruct *cmdu;
 	struct netif_bk *bk;
-	int ret;
 
 	req = (struct tlv_backhaul_steer_req *) extract_tlv_by_type(rec_cmdu,
 			MAP_TLV_BACKHAUL_STEERING_REQUEST);
@@ -2033,6 +2142,7 @@ static const map_cmdu_handler_t i1905ftable[] = {
 	/* [0x07] = handle_ap_autoconfig_search, */
 	[0x08] = handle_ap_autoconfig_response,
 	[0x09] = handle_ap_autoconfig_wsc,
+	[0x0a] = handle_ap_autoconfig_renew,
 };
 
 
@@ -2157,15 +2267,15 @@ const char *tlv_friendlyname[] = {
 bool is_cmdu_for_us(struct agent *a, uint16_t type)
 {
 	// TODO: handle only cmdu types relevant for module's role/profile.
-	//
-	// Since map-plugin now sends cmdu events, agent must filter out cmdus
-	// that it is not supposed to handle.
-	// When map-plugin directly call's map-module's 'cmd', then the
-	// additonal cmdu type validation/filtering it does becomes useful. In
-	// the latter case, agent doesn't need to do additonal checks for valid
-	// cmdu types.
+	/* Since map-plugin now sends cmdu events, agent must filter out cmdus
+	 * that it is not supposed to handle.
+	 * When map-plugin directly call's map-module's 'cmd', then the
+	 * additonal cmdu type validation/filtering it does becomes useful. In
+	 * the latter case, agent doesn't need to do additonal checks for valid
+	 * cmdu types.
+	 */
 
-	// until then, the following should be okay..
+	/* until then, the following should be okay.. */
 
 	if (type >= CMDU_TYPE_1905_START && type <= CMDU_TYPE_1905_END) {
 		if (i1905ftable[type])
@@ -2250,7 +2360,8 @@ int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu)
 
 	blobmsg_add_u32(&b, "type", cmdu->message_type);
 	blobmsg_add_string(&b, "egress", cmdu->intf_name);
-	blobmsg_add_u32(&b, "mid", cmdu->message_id);
+	if (cmdu->message_id)
+		blobmsg_add_u32(&b, "mid", cmdu->message_id);
 
 	hwaddr_ntoa(cmdu->origin, dst_addr);
 	blobmsg_add_string(&b, "dst_macaddr", dst_addr);
diff --git a/src/core/agent_map.h b/src/core/agent_map.h
index af1033a81..da3d23a6e 100644
--- a/src/core/agent_map.h
+++ b/src/core/agent_map.h
@@ -2,6 +2,7 @@
 #ifndef AGENT_MAP_H
 #define AGENT_MAP_H
 
+struct channel_response;
 
 uint8_t *extract_tlv_by_type(struct cmdu_cstruct *cmdu, uint8_t tlv_type);
 
diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c
index 0d83c425b..67d271fe6 100644
--- a/src/core/agent_tlv_generator.c
+++ b/src/core/agent_tlv_generator.c
@@ -111,7 +111,7 @@ struct tlv_ap_radio_basic_cap *agent_gen_ap_radio_basic_cap(struct agent *a,
 
 	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->max_bss_nr = 4; /* Max BSS per Radio */
 	p->operating_classes_nr = radio->num_supp_opclass;
 
 	if (p->operating_classes_nr > 0)
@@ -222,16 +222,15 @@ struct tlv_wsc *agent_gen_wsc(struct agent *a, struct cmdu_cstruct *cmdu,
 	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);
+	rv = wscBuildM1(radio->name, &p->wsc_frame, &len, (void **)&key,
+			a->almac, 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
+	/* 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);
@@ -239,7 +238,8 @@ struct tlv_wsc *agent_gen_wsc(struct agent *a, struct cmdu_cstruct *cmdu,
 		goto fail_key;
 
 	memcpy(radio->autconfig.m1_frame, p->wsc_frame, len);
-	// discard previous key if it has not been used
+
+	/* discard previous key if it has not been used */
 	if (radio->autconfig.key) {
 		free(radio->autconfig.key->key);
 		free(radio->autconfig.key);
@@ -323,8 +323,6 @@ fail_p:
 struct tlv_cac_cap *agent_gen_cac_cap(struct agent *a)
 {
 	struct tlv_cac_cap *p;
-	struct wifi_radio_element *radio = NULL;
-	struct wifi_opclass_supported_element *opclass = NULL;
 	int i;
 
 	p = (struct tlv_cac_cap *) calloc(1, sizeof(*p));
@@ -361,7 +359,7 @@ struct tlv_cac_cap *agent_gen_cac_cap(struct agent *a)
 			int k;
 
 			p->radio_data[i].cac_data[j].cac_method_supported = CAC_CAP_METHOD_CONTI_CAC;
-			p->radio_data[i].cac_data[j].duration = 60; //Default duration is 60, 600 for channels (120, 124 & 128)
+			p->radio_data[i].cac_data[j].duration = 60; /* Default duration is 60, 600 for channels (120, 124 & 128) */
 			// TODO: Assumption, All the supporting op_class supported continuous CAC method,
 			// Currently no parmaeter/method to classify the same.
 			p->radio_data[i].cac_data[j].nbr_op_classes = radio->num_supp_opclass;
@@ -449,7 +447,7 @@ struct tlv_oper_ch_report *agent_gen_operate_channel_report(struct agent *a,
 	if (!p->op_ch_op_class) {
 		fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
 		p->op_ch_op_class_nr = 0;
-		return;
+		return NULL;
 	}
 
 	for (j = 0; j < p->op_ch_op_class_nr; j++) {
@@ -457,8 +455,9 @@ struct tlv_oper_ch_report *agent_gen_operate_channel_report(struct agent *a,
 		p->op_ch_op_class[j].channel = radio->current_channel;
 	}
 
-	//current transmit power is the (operating class tx power) *
-	//	(current_tx_power_percent)/100
+	/* current transmit power is the (operating class tx power) *
+	 *	(current_tx_power_percent)/100
+	 */
 	for (j = 0; j < radio->num_supp_opclass; j++) {
 		if (radio->supp_opclass[j].id == radio->current_opclass)
 			p->curr_tx_power =
@@ -512,7 +511,7 @@ void agent_gen_radio_channel_preference(struct agent *a,
 		p->op_class[j].op_class = radio->supp_opclass[j].id;
 		count = 0;
 
-		//Here we fill all the channels that are not having max preference 15
+		/* Here we fill all the channels that are not having max preference 15 */
 		for (k = 0; k < radio->supp_opclass[j].num_supported_channels; k++) {
 			if (radio->supp_opclass[j].supp_chanlist[k].pref != 0xff)
 				count++;
@@ -649,6 +648,20 @@ struct tlv_error_code *agent_gen_tlv_error_code(struct agent *a,
 	return p;
 }
 
+struct tlv_al_mac *agent_gen_al_mac(struct agent *a, uint8_t *hwaddr)
+{
+	struct tlv_al_mac *p;
+
+	p = calloc(1, sizeof(struct tlv_al_mac));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = TLV_TYPE_AL_MAC_ADDRESS_TYPE;
+	memcpy(p->al_mac_address, hwaddr, 6);
+
+	return p;
+}
+
 struct tlv_steer_btm_report *agent_gen_steer_btm_report(struct agent *a,
 		uint8_t *target_bssid, uint8_t *src_bssid,
 		uint8_t *sta, uint8_t status_code)
@@ -672,3 +685,43 @@ struct tlv_steer_btm_report *agent_gen_steer_btm_report(struct agent *a,
 
 	return p;
 }
+
+/**
+ * band -
+ *	0x00 2.4GHz
+ *	0x01 5GHz
+ *	0x02 60GHz
+ */
+struct tlv_autoconf_freq_band *agent_gen_autoconf_freq_band(struct agent *a,
+		uint8_t band)
+{
+	struct tlv_autoconf_freq_band *p;
+
+	p = calloc(1, sizeof(struct tlv_autoconf_freq_band));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = TLV_TYPE_AUTOCONFIG_FREQ_BAND;
+	p->freq_band = band;
+
+	return p;
+}
+
+/**
+ *  role -
+ *	0x00 registrar
+ */
+struct tlv_searched_role *agent_gen_searched_role(struct agent *a,
+		uint8_t role)
+{
+	struct tlv_searched_role *p;
+
+	p = calloc(1, sizeof(struct tlv_searched_role));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = TLV_TYPE_SEARCHED_ROLE;
+	p->role = role;
+
+	return p;
+}
diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h
index c5ef25efc..68112982f 100644
--- a/src/core/agent_tlv_generator.h
+++ b/src/core/agent_tlv_generator.h
@@ -43,4 +43,9 @@ struct tlv_error_code *agent_gen_tlv_error_code(struct agent *a,
 struct tlv_steer_btm_report *agent_gen_steer_btm_report(struct agent *a,
 		uint8_t *target_bssid, uint8_t *src_bssid,
 		uint8_t *sta, uint8_t status_code);
+struct tlv_al_mac *agent_gen_al_mac(struct agent *a, uint8_t *hwaddr);
+struct tlv_autoconf_freq_band *agent_gen_autoconf_freq_band(struct agent *a,
+		uint8_t band);
+struct tlv_searched_role *agent_gen_searched_role(struct agent *a,
+		uint8_t role);
 #endif
diff --git a/src/core/agent_ubus.c b/src/core/agent_ubus.c
index c1e9c75ee..fe16d6eb5 100644
--- a/src/core/agent_ubus.c
+++ b/src/core/agent_ubus.c
@@ -106,14 +106,12 @@ static const struct blobmsg_policy config_policy_params[__CFG_POLICY_MAX] = {
 };
 
 enum {
-	SEARCH_POLICY_AGENT,
-	SEARCH_POLICY_EGRESS,
+	SEARCH_POLICY_BAND,
 	__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 }
+	[SEARCH_POLICY_BAND] = { .name = "band", .type = BLOBMSG_TYPE_INT32 },
 };
 
 static int steer_policy(struct ubus_context *ctx, struct ubus_object *obj,
@@ -290,7 +288,7 @@ static int steer(struct ubus_context *ctx, struct ubus_object *obj,
 	}
 #endif
 
-	if (wifiagent_steer_sta(ctx, ifname, sta_macaddr, i, bsslist, optime) != 0)
+	if (wifiagent_steer_sta(ctx, ifname, sta_macaddr, i, bsslist, optime))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
 	return UBUS_STATUS_OK;
@@ -412,106 +410,51 @@ static int agent_config_ap(struct ubus_context *ctx, struct ubus_object *obj,
 	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;
+	int i, tlv_index = 0, band, ieee1905band;
 
-	blobmsg_parse(config_policy_params, __SEARCH_POLICY_MAX, tb,
+	blobmsg_parse(search_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;
-	}
-
-	if (tb[SEARCH_POLICY_AGENT]) {
-		char agent[18] = {0};
+	if (tb[SEARCH_POLICY_BAND]) {
+		band = blobmsg_get_u32(tb[SEARCH_POLICY_BAND]);
 
-		strncpy(agent, blobmsg_data(tb[SEARCH_POLICY_AGENT]),
-				sizeof(agent) - 1);
-		if (!hwaddr_aton(agent, cmdu->origin))
+		if (band == 2)
+			band = BAND_2;
+		else if (band == 5)
+			band = BAND_5;
+		else {
+			trace("|%s:%d| Please provide band as '2', '5' or N/A\n",
+					__func__, __LINE__);
 			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;
+	for (i = 0; i < a->num_radios; i++) {
+		struct cmdu_cstruct *cmdu;
+		struct wifi_radio_element *radio = &a->radios[i];
 
-	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs,
-			sizeof(uint8_t *));
+		if (tb[SEARCH_POLICY_BAND])
+			if (band != radio->band)
+				continue;
 
-	if (!cmdu->tlvs)
-		goto fail_p2;
+		cmdu = agent_gen_ap_autoconfig_search(a, radio, NULL, 0x02);
+		if (!cmdu)
+			continue;
 
-	cmdu->tlvs[tlv_index++] = (uint8_t *)p;
-	cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
-	cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+		trace("|%s:%d| Sending Autoconfig Search for radio %s(%s)\n",
+				__func__, __LINE__, radio->name,
+				(radio->band == BAND_2 ? "2.4GHz" : "5GHz"));
+		agent_send_cmdu(a, cmdu);
+		map_free_cmdu(cmdu);
+	}
 
-	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)
@@ -519,9 +462,9 @@ 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[8] = {
-		UBUS_METHOD("ap_search", agent_ap_search, search_policy_params),
-		UBUS_METHOD("config_ap", agent_config_ap, config_policy_params),
+	struct ubus_method m[7] = {
+		UBUS_METHOD("apconfig", 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),
 		UBUS_METHOD("assoc_control", assoc_control,
@@ -616,27 +559,6 @@ void agent_remove_object(struct agent *a)
 	}
 }
 
-/*
-struct ubus_method wifiagent_methods[] = {
-	UBUS_METHOD("config_ap", agent_config_ap, config_ap_params),
-	UBUS_METHOD("steer_policy", steer_policy, steer_policy_params),
-	UBUS_METHOD("steer", steer, steer_params),
-	UBUS_METHOD("assoc_control", assoc_control, assoc_control_params),
-	UBUS_METHOD("cmd", cmd, cmd_params),
-	UBUS_METHOD("cmd_async", cmd_async, cmd_params),
-	UBUS_METHOD_NOARG("status", agent_status),
-};
-
-struct ubus_object_type wifiagent_type =
-	UBUS_OBJECT_TYPE("map.agent", wifiagent_methods);
-
-struct ubus_object wifiagent_object = {
-	.name = "map.agent",
-	.type = &wifiagent_type,
-	.methods = wifiagent_methods,
-	.n_methods = ARRAY_SIZE(wifiagent_methods),
-};
-*/
 #ifdef NOTIFY_EVENTS
 void wifiagent_notify_event(struct agent *a, void *ev_type, void *ev_data)
 {
diff --git a/src/core/config.c b/src/core/config.c
index 5661d95c0..5db119a0d 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -49,7 +49,7 @@
 #define UCI_WLAN_IFACE "wifi-iface"
 #define UCI_WIRELESS "wireless"
 #define UCI_IEEE1905 "ieee1905"
-#define UCI_AGENT "agent"
+#define UCI_AGENT "mapagent"
 
 int verbose;
 
@@ -73,6 +73,34 @@ int set_value(struct uci_context *ctx, struct uci_package *pkg,
 	return -1;
 }
 
+int set_value_by_string(const char *package, const char *section,
+		const char *key, const char *value, enum uci_option_type type)
+{
+	struct uci_ptr ptr = {0};
+	struct uci_context *ctx;
+	int rv;
+
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return -1;
+
+	ptr.package = package;
+	ptr.section = section;
+	ptr.option = key;
+	ptr.value = value;
+
+	if (type == UCI_TYPE_STRING)
+		rv = uci_set(ctx, &ptr);
+
+	if (type == UCI_TYPE_LIST)
+		rv = uci_add_list(ctx, &ptr);
+
+	uci_commit(ctx, &ptr.p, false);
+
+	uci_free_context(ctx);
+	return -1;
+}
+
 struct uci_section *config_get_iface_section(struct uci_context *ctx,
 		struct uci_package *pkg, const char *type, const char *ifname)
 {
@@ -104,6 +132,7 @@ struct uci_package *uci_load_pkg(struct uci_context **ctx, const char *config)
 		if (!*ctx)
 			return NULL;
 	}
+
 	if (uci_load(*ctx, config, &pkg) != UCI_OK) {
 		free(*ctx);
 		return NULL;
@@ -112,6 +141,48 @@ struct uci_package *uci_load_pkg(struct uci_context **ctx, const char *config)
 	return pkg;
 }
 
+/* TODO: causes segfault in disc? */
+char *uci_get_bridge(char *ifname, char *bridge)
+{
+	struct uci_context *ctx;
+	struct uci_package *pkg;
+	struct uci_element *e;
+
+	strncpy(bridge, "lan", 15);
+	return bridge;
+
+	pkg = uci_load_pkg(&ctx, UCI_WIRELESS);
+	if (!pkg)
+		return NULL;
+
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_section *s = uci_to_section(e);
+		struct uci_option *opt;
+
+		if (strcmp(s->type, UCI_WLAN_IFACE))
+			continue;
+
+		opt = uci_lookup_option(ctx, s,	"ifname");
+		if (!opt || opt->type != UCI_TYPE_STRING)
+			continue;
+
+		if (!strncmp(opt->v.string, ifname, 16))
+			continue;
+
+		opt = uci_lookup_option(ctx, s,	"network");
+		if (!opt || opt->type != UCI_TYPE_STRING)
+			continue;
+
+		strncpy(bridge, opt->v.string, 16);
+		break;
+	}
+
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
+	return bridge;
+}
+
+
 /* TODO: can it be generalized? */
 int wifi_set_iface_bssid(const char *ifname, uint8_t *bssid)
 {
@@ -201,9 +272,9 @@ int wifi_apply_iface_cfg(const char *ifname, const char *encryption,
 	set_value(ctx, pkg, section, "encryption", encryption, UCI_TYPE_STRING);
 	set_value(ctx, pkg, section, "ssid", ssid, UCI_TYPE_STRING);
 	set_value(ctx, pkg, section, "key", key, UCI_TYPE_STRING);
+	set_value(ctx, pkg, section, "wds", "1", UCI_TYPE_STRING);
 
 	uci_commit(ctx, &pkg, false);
-
 out_pkg:
 	uci_unload(ctx, pkg);
 out_uci:
@@ -342,7 +413,7 @@ out:
 }
 
 /* below functions are mostly taken from ieee1905d */
-static bool uci_check_wifi_iface(char *package_name, char *ifname,
+bool uci_check_wifi_iface(char *package_name, char *ifname,
 		char *section)
 {
 	bool ret;
@@ -384,7 +455,7 @@ static bool uci_check_wifi_iface(char *package_name, char *ifname,
 	return ret;
 }
 
-static bool uci_set_wireless_interface_option(char *package_name,
+bool uci_set_wireless_interface_option(char *package_name,
 		char *section_type, char *ifname, char *option, char *value)
 {
 	struct uci_context *ctx;
@@ -468,7 +539,7 @@ static bool get_encryption_value(uint16_t auth_type, uint16_t encryption_type,
 	return true;
 }
 
-static bool uci_add_wireless_iface_sec(char *package_name, char *interface_name,
+bool uci_add_wireless_iface_sec(char *package_name, char *interface_name,
 		char *section_name)
 {
 	struct uci_context *ctx;
@@ -555,7 +626,50 @@ bool uci_reload_services(void)
 	return false;
 }
 
-int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
+/* TODO: introduce option and vendor extension to make this logic redundant */
+int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band)
+{
+	struct netif_bkcfg *bk;
+	struct netif_fhcfg *fh;
+
+	list_for_each_entry(bk, &cfg->bklist, list) {
+		if (bk->band != band)
+			continue;
+
+		list_for_each_entry(fh, &cfg->fhlist, list) {
+			if (fh->band != band)
+				continue;
+
+			dbg("Applying bBSS credentials to %s:\n", fh->name);
+			dbg("  - SSID            : %s\n", bk->ssid);
+			dbg("  - NETWORK_KEY     : %s\n", bk->key);
+
+			uci_set_wireless_interface_option(UCI_WIRELESS,
+					UCI_WLAN_IFACE,
+					fh->name,
+					"multi_ap_backhaul_ssid",
+					bk->ssid);
+			uci_set_wireless_interface_option(UCI_WIRELESS,
+					UCI_WLAN_IFACE,
+					fh->name,
+					"multi_ap_backhaul_key",
+					bk->key);
+			uci_set_wireless_interface_option(UCI_WIRELESS,
+					UCI_WLAN_IFACE,	fh->name, "wps", "1");
+			uci_set_wireless_interface_option(UCI_WIRELESS,
+					UCI_WLAN_IFACE,	fh->name,
+					"wps_pushbutton", "1");
+		}
+
+		break;
+	}
+
+	return 0;
+}
+
+
+/* TODO: batch the changes arther than commit oneby one */
+int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 		uint16_t auth_type, uint16_t encryption_type,
 		uint8_t *network_key, uint8_t mapie, uint8_t band)
 {
@@ -563,13 +677,12 @@ int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
 	char auth_type_str[20] = {0};
 	char multiap_str[2] = {0};
 	uint8_t multi_ap = 0;
-	bool sta_mode;
+	bool bk_mode;
 	char band_str[2] = {0};
+	char agent_section[16] = {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);
@@ -581,7 +694,7 @@ int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
 
 	multi_ap |= (BIT(5, mapie) << 1);
 	multi_ap |= BIT(6, mapie);
-	sta_mode = BIT(7, mapie);
+	bk_mode = BIT(6, mapie);
 
 	snprintf(multiap_str, sizeof(multiap_str), "%d", multi_ap);
 
@@ -591,18 +704,19 @@ int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
 		return M2_PROCESS_ERROR;
 	}
 
+	strncpy(agent_section, (bk_mode ? UCI_BK_AGENT : UCI_FH_AGENT),
+			sizeof(agent_section));
+
 	// Set uci in agent
 	ret = uci_check_wifi_iface(UCI_AGENT, interface_name,
-			(sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT));
+			agent_section);
 	if (!ret) {
 		ret = uci_add_wireless_iface_sec(UCI_AGENT, interface_name,
-				(sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT));
+				agent_section);
 		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)
@@ -610,42 +724,29 @@ int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
 	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) {
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+			interface_name, "band",	band_str);
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+			interface_name, "band",	band_str);
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+			interface_name,	"device", device);
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+			interface_name,	"ssid", ssid);
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+			interface_name,	"key", network_key);
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+			interface_name,	"encryption", auth_type_str);
+	if (bk_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),
+				UCI_BK_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);
@@ -656,6 +757,8 @@ int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
 			return M2_PROCESS_ERROR;
 	}
 
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+			interface_name, "network", "lan");
 	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,
@@ -663,11 +766,15 @@ int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
 	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);
+			interface_name, "mode", "ap");
 	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
-			interface_name, "mode", (sta_mode ? "sta" : "ap"));
-
-	uci_reload_services();
+			interface_name, "device", device);
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+			interface_name, "multi_ap", multiap_str);
+	if (bk_mode) {
+		uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+			interface_name, "hidden", "1");
+	}
 	return M2_PROCESS_OK;
 }
 /* end of functions taken from ieee1905d */
@@ -802,77 +909,6 @@ void agent_config_dump(struct agent_config *cfg)
 	}
 }
 
-int agent_config_defaults(struct agent *a, struct agent_config *cfg)
-{
-	struct list_head *p, *tmp;
-	struct netif_fh *ifptr;
-	struct netif_fhcfg *new;
-
-	if (!cfg)
-		return -1;
-
-	cfg->enabled = false;
-	cfg->runfreq = AGENT_RUN_AUTO;
-
-	INIT_LIST_HEAD(&cfg->fhlist);
-	INIT_LIST_HEAD(&cfg->bklist);
-	list_for_each_entry(ifptr, &a->fhlist, list) {
-		/* struct list_head pollist; */
-		struct steer_rule *r;
-
-		new = calloc(1, sizeof(struct netif_fhcfg));
-		if (!new) {
-			warn("OOM! config\n");
-			goto err_alloc;
-		}
-
-		snprintf(new->name, 16, "%s", ifptr->name);
-		new->enabled = false;
-		new->steer_btm_retry = STEER_BTM_RETRY;
-		new->steer_btm_retry_secs = STEER_BTM_RETRY_INT;
-		new->fallback_legacy = STEER_LEGACY_FALLBACK_INT;
-		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;
-		INIT_LIST_HEAD(&new->steer_policylist);
-		/* nrules = get_registered_steer_rules(&pollist); */ /* TODO */
-		list_for_each_entry(r, &regd_steer_rules, list) {
-			struct steer_policy *pol;
-
-			pol = calloc(1, sizeof(struct steer_policy));
-			if (!pol)
-				goto err_alloc_policy;
-
-			snprintf(pol->name, 16, "%s", r->name);
-			pol->enabled = false;
-			if (r->init_config)
-				r->init_config(r, &pol->policy);
-			list_add(&pol->list, &new->steer_policylist);
-		}
-
-		INIT_LIST_HEAD(&new->steer_excludelist);
-		INIT_LIST_HEAD(&new->steer_btm_excludelist);
-		INIT_LIST_HEAD(&new->assoc_ctrllist);
-
-		ifptr->cfg = new;
-		dbg("%s: %s netif_fh->cfg = %p\n", __func__, ifptr->name,
-				ifptr->cfg);
-		list_add(&new->list, &cfg->fhlist);
-	}
-
-	return 0;
-
-err_alloc_policy:
-	/* TODO */
-err_alloc:
-	list_for_each_safe(p, tmp, &cfg->fhlist) {
-		list_del(p);
-		free(p);
-	}
-
-	return -1;
-}
-
 /* create fh-iface config and initialize with default values */
 struct netif_fhcfg *create_fronthaul_iface_config(struct agent_config *cfg,
 							const char *ifname)
@@ -1174,18 +1210,24 @@ void register_config(struct config *c)
 #endif
 
 static int agent_config_get_wifi_agent(struct agent_config *a,
-						struct uci_section *s)
+		struct uci_section *s)
 {
 	enum {
 		A_ENABLED,
 		A_DEBUG,
 		A_PROFILE,
+		A_BRCM_SETUP,
+		/*A_CONFIGURED,*/
+		A_CNTLR_MAC,
 		NUM_POLICIES
 	};
 	const struct uci_parse_option opts[] = {
 		{ .name = "enabled", .type = UCI_TYPE_STRING },
 		{ .name = "debug", .type = UCI_TYPE_STRING },
 		{ .name = "profile", .type = UCI_TYPE_STRING },
+		{ .name = "brcm_setup", .type = UCI_TYPE_STRING },
+		/*{ .name = "configured", .type = UCI_TYPE_STRING },*/
+		{ .name = "controller_macaddr", .type = UCI_TYPE_STRING },
 	};
 	struct uci_option *tb[NUM_POLICIES];
 
@@ -1203,24 +1245,41 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 	if (tb[A_PROFILE])
 		a->profile = atoi(tb[A_PROFILE]->v.string);
 
+	if (tb[A_BRCM_SETUP])
+		a->brcm_setup = atoi(tb[A_BRCM_SETUP]->v.string);
+
+	/*if (tb[A_CONFIGURED])
+		a->configured = atoi(tb[A_CONFIGURED]->v.string);*/
+
+	if (tb[A_CNTLR_MAC])
+		hwaddr_aton(tb[A_CNTLR_MAC]->v.string, a->cntlr_almac);
+
 	return 0;
 }
 
 static int agent_config_get_bk_iface(struct agent_config *a,
-						struct uci_section *s)
+		struct uci_section *s)
 {
 	enum {
 		BK_IFNAME,
+		BK_DEVICE,
 		BK_BAND,
 		BK_ENABLED,
 		BK_ONBOARDED,
+		BK_SSID,
+		BK_KEY,
+		BK_ENCRYPTION,
 		NUM_POLICIES
 	};
 	const struct uci_parse_option opts[] = {
 		{ .name = "ifname", .type = UCI_TYPE_STRING },
+		{ .name = "device", .type = UCI_TYPE_STRING },
 		{ .name = "band", .type = UCI_TYPE_STRING },
 		{ .name = "enabled", .type = UCI_TYPE_STRING },
-		{ .name = "onboarded", .type = UCI_TYPE_STRING }
+		{ .name = "onboarded", .type = UCI_TYPE_STRING },
+		{ .name = "ssid", .type = UCI_TYPE_STRING },
+		{ .name = "key", .type = UCI_TYPE_STRING },
+		{ .name = "encryption", .type = UCI_TYPE_STRING }
 	};
 	struct uci_option *tb[NUM_POLICIES];
 	struct netif_bkcfg *bk;
@@ -1246,6 +1305,13 @@ static int agent_config_get_bk_iface(struct agent_config *a,
 		return -1;
 	}
 
+	if (tb[BK_DEVICE]) {
+		const char *device;
+
+		device = tb[BK_DEVICE]->v.string;
+		strncpy(bk->device, device, sizeof(bk->device) - 1);
+	}
+
 	if (tb[BK_ENABLED])
 		bk->enabled = atoi(tb[BK_ENABLED]->v.string);
 
@@ -1261,6 +1327,27 @@ static int agent_config_get_bk_iface(struct agent_config *a,
 			bk->band = BAND_5;
 	}
 
+	if (tb[BK_SSID]) {
+		const char *ssid;
+
+		ssid = tb[BK_SSID]->v.string;
+		strncpy(bk->ssid, ssid, sizeof(bk->ssid) - 1);
+	}
+
+	if (tb[BK_KEY]) {
+		const char *key;
+
+		key = tb[BK_KEY]->v.string;
+		strncpy(bk->key, key, sizeof(bk->key) - 1);
+	}
+
+	if (tb[BK_ENCRYPTION]) {
+		const char *encryption;
+
+		encryption = tb[BK_ENCRYPTION]->v.string;
+		strncpy(bk->encryption, encryption, sizeof(bk->encryption) - 1);
+	}
+
 	return 0;
 }
 
@@ -1271,6 +1358,7 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		FH_IFNAME,
 		FH_BAND,
 		FH_STEER,
+		FH_DEVICE,
 		FH_EXCLUDE,
 		FH_EXCLUDE_BTM,
 		FH_ASSOC_CTRL,
@@ -1280,12 +1368,16 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		FH_STEER_LEGACY_RASSOC_SECS,
 		FH_STEER_LEGACY_RETRY_SECS,
 		FH_ASSOC_CTRL_SECS,
+		FH_SSID,
+		FH_KEY,
+		FH_ENCRYPTION,
 		NUM_POLICIES,
 	};
 	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 = "device", .type = UCI_TYPE_STRING },
 		{ .name = "exclude", .type = UCI_TYPE_LIST },
 		{ .name = "exclude_btm", .type = UCI_TYPE_LIST },
 		{ .name = "assoc_ctrl", .type = UCI_TYPE_LIST },
@@ -1294,7 +1386,10 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		{ .name = "fallback_legacy", .type = UCI_TYPE_STRING },
 		{ .name = "steer_legacy_reassoc_secs", .type = UCI_TYPE_STRING },
 		{ .name = "steer_legacy_retry_secs", .type = UCI_TYPE_STRING },
-		{ .name = "assoc_ctrl_secs", .type = UCI_TYPE_STRING }
+		{ .name = "assoc_ctrl_secs", .type = UCI_TYPE_STRING },
+		{ .name = "ssid", .type = UCI_TYPE_STRING },
+		{ .name = "key", .type = UCI_TYPE_STRING },
+		{ .name = "encryption", .type = UCI_TYPE_STRING }
 	};
 	struct uci_option *tb[NUM_POLICIES];
 	struct netif_fhcfg *fh;
@@ -1356,6 +1451,14 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		dbg("\n");
 	}
 
+	if (tb[FH_DEVICE]) {
+		const char *device;
+
+		device = tb[FH_DEVICE]->v.string;
+
+		strncpy(fh->device, device, sizeof(fh->device) - 1);
+	}
+
 	if (tb[FH_EXCLUDE]) {
 		struct uci_element *xi;
 
@@ -1399,6 +1502,27 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		fh->assoc_control_time =
 				atoi(tb[FH_ASSOC_CTRL_SECS]->v.string);
 
+	if (tb[FH_SSID]) {
+		const char *ssid;
+
+		ssid = tb[FH_SSID]->v.string;
+		strncpy(fh->ssid, ssid, sizeof(fh->ssid) - 1);
+	}
+
+	if (tb[FH_KEY]) {
+		const char *key;
+
+		key = tb[FH_KEY]->v.string;
+		strncpy(fh->key, key, sizeof(fh->key) - 1);
+	}
+
+	if (tb[FH_ENCRYPTION]) {
+		const char *encryption;
+
+		encryption = tb[FH_ENCRYPTION]->v.string;
+		strncpy(fh->encryption, encryption, sizeof(fh->encryption) - 1);
+	}
+
 	return 0;
 }
 
@@ -1431,7 +1555,7 @@ int agent_config_reload(struct agent_config *cfg)
 	if (!ctx)
 		return -1;
 
-	if (uci_load(ctx, "agent", &pkg)) {
+	if (uci_load(ctx, "mapagent", &pkg)) {
 		uci_free_context(ctx);
 		return -1;
 	}
@@ -1439,7 +1563,7 @@ int agent_config_reload(struct agent_config *cfg)
 	uci_foreach_element(&pkg->sections, e) {
 		struct uci_section *s = uci_to_section(e);
 
-		if (!strcmp(s->type, "wifiagent"))
+		if (!strcmp(s->type, "agent"))
 			agent_config_get_wifi_agent(cfg, s);
 		else if (!strcmp(s->type, "fh-iface"))
 			agent_config_get_fh_iface(cfg, s);
diff --git a/src/core/config.h b/src/core/config.h
index f676ac23a..f10840a1e 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -55,6 +55,10 @@ void stax_del_entry(struct list_head *h, char *sta_macstr);
  */
 struct netif_fhcfg {
 	char name[16];
+	char device[16];
+	char ssid[33];
+	char key[65];
+	char encryption[32];
 	enum wifi_band band;
 	bool enabled;
 	bool sta_steer_enabled;
@@ -92,6 +96,10 @@ struct netif_fhcfg {
 struct netif_bkcfg {
 	char name[16];
 	enum wifi_band band;
+	char device[16];
+	char ssid[33];
+	char key[65];
+	char encryption[32];
 	bool enabled;
 	bool onboarded;
 	/* TODO: others as needed */
@@ -116,6 +124,9 @@ struct agent_config {
 	unsigned char oui0[32];
 	int ouis;
 	uint8_t profile;
+	bool brcm_setup;
+	bool configured;
+	uint8_t cntlr_almac[6];
 };
 
 #if 0
@@ -137,11 +148,14 @@ enum m2_process_status {
 int set_value(struct uci_context *ctx, struct uci_package *pkg,
 		struct uci_section *section, const char *key,
 		const char *value, enum uci_option_type type);
+int set_value_by_string(const char *package, const char *section,
+		const char *key, const char *value, enum uci_option_type type);
 struct uci_section *config_get_iface_section(struct uci_context *ctx,
 		struct uci_package *pkg, const char *type, const char *ifname);
 bool uci_reload_services(void);
 struct uci_package *uci_load_pkg(struct uci_context **ctx, const char *config);
 int wifi_set_iface_bssid(const char *ifname, uint8_t *bssid);
+char *uci_get_bridge(char *ifname, char *bridge);
 
 /* END TODO */
 
@@ -170,12 +184,20 @@ int config_add_default_wifi_iface(const char *config, const char *type,
 		const char *ifname, const char *device, const char *network,
 		const char *mode);
 
+bool uci_check_wifi_iface(char *package_name, char *ifname,
+		char *section);
+bool uci_set_wireless_interface_option(char *package_name,
+		char *section_type, char *ifname, char *option, char *value);
+bool uci_add_wireless_iface_sec(char *package_name, char *interface_name,
+		char *section_name);
+
 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,
+int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 		uint16_t auth_type, uint16_t encryption_type,
 		uint8_t *network_key, uint8_t mapie, uint8_t band);
+int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band);
 #endif
diff --git a/src/utils/brcm_nl.c b/src/utils/brcm_nl.c
new file mode 100644
index 000000000..25cd402e7
--- /dev/null
+++ b/src/utils/brcm_nl.c
@@ -0,0 +1,109 @@
+
+/*
+ * compile:
+ *   gcc -I/usr/include/libnl3 -o nl_rtlink nl_rtlink.c -lnl-3 -lnl-route-3
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <uci.h>
+#include <string.h>
+
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/msg.h>
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include <libubox/blobmsg.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/uloop.h>
+#include <libubox/ustream.h>
+#include <libubox/utils.h>
+#include <libubus.h>
+
+#include <easy/easy.h>
+
+#define UCI_WIRELESS "wireless"
+#define UCI_WLAN_IFACE "wifi-iface"
+
+static bool get_bridge(char *ifname, char *bridge)
+{
+	strncpy(bridge, "br-lan", 15);
+	return true;
+}
+
+static int func(struct nl_msg *msg, void *arg)
+{
+	struct nlmsghdr *nlh = nlmsg_hdr(msg);
+
+	switch (nlh->nlmsg_type) {
+	case RTM_NEWLINK:
+	case RTM_DELLINK:
+		{
+			struct ifinfomsg *ifi;
+			char ifname[16] = {0};
+			char bridge[16] = {0};
+			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");
+
+			//if (!(ifi->ifi_flags & IFF_UP))
+			//	break;
+
+			if (!strstr(ifname, "wds"))
+				break;
+
+			if (!get_bridge(ifname, bridge))
+				break;
+
+			/* add wds iface to bridge */
+			ret = br_addif(bridge, ifname);
+			if (!ret)
+				printf("Successfully added interface %s to " \
+						"bridge %s\n", ifname, bridge);
+
+			/* bring up wds interface */
+			ret = if_setflags(ifname, IFF_UP);
+			if (!ret)
+				printf("Successfully brought up interface %s",
+						ifname);
+			break;
+		}
+	default:
+		break;
+
+	}
+
+	return 0;
+}
+
+int brcm_nl_loop(void)
+{
+	struct nl_sock *sk;
+
+	sk = nl_socket_alloc();
+	if (!sk)
+		return 1;
+
+	nl_socket_disable_seq_check(sk);
+
+	nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, func, NULL);
+
+	nl_connect(sk, NETLINK_ROUTE);
+	nl_socket_add_memberships(sk, RTNLGRP_LINK, 0);
+
+	for (;;)
+		nl_recvmsgs_default(sk);
+
+	return 0;
+}
diff --git a/src/utils/brcm_nl.h b/src/utils/brcm_nl.h
new file mode 100644
index 000000000..d87d288bc
--- /dev/null
+++ b/src/utils/brcm_nl.h
@@ -0,0 +1,6 @@
+#ifndef BRCM_NL_H
+#define BRCM_NL
+
+int brcm_nl_loop(void);
+
+#endif
diff --git a/src/utils/debug.c b/src/utils/debug.c
index 77291aee5..411077e28 100644
--- a/src/utils/debug.c
+++ b/src/utils/debug.c
@@ -200,7 +200,6 @@ void log_test(int level, void *var, int len)
 
 	fprintf(testfile, "%s\n", bstr);
 	fflush(testfile);
-out:
 	free(bstr);
 }
 
diff --git a/src/utils/utils.c b/src/utils/utils.c
index 62872845b..7d44bb921 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -21,6 +21,9 @@
 #include <libubox/list.h>
 #include <json-c/json.h>
 
+#include <easy/easy.h>
+#include <wifi.h>
+
 #include "debug.h"
 
 bool match_oui0(unsigned char *oui, unsigned char *hwaddr, int ouis)
@@ -444,3 +447,24 @@ bool json_get_bool(struct json_object *object, const char *key)
 	return json_object_get_boolean(value) ? 1 : 0;
 
 }
+
+uint8_t wifi_band_to_ieee1905band(uint8_t band)
+{
+	uint8_t ieee1905band = -1;
+
+	switch (band) {
+	case BAND_2:
+		ieee1905band = 0x00;
+		break;
+	case BAND_5:
+		ieee1905band = 0x01;
+		break;
+	case BAND_60:
+		ieee1905band = 0x02;
+		break;
+	default:
+		break;
+	}
+
+	return ieee1905band;
+}
diff --git a/src/utils/utils.h b/src/utils/utils.h
index bdde468c6..3dabc4c81 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -155,5 +155,6 @@ int list_dup(struct list_head *h, struct list_head *new,
 int set_sighandler(int sig, void (*handler)(int));
 int unset_sighandler(int sig);
 void do_daemonize(const char *pidfile);
+uint8_t wifi_band_to_ieee1905band(uint8_t band);
 
 #endif /* UTILS_H */
-- 
GitLab