diff --git a/src/core/agent.c b/src/core/agent.c
index d6201c67b92160601cdaa79c7fc75e376b97b18b..5df9bc35ff28d2ac6508c303d18d7562ac5d5df2 100644
--- a/src/core/agent.c
+++ b/src/core/agent.c
@@ -223,6 +223,34 @@ static int ubus_call_object(struct agent *a, wifi_object_t wobj,
 	return 0;
 }
 
+static int ubus_call_object_subscribe_unsubscribe(struct agent *a, wifi_object_t wobj,
+		const char *method,
+		void (*response_cb)(struct ubus_request *, int, struct blob_attr *),
+		void *priv)
+{
+	struct blob_buf bb = {};
+	int ret;
+	struct subscribe_fr {
+		uint8_t type;
+		uint8_t stype;
+	} *subfr;
+
+	subfr = (struct subscribe_fr *)priv;
+	blob_buf_init(&bb, 0);
+	blobmsg_add_u32(&bb, "type", subfr->type);
+	blobmsg_add_u32(&bb, "stype", subfr->stype);
+	ret = ubus_invoke(a->ubus_ctx, wobj, method, bb.head,
+			response_cb, priv, 2 * 1000);
+	if (ret) {
+		err("Failed to get '%s' (ret = %d)\n", method, ret);
+		blob_buf_free(&bb);
+		return -1;
+	}
+
+	blob_buf_free(&bb);
+	return 0;
+}
+
 static uint32_t ubus_get_object(struct ubus_context *ctx, const char *name)
 {
 	uint32_t id;
@@ -1624,6 +1652,71 @@ out_frame:
 	return -1;
 }
 
+static int get_frame_type(struct agent *a, struct json_object *frameobj)
+{
+	const char *framestr;
+	int frame_type = -1;
+
+	framestr = json_object_to_json_string(frameobj);
+	if (!framestr)
+		return -1;
+
+	if (strstr(framestr, "reassoc"))
+		frame_type = WIFI_FRAME_REASSOC_REQ;
+	else if (strstr(framestr, "assoc"))
+		frame_type = WIFI_FRAME_ASSOC_REQ;
+	else if (strstr(framestr, "deauth"))
+		frame_type = WIFI_FRAME_DEAUTH;
+	else if (strstr(framestr, "auth"))
+		frame_type = WIFI_FRAME_AUTH;
+	else if (strstr(framestr, "action"))
+		frame_type = WIFI_FRAME_ACTION;
+
+	return frame_type;
+}
+
+static int wifi_parse_all_frame(struct agent *a, struct json_object *frameobj)
+{
+	trace("%s\n", __func__);
+	const char *framestr;
+	int stype;
+	uint8_t protocol = 0xff;
+
+	stype = get_frame_type(a, frameobj);
+	if (stype == -1)
+		return -1;
+
+	switch (stype) {
+	case WIFI_FRAME_REASSOC_REQ:
+		protocol = 0x01;
+		framestr = json_get_string(frameobj, "reassoc");
+		break;
+	case WIFI_FRAME_ASSOC_REQ:
+		protocol = 0x00;
+		framestr = json_get_string(frameobj, "assoc");
+		break;
+	case WIFI_FRAME_DEAUTH:
+		framestr = json_get_string(frameobj, "deauth");
+		break;
+	case WIFI_FRAME_AUTH:
+		framestr = json_get_string(frameobj, "auth");
+		break;
+	case WIFI_FRAME_ACTION:
+		framestr = json_get_string(frameobj, "action");
+		break;
+	default:
+		framestr = NULL;
+		break;
+	}
+
+	if (!framestr)
+		return -1;
+
+	prepare_tunneled_message((void *)a, protocol, framestr);
+
+	return 0;
+}
+
 static void wifi_iface_event_handler(void *c, struct blob_attr *msg)
 {
 	struct agent *a = (struct agent *)c;
@@ -1656,9 +1749,15 @@ static void wifi_iface_event_handler(void *c, struct blob_attr *msg)
 	if (!event)
 		goto out_json;
 
-	if (!strcmp(event, "frame-rx"))
+	if (!strcmp(event, "frame-rx")) {
 		wifi_parse_frame(a, data);
 
+		/* parse all tunneled type message
+		 * (assoc, reassoc, BTM, WNM, ANQP)
+		 */
+		wifi_parse_all_frame(a, data);
+	}
+
 out_json:
 	json_object_put(jmsg);
 out_str:
@@ -3398,6 +3497,14 @@ static int agent_init_interfaces(struct agent *a)
 
 		fn = netif_alloc_fh(f->name);
 		if (fn) {
+			struct subscribe_fr {
+				uint8_t type;
+				uint8_t stype;
+			} subfr[] = {{0, 0}, {0, 2}, {0, 10},
+				{0, 11}, {0, 12}, {0, 13}};
+			int num_subfr = ARRAY_SIZE(subfr);
+			int k;
+
 			fn->wifi = wobj;
 			fn->radio = r_wobj;
 			fn->cfg = f;
@@ -3405,8 +3512,11 @@ static int agent_init_interfaces(struct agent *a)
 			list_add(&fn->list, &a->fhlist);
 
 			ubus_call_object(a, wobj, "status", parse_ap, fn);
-			ubus_call_object(a, wobj, "subscribe_frame",
-					NULL, NULL);
+
+			for (k = 0; k < num_subfr; k++)
+				ubus_call_object_subscribe_unsubscribe(a, wobj,
+						"subscribe_frame", NULL, &subfr[k]);
+
 			ubus_call_object(a, wobj, "stats", parse_ap_stats, fn);
 		}
 	}
diff --git a/src/core/agent.h b/src/core/agent.h
index 4336fb777b07093b32f1cb4a8bb25a31e25edd41..85f281ec8dcc871ca8d815fc429f1b081e63fe0f 100644
--- a/src/core/agent.h
+++ b/src/core/agent.h
@@ -481,5 +481,7 @@ 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);
+int prepare_tunneled_message(void *agent, uint8_t protocol,
+		const char *framestr);
 
 #endif /* AGENT_H */
diff --git a/src/core/agent_cmdu_generator.c b/src/core/agent_cmdu_generator.c
index 73e84b74b560a5a32910bc70de6c82dc1af072c1..aeff49442cf267f460ae072523d45535f57c5087 100644
--- a/src/core/agent_cmdu_generator.c
+++ b/src/core/agent_cmdu_generator.c
@@ -579,3 +579,70 @@ error:
 
 	return NULL;
 }
+
+struct cmdu_cstruct *agent_gen_tunneled_msg(struct agent *a, uint8_t protocol,
+		uint8_t *sta, int frame_len, uint8_t *frame_body)
+{
+	struct cmdu_cstruct *cmdu;
+	struct tlv_source_info *p1;
+	struct tlv_tunnel_msg_type *p2;
+	struct tlv_tunneled *p3;
+	int tlv_index = 0;
+
+	/* TODO: check profile type
+	 * return NULL,in case of PROFILE-1
+	 * #ifdef PROFILE1
+	 * return NULL;
+	 * #endif
+	 */
+
+	if (!sta && !frame_body)
+		return NULL;
+
+	cmdu = calloc(1, sizeof(struct cmdu_cstruct));
+	if (!cmdu)
+		return NULL;
+
+	cmdu->message_type = CMDU_TUNNELED;
+	memcpy(cmdu->origin, a->cntlr_almac, 6);
+	/* TODO/FIXME: interface name
+	 * hardcoded: br-lan
+	 */
+	strncpy(cmdu->intf_name, "br-lan", IFNAMESIZE - 1);
+
+	cmdu->num_tlvs = 3;
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs,
+			sizeof(uint8_t *));
+	if (!cmdu->tlvs) {
+		cmdu->num_tlvs = 0;
+		goto error;
+	}
+
+	/* Source Info TLV */
+	p1 = agent_gen_source_info(a, sta);
+	if (!p1)
+		goto error;
+
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
+
+	/* Tunneled message type TLV */
+	p2 = agent_gen_tunnel_msg_type(a, protocol);
+	if (!p2)
+		goto error;
+
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+
+	/* Tunneled TLV */
+	p3 = agent_gen_tunneled(a, frame_len, frame_body);
+	if (!p3)
+		goto error;
+
+	cmdu->tlvs[tlv_index++] = (uint8_t *)p3;
+
+	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 ced1c60c67929bb290b9b307173886305e0e3e40..2eb4d20eb0577f62f862df64eab2dc90f05ab68c 100644
--- a/src/core/agent_cmdu_generator.h
+++ b/src/core/agent_cmdu_generator.h
@@ -19,5 +19,7 @@ struct cmdu_cstruct *agent_gen_assoc_sta_metric_response_per_intf(
 		struct agent *a, char *ifname);
 struct cmdu_cstruct *agent_gen_assoc_sta_metric_response(
 		struct agent *a, struct cmdu_cstruct *rec_cmdu);
+struct cmdu_cstruct *agent_gen_tunneled_msg(struct agent *a, uint8_t protocol,
+		uint8_t *sta, int frame_len, uint8_t *frame_body);
 
 #endif
diff --git a/src/core/agent_map.c b/src/core/agent_map.c
index 3bef6dcdd0bcf193c67e295270513ee1320da68a..a97e67a1d0af31116133b1d38d3c16697760f5dd 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -3013,6 +3013,57 @@ int handle_error_response(void *agent, struct cmdu_cstruct *cmdu)
 	return 0;
 }
 
+int prepare_tunneled_message(void *agent,
+		uint8_t protocol, const char *framestr)
+{
+	trace("%s: --->\n", __func__);
+	struct agent *a = (struct agent *)agent;
+	struct cmdu_cstruct *cmdu;
+	uint8_t *frame;
+	uint8_t sta_mac[6] = { 0 };
+	int len;
+	int index;
+
+	if (!framestr)
+		return -1;
+
+	/* TODO/FIXME: add other protocol
+	 * checking (BTM/WNM/ANQP)
+	 * as of now checking assoc/reassoc
+	 * type only.
+	 */
+	if ((protocol != 0x00) && (protocol != 0x01))
+		return -1;
+
+	len = strlen(framestr);
+	len = (len - 1) / 2;
+	frame = calloc(len, sizeof(uint8_t));
+	if (!frame)
+		return -1;
+
+	if (!strtob((char *)framestr, len, frame))
+		goto error;
+
+	index = 2 + 2 + 6;	/* sta mac index */
+	memcpy(sta_mac, frame + index, 6);
+
+	cmdu = agent_gen_tunneled_msg(a, protocol, sta_mac,
+			len, frame);
+	if (!cmdu)
+		goto error;
+
+	agent_send_cmdu(a, cmdu);
+	map_free_cmdu(cmdu);
+	free(frame);
+
+	return 0;
+
+error:
+	free(frame);
+
+	return -1;
+}
+
 int handle_backhaul_sta_caps_query(void *agent, struct cmdu_cstruct *cmdu)
 {
 	trace("%s: --->\n", __func__);
diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c
index 946e380020a65034de499c7654a7a15d7e314692..d87296d502c16d17550e209103f4a5051ea238b3 100644
--- a/src/core/agent_tlv_generator.c
+++ b/src/core/agent_tlv_generator.c
@@ -901,6 +901,61 @@ struct tlv_ap_radio_identifier *agent_gen_ap_radio_identifier(
 	return p;
 }
 
+struct tlv_source_info *agent_gen_source_info(
+		struct agent *a, uint8_t *mac)
+{
+	struct tlv_source_info *p;
+
+	if (!mac)
+		return NULL;
+
+	p = calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_SOURCE_INFO;
+	memcpy(p->mac, mac, 6);
+	return p;
+}
+
+struct tlv_tunnel_msg_type *agent_gen_tunnel_msg_type(
+		struct agent *a, uint8_t protocol)
+{
+	struct tlv_tunnel_msg_type *p;
+
+	p = calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_TUNNELED_MSG_TYPE;
+	p->tunnel_protocol_type = protocol;
+	return p;
+}
+
+struct tlv_tunneled *agent_gen_tunneled(struct agent *a,
+		int frame_len, uint8_t *frame_body)
+{
+	struct tlv_tunneled *p;
+
+	if ((!frame_body) || (frame_len <= 0))
+		return NULL;
+
+	p = calloc(1, sizeof(*p));
+	if (!p)
+		return NULL;
+
+	p->tlv_type = MAP_TLV_TUNNELED;
+	p->tlv_len = frame_len;
+	p->frame_body = calloc(frame_len, sizeof(uint8_t));
+	if (!p->frame_body) {
+		free(p);
+		return NULL;
+	}
+
+	memcpy(p->frame_body, frame_body, frame_len);
+	return p;
+}
+
 int agent_fill_steering_policy(struct agent *a,
 		struct tlv_steering_policy *p,
 		struct uci_context *ctx, struct uci_package *pkg)
diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h
index cd2587a25d439c894d9595c633fd47262c5edb36..5c4117eb37c737745bb80225fe396b93ab445021 100644
--- a/src/core/agent_tlv_generator.h
+++ b/src/core/agent_tlv_generator.h
@@ -67,6 +67,11 @@ 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);
+struct tlv_source_info *agent_gen_source_info(struct agent *a, uint8_t *mac);
+struct tlv_tunnel_msg_type *agent_gen_tunnel_msg_type(
+		struct agent *a, uint8_t protocol);
+struct tlv_tunneled *agent_gen_tunneled(struct agent *a,
+		int frame_len, uint8_t *frame_body);
 
 /* Policy config related functions */
 int agent_fill_steering_policy(struct agent *a,