diff --git a/src/core/cntlr_map.c b/src/core/cntlr_map.c
index cf3b410dbbe14a76dfb630774e7af266f0dde852..153ac51f6f7c3945533d4f381193fde4d836f4d6 100644
--- a/src/core/cntlr_map.c
+++ b/src/core/cntlr_map.c
@@ -27,6 +27,7 @@
 #include <libubox/utils.h>
 #include <libubus.h>
 
+#include <easy/easy.h>
 
 #include "map_module.h"
 #include "utils.h"
@@ -88,8 +89,88 @@ int handle_1905_ack(void *cntlr, struct cmdu_cstruct *cmdu)
 	return 0;
 }
 
+
+static bool ap_caps_info_from_tlv(struct controller *c,
+					struct cmdu_cstruct *cmdu_data)
+{
+	int i, j, k;
+	int radio_index, bss_index;
+	uint8_t *tlv = NULL;
+
+	for (i = 0; i < cmdu_data->num_tlvs; i++) {
+		tlv = cmdu_data->tlvs[i];
+		trace("CMDU type: %s\n", map_stringify_tlv_type(*tlv));
+		switch (*tlv) {
+		case MAP_TLV_AP_CAPABILITY:
+			{
+				struct tlv_ap_cap *p = (struct tlv_ap_cap *)tlv;
+
+				trace("\top_ch_metric_reporting: %d\n", p->op_ch_metric_reporting);
+				trace("\tnon_op_ch_metric_reporting: %d\n", p->non_op_ch_metric_reporting);
+				trace("\tagent_init_rcpi_steering: %d\n", p->agent_init_rcpi_steering);
+				break;
+			}
+		case MAP_TLV_AP_RADIO_BASIC_CAPABILITIES:
+			{
+				struct tlv_ap_radio_basic_cap *p = (struct tlv_ap_radio_basic_cap *)tlv;
+
+				trace("\tradio_id: " MACFMT "\n", MAC2STR(p->radio_id));
+				trace("\tmax_bss_nr: %d\n", p->max_bss_nr);
+				trace("\toperating_classes_nr: %d\n", p->operating_classes_nr);
+				for (j = 0; j < p->operating_classes_nr; j++) {
+					trace("\t\top_class: %d\n", p->operating_class[j].op_class);
+					trace("\t\tmax_tx_power: %d\n", p->operating_class[j].max_tx_power);
+					trace("\t\tnon_op_ch_nr: %d\n", p->operating_class[j].non_op_ch_nr);
+
+					for (k = 0; k < p->operating_class[j].non_op_ch_nr; k++)
+						trace("\t\t\tchannel: %d\n", p->operating_class[j].channel[k]);
+				}
+				break;
+			}
+		case MAP_TLV_AP_HT_CAPABILITIES:
+			{
+				struct tlv_ap_ht_cap *p = (struct tlv_ap_ht_cap *)tlv;
+
+				trace("\tradio_id: " MACFMT "\n", MAC2STR(p->radio_id));
+				trace("\tmax_tx_streams_supported: %02x\n", p->max_tx_streams_supported);
+				trace("\tmax_rx_streams_supported: %02x\n", p->max_rx_streams_supported);
+				trace("\tgi_20_support: %s\n", (p->gi_20_support ? "true" : "false"));
+				trace("\tgi_40_support: %s\n", (p->gi_40_support ? "true" : "false"));
+				trace("\tht_40_support: %s\n", (p->ht_40_support ? "true" : "false"));
+				break;
+			}
+		case MAP_TLV_AP_VHT_CAPABILITIES:
+			{
+				struct tlv_ap_vht_cap *p = (struct tlv_ap_vht_cap *)tlv;
+
+				trace("\tradio_id: " MACFMT "\n", MAC2STR(p->radio_id));
+				trace("\tvht_tx_mcs_supported: %04x\n", p->vht_tx_mcs_supported);
+				trace("\tvht_rx_mcs_supported: %04x\n", p->vht_rx_mcs_supported);
+				trace("\tmax_tx_streams_supported: %02x\n", p->max_tx_streams_supported);
+				trace("\tmax_rx_streams_supported: %02x\n", p->max_rx_streams_supported);
+				trace("\tgi_80_support: %s\n", (p->gi_80_support ? "true" : "false"));
+				trace("\tgi_160_support: %s\n", (p->gi_160_support ? "true" : "false"));
+				trace("\tvht160_support: %s\n", (p->vht_160_support ? "true" : "false"));
+				trace("\tsu_beamformer_capable: %s\n", (p->su_beamformer_capable ? "true" : "false"));
+				trace("\tmu_beamformer_capable: %s\n", (p->mu_beamformer_capable ? "true" : "false"));
+				break;
+			}
+		default:
+			fprintf(stdout, "unknown TLV in CMDU:|%s|", map_stringify_cmdu_type(cmdu_data->message_type));
+			break;
+		}
+		trace("\n");
+	}
+
+	return 0;
+}
+
 int handle_ap_caps_report(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
+	trace("parsing AP capabilities of |%s:" MACFMT "|\n", cmdu->intf_name, MAC2STR(cmdu->origin));
+
+	ap_caps_info_from_tlv(cntlr, cmdu);
 
 	return 0;
 }
@@ -115,6 +196,7 @@ int handle_oper_channel_report(void *cntlr, struct cmdu_cstruct *cmdu)
 
 int handle_sta_caps_report(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("received sta caps report!\n");
 	return 0;
 }
 
diff --git a/src/core/cntlr_ubus.c b/src/core/cntlr_ubus.c
index 29ac9064e4a853456cd386eb8d91d05edca119b2..176119cd447af0d73ef8700a8652489c795add59 100644
--- a/src/core/cntlr_ubus.c
+++ b/src/core/cntlr_ubus.c
@@ -31,6 +31,150 @@
 
 #include "map_module.h"
 
+#include <map1905/map2.h>
+#include <map1905/maputils.h>
+
+enum {
+	AP_POLICY_AGENT,
+	//AP_POLICY_BSSID,
+	__AP_POLICY_MAX,
+};
+
+static const struct blobmsg_policy ap_caps_policy_params[__AP_POLICY_MAX] = {
+	[AP_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING }, // agent = ieee1905 AL macaddress of an agent, agent = "ff:ff:ff:ff:ff:ff" means all agents
+	//[AP_POLICY_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }
+};
+
+
+static void send_cmdu_cb(struct ubus_request *req,
+				int type, struct blob_attr *msg)
+{
+	struct json_object *jobj = NULL;
+	struct json_object *tmp;
+	uint16_t *mid;
+	char *str;
+
+	if (!msg || !req->priv) {
+		fprintf(stderr, "%s:Message recieved is NULL\n", __func__);
+		return;
+	}
+
+	mid = (uint16_t *)req->priv;
+
+	str = (char *)blobmsg_format_json_indent(msg, true, -1);
+	if (str) {
+		jobj = json_tokener_parse(str);
+		free(str);
+	}
+
+	if (jobj == NULL)
+		return;
+
+	if (json_object_object_get_ex(jobj, "mid", &tmp)) {
+		*mid = json_object_get_int(tmp);
+		fprintf(stdout, "%s:%d map-mid:%d\n", __func__, __LINE__, *mid);
+	}
+
+	json_object_put(jobj);
+}
+
+static int send_cmdu(struct controller *c,
+					struct cmdu_cstruct *cmdu_data)
+{
+	char *tlv_data = NULL;
+	uint16_t tlv_data_len = 1;
+	uint16_t tlv_str_len = 0;
+	int copy_index;
+	struct blob_buf b = { 0 };
+	char dst_addr[18] = { 0 };
+	char tlv_str[512] = { 0 };
+	uint8_t is_store_mid = 1;
+	uint8_t *ss = NULL;
+	uint16_t msgid = 0;
+	uint16_t len;
+	int ret = 0;
+	size_t i;
+	uint32_t id;
+	struct ieee1905_cmdu_msg *cmsg = NULL;
+
+	fprintf(stdout, "|%s:%d| Entry \n", __func__, __LINE__);
+
+	memset(&b, 0, sizeof(struct blob_buf));
+	blob_buf_init(&b, 0);
+
+	blobmsg_add_u32(&b, "type", cmdu_data->message_type);
+	blobmsg_add_string(&b, "egress", cmdu_data->intf_name);
+
+	blobmsg_add_u32(&b, "mid", cmdu_data->message_id);
+
+	hwaddr_ntoa(cmdu_data->origin, dst_addr);
+	blobmsg_add_string(&b, "dst_macaddr", dst_addr);
+
+	fprintf(stdout, "|%s:%d|cmdu:%s|dst:%s|\n", __func__, __LINE__,
+			map_stringify_cmdu_type(cmdu_data->message_type), dst_addr);
+
+	if (cmdu_data->num_tlvs > 0) {
+		for (i = 0; i < cmdu_data->num_tlvs; i++) {
+			len = 0;
+			ss = map_put_tlv_cstruct(cmdu_data->tlvs[i], &len);
+			if (ss) {
+				btostr(ss, len, tlv_str);
+				tlv_str_len = 2 * len;
+				tlv_data_len += tlv_str_len;
+				tlv_data = realloc(tlv_data, tlv_data_len * sizeof(char));
+				if (!tlv_data) {
+					fprintf(stderr, "%s:%d out of memory.!\n", __func__, __LINE__);
+					free(ss);
+					goto out;
+				}
+
+				copy_index = tlv_data_len - tlv_str_len - 1;
+				memcpy(tlv_data + copy_index, tlv_str, tlv_str_len);
+				memset(tlv_str, 0, sizeof(tlv_str));
+				free(ss);
+			}
+		}
+
+		tlv_data[tlv_data_len - 1] = '\0';
+		blobmsg_add_string(&b, "data", tlv_data);
+		if (tlv_data)
+			free(tlv_data);
+	}
+
+
+	if (ubus_lookup_id(c->ubus_ctx, "map.1905", &id)) {
+		fprintf(stderr, "[%s:%d] not present", __func__, __LINE__);
+		goto out;
+	}
+
+	ret = ubus_invoke(c->ubus_ctx, id, "send",
+				b.head, send_cmdu_cb,
+				(void *)&msgid,
+				1000);
+	if (ret) {
+		fprintf(stderr, "[%s:%d] ubus call failed for |map.1905 send|",
+					__func__, __LINE__);
+		goto out;
+	}
+
+	//TODO: improve /////////////////////////
+//	if (is_store_mid) {
+//		cmsg = &priv->cmsg;
+//		for (i = 0; i < MAX_CMDU_MSG; i++) {
+//			if (cmsg->msg_id[i] == -1) {
+//				cmsg->msg_id[i] = msgid;
+//				cmsg->msg_ts[i] = time(NULL);
+//				break;
+//			}
+//		}
+//	}
+	/////////////////////////////////////////
+
+out:
+	blob_buf_free(&b);
+
+	return ret;
+}
 
 static int cntlr_status(struct ubus_context *ctx, struct ubus_object *obj,
 			struct ubus_request_data *req, const char *method,
@@ -118,13 +262,80 @@ static int cntlr_status(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
+static int cntlr_req_cap(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct cmdu_cstruct *cmdu_data;
+	uint32_t total_bss = 0;
+	uint32_t k = 0;
+	uint32_t i, j;
+
+	cmdu_data = (struct cmdu_cstruct *)calloc(1, sizeof(struct cmdu_cstruct));
+	if (!cmdu_data) {
+		fprintf(stderr, "failed to malloc cmdu\n");
+		return -1;
+	}
+
+	cmdu_data->message_type = CMDU_CLIENT_CAPABILITY_QUERY;
+	cmdu_data->message_id = 1;
+
+	fprintf(stderr, "map.1905 egress interface:|%s|\n", cmdu_data->intf_name);
+
+	send_cmdu(NULL, cmdu_data);
+
+	return 0;
+}
+
+static int cntlr_ap_caps(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__AP_POLICY_MAX];
+	struct controller *c = container_of(obj, struct controller, obj);
+	char mac[18] = {0};
+	struct cmdu_cstruct *cmdu_data;
+	uint32_t total_bss = 0;
+	uint32_t k = 0;
+	uint32_t i, j;
+
+	cmdu_data = (struct cmdu_cstruct *)calloc(1, sizeof(struct cmdu_cstruct));
+	if (!cmdu_data) {
+		fprintf(stderr, "failed to malloc cmdu\n");
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	blobmsg_parse(ap_caps_policy_params, __AP_POLICY_MAX, tb, blob_data(msg), blob_len(msg));
+
+
+	if (tb[AP_POLICY_AGENT]) {
+		strncpy(mac, blobmsg_data(tb[AP_POLICY_AGENT]), sizeof(mac) - 1);
+		printf("mac = %s\n", mac);
+		if (!hwaddr_aton(mac, cmdu_data->origin))
+			return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	// TODO: ff:ff:ff:ff:ff:ff = send to all agents
+
+	cmdu_data->message_type = CMDU_AP_CAPABILITY_QUERY;
+	cmdu_data->message_id = 1;
+
+	cmdu_data->num_tlvs = 0;
+
+	send_cmdu(c, cmdu_data);
+
+	return 0;
+}
+
 int cntlr_publish_object(struct controller *c, const char *objname)
 {
 	struct ubus_object *obj;
 	struct ubus_object_type *obj_type;
 	struct ubus_method *obj_methods;
-	struct ubus_method m[2] = {
+	struct ubus_method m[3] = {
 		UBUS_METHOD_NOARG("status", cntlr_status),
+		UBUS_METHOD_NOARG("req_cap", cntlr_req_cap),
+		UBUS_METHOD("ap_caps", cntlr_ap_caps, ap_caps_policy_params),
 	};
 	int num_methods = ARRAY_SIZE(m);
 	int ret;