diff --git a/src/core/agent_cmdu_generator.c b/src/core/agent_cmdu_generator.c
index faa258700acf8be93ad11d17fd8dbba8b7eed91a..3b2d19d77aacfbb9fc4ffe2d291cd6451ce7ca01 100644
--- a/src/core/agent_cmdu_generator.c
+++ b/src/core/agent_cmdu_generator.c
@@ -160,3 +160,230 @@ fail_cmdu:
 	free(cmdu);
 	return NULL;
 }
+
+struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
+		struct cmdu_cstruct *rec_cmdu)
+{
+	int i, j;
+	int tlv_index = 0;
+	uint8_t *tmp;
+	struct cmdu_cstruct *cmdu;
+
+	cmdu = calloc(1, sizeof(struct cmdu_cstruct));
+	if (!cmdu) {
+		dbg("Out of memory.!\n");
+		return NULL;
+	}
+
+	cmdu->message_type = CMDU_AP_METRICS_RESPONSE;
+	memcpy(cmdu->origin, rec_cmdu->origin, 6);
+	strncpy(cmdu->intf_name, rec_cmdu->intf_name, IFNAMESIZE - 1);
+	cmdu->message_id = rec_cmdu->message_id;
+
+	/* Calculate number of TLVs required for the response
+	 * based on the received CMDU
+	 */
+	for (i = 0; i < rec_cmdu->num_tlvs; i++) {
+		tmp = (uint8_t *)rec_cmdu->tlvs[i];
+
+		switch (*tmp) {
+		case MAP_TLV_AP_RADIO_IDENTIFIER:
+			{
+				int radio_index;
+				struct tlv_ap_radio_identifier *p =
+					(struct tlv_ap_radio_identifier *)tmp;
+
+				radio_index = get_radio_index(a, p->radio_id);
+				if (radio_index != -1) {
+// #ifdef PROFILE2
+					/* Radio Metrics TLV */
+					cmdu->num_tlvs++;
+// #endif
+				}
+				break;
+			}
+
+		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;
+
+					bss_index = get_radio_and_bss_index(a,
+							p->ap_metric_query_bssid[j].bssid,
+							&radio_index);
+
+					if (bss_index == -1)
+						continue;
+
+					/* AP Metrics TLV */
+					cmdu->num_tlvs++;
+// #ifdef PROFILE2
+					/* AP Extended Metrics TLV */
+					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) {
+						/* Associated STA Traffic Stats TLV */
+						cmdu->num_tlvs += num_sta;
+					// }
+
+					// if (fh->cfg->include_sta_metric) {
+						/* Associated STA Link Metrics TLV */
+						cmdu->num_tlvs += num_sta;
+
+// #ifdef PROFILE2
+						/* Associated STA Extended Link Metrics TLV */
+						cmdu->num_tlvs += num_sta;
+// #endif
+					// }
+
+				}
+				break;
+			}
+
+		default:
+			dbg("Unsupported tlv in cmdu:%s\n",
+					map_stringify_cmdu_type(rec_cmdu->message_type));
+			break;
+		}
+	}
+
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *));
+	if (!cmdu->tlvs) {
+		cmdu->num_tlvs = 0;
+		goto error;
+	}
+
+	/* Process response based on received CMDU */
+	for (i = 0; i < rec_cmdu->num_tlvs; i++) {
+		tmp = (uint8_t *)rec_cmdu->tlvs[i];
+
+		switch (*tmp) {
+		case MAP_TLV_AP_RADIO_IDENTIFIER:
+			{
+				int radio_index;
+				struct tlv_radio_metrics *p1;
+				struct tlv_ap_radio_identifier *p =
+					(struct tlv_ap_radio_identifier *)tmp;
+
+				radio_index = get_radio_index(a, p->radio_id);
+				if (radio_index != -1) {
+// #ifdef PROFILE2
+					/* Radio Metrics TLV */
+					p1 = agent_gen_radio_metrics(a,
+							radio_index);
+					if (!p1)
+						goto error;
+
+					cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
+// #endif
+				}
+				break;
+			}
+
+		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++) {
+					struct sta *s;
+
+					bss_index = get_radio_and_bss_index(a,
+							p->ap_metric_query_bssid[j].bssid,
+							&radio_index);
+
+					if (bss_index == -1)
+						continue;
+
+					radio = a->radios + radio_index;
+					bss = radio->bsslist + bss_index;
+					/* AP Metrics TLV */
+					p2 = agent_gen_ap_metrics(a,
+							radio_index, bss_index);
+					if (!p2)
+						goto error;
+
+					cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+// #ifdef PROFILE2
+					/* AP Extended Metrics TLV */
+					p3 = agent_gen_ap_ext_metrics(a,
+							radio_index, bss_index);
+					if (!p3)
+						goto error;
+
+					cmdu->tlvs[tlv_index++] = (uint8_t *)p3;
+// #endif
+
+					fh = wifi_radio_to_ap(a, radio->name);
+					if (fh == NULL)
+						continue;
+
+
+					list_for_each_entry(s, &fh->stalist, list) {
+						// if (fh->cfg->include_sta_stats) {
+							/* Associated STA Traffic Stats TLV */
+							struct tlv_assoc_sta_traffic_stats *p4;
+
+							p4 = agent_gen_assoc_sta_traffic_stats(a, s);
+							if (!p4)
+								goto error;
+
+							cmdu->tlvs[tlv_index++] = (uint8_t *)p4;
+						// }
+
+						// if (fh->cfg->include_sta_metric) {
+							struct tlv_assoc_sta_link_metrics *p5;
+							struct tlv_assoc_sta_ext_link_metric *p6;
+
+							p5 = agent_gen_assoc_sta_link_metrics(a, s, bss->bssid);
+							if (!p5)
+								goto error;
+
+							cmdu->tlvs[tlv_index++] = (uint8_t *)p5;
+
+// #ifdef PROFILE2
+							p6 = agent_gen_assoc_sta_ext_link_metric(a, s, bss->bssid);
+							if (!p6)
+								goto error;
+
+							cmdu->tlvs[tlv_index++] = (uint8_t *)p6;
+// #endif
+						// }
+
+					}
+				}
+				break;
+			}
+		}
+	}
+
+	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 acf40545f190fba54a8390ce3c5c208c556b3a31..f126aacb0fc7801f001a95d73b113cb2bcb1bec9 100644
--- a/src/core/agent_cmdu_generator.h
+++ b/src/core/agent_cmdu_generator.h
@@ -13,4 +13,10 @@
 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 *agent_gen_ap_metrics_response(struct agent *a,
+		struct cmdu_cstruct *rec_cmdu);
+
+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 59b8ea7cebb2381060531b88103e6754b97e28cc..e5b984b2e1df9820dcfbbf7ffdf006387ecf702f 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -54,6 +54,7 @@
 #include <wsc.h>
 
 #include "agent_tlv_generator.h"
+#include "agent_cmdu_generator.h"
 
 #define UBUS_TIMEOUT            1000
 
@@ -860,6 +861,181 @@ int handle_ap_autoconfig_renew(void *agent, struct cmdu_cstruct *cmdu)
 
 	return 0;
 }
+int get_radio_index(struct agent *a, uint8_t *mac)
+{
+	int i;
+
+	for (i = 0; i < a->num_radios; i++) {
+		if (hwaddr_equal(a->radios[i].macaddr, mac))
+			return i;
+	}
+
+	return -1;
+}
+
+int get_bss_index(struct wifi_radio_element *radio, uint8_t *bssid)
+{
+	int i;
+
+	for (i = 0; i < radio->num_bss; i++) {
+		if (hwaddr_equal(radio->bsslist[i].bssid, bssid))
+			return i;
+	}
+
+	return -1;
+}
+
+int get_radio_and_bss_index(struct agent *a, uint8_t *bssid,
+		int *radio_index)
+{
+	int i;
+	int bss_index;
+
+	for (i = 0; i < a->num_radios; i++) {
+		bss_index = get_bss_index(&a->radios[i], bssid);
+		if (bss_index != -1) {
+			*radio_index = i;
+			return bss_index;
+		}
+	}
+
+	return -1;
+}
+
+/* ifname: some value, 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)
+{
+	int total_bss = 0;
+	int i, j, k;
+	int tlv_index = 0;
+	struct agent *a = (struct agent *)agent;
+	struct wifi_radio_element *radio;
+	struct wifi_bss_element *bss;
+	struct tlv_ap_metric_query *p1;
+
+	if (ifname == NULL) {
+		/* AP Metrics Query TLV */
+		cmdu->num_tlvs++;
+// #ifdef PROFILE2
+		/* AP Radio Identifier TLV */
+		cmdu->num_tlvs += a->num_radios;
+// #endif
+
+		for (i = 0; i < a->num_radios; i++)
+			total_bss += a->radios[i].num_bss;
+
+	} else if (ifname && (ifname[0] != '\0')) {
+		/* AP Metrics Query TLV */
+		cmdu->num_tlvs++;
+// #ifdef PROFILE2
+		/* AP Radio Identifier TLV */
+		cmdu->num_tlvs++;
+// #endif
+
+		radio = wifi_ifname_to_radio_element(a, ifname);
+		if (!radio) {
+			cmdu->num_tlvs = 0;
+			return -1;
+		}
+
+		total_bss = radio->num_bss;
+	}
+
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *));
+	if (!cmdu->tlvs) {
+		cmdu->num_tlvs = 0;
+		return -1;
+	}
+
+
+	p1 = calloc(1, sizeof(*p1));
+	if (!p1)
+		return -1;
+
+	p1->tlv_type = MAP_TLV_AP_METRIC_QUERY;
+	p1->bssid_nr = total_bss;
+	p1->ap_metric_query_bssid = calloc(p1->bssid_nr,
+			sizeof(*p1->ap_metric_query_bssid));
+	if (!p1->ap_metric_query_bssid) {
+		free(p1);
+		return -1;
+	}
+
+	if (ifname == NULL) {
+		struct tlv_ap_radio_identifier *p2;
+
+		k = 0;
+		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);
+				cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+			}
+// #endif
+
+			for (j = 0; j < radio->num_bss; j++) {
+				bss = radio->bsslist + j;
+				memcpy(p1->ap_metric_query_bssid[k].bssid,
+						bss->bssid, 6);
+				k++;
+			}
+		}
+
+	} else if (ifname && (ifname[0] != '\0')) {
+		struct tlv_ap_radio_identifier *p2;
+
+		k = 0;
+		radio = wifi_ifname_to_radio_element(a, ifname);
+		if (!radio) {
+			map_free_tlv_cstruct((uint8_t *)p1);
+			return -1;
+		}
+
+// #ifdef PROFILE2
+		p2 = calloc(1, sizeof(*p2));
+		if (p2) {
+			p2->tlv_type = MAP_TLV_AP_RADIO_IDENTIFIER;
+			memcpy(p2->radio_id, radio->macaddr, 6);
+			cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+		}
+// #endif
+
+		for (i = 0; i < radio->num_bss; i++) {
+			bss = radio->bsslist + i;
+			memcpy(p1->ap_metric_query_bssid[k].bssid,
+					bss->bssid, 6);
+			k++;
+		}
+
+	}
+
+	cmdu->tlvs[tlv_index] = (uint8_t *)p1;
+
+	return 0;
+}
+
+static int prepare_ap_metrics_response(void *agent,
+		struct cmdu_cstruct *rec_cmdu)
+{
+	trace("%s: --->\n", __func__);
+	struct cmdu_cstruct *cmdu;
+	struct agent *a = (struct agent *)agent;
+
+	cmdu = agent_gen_ap_metrics_response(a, rec_cmdu);
+	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)
 {
@@ -1495,6 +1671,7 @@ fail_cmdu:
 int handle_ap_metrics_query(void *agent, struct cmdu_cstruct *cmdu)
 {
 	trace("%s: --->\n", __func__);
+	prepare_ap_metrics_response(agent, cmdu);
 	return 0;
 }
 
diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c
index 67d271fe67c2d8a26290d936bf36e7c413893192..532a4a542d39188b58a1fa86f100cbe6fbb7bbff 100644
--- a/src/core/agent_tlv_generator.c
+++ b/src/core/agent_tlv_generator.c
@@ -725,3 +725,166 @@ struct tlv_searched_role *agent_gen_searched_role(struct agent *a,
 
 	return p;
 }
+
+struct tlv_radio_metrics *agent_gen_radio_metrics(struct agent *a,
+		int radio_index)
+{
+	struct tlv_radio_metrics *p;
+	struct wifi_radio_element *radio = a->radios + radio_index;
+
+	p = (struct tlv_radio_metrics *)calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_RADIO_METRICS;
+	memcpy(p->radio_id, radio->macaddr, 6);
+	p->noise = radio->anpi;
+	/*
+	 * TODO/FIXME:
+	 * transmit, receive_self & receive_other;
+	 * these params need to be exposed in wifi.radio.<intf>.
+	 */
+	p->transmit = radio->tx_utilization;
+	p->receive_self = radio->rx_utilization;
+	p->receive_other = radio->other_utilization;
+
+	return p;
+}
+
+struct tlv_ap_metrics *agent_gen_ap_metrics(struct agent *a,
+		int radio_index, int bss_index)
+{
+	struct tlv_ap_metrics *p;
+	struct wifi_radio_element *radio = a->radios + radio_index;
+	struct wifi_bss_element *bss = radio->bsslist + bss_index;
+
+	p = (struct tlv_ap_metrics *)calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_AP_METRICS;
+	memcpy(p->bssid, bss->bssid, 6);
+	if (bss->is_ac_be) {
+		p->is_ac_be = bss->is_ac_be;
+		memcpy(p->service_param_info_be, bss->est_wmm_be, 3);
+	}
+	if (bss->is_ac_bk) {
+		p->is_ac_bk = bss->is_ac_bk;
+		memcpy(p->service_param_info_bk, bss->est_wmm_bk, 3);
+	}
+	if (bss->is_ac_vo) {
+		p->is_ac_vo = bss->is_ac_vo;
+		memcpy(p->service_param_info_vo, bss->est_wmm_vo, 3);
+	}
+	if (bss->is_ac_vi) {
+		p->is_ac_vi = bss->is_ac_vi;
+		memcpy(p->service_param_info_vi, bss->est_wmm_vi, 3);
+	}
+
+	return p;
+}
+
+struct tlv_ap_ext_metrics *agent_gen_ap_ext_metrics(struct agent *a,
+		int radio_index, int bss_index)
+{
+	struct tlv_ap_ext_metrics *p;
+	struct wifi_radio_element *radio = a->radios + radio_index;
+	struct wifi_bss_element *bss = radio->bsslist + bss_index;
+
+	p = (struct tlv_ap_ext_metrics *)calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_AP_EXTENDED_METRICS;
+	memcpy(p->bssid, bss->bssid, 6);
+	p->uni_bytes_sent = bss->tx_ucast_bytes;
+	p->uni_bytes_recv = bss->rx_ucast_bytes;
+	p->multi_bytes_sent = bss->tx_mcast_bytes;
+	p->multi_bytes_recv = bss->rx_mcast_bytes;
+	p->bro_bytes_sent = bss->tx_bcast_bytes;
+	p->bro_bytes_recv = bss->rx_bcast_bytes;
+
+	return p;
+}
+
+struct tlv_assoc_sta_traffic_stats *agent_gen_assoc_sta_traffic_stats(
+		struct agent *a, struct sta *s)
+{
+	struct tlv_assoc_sta_traffic_stats *p;
+
+	p = (struct tlv_assoc_sta_traffic_stats *)calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_ASSOCIATED_STA_TRAFFIC_STATS;
+	memcpy(p->addr, s->macaddr, 6);
+	p->bytes_sent = s->tx_bytes;
+	p->bytes_received = s->rx_bytes;
+	p->packets_sent = s->tx_pkts;
+	p->packets_received = s->rx_pkts;
+	p->tx_packets_err = s->tx_fail_pkts;
+	p->rx_packets_err = s->rx_fail_pkts;
+
+	return p;
+}
+
+struct tlv_assoc_sta_link_metrics *agent_gen_assoc_sta_link_metrics(
+		struct agent *a, struct sta *s, uint8_t *bssid)
+{
+	int i;
+	struct tlv_assoc_sta_link_metrics *p;
+
+	p = (struct tlv_assoc_sta_link_metrics *)calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_ASSOCIATED_STA_LINK_METRICS;
+	memcpy(p->addr, s->macaddr, 6);
+	/* Reported BSS for specific STA */
+	p->bssid_nr = 1;
+	p->sta_link_metrics_bssid = calloc(p->bssid_nr, sizeof(*p->sta_link_metrics_bssid));
+	if (p->sta_link_metrics_bssid) {
+		for (i = 0; i < p->bssid_nr; i++) {
+			memcpy(p->sta_link_metrics_bssid[i].bssid, bssid, 6);
+			p->sta_link_metrics_bssid[i].time_delta = s->connected_ms;
+			p->sta_link_metrics_bssid[i].dl_mac_data_rate = s->rx_thput;
+			p->sta_link_metrics_bssid[i].ul_mac_data_rate = s->tx_thput;
+			p->sta_link_metrics_bssid[i].ul_rcpi = s->rssi[0];
+		}
+	}
+
+	return p;
+}
+
+struct tlv_assoc_sta_ext_link_metric *agent_gen_assoc_sta_ext_link_metric(
+		struct agent *a, struct sta *s, uint8_t *bssid)
+{
+	int i;
+	struct tlv_assoc_sta_ext_link_metric *p;
+
+	p = (struct tlv_assoc_sta_ext_link_metric *)calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_ASSOCIATED_STA_EXT_LINK_METRICS;
+	memcpy(p->mac, s->macaddr, 6);
+	/* Reported BSS for specific STA */
+	p->nbr_bssid = 1;
+	p->data = calloc(p->nbr_bssid, sizeof(*p->data));
+	if (p->data) {
+		for (i = 0; i < p->nbr_bssid; i++) {
+			memcpy(p->data[i].bssid, bssid, 6);
+			p->data[i].last_data_dwn_rate = s->rx_rate;
+			p->data[i].last_data_up_rate = s->tx_rate;
+			/*
+			 * TODO/FIXME:
+			 * Need to add parameters for uti_recv, uti_transmit in
+			 * wifi.ap.<intf> stations UBUS method.
+			 */
+			p->data[i].uti_recv = 101;
+			p->data[i].uti_transmit = 101;
+		}
+	}
+
+	return p;
+}
diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h
index 68112982ff333f8c2d8598b37b7f5d38cd3d3dc4..d6e67cd3426d1194d09a68b397c1fda186c337d2 100644
--- a/src/core/agent_tlv_generator.h
+++ b/src/core/agent_tlv_generator.h
@@ -48,4 +48,16 @@ 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);
+struct tlv_radio_metrics *agent_gen_radio_metrics(struct agent *a,
+		int radio_index);
+struct tlv_ap_metrics *agent_gen_ap_metrics(struct agent *a,
+		int radio_index, int bss_index);
+struct tlv_ap_ext_metrics *agent_gen_ap_ext_metrics(struct agent *a,
+		int radio_index, int bss_index);
+struct tlv_assoc_sta_traffic_stats *agent_gen_assoc_sta_traffic_stats(
+		struct agent *a, struct sta *s);
+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);
 #endif