diff --git a/src/core/agent.c b/src/core/agent.c
index 566373d35e0b94b08da72adf590126bef6a9bb35..102528b31cef307cb65161e5a8c5f926201777a8 100644
--- a/src/core/agent.c
+++ b/src/core/agent.c
@@ -1055,7 +1055,7 @@ static int maybe_steer_sta(struct sta *s, unsigned int *res,
 					struct pref_neighbor **nbr)
 {
 	struct netif_fh *vif = s->vif;
-	struct netif_fhcfg *cfg = vif->cfg;
+	struct agent *a = vif->agent;
 	struct stax *x;
 
 	/* dbg("%s: vif = %p  cfg = %p ifname = %s\n",
@@ -1065,7 +1065,7 @@ static int maybe_steer_sta(struct sta *s, unsigned int *res,
 	/* TODO: don't check here ..
 	 * flag exclude whenever cfg is updated to exclude a STA.
 	 */
-	list_for_each_entry(x, &cfg->steer_excludelist, list) {
+	list_for_each_entry(x, &a->cfg.steer_excludelist, list) {
 		unsigned char xmac[6] = {0};
 		int m_len;
 
@@ -1272,7 +1272,7 @@ static int wifi_add_sta(struct agent *a, const char *vif,
 	}
 
 //	TODO: test more thorouhgly and comment back in
-//	list_for_each_entry(x, &cfg->steer_excludelist, list) {
+//	list_for_each_entry(x, &a->cfg.steer_excludelist, list) {
 //		unsigned char xmac[6] = {0};
 //		int m_len;
 //
@@ -3912,33 +3912,25 @@ int wifiagent_process_cmd(struct ubus_context *ctx,
 		{
 			int num = len / 17;
 			int i;
-			struct netif_fh *n;
-
-			list_for_each_entry(n, &a->fhlist, list) {
-				struct netif_fhcfg *ncfg = n->cfg;
+			struct agent_config *cfg = &a->cfg;
 
-				if (!n->cfg || !n->cfg->enabled)
-					continue;
+			if (!cfg->enabled)
+				break;
 
-				dbg("Cmd '%d': num addresses = %d\n", cmd_id,
-						num);
-				for (i = 0; i < num; i++) {
-					char p[18] = {0};
-
-					snprintf(p, 18, "%s", &cmd_data[i * 17]);
-					ret = config_update2("wifiagent",
-							&a->cfg,
-							"fh-iface", "ifname",
-							n->name,
-							"exclude", add,	p, 18);
-					if (add)
-						stax_add_entry(&ncfg->steer_excludelist,
-								p);
-					else
-						stax_del_entry(&ncfg->steer_excludelist,
-								p);
-				}
+			dbg("Cmd '%d': num addresses = %d\n", cmd_id, num);
+			for (i = 0; i < num; i++) {
+				char p[18] = {0};
+
+				snprintf(p, 18, "%s", &cmd_data[i * 17]);
+				ret = config_update("agent", &a->cfg,
+						"wifiagent", "exclude",
+						add, p, 18);
+				if (add)
+					stax_add_entry(&cfg->steer_excludelist, p);
+				else
+					stax_del_entry(&cfg->steer_excludelist, p);
 			}
+
 		}
 		break;
 	case CMD_STEER:
diff --git a/src/core/agent.h b/src/core/agent.h
index 599608b9f5b8697085e409a39f540776ef62328b..92eb344bafa106f7dba18d9bbc64dfdbab7567a4 100644
--- a/src/core/agent.h
+++ b/src/core/agent.h
@@ -167,6 +167,13 @@ struct netif_fh {
 	struct uloop_timeout rdr_timer; /** radar nop timer */
 	struct uloop_timeout nbr_timer; /** refresh neighbor list timer */
 	struct uloop_timeout bss_timer; /** refresh own bss timer */
+
+	/* Channel utilization threshold timer */
+	struct uloop_timeout util_threshold_timer;
+
+	/* STA Metrics Reporting RCPI Threshold timer */
+	struct uloop_timeout rcpi_threshold_timer;
+
 	struct list_head restrict_stalist;  /* list of restrict_sta_entry */
 	struct list_head nbrlist;
 	int nbr_nr;
@@ -181,6 +188,12 @@ struct netif_fh {
 	uint8_t tx_spatial_streams;
 
 	struct wifi_caps_element caps;
+
+	/* previous rcpi threshold value */
+	uint8_t prev_rcpi;
+
+	/* previous channel utilization threshold value */
+	uint8_t prev_util;
 };
 
 /* backhaul wifi (sta) interface */
@@ -458,5 +471,7 @@ 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);
+struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a,
+		char *ifname);
 
 #endif /* AGENT_H */
diff --git a/src/core/agent_cmdu_generator.c b/src/core/agent_cmdu_generator.c
index 3b2d19d77aacfbb9fc4ffe2d291cd6451ce7ca01..7d5680a532a209b9db29dfca7ff8f77d8c6e1e03 100644
--- a/src/core/agent_cmdu_generator.c
+++ b/src/core/agent_cmdu_generator.c
@@ -205,22 +205,18 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
 
 		case MAP_TLV_AP_METRIC_QUERY:
 			{
-				int radio_index;
-				int bss_index;
-				struct wifi_radio_element *radio;
-				struct netif_fh *fh;
 				struct tlv_ap_metric_query *p =
 					(struct tlv_ap_metric_query *)tmp;
 
 				for (j = 0; j < p->bssid_nr; j++) {
 					int num_sta = 0;
 					struct sta *s;
+					uint8_t bssid[6] = { 0 };
+					struct netif_fh *fh;
 
-					bss_index = get_radio_and_bss_index(a,
-							p->ap_metric_query_bssid[j].bssid,
-							&radio_index);
-
-					if (bss_index == -1)
+					memcpy(bssid, p->ap_metric_query_bssid[j].bssid, 6);
+					fh = wifi_get_netif_by_bssid(a, bssid);
+					if (!fh)
 						continue;
 
 					/* AP Metrics TLV */
@@ -230,20 +226,15 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
 					cmdu->num_tlvs++;
 // #endif
 
-					radio = a->radios + radio_index;
-					fh = wifi_radio_to_ap(a, radio->name);
-					if (fh == NULL)
-						continue;
-
 					list_for_each_entry(s, &fh->stalist, list)
 						num_sta++;
 
-					// if (fh->cfg->include_sta_stats) {
+					if (fh->cfg->include_sta_stats) {
 						/* Associated STA Traffic Stats TLV */
 						cmdu->num_tlvs += num_sta;
-					// }
+					}
 
-					// if (fh->cfg->include_sta_metric) {
+					if (fh->cfg->include_sta_metric) {
 						/* Associated STA Link Metrics TLV */
 						cmdu->num_tlvs += num_sta;
 
@@ -251,7 +242,7 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
 						/* Associated STA Extended Link Metrics TLV */
 						cmdu->num_tlvs += num_sta;
 // #endif
-					// }
+					}
 
 				}
 				break;
@@ -299,18 +290,18 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
 
 		case MAP_TLV_AP_METRIC_QUERY:
 			{
-				int radio_index;
-				int bss_index;
 				struct wifi_radio_element *radio;
 				struct wifi_bss_element *bss;
-				struct netif_fh *fh;
 				struct tlv_ap_metrics *p2;
 				struct tlv_ap_ext_metrics *p3;
 				struct tlv_ap_metric_query *p =
 					(struct tlv_ap_metric_query *)tmp;
 
 				for (j = 0; j < p->bssid_nr; j++) {
+					int radio_index;
+					int bss_index;
 					struct sta *s;
+					struct netif_fh *fh;
 
 					bss_index = get_radio_and_bss_index(a,
 							p->ap_metric_query_bssid[j].bssid,
@@ -338,13 +329,12 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
 					cmdu->tlvs[tlv_index++] = (uint8_t *)p3;
 // #endif
 
-					fh = wifi_radio_to_ap(a, radio->name);
+					fh = wifi_get_netif_by_bssid(a, bss->bssid);
 					if (fh == NULL)
 						continue;
 
-
 					list_for_each_entry(s, &fh->stalist, list) {
-						// if (fh->cfg->include_sta_stats) {
+						if (fh->cfg->include_sta_stats) {
 							/* Associated STA Traffic Stats TLV */
 							struct tlv_assoc_sta_traffic_stats *p4;
 
@@ -353,9 +343,9 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
 								goto error;
 
 							cmdu->tlvs[tlv_index++] = (uint8_t *)p4;
-						// }
+						}
 
-						// if (fh->cfg->include_sta_metric) {
+						if (fh->cfg->include_sta_metric) {
 							struct tlv_assoc_sta_link_metrics *p5;
 							struct tlv_assoc_sta_ext_link_metric *p6;
 
@@ -372,7 +362,7 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
 
 							cmdu->tlvs[tlv_index++] = (uint8_t *)p6;
 // #endif
-						// }
+						}
 
 					}
 				}
@@ -387,3 +377,94 @@ error:
 	map_free_cmdu(cmdu);
 	return NULL;
 }
+
+struct cmdu_cstruct *agent_gen_assoc_sta_metric_response(
+		struct agent *a, char *ifname)
+{
+	int i;
+	int tlv_index = 0;
+	struct cmdu_cstruct *cmdu;
+	struct wifi_radio_element *radio;
+	struct wifi_bss_element *bss;
+
+	cmdu = calloc(1, sizeof(struct cmdu_cstruct));
+	if (!cmdu)
+		return NULL;
+
+	cmdu->message_type = CMDU_ASSOC_STA_LINK_METRICS_RESPONSE;
+	memcpy(cmdu->origin, a->cntlr_almac, 6);
+	/* TODO/FIXME: interface name
+	 * hardcoded: br-lan
+	 */
+	strncpy(cmdu->intf_name, "br-lan", IFNAMESIZE - 1);
+
+	radio = wifi_ifname_to_radio_element(a, ifname);
+	if (!radio)
+		goto error;
+
+	/* Calculate number of TLVs required for the response
+	 */
+	for (i = 0; i < radio->num_bss; i++) {
+		struct netif_fh *fh;
+		int num_sta = 0;
+		struct sta *s;
+
+		bss = radio->bsslist + i;
+		fh = wifi_get_netif_by_bssid(a, bss->bssid);
+		if (!fh)
+			continue;
+
+		list_for_each_entry(s, &fh->stalist, list)
+			num_sta++;
+
+		/* Associated STA Link Metrics TLV */
+		cmdu->num_tlvs += num_sta;
+// #ifdef PROFILE2
+		/* Associated STA Extended Link Metrics TLV */
+		cmdu->num_tlvs += num_sta;
+// #endif
+	}
+
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *));
+	if (!cmdu->tlvs) {
+		cmdu->num_tlvs = 0;
+		goto error;
+	}
+
+	for (i = 0; i < radio->num_bss; i++) {
+		struct sta *s;
+		struct netif_fh *fh;
+
+		bss = radio->bsslist + i;
+		fh = wifi_get_netif_by_bssid(a, bss->bssid);
+		if (!fh)
+			continue;
+
+		list_for_each_entry(s, &fh->stalist, list) {
+			struct tlv_assoc_sta_link_metrics *p1;
+			struct tlv_assoc_sta_ext_link_metric *p2;
+
+			p1 = agent_gen_assoc_sta_link_metrics(a, s, bss->bssid);
+			if (!p1)
+				goto error;
+
+			cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
+
+// #ifdef PROFILE2
+			p2 = agent_gen_assoc_sta_ext_link_metric(a, s, bss->bssid);
+			if (!p2)
+				goto error;
+
+			cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+// #endif
+		}
+
+	}
+
+	return cmdu;
+
+error:
+	map_free_cmdu(cmdu);
+
+	return NULL;
+}
diff --git a/src/core/agent_cmdu_generator.h b/src/core/agent_cmdu_generator.h
index f126aacb0fc7801f001a95d73b113cb2bcb1bec9..d416d15d6f0a1f13baccbe32d79cd5807e93d2a8 100644
--- a/src/core/agent_cmdu_generator.h
+++ b/src/core/agent_cmdu_generator.h
@@ -15,8 +15,7 @@ struct cmdu_cstruct *agent_gen_ap_autoconfig_search(struct agent *a,
 		uint8_t profile);
 struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
 		struct cmdu_cstruct *rec_cmdu);
+struct cmdu_cstruct *agent_gen_assoc_sta_metric_response(
+		struct agent *a, char *ifname);
 
-int get_radio_index(struct agent *a, uint8_t *mac);
-int get_bss_index(struct wifi_radio_element *radio, uint8_t *bssid);
-int get_radio_and_bss_index(struct agent *a, uint8_t *bssid, int *radio_index);
 #endif
diff --git a/src/core/agent_map.c b/src/core/agent_map.c
index 0dbcc4d850b47315e46d499b69e509c3ee10ae31..de486af28c531e53470d64cb71b4ae309f753796 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -58,6 +58,10 @@
 
 #define UBUS_TIMEOUT            1000
 
+/* TODO/FIXME: hardcoded 5 sec */
+#define UTIL_THRESHOLD_TIMER	(5 * 1000)
+#define RCPI_THRESHOLD_TIMER	(5 * 1000)
+
 #define MAX_RADIO 20
 
 struct channel_response {
@@ -596,6 +600,19 @@ static struct wifi_radio_element *wifi_get_radio_by_mac(struct agent *a,
 	return NULL;
 }
 
+/* get netif_fh based on bssid */
+struct netif_fh *wifi_get_netif_by_bssid(struct agent *a, uint8_t *bssid)
+{
+	struct netif_fh *fh;
+
+	list_for_each_entry(fh, &a->fhlist, list) {
+		if (hwaddr_equal(fh->bssid, bssid))
+			return fh;
+	}
+
+	return NULL;
+}
+
 int wifi_teardown_iface(const char *ifname)
 {
 	config_del_iface("wireless", "wifi-iface", ifname);
@@ -917,12 +934,13 @@ int get_radio_and_bss_index(struct agent *a, uint8_t *bssid,
 	return -1;
 }
 
-/* ifname: some value, prepare the query for that specific interface,
+/* ifname: interface name, prepare the query for that specific interface;
  * ifname: NULL, include all the interface.
  */
-static int prepare_ap_metrics_query(void *agent,
-		struct cmdu_cstruct *cmdu, char *ifname)
+static struct cmdu_cstruct *prepare_ap_metrics_query(
+		void *agent, char *ifname)
 {
+	trace("%s --->\n", __func__);
 	int total_bss = 0;
 	int i, j, k;
 	int tlv_index = 0;
@@ -930,6 +948,15 @@ static int prepare_ap_metrics_query(void *agent,
 	struct wifi_radio_element *radio;
 	struct wifi_bss_element *bss;
 	struct tlv_ap_metric_query *p1;
+	struct cmdu_cstruct *cmdu;
+
+	cmdu = calloc(1, sizeof(struct cmdu_cstruct));
+	if (!cmdu)
+		return NULL;
+
+	cmdu->message_type = CMDU_AP_METRICS_QUERY;
+	memcpy(cmdu->origin, a->cntlr_almac, 6);
+	strncpy(cmdu->intf_name, "br-lan", IFNAMESIZE - 1);
 
 	if (ifname == NULL) {
 		/* AP Metrics Query TLV */
@@ -953,7 +980,7 @@ static int prepare_ap_metrics_query(void *agent,
 		radio = wifi_ifname_to_radio_element(a, ifname);
 		if (!radio) {
 			cmdu->num_tlvs = 0;
-			return -1;
+			goto error;
 		}
 
 		total_bss = radio->num_bss;
@@ -962,13 +989,13 @@ static int prepare_ap_metrics_query(void *agent,
 	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *));
 	if (!cmdu->tlvs) {
 		cmdu->num_tlvs = 0;
-		return -1;
+		goto error;
 	}
 
 
 	p1 = calloc(1, sizeof(*p1));
 	if (!p1)
-		return -1;
+		goto error;
 
 	p1->tlv_type = MAP_TLV_AP_METRIC_QUERY;
 	p1->bssid_nr = total_bss;
@@ -976,7 +1003,7 @@ static int prepare_ap_metrics_query(void *agent,
 			sizeof(*p1->ap_metric_query_bssid));
 	if (!p1->ap_metric_query_bssid) {
 		free(p1);
-		return -1;
+		goto error;
 	}
 
 	if (ifname == NULL) {
@@ -986,12 +1013,9 @@ static int prepare_ap_metrics_query(void *agent,
 		for (i = 0; i < a->num_radios; i++) {
 			radio = a->radios + i;
 // #ifdef PROFILE2
-			p2 = calloc(1, sizeof(*p2));
-			if (p2) {
-				p2->tlv_type = MAP_TLV_AP_RADIO_IDENTIFIER;
-				memcpy(p2->radio_id, radio->macaddr, 6);
+			p2 = agent_gen_ap_radio_identifier(a, radio->macaddr);
+			if (p2)
 				cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
-			}
 // #endif
 
 			for (j = 0; j < radio->num_bss; j++) {
@@ -1009,16 +1033,13 @@ static int prepare_ap_metrics_query(void *agent,
 		radio = wifi_ifname_to_radio_element(a, ifname);
 		if (!radio) {
 			map_free_tlv_cstruct((uint8_t *)p1);
-			return -1;
+			goto error;
 		}
 
 // #ifdef PROFILE2
-		p2 = calloc(1, sizeof(*p2));
-		if (p2) {
-			p2->tlv_type = MAP_TLV_AP_RADIO_IDENTIFIER;
-			memcpy(p2->radio_id, radio->macaddr, 6);
+		p2 = agent_gen_ap_radio_identifier(a, radio->macaddr);
+		if (p2)
 			cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
-		}
 // #endif
 
 		for (i = 0; i < radio->num_bss; i++) {
@@ -1032,7 +1053,10 @@ static int prepare_ap_metrics_query(void *agent,
 
 	cmdu->tlvs[tlv_index] = (uint8_t *)p1;
 
-	return 0;
+	return cmdu;
+error:
+	map_free_cmdu(cmdu);
+	return NULL;
 }
 
 static int prepare_ap_metrics_response(void *agent,
@@ -1052,6 +1076,23 @@ static int prepare_ap_metrics_response(void *agent,
 	return 0;
 }
 
+static int prepare_assoc_sta_metric_response(void *agent, char *ifname)
+{
+	trace("%s: --->\n", __func__);
+	struct cmdu_cstruct *cmdu;
+	struct agent *a = (struct agent *)agent;
+
+	cmdu = agent_gen_assoc_sta_metric_response(a, ifname);
+	if (!cmdu)
+		return -1;
+
+	agent_send_cmdu(a, cmdu);
+	map_free_cmdu(cmdu);
+
+	return 0;
+
+}
+
 int handle_1905_ack(void *agent, struct cmdu_cstruct *cmdu)
 {
 	trace("agent: %s: --->\n", __func__);
@@ -1178,63 +1219,276 @@ fail:
 	return -1;
 }
 
-int handle_map_policy_config(void *agent, struct cmdu_cstruct *cmdu)
+static uint8_t rssi_to_rcpi(int rssi)
+{
+	if (!rssi)
+		return 255;
+	else if (rssi < -110)
+		return 0;
+	else if (rssi > 0)
+		return 220;
+	else
+		return (rssi + 110) * 2;
+}
+
+static uint8_t calculate_radio_util(struct agent *a, char *ifname)
+{
+	struct wifi_radio_element *radio;
+
+	radio = wifi_ifname_to_radio_element(a, ifname);
+	if (!radio)
+		return 0;
+
+	return radio->total_utilization;
+}
+
+static uint8_t calculate_radio_rcpi(struct agent *a, char *ifname)
+{
+	int j, k;
+	struct wifi_radio_element *radio;
+	struct wifi_bss_element *bss;
+	struct wifi_sta_element *sta;
+	int8_t rssi = 0;
+	uint8_t rcpi = 0;
+
+	radio = wifi_ifname_to_radio_element(a, ifname);
+	if (!radio)
+		return 0;
+
+	for (j = 0; j < radio->num_bss; j++) {
+		bss = radio->bsslist + j;
+		for (k = 0; k < bss->num_stations; k++) {
+			sta = bss->stalist + k;
+			rssi += sta->rssi;
+		}
+	}
+
+	rcpi = rssi_to_rcpi(rssi);
+
+	return rcpi;
+}
+
+static void agent_metric_report_timer_cb(struct uloop_timeout *t)
+{
+	struct agent_config *cfg =
+		container_of(t, struct agent_config, metric_report_timer);
+	struct agent *a = container_of(cfg, struct agent, cfg);
+	struct cmdu_cstruct *cmdu;
+	char *ifname = NULL;
+
+	cmdu = prepare_ap_metrics_query((void *)a, ifname);
+	if (!cmdu)
+		goto refresh_interval;
+
+	prepare_ap_metrics_response(a, cmdu);
+	map_free_cmdu(cmdu);
+
+refresh_interval:
+	uloop_timeout_set(&cfg->metric_report_timer,
+			cfg->pcfg->report_interval * 1000);
+}
+
+static void agent_util_threshold_timer_cb(struct uloop_timeout *t)
+{
+	struct netif_fh *p = container_of(t, struct netif_fh,
+			util_threshold_timer);
+	struct agent *a = p->agent;
+	struct cmdu_cstruct *cmdu;
+	uint8_t curr_util = 0;
+	uint8_t prev_util;
+
+	curr_util = calculate_radio_util(a, p->name);
+	prev_util = p->prev_util;
+	if (((prev_util > p->cfg->util_threshold) &&
+				(curr_util > p->cfg->util_threshold)) ||
+			((prev_util < p->cfg->util_threshold) &&
+			 (curr_util < p->cfg->util_threshold)))
+		goto refresh_interval;
+
+	cmdu = prepare_ap_metrics_query((void *)a, p->name);
+	if (!cmdu)
+		goto refresh_interval;
+
+	prepare_ap_metrics_response(a, cmdu);
+	map_free_cmdu(cmdu);
+
+refresh_interval:
+	p->prev_util = curr_util;
+	uloop_timeout_set(&p->util_threshold_timer, UTIL_THRESHOLD_TIMER);
+}
+
+static void agent_rcpi_thresold_timer_cb(struct uloop_timeout *t)
+{
+	struct netif_fh *p = container_of(t, struct netif_fh,
+			rcpi_threshold_timer);
+	struct agent *a = p->agent;
+	uint8_t curr_rcpi = 0;
+	uint8_t prev_rcpi;
+
+	curr_rcpi = calculate_radio_rcpi(a, p->name);
+	prev_rcpi = p->prev_rcpi;
+	if (((prev_rcpi > p->cfg->rcpi_threshold) &&
+				(curr_rcpi > p->cfg->rcpi_threshold)) ||
+			((prev_rcpi < p->cfg->rcpi_threshold) &&
+			 (curr_rcpi < p->cfg->rcpi_threshold)))
+		goto refresh_interval;
+
+	prepare_assoc_sta_metric_response(a, p->name);
+
+refresh_interval:
+	p->prev_rcpi = curr_rcpi;
+	uloop_timeout_set(&p->rcpi_threshold_timer, RCPI_THRESHOLD_TIMER);
+}
+
+static int agent_process_policy_config(struct agent *a)
 {
-	//struct tlv *t;
+	trace("%s: --->\n", __func__);
+	int i;
+	struct agent_config *cfg = &a->cfg;
+	struct policy_cfg *c = cfg->pcfg;
+
+	if (c && (c->report_interval > 0)) {
+		cfg->metric_report_timer.cb = agent_metric_report_timer_cb;
+		uloop_timeout_set(&cfg->metric_report_timer,
+				c->report_interval * 1000);
+	}
+
+	for (i = 0; i < a->num_radios; i++) {
+		struct netif_fh *p;
+
+		p = wifi_radio_to_ap(a, a->radios[i].name);
+		if (!p)
+			continue;
+
+		if (p->cfg->util_threshold > 0) {
+			p->util_threshold_timer.cb =
+				agent_util_threshold_timer_cb;
+			uloop_timeout_set(&p->util_threshold_timer,
+					UTIL_THRESHOLD_TIMER);
+		}
+
+		if (p->cfg->rcpi_threshold > 0) {
+			p->rcpi_threshold_timer.cb =
+				agent_rcpi_thresold_timer_cb;
+			uloop_timeout_set(&p->rcpi_threshold_timer,
+					RCPI_THRESHOLD_TIMER);
+		}
+	}
+
+	/* TODO:
+	 * 17.2.37: report independent channel scan,
+	 * will be useful while extending channel scan response
+	 *
+	 * 17.2.66: Backhaul configuration
+	 * 17.2.49, 17.2.50: Will be used in traffic seperation
+	 *
+	 * 17.2.58: report unsuccesful association,
+	 * Sta events should be checked & reported accordingly
+	 */
 
+	return 0;
+}
+
+int handle_map_policy_config(void *agent, struct cmdu_cstruct *cmdu)
+{
 	trace("%s: --->\n", __func__);
+	int i;
+	uint8_t *tlv;
+	struct agent *a = (struct agent *)agent;
+	struct uci_context *ctx;
+	struct uci_package *pkg;
 
-#if 0
-	for_each_tlv(t, tlvs, len) {
-		fprintf(stderr, "type = 0x%02x\n", t->type);
+	/* send the 1905 ack message to controller */
+	// handle_1905_ack(a, cmdu);
 
-		switch (t->type) {
-		case 0x89 /* MAP_TLV_STEERING_POLICY */:
+	ctx = uci_alloc_context();
+	if (!ctx)
+		return -1;
+
+	if (uci_load(ctx, "mapagent", &pkg)) {
+		uci_free_context(ctx);
+		return -1;
+	}
+
+	for (i = 0; i < cmdu->num_tlvs; i++) {
+		tlv = (uint8_t *)cmdu->tlvs[i];
+		fprintf(stderr, "TLV: %s\n", map_stringify_tlv_type(*tlv));
+
+		switch (*tlv) {
+		case MAP_TLV_STEERING_POLICY:
 			{
-				//struct tlv_0x89 *a = tlv_get_struct(0x89, t);
+				struct tlv_steering_policy *p =
+					(struct tlv_steering_policy *)tlv;
 
-				//free(a);
+				agent_fill_steering_policy(a, p, ctx, pkg);
+				break;
 			}
-			break;
 
-		case 0x8a /* MAP_TLV_METRIC_REPORTING_POLICY */:
+		case MAP_TLV_METRIC_REPORTING_POLICY:
 			{
+				struct tlv_metric_report_policy *p =
+					(struct tlv_metric_report_policy *)tlv;
+
+				agent_fill_metric_report_policy(a, p, ctx, pkg);
+				break;
 			}
-			break;
 
-		case 0xb5 /* MAP_TLV_DEFAULT_8021Q_SETTINGS_TLV */:
+		case MAP_TLV_DEFAULT_8021Q_SETTINGS:
 			{
+				struct tlv_default_8021q_settings *p =
+					(struct tlv_default_8021q_settings *)tlv;
+
+				agent_fill_8021q_setting(a, p, ctx, pkg);
+				break;
 			}
-			break;
 
-		case 0xb6 /* MAP_TLV_TRAFFIC_SEPARATION_POLICY_TLV */:
+		case MAP_TLV_TRAFFIC_SEPARATION_POLICY:
 			{
+				struct tlv_traffic_sep_policy *p =
+					(struct tlv_traffic_sep_policy *)tlv;
+
+				agent_fill_traffic_sep_policy(a, p, ctx, pkg);
+				break;
 			}
-			break;
 
-		case 0xa4 /* MAP_TLV_CHANNEL_SCAN_REPORTING_POLICY_TLV */:
+		case MAP_TLV_CHANNEL_SCAN_REPORTING_POLICY:
 			{
+				struct tlv_ch_scan_rep_policy *p =
+					(struct tlv_ch_scan_rep_policy *)tlv;
+
+				agent_fill_ch_scan_rep_policy(a, p, ctx, pkg);
+				break;
 			}
-			break;
 
-		case 0xc4 /* MAP_TLV_UNSUCCESS_ASSOCIATION_POLICY_TLV */:
+		case MAP_TLV_UNSUCCESS_ASSOCIATION_POLICY:
 			{
+				struct tlv_unsuccess_assoc_policy *p =
+					(struct tlv_unsuccess_assoc_policy *)tlv;
+
+				agent_fill_unsuccess_assoc_policy(a, p, ctx, pkg);
+				break;
 			}
-			break;
 
-		case 0xd0 /* MAP_TLV_BACKHAUL_BSS_CONFIG_TLV */:
+		case MAP_TLV_BACKHAUL_BSS_CONFIG:
 			{
-			}
-			break;
+				struct tlv_backhaul_bss_config *p =
+					(struct tlv_backhaul_bss_config *)tlv;
 
-		default:
-			break;
+				agent_fill_backhaul_bss_config(a, p, ctx, pkg);
+				break;
+			}
 		}
 	}
-#endif
 
-	/* update core structs in agent */
-	//TODO
+	/* update agent config file */
+	uci_commit(ctx, &pkg, false);
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
+
+	/* Reload agent config */
+	agent_config_reload(&a->cfg);
+
+	agent_process_policy_config(a);
 
 	return 0;
 }
diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c
index 532a4a542d39188b58a1fa86f100cbe6fbb7bbff..7ca4c85944b130089316b813fa3dcde3471be03c 100644
--- a/src/core/agent_tlv_generator.c
+++ b/src/core/agent_tlv_generator.c
@@ -888,3 +888,606 @@ struct tlv_assoc_sta_ext_link_metric *agent_gen_assoc_sta_ext_link_metric(
 
 	return p;
 }
+
+struct tlv_ap_radio_identifier *agent_gen_ap_radio_identifier(
+		struct agent *a, uint8_t *radio_id)
+{
+	struct tlv_ap_radio_identifier *p;
+
+	p = calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_AP_RADIO_IDENTIFIER;
+	memcpy(p->radio_id, radio_id, 6);
+
+	return p;
+}
+
+int agent_fill_steering_policy(struct agent *a,
+		struct tlv_steering_policy *p,
+		struct uci_context *ctx, struct uci_package *pkg)
+{
+	int ret, i;
+	struct uci_element *e;
+	struct uci_ptr ptr;
+	char buf[64] = {0};
+	char addr[18] = {0};
+
+	/* Add exclude list & btm exclude list in 'agent' section */
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_section *s = uci_to_section(e);
+
+		if (strcmp(s->type, "agent"))
+			continue;
+
+		for (i = 0; i < p->local_disallowed_sta_nr; i++) {
+			memset(buf, 0, sizeof(buf));
+			memset(addr, 0, sizeof(addr));
+			hwaddr_ntoa(p->local_disallowed_sta_macs[i].addr, addr);
+			snprintf(buf, sizeof(buf) - 1,
+					"%s.%s.steer_exclude=%s",
+					pkg->e.name, s->e.name, addr);
+			ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+			if (ret != UCI_OK)
+				return -1;
+
+			uci_add_list(ctx, &ptr);
+			uci_save(ctx, ptr.p);
+		}
+
+		for (i = 0; i < p->btm_disallowed_sta_nr; i++) {
+			memset(buf, 0, sizeof(buf));
+			memset(addr, 0, sizeof(addr));
+			hwaddr_ntoa(p->btm_disallowed_sta_macs[i].addr, addr);
+			snprintf(buf, sizeof(buf) - 1,
+					"%s.%s.steer_exclude_btm=%s",
+					pkg->e.name, s->e.name, addr);
+			ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+			if (ret != UCI_OK)
+				return -1;
+
+			uci_add_list(ctx, &ptr);
+			uci_save(ctx, ptr.p);
+		}
+
+		break;
+	}
+
+	for (i = 0; i < p->control_policy_radio_nr; i++) {
+		int j, k;
+		int radio_index;
+		struct wifi_radio_element *radio;
+		int ifs_index = -1;
+
+		radio_index = get_radio_index(a, p->control_policy[i].radio_id);
+		if (radio_index == -1)
+			continue;
+
+		radio = a->radios + radio_index;
+		for (j = 0; j < WIFI_DEVICE_MAX_NUM; j++) {
+			if (!strcmp(a->ifs[j].radio, radio->name)) {
+				ifs_index = j;
+				break;
+			}
+		}
+
+		if (ifs_index == -1)
+			continue;
+
+		/* add the configuration in each iface section for specific radio */
+		for (k = 0; k < WIFI_DEVICE_MAX_NUM; k++) {
+			uci_foreach_element(&pkg->sections, e) {
+				char iface_name[16] = {0};
+				struct uci_section *s = uci_to_section(e);
+				struct uci_element *e1;
+
+				if (strcmp(s->type, "fh-iface"))
+					continue;
+
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1, "%s.%s.ifname",
+						pkg->e.name, s->e.name);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ptr.value && (ret != UCI_OK)) {
+					fprintf(stderr, "value not found\n");
+					continue;
+				}
+
+				e1 = ptr.last;
+				if (e1->type == UCI_TYPE_OPTION)
+					strncpy(iface_name, ptr.o->v.string, 15);
+
+				if (strcmp(iface_name, a->ifs[ifs_index].iface[k].name))
+					continue;
+
+				/* Add the policy config params */
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1,
+						"%s.%s.policy=%d",
+						pkg->e.name, s->e.name,
+						p->control_policy[i].steering_policy);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ret != UCI_OK)
+					return -1;
+
+				uci_set(ctx, &ptr);
+				uci_save(ctx, ptr.p);
+
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1,
+						"%s.%s.util_threshold=%d",
+						pkg->e.name, s->e.name,
+						p->control_policy[i].channel_utilization_thres);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ret != UCI_OK)
+					return -1;
+
+				uci_set(ctx, &ptr);
+				uci_save(ctx, ptr.p);
+
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1,
+						"%s.%s.rcpi_threshold=%d",
+						pkg->e.name, s->e.name,
+						p->control_policy[i].rcpi_steering_thres);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ret != UCI_OK)
+					return -1;
+
+				uci_set(ctx, &ptr);
+				uci_save(ctx, ptr.p);
+
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int agent_fill_metric_report_policy(struct agent *a,
+		struct tlv_metric_report_policy *p, struct uci_context *ctx,
+		struct uci_package *pkg)
+{
+	int ret, i;
+	struct uci_element *e;
+	struct uci_ptr ptr;
+	char buf[64] = {0};
+	bool is_section_found = false;
+	struct uci_section *s;
+
+	uci_foreach_element(&pkg->sections, e) {
+		s = uci_to_section(e);
+
+		if (!strcmp(s->type, "policy")) {
+			is_section_found = true;
+			break;
+		}
+	}
+
+	if (!is_section_found) {
+		/* add a new section 'policy' */
+		ret = uci_add_section(ctx, pkg, "policy", &s);
+		if (ret != UCI_OK)
+			return -1;
+
+		uci_save(ctx, pkg);
+	}
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1,
+			"%s.%s.report_interval=%d",
+			pkg->e.name, s->e.name, p->interval);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	/* Add radio specific params in fh-iface section */
+	for (i = 0; i < p->metric_reporting_policy_radio_nr; i++) {
+		int j, k;
+		int ifs_index = -1;
+		int radio_index;
+		struct wifi_radio_element *radio;
+
+		radio_index = get_radio_index(a,
+				p->metric_reporting_policy[i].radio_id);
+		if (radio_index == -1)
+			continue;
+
+		radio = a->radios + radio_index;
+		for (j = 0; j < WIFI_DEVICE_MAX_NUM; j++) {
+			if (!strcmp(a->ifs[j].radio, radio->name)) {
+				ifs_index = j;
+				break;
+			}
+		}
+
+		if (ifs_index == -1)
+			continue;
+
+		/* add configuration in each iface section for specific radio */
+		for (k = 0; k < WIFI_DEVICE_MAX_NUM; k++) {
+			uci_foreach_element(&pkg->sections, e) {
+				char iface_name[16] = {0};
+				struct uci_section *s = uci_to_section(e);
+				struct uci_element *e1;
+
+				if (strcmp(s->type, "fh-iface"))
+					continue;
+
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1, "%s.%s.ifname",
+						pkg->e.name, s->e.name);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ptr.value && (ret != UCI_OK)) {
+					fprintf(stderr, "value not found\n");
+					continue;
+				}
+
+				e1 = ptr.last;
+				if (e1->type == UCI_TYPE_OPTION)
+					strncpy(iface_name, ptr.o->v.string, 15);
+
+				if (strcmp(iface_name, a->ifs[ifs_index].iface[k].name))
+					continue;
+
+				/* Add the policy config params */
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1,
+						"%s.%s.report_rcpi_threshold=%d",
+						pkg->e.name, s->e.name,
+						p->metric_reporting_policy[i].rcpi_thres);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ret != UCI_OK)
+					return -1;
+
+				uci_set(ctx, &ptr);
+				uci_save(ctx, ptr.p);
+
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1,
+						"%s.%s.rcpi_hysteresis_margin=%d",
+						pkg->e.name, s->e.name,
+						p->metric_reporting_policy[i].rcpi_hysteresis_margin);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ret != UCI_OK)
+					return -1;
+
+				uci_set(ctx, &ptr);
+				uci_save(ctx, ptr.p);
+
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1,
+						"%s.%s.report_util_threshold=%d",
+						pkg->e.name, s->e.name,
+						p->metric_reporting_policy[i].channel_utilization_thres);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ret != UCI_OK)
+					return -1;
+
+				uci_set(ctx, &ptr);
+				uci_save(ctx, ptr.p);
+
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1,
+						"%s.%s.include_sta_stats=%d",
+						pkg->e.name, s->e.name,
+						p->metric_reporting_policy[i].is_assoc_sta_traffic_stats);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ret != UCI_OK)
+					return -1;
+
+				uci_set(ctx, &ptr);
+				uci_save(ctx, ptr.p);
+
+				memset(buf, 0, sizeof(buf));
+				snprintf(buf, sizeof(buf) - 1,
+						"%s.%s.include_sta_metric=%d",
+						pkg->e.name, s->e.name,
+						p->metric_reporting_policy[i].is_assoc_sta_link_metrics);
+				ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+				if (ret != UCI_OK)
+					return -1;
+
+				uci_set(ctx, &ptr);
+				uci_save(ctx, ptr.p);
+
+				break;
+			}
+		}
+
+	}
+
+	return 0;
+}
+
+int agent_fill_8021q_setting(struct agent *a,
+		struct tlv_default_8021q_settings *p, struct uci_context *ctx,
+		struct uci_package *pkg)
+{
+	int ret;
+	struct uci_element *e;
+	struct uci_ptr ptr;
+	char buf[64] = {0};
+	struct uci_section *s;
+	bool is_section_found = false;
+
+	uci_foreach_element(&pkg->sections, e) {
+		s = uci_to_section(e);
+
+		if (!strcmp(s->type, "policy")) {
+			is_section_found = true;
+			break;
+		}
+	}
+
+	if (!is_section_found) {
+		/* add a new section 'policy' */
+		ret = uci_add_section(ctx, pkg, "policy", &s);
+		if (ret != UCI_OK)
+			return -1;
+
+		uci_save(ctx, pkg);
+	}
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1, "%s.%s.pvid=%d",
+			pkg->e.name, s->e.name,
+			p->primary_vid);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1, "%s.%s.pcp_default=%d",
+			pkg->e.name, s->e.name, p->pcp);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	return 0;
+}
+
+int agent_fill_traffic_sep_policy(struct agent *a,
+		struct tlv_traffic_sep_policy *p, struct uci_context *ctx,
+		struct uci_package *pkg)
+{
+	int ret, i;
+	struct uci_element *e;
+	struct uci_ptr ptr;
+	char buf[64];
+
+	for (i = 0; i < p->nbr_ssid; i++) {
+		uci_foreach_element(&pkg->sections, e) {
+			struct uci_element *e1;
+			struct uci_section *s = uci_to_section(e);
+			char section_ssid[32] = {0};
+
+			if (strcmp(s->type, "fh-iface") &&
+					strcmp(s->type, "bk-iface"))
+				continue;
+
+			memset(buf, 0, sizeof(buf));
+			snprintf(buf, sizeof(buf) - 1, "%s.%s.ssid",
+					pkg->e.name, s->e.name);
+			ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+			if (ret != UCI_OK)
+				return -1;
+
+
+			e1 = ptr.last;
+			if (e1->type == UCI_TYPE_OPTION)
+				strncpy(section_ssid, ptr.o->v.string, 31);
+
+			if (strcmp(section_ssid, p->data[i].ssid))
+				continue;
+
+			memset(buf, 0, sizeof(buf));
+			snprintf(buf, sizeof(buf) - 1, "%s.%s.vid=%d",
+					pkg->e.name, s->e.name,
+					p->data[i].vid);
+			ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+			if (ret != UCI_OK)
+				return -1;
+
+			uci_set(ctx, &ptr);
+			uci_save(ctx, ptr.p);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int agent_fill_ch_scan_rep_policy(struct agent *a,
+		struct tlv_ch_scan_rep_policy *p, struct uci_context *ctx,
+		struct uci_package *pkg)
+{
+	int ret;
+	struct uci_element *e;
+	struct uci_ptr ptr;
+	char buf[64] = {0};
+	bool is_section_found = false;
+	struct uci_section *s;
+
+	uci_foreach_element(&pkg->sections, e) {
+		s = uci_to_section(e);
+
+		if (!strcmp(s->type, "policy")) {
+			is_section_found = true;
+			break;
+		}
+	}
+
+	if (!is_section_found) {
+		/* add a new section 'policy' */
+		ret = uci_add_section(ctx, pkg, "policy", &s);
+		if (ret != UCI_OK)
+			return -1;
+
+		uci_save(ctx, pkg);
+	}
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1, "%s.%s.report_scan=%d",
+			pkg->e.name, s->e.name,
+			p->ch_scans);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	return 0;
+}
+
+int agent_fill_unsuccess_assoc_policy(struct agent *a,
+		struct tlv_unsuccess_assoc_policy *p, struct uci_context *ctx,
+		struct uci_package *pkg)
+{
+	int ret;
+	struct uci_element *e;
+	struct uci_ptr ptr;
+	char buf[64] = {0};
+	bool is_section_found = false;
+	struct uci_section *s;
+
+	uci_foreach_element(&pkg->sections, e) {
+		s = uci_to_section(e);
+
+		if (!strcmp(s->type, "policy")) {
+			is_section_found = true;
+			break;
+		}
+	}
+
+	if (!is_section_found) {
+		/* add a new section 'policy' */
+		ret = uci_add_section(ctx, pkg, "policy", &s);
+		if (ret != UCI_OK)
+			return -1;
+
+		uci_save(ctx, pkg);
+	}
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1,
+			"%s.%s.report_sta_assocfails=%d",
+			pkg->e.name, s->e.name, p->report);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1,
+			"%s.%s.report_sta_assocfails_rate=%d",
+			pkg->e.name, s->e.name,
+			p->max_reporting_rate);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	return 0;
+}
+
+int agent_fill_backhaul_bss_config(struct agent *a,
+		struct tlv_backhaul_bss_config *p, struct uci_context *ctx,
+		struct uci_package *pkg)
+{
+	struct netif_fh *fh;
+	struct uci_element *e;
+	struct uci_ptr ptr;
+	int ret;
+	bool is_bksec_found = false;
+	struct uci_section *s;
+	char buf[64] = {0};
+
+	fh = wifi_get_netif_by_bssid(a, p->bssid);
+	if (fh == NULL)
+		return -1;
+
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_element *e1;
+		char section_ifname[16] = {0};
+
+		s = uci_to_section(e);
+		if (strcmp(s->type, "bk-iface"))
+			continue;
+
+		memset(buf, 0, sizeof(buf));
+		snprintf(buf, sizeof(buf) - 1, "%s.%s.ifname",
+				pkg->e.name, s->e.name);
+		ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+		if (ptr.value && (ret != UCI_OK))
+			return -1;
+
+		e1 = ptr.last;
+		if (e1->type == UCI_TYPE_OPTION)
+			strncpy(section_ifname, ptr.o->v.string, 15);
+
+		if (!strcmp(section_ifname, fh->name)) {
+			is_bksec_found = true;
+			break;
+		}
+	}
+
+	if (!is_bksec_found) {
+		/* Add a new 'bk-iface section' */
+		ret = uci_add_section(ctx, pkg, "bk-iface", &s);
+		if (ret != UCI_OK)
+			return -1;
+
+		uci_save(ctx, pkg);
+	}
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1, "%s.%s.ifname=%s",
+			pkg->e.name, s->e.name, fh->name);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1,
+			"%s.%s.disallow_bsta_p1=%d",
+			pkg->e.name, s->e.name, p->p1);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf) - 1,
+			"%s.%s.disallow_bsta_p2=%d",
+			pkg->e.name, s->e.name, p->p2);
+	ret = uci_lookup_ptr(ctx, &ptr, buf, true);
+	if (ret != UCI_OK)
+		return -1;
+
+	uci_set(ctx, &ptr);
+	uci_save(ctx, ptr.p);
+
+	return 0;
+}
diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h
index d6e67cd3426d1194d09a68b397c1fda186c337d2..f3ff1d17b3b63bb98ee5359a94281aa80c80ca55 100644
--- a/src/core/agent_tlv_generator.h
+++ b/src/core/agent_tlv_generator.h
@@ -10,6 +10,11 @@
 #ifndef CNTLR_TLV_GEN_H
 #define CNTLR_TLV_GEN_H
 
+int get_radio_index(struct agent *a, uint8_t *mac);
+int get_bss_index(struct wifi_radio_element *radio, uint8_t *bssid);
+int get_radio_and_bss_index(struct agent *a, uint8_t *bssid, int *radio_index);
+struct netif_fh *wifi_get_netif_by_bssid(struct agent *a, uint8_t *bssid);
+
 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,
@@ -60,4 +65,30 @@ struct tlv_assoc_sta_link_metrics *agent_gen_assoc_sta_link_metrics(
 		struct agent *a, struct sta *s, uint8_t *bssid);
 struct tlv_assoc_sta_ext_link_metric *agent_gen_assoc_sta_ext_link_metric(
 		struct agent *a, struct sta *s, uint8_t *bssid);
+struct tlv_ap_radio_identifier *agent_gen_ap_radio_identifier(
+		struct agent *a, uint8_t *radio_id);
+
+/* Policy config related functions */
+int agent_fill_steering_policy(struct agent *a,
+		struct tlv_steering_policy *p,
+		struct uci_context *ctx, struct uci_package *pkg);
+int agent_fill_metric_report_policy(struct agent *a,
+		struct tlv_metric_report_policy *p,
+		struct uci_context *ctx, struct uci_package *pkg);
+int agent_fill_8021q_setting(struct agent *a,
+		struct tlv_default_8021q_settings *p,
+		struct uci_context *ctx, struct uci_package *pkg);
+int agent_fill_traffic_sep_policy(struct agent *a,
+		struct tlv_traffic_sep_policy *p,
+		struct uci_context *ctx, struct uci_package *pkg);
+int agent_fill_ch_scan_rep_policy(struct agent *a,
+		struct tlv_ch_scan_rep_policy *p,
+		struct uci_context *ctx, struct uci_package *pkg);
+int agent_fill_unsuccess_assoc_policy(struct agent *a,
+		struct tlv_unsuccess_assoc_policy *p,
+		struct uci_context *ctx, struct uci_package *pkg);
+int agent_fill_backhaul_bss_config(struct agent *a,
+		struct tlv_backhaul_bss_config *p,
+		struct uci_context *ctx, struct uci_package *pkg);
+
 #endif
diff --git a/src/core/config.c b/src/core/config.c
index de49dd297ab7c68516ebcc6f09c2917f5056faa1..46e5c1921a278b313981d7cbfe924910dbdc4ea1 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -859,7 +859,7 @@ void stax_del_entry(struct list_head *h, char *sta_macstr)
 	}
 }
 
-static int clean_steer_btm_excl(struct netif_fhcfg *p)
+static int clean_steer_btm_excl(struct agent_config *p)
 {
 	struct stax *n, *tmp;
 
@@ -870,7 +870,7 @@ static int clean_steer_btm_excl(struct netif_fhcfg *p)
 
 	return 0;
 }
-static int clean_steer_excl(struct netif_fhcfg *p)
+static int clean_steer_excl(struct agent_config *p)
 {
 	struct stax *n, *tmp;
 
@@ -891,6 +891,16 @@ void agent_config_dump(struct agent_config *cfg)
 	if (!cfg)
 		return;
 
+	dbg("  Steer Exclude Lists -------\n");
+	list_for_each_entry(x, &cfg->steer_excludelist, list) {
+		dbg("    mac: %s\n", x->macstring);
+	}
+
+	dbg("  Steer BTM Exclude Lists -------\n");
+	list_for_each_entry(x, &cfg->steer_btm_excludelist, list) {
+		dbg("    mac: %s\n", x->macstring);
+	}
+
 	list_for_each_entry(n, &cfg->fhlist, list) {
 		dbg("name: %s\n", n->name);
 		dbg("  enabled  : %s\n", n->enabled ? "true" : "false");
@@ -906,16 +916,6 @@ void agent_config_dump(struct agent_config *cfg)
 			 */
 		}
 
-		dbg("  Steer Exclude Lists -------\n");
-		list_for_each_entry(x, &n->steer_excludelist, list) {
-			dbg("    mac: %s\n", x->macstring);
-		}
-
-		dbg("  Steer BTM Exclude Lists -------\n");
-		list_for_each_entry(x, &n->steer_btm_excludelist, list) {
-			dbg("    mac: %s\n", x->macstring);
-		}
-
 		dbg("  Assoc Ctrl Lists -------\n");
 		list_for_each_entry(x, &n->assoc_ctrllist, list) {
 			dbg("    mac: %s\n", x->macstring);
@@ -963,8 +963,6 @@ struct netif_fhcfg *create_fronthaul_iface_config(struct agent_config *cfg,
 		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);
 
 	/* f->cfg = new; */
@@ -1233,6 +1231,8 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 		A_BRCM_SETUP,
 		/*A_CONFIGURED,*/
 		A_CNTLR_MAC,
+		A_EXCLUDE,
+		A_EXCLUDE_BTM,
 		NUM_POLICIES
 	};
 	const struct uci_parse_option opts[] = {
@@ -1242,6 +1242,8 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 		{ .name = "brcm_setup", .type = UCI_TYPE_STRING },
 		/*{ .name = "configured", .type = UCI_TYPE_STRING },*/
 		{ .name = "controller_macaddr", .type = UCI_TYPE_STRING },
+		{ .name = "exclude", .type = UCI_TYPE_LIST },
+		{ .name = "exclude_btm", .type = UCI_TYPE_LIST },
 	};
 	struct uci_option *tb[NUM_POLICIES];
 
@@ -1268,6 +1270,28 @@ static int agent_config_get_wifi_agent(struct agent_config *a,
 	if (tb[A_CNTLR_MAC])
 		hwaddr_aton(tb[A_CNTLR_MAC]->v.string, a->cntlr_almac);
 
+	if (tb[A_EXCLUDE]) {
+		struct uci_element *xi;
+
+		dbg("Steer: exclude: ");
+		uci_foreach_element(&tb[A_EXCLUDE]->v.list, xi) {
+			dbg("%s ", xi->name);
+			stax_add_entry(&a->steer_excludelist, xi->name);
+		}
+		dbg("\n");
+	}
+
+	if (tb[A_EXCLUDE_BTM]) {
+		struct uci_element *xi;
+
+		dbg("Steer: exclude_btm: ");
+		uci_foreach_element(&tb[A_EXCLUDE_BTM]->v.list, xi) {
+			dbg("%s ", xi->name);
+			stax_add_entry(&a->steer_btm_excludelist, xi->name);
+		}
+		dbg("\n");
+	}
+
 	return 0;
 }
 
@@ -1348,6 +1372,8 @@ static int agent_config_get_bk_iface(struct agent_config *a,
 		BK_SSID,
 		BK_KEY,
 		BK_ENCRYPTION,
+		BK_DISALLOWED_BSTA_P1,
+		BK_DISALLOWED_BSTA_P2,
 		NUM_POLICIES
 	};
 	const struct uci_parse_option opts[] = {
@@ -1358,7 +1384,9 @@ static int agent_config_get_bk_iface(struct agent_config *a,
 		{ .name = "onboarded", .type = UCI_TYPE_STRING },
 		{ .name = "ssid", .type = UCI_TYPE_STRING },
 		{ .name = "key", .type = UCI_TYPE_STRING },
-		{ .name = "encryption", .type = UCI_TYPE_STRING }
+		{ .name = "encryption", .type = UCI_TYPE_STRING },
+		{ .name = "disallow_bsta_p1", .type = UCI_TYPE_STRING },
+		{ .name = "disallow_bsta_p2", .type = UCI_TYPE_STRING }
 	};
 	struct uci_option *tb[NUM_POLICIES];
 	struct netif_bkcfg *bk;
@@ -1427,6 +1455,14 @@ static int agent_config_get_bk_iface(struct agent_config *a,
 		strncpy(bk->encryption, encryption, sizeof(bk->encryption) - 1);
 	}
 
+	if (tb[BK_DISALLOWED_BSTA_P1])
+		bk->disallowed_bsta_p1 =
+			atoi(tb[BK_DISALLOWED_BSTA_P1]->v.string);
+
+	if (tb[BK_DISALLOWED_BSTA_P2])
+		bk->disallowed_bsta_p2 =
+			atoi(tb[BK_DISALLOWED_BSTA_P2]->v.string);
+
 	return 0;
 }
 
@@ -1438,8 +1474,6 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		FH_BAND,
 		FH_STEER,
 		FH_DEVICE,
-		FH_EXCLUDE,
-		FH_EXCLUDE_BTM,
 		FH_ASSOC_CTRL,
 		FH_BTM_RETRY,
 		FH_BTM_RETRY_SECS,
@@ -1450,6 +1484,14 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		FH_SSID,
 		FH_KEY,
 		FH_ENCRYPTION,
+		FH_POLICY,
+		FH_UTIL_THRESHOLD,
+		FH_RCPI_THRESHOLD,
+		FH_REPORT_RCPI_THRESHOLD,
+		FH_RCPI_HYSTERESIS_MARGIN,
+		FH_REPORT_UTIL_THRESHOLD,
+		FH_INCLUDE_STA_STATS,
+		FH_INCLUDE_STA_METRIC,
 		NUM_POLICIES,
 	};
 	const struct uci_parse_option opts[] = {
@@ -1457,8 +1499,6 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		{ .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 },
 		{ .name = "btm_retry", .type = UCI_TYPE_STRING },
 		{ .name = "btm_retry_secs", .type = UCI_TYPE_STRING },
@@ -1468,7 +1508,15 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		{ .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 }
+		{ .name = "encryption", .type = UCI_TYPE_STRING },
+		{ .name = "policy", .type = UCI_TYPE_STRING },
+		{ .name = "util_threshold", .type = UCI_TYPE_STRING },
+		{ .name = "rcpi_threshold", .type = UCI_TYPE_STRING },
+		{ .name = "report_rcpi_threshold", .type = UCI_TYPE_STRING },
+		{ .name = "rcpi_hysteresis_margin", .type = UCI_TYPE_STRING },
+		{ .name = "report_util_threshold", .type = UCI_TYPE_STRING },
+		{ .name = "include_sta_stats", .type = UCI_TYPE_STRING },
+		{ .name = "include_sta_metric", .type = UCI_TYPE_STRING }
 	};
 	struct uci_option *tb[NUM_POLICIES];
 	struct netif_fhcfg *fh;
@@ -1488,8 +1536,6 @@ static int agent_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);
 		}
@@ -1538,28 +1584,6 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		strncpy(fh->device, device, sizeof(fh->device) - 1);
 	}
 
-	if (tb[FH_EXCLUDE]) {
-		struct uci_element *xi;
-
-		dbg("Steer: exclude: ");
-		uci_foreach_element(&tb[FH_EXCLUDE]->v.list, xi) {
-			dbg("%s ", xi->name);
-			stax_add_entry(&fh->steer_excludelist, xi->name);
-		}
-		dbg("\n");
-	}
-
-	if (tb[FH_EXCLUDE_BTM]) {
-		struct uci_element *xi;
-
-		dbg("Steer: exclude_btm: ");
-		uci_foreach_element(&tb[FH_EXCLUDE_BTM]->v.list, xi) {
-			dbg("%s ", xi->name);
-			stax_add_entry(&fh->steer_btm_excludelist, xi->name);
-		}
-		dbg("\n");
-	}
-
 	if (tb[FH_BTM_RETRY])
 		fh->steer_btm_retry = atoi(tb[FH_BTM_RETRY]->v.string);
 
@@ -1602,6 +1626,35 @@ static int agent_config_get_fh_iface(struct agent_config *a,
 		strncpy(fh->encryption, encryption, sizeof(fh->encryption) - 1);
 	}
 
+	if (tb[FH_POLICY])
+		fh->policy = atoi(tb[FH_POLICY]->v.string);
+
+	if (tb[FH_UTIL_THRESHOLD])
+		fh->util_threshold = atoi(tb[FH_UTIL_THRESHOLD]->v.string);
+
+	if (tb[FH_RCPI_THRESHOLD])
+		fh->rcpi_threshold = atoi(tb[FH_RCPI_THRESHOLD]->v.string);
+
+	if (tb[FH_REPORT_RCPI_THRESHOLD])
+		fh->report_rcpi_threshold =
+			atoi(tb[FH_REPORT_RCPI_THRESHOLD]->v.string);
+
+	if (tb[FH_RCPI_HYSTERESIS_MARGIN])
+		fh->rcpi_hysteresis_margin =
+			atoi(tb[FH_RCPI_HYSTERESIS_MARGIN]->v.string);
+
+	if (tb[FH_REPORT_UTIL_THRESHOLD])
+		fh->report_util_threshold =
+			atoi(tb[FH_REPORT_UTIL_THRESHOLD]->v.string);
+
+	if (tb[FH_INCLUDE_STA_STATS])
+		fh->include_sta_stats =
+			atoi(tb[FH_INCLUDE_STA_STATS]->v.string);
+
+	if (tb[FH_INCLUDE_STA_METRIC])
+		fh->include_sta_metric =
+			atoi(tb[FH_INCLUDE_STA_METRIC]->v.string);
+
 	return 0;
 }
 
@@ -1621,6 +1674,64 @@ static int agent_config_get_steer_param(struct agent_config *a,
 	return 0;
 }
 
+static int agent_config_get_policy_param(struct agent_config *a,
+		struct uci_section *s)
+{
+	enum {
+		POL_REPORT_INTERVAL,
+		POL_PVID,
+		POL_PCP_DEFAULT,
+		POL_REPORT_SCAN,
+		POL_REPORT_STA_ASSOCFAILS,
+		POL_REPORT_STA_ASSOCFAILS_RATE,
+		NUM_POLICIES
+	};
+	const struct uci_parse_option opts[] = {
+		{ .name = "report_interval", .type = UCI_TYPE_STRING },
+		{ .name = "pvid", .type = UCI_TYPE_STRING },
+		{ .name = "pcp_default", .type = UCI_TYPE_STRING },
+		{ .name = "repost_scan", .type = UCI_TYPE_STRING },
+		{ .name = "report_sta_assocfails", .type = UCI_TYPE_STRING },
+		{ .name = "report_sta_assocfails_rate", .type = UCI_TYPE_STRING },
+	};
+
+	struct uci_option *tb[NUM_POLICIES];
+	struct policy_cfg *cfg;
+
+	uci_parse_section(s, opts, NUM_POLICIES, tb);
+
+	cfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg));
+	if (!cfg)
+		return -1;
+
+	if (tb[POL_REPORT_INTERVAL])
+		cfg->report_interval = atoi(tb[POL_REPORT_INTERVAL]->v.string);
+
+	if (tb[POL_PVID])
+		cfg->pvid = atoi(tb[POL_PVID]->v.string);
+
+	if (tb[POL_PCP_DEFAULT])
+		cfg->pcp_default = atoi(tb[POL_PCP_DEFAULT]->v.string);
+
+	if (tb[POL_REPORT_SCAN])
+		cfg->report_scan = atoi(tb[POL_REPORT_SCAN]->v.string);
+
+	if (tb[POL_REPORT_STA_ASSOCFAILS])
+		cfg->report_sta_assocfails =
+			atoi(tb[POL_REPORT_STA_ASSOCFAILS]->v.string);
+
+	if (tb[POL_REPORT_STA_ASSOCFAILS_RATE])
+		cfg->report_sta_assocfails_rate =
+			atoi(tb[POL_REPORT_STA_ASSOCFAILS_RATE]->v.string);
+
+	if (a->pcfg)
+		free(a->pcfg);
+
+	a->pcfg = cfg;
+
+	return 0;
+}
+
 int agent_config_reload(struct agent_config *cfg)
 {
 	struct uci_context *ctx;
@@ -1652,6 +1763,8 @@ int agent_config_reload(struct agent_config *cfg)
 			agent_config_get_bk_iface(cfg, s);
 		else if (!strcmp(s->type, "steer"))
 			agent_config_get_steer_param(cfg, s);
+		else if (!strcmp(s->type, "policy"))
+			agent_config_get_policy_param(cfg, s);
 	}
 
 	uci_free_context(ctx);
@@ -1886,6 +1999,8 @@ int agent_config_init(struct agent_config *cfg)
 	INIT_LIST_HEAD(&cfg->fhlist);
 	INIT_LIST_HEAD(&cfg->bklist);
 	INIT_LIST_HEAD(&cfg->radiolist);
+	INIT_LIST_HEAD(&cfg->steer_excludelist);
+	INIT_LIST_HEAD(&cfg->steer_btm_excludelist);
 
 	agent_config_prepare(cfg);
 	agent_config_reload(cfg);
@@ -1910,8 +2025,6 @@ int clean_all_bk(struct agent_config *cfg)
 
 void clean_fh(struct netif_fhcfg *p)
 {
-	clean_steer_btm_excl(p);
-	clean_steer_excl(p);
 	list_del(&p->list);
 	free(p);
 }
@@ -1930,6 +2043,11 @@ int agent_config_clean(struct agent_config *cfg)
 {
 	clean_all_fh(cfg);
 	clean_all_bk(cfg);
+	clean_steer_btm_excl(cfg);
+	clean_steer_excl(cfg);
+
+	if (cfg->pcfg)
+		free(cfg->pcfg);
 
 	return 0;
 }
diff --git a/src/core/config.h b/src/core/config.h
index c13ddbadba2e0dea47e0ec19806527412a0b55d3..1c8d3d64782b236dfa9f83e6368db69451c16e06 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -50,6 +50,12 @@ struct stax {
 void stax_add_entry(struct list_head *h, char *sta_macstr);
 void stax_del_entry(struct list_head *h, char *sta_macstr);
 
+enum agent_steer_policy {
+	AGENT_STEER_DISALLOW,		/* agent shall not steer based on rcpi */
+	AGENT_STEER_RCPI_MANDATE,	/* agent shall steer based on rcpi */
+	AGENT_STEER_RCPI_ALLOW,		/* agent may steer based on rcpi */
+};
+
 /* per-bss interface config is good for now.
  * per-sta config is overkill, or maybe not ;)
  */
@@ -81,15 +87,18 @@ struct netif_fhcfg {
 	/** ordered list of policies effective on per-bss interface */
 	struct list_head steer_policylist;
 
-	/** STAs excluded from steering; list of stax structs */
-	struct list_head steer_excludelist;
-
-	/** STAs excluded from BTM req steering; list of stax structs */
-	struct list_head steer_btm_excludelist;
-
 	/** STAs assoc controlled; list of stax structs */
 	struct list_head assoc_ctrllist;
 
+	enum agent_steer_policy policy;
+	uint8_t util_threshold;
+	uint8_t rcpi_threshold;
+	uint8_t report_rcpi_threshold;
+	uint8_t rcpi_hysteresis_margin;
+	uint8_t report_util_threshold;
+	bool include_sta_stats;
+	bool include_sta_metric;
+
 	struct list_head list;  /* link to next netif_config */
 };
 
@@ -102,10 +111,22 @@ struct netif_bkcfg {
 	char encryption[32];
 	bool enabled;
 	bool onboarded;
+	bool disallowed_bsta_p1;
+	bool disallowed_bsta_p2;
 	/* TODO: others as needed */
 	struct list_head list;  /* link to next netif_bkcfg */
 };
 
+
+struct policy_cfg {
+	uint8_t report_interval;
+	uint16_t pvid;
+	uint8_t pcp_default;
+	bool report_scan;
+	bool report_sta_assocfails;
+	uint32_t report_sta_assocfails_rate;
+};
+
 enum runfreq {
 	AGENT_RUN_OFF,
 	AGENT_RUN_HIGH,
@@ -136,6 +157,16 @@ struct agent_config {
 	bool brcm_setup;
 	bool configured;
 	uint8_t cntlr_almac[6];
+
+	struct policy_cfg *pcfg;  /* policy section */
+	struct uloop_timeout metric_report_timer;
+
+	/** STAs excluded from steering; list of stax structs */
+	struct list_head steer_excludelist;
+
+	/** STAs excluded from BTM req steering; list of stax structs */
+	struct list_head steer_btm_excludelist;
+
 };
 
 #if 0