diff --git a/src/Makefile b/src/Makefile
index 97dd4a2c7d82e020e6df58b6b04e75bbecf98279..b58a578b323ee87584429c588e61f9795751c729 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -37,6 +37,9 @@ LIBS = -lubus -lubox -ljson-c -lblobmsg_json -luci -pthread
 LIBS += -rdynamic -ldl
 LIBS += -leasy -lwifiutils
 LIBS += -lieee1905 -lmaputil
+ifneq (,$(findstring USE_LIBDPP,$(CFLAGS)))
+LIBS += -ldpp
+endif
 
 plugin_subdirs ?= $(wildcard plugins/*/*)
 plugin_sofile = $(wildcard $(d)/*.so)
diff --git a/src/cntlr.c b/src/cntlr.c
index 937e7c96689f1b2f7e6815fbb7ffd69a1384db2f..bb857d338e8adbe48cc02be60c17b79897d7db0c 100644
--- a/src/cntlr.c
+++ b/src/cntlr.c
@@ -34,6 +34,8 @@
 
 #include "timer.h"
 #if (EASYMESH_VERSION > 2)
+#include <dpp_api.h>
+
 #include "dpp.h"
 #endif
 
@@ -2177,6 +2179,7 @@ void run_controller(void)
 	INIT_LIST_HEAD(&c->dpp_ctx.enrolleelist);
 	INIT_LIST_HEAD(&c->dpp_ctx.chirplist);
 #endif
+
 	as_init_table(&c->as_table);
 	allmac_init_table(&c->mac_table);
 	init_bh_topology();
@@ -2187,6 +2190,26 @@ void run_controller(void)
 
 	ubus_add_uloop(ctx);
 
+#if (EASYMESH_VERSION > 2)
+	{
+		char *argv[] = {"-I", "-C", "-V", "2"};
+		int argc = 4;
+		int ret;
+
+		ret = dpp_init(&c->dpp, argc, argv);
+		if (ret) {
+			dbg("Failed to init dpp context\n");
+			goto out_exit;
+		}
+
+		dpp_register_cb(c->dpp, dpp_frame_handler);
+		dpp_set_ctx_private_data(c->dpp, c);
+
+
+		dpp_cntlr_read_uris(c);
+	}
+#endif
+
 	cntlr_config_defaults(c, &c->cfg);
 
 	ret = cntlr_get_ieee1905_almac(c, c->almac);
@@ -2254,10 +2277,6 @@ void run_controller(void)
 	memset(&c->dlem.network.steer_summary, 0, sizeof(struct wifi_steer_summary));
 	cntlr_dbg("current wifi_cntlr profile %d\n", c->cfg.map_profile);
 
-#if (EASYMESH_VERSION > 2)
-	dpp_cntlr_read_uris(c);
-#endif
-
 	uloop_run();
 
 out_exit:
diff --git a/src/cntlr.h b/src/cntlr.h
index d7383758dd50d41ad6cb3e1fb28ddbffc6807e02..97adc8706f9bcd3219cae3bce891abfa03b2a4aa 100644
--- a/src/cntlr.h
+++ b/src/cntlr.h
@@ -307,9 +307,6 @@ struct controller {
 	struct list_head stalist; /* list of sta */
 	struct list_head bcnreqlist;
 	struct list_head linklist;
-#if (EASYMESH_VERSION > 2)
-	struct dpp_context dpp_ctx;
-#endif
 	atimer_t radar_timer;
 	atimer_t discovery_timer;
 	atimer_t start_timer;
@@ -333,6 +330,11 @@ struct controller {
 	struct list_head sclist;	/* steer_control module list */
 	struct steer_control *sctrl;	/* active steer-control module */
 
+#if (EASYMESH_VERSION > 2)
+	struct dpp_context_wifi dpp_ctx;
+	void *dpp;
+#endif
+
 	struct wifi_data_element dlem; /* wifi data elements */
 };
 
diff --git a/src/cntlr_cmdu.c b/src/cntlr_cmdu.c
index f92ddbdf19c57b87b0240d2f68bc7a4a7dba4f83..166e43a843f662090f672b72106f55564de9ada0 100644
--- a/src/cntlr_cmdu.c
+++ b/src/cntlr_cmdu.c
@@ -530,6 +530,9 @@ out:
 }
 
 struct cmdu_buff *cntlr_gen_ap_autoconfig_response(struct controller *c,
+#if (EASYMESH_VERSION > 2)
+		bool hash_validity, uint8_t *hash, uint16_t hashlen,
+#endif
 		uint8_t *dest, uint8_t band, uint16_t mid)
 {
 	struct cmdu_buff *resp;
@@ -562,11 +565,14 @@ struct cmdu_buff *cntlr_gen_ap_autoconfig_response(struct controller *c,
 		ret = cntlr_gen_device_1905_layer_security_cap(c, resp);
 		if (ret)
 			goto out;
-#if 0
-		ret = cntlr_gen_chirp_value_tlv(c, resp);
-		if (ret)
-			goto out;
-#endif
+
+		if (hash) {
+			ret = cntlr_gen_chirp_value_tlv(c, resp, NULL,
+							hash_validity, hashlen,
+							hash);
+			if (ret)
+				goto out;
+		}
 
 #if (EASYMESH_VERSION > 5)
 		ret = cntlr_gen_cntlr_capability(c, resp, CONTROLLER_EARLY_AP_CAP_SUPPORTED);
@@ -1086,21 +1092,25 @@ error:
 }
 
 #if (EASYMESH_VERSION > 2)
-struct cmdu_buff *cntlr_gen_direct_encap_dpp(struct controller *c)
+struct cmdu_buff *cntlr_gen_direct_encap_dpp(struct controller *c,
+					      uint8_t *dst,
+					      uint8_t *frame,
+					      uint16_t framelen)
 {
 	struct cmdu_buff *frm;
 	uint16_t mid = 0;
 
 	/* TODO: Pass direct_encap_dpp_data parameter */
-
-	frm = cmdu_alloc_simple(CMDU_DIRECT_ENCAP_DPP, &mid);
+	frm = cmdu_alloc_frame(5000);
 	if (!frm) {
-		dbg("%s: -ENOMEM\n", __func__);
+		trace("%s: -ENOMEM\n", __func__);
 		return NULL;
 	}
+	cmdu_set_type(frm, CMDU_DIRECT_ENCAP_DPP);
+	cmdu_set_mid(frm, mid);
 
 	/* One DPP Message TLV */
-	if (cntlr_gen_dpp_message_tlv(c, frm)) {
+	if (cntlr_gen_dpp_message_tlv(c, frm, framelen, frame)) {
 		dbg("%s: cntlr_gen_dpp_message_tlv failed.\n", __func__);
 		goto out;
 	}
@@ -1145,7 +1155,7 @@ struct cmdu_buff *cntlr_gen_proxied_encap_dpp(struct controller *c,
 
 	/* Zero or One Chirp Value TLV */
 	if (hashlen && hash) {
-		if (cntlr_gen_chirp_value_tlv(c, frm, enrollee, hashlen, hash)) {
+		if (cntlr_gen_chirp_value_tlv(c, frm, enrollee, 1 /* TODO: hash_validity */, hashlen, hash)) {
 			dbg("%s: cntlr_gen_chirp_value_tlv failed.\n", __func__);
 			goto out;
 		}
diff --git a/src/cntlr_cmdu.h b/src/cntlr_cmdu.h
index 968c24a04b58ec9951876a48faa116d26c2cef9a..3066422d7113ae77f6a94256219d5bb0efce101b 100644
--- a/src/cntlr_cmdu.h
+++ b/src/cntlr_cmdu.h
@@ -42,6 +42,9 @@ struct cmdu_buff *cntlr_gen_unassoc_sta_metric_query(struct controller *c,
 struct cmdu_buff *cntlr_gen_ap_autoconfig_search(struct controller *c,
 		uint8_t profile, uint8_t band);
 struct cmdu_buff *cntlr_gen_ap_autoconfig_response(struct controller *c,
+#if (EASYMESH_VERSION > 2)
+		bool hash_validity, uint8_t *hash, uint16_t hashlen,
+#endif
 		uint8_t *dest, uint8_t band, uint16_t mid);
 struct cmdu_buff *cntlr_gen_ap_autoconfig_wsc(struct controller *c,
 		struct node *n, struct cmdu_buff *rx_cmdu, uint8_t *radio_id,
@@ -99,7 +102,10 @@ struct cmdu_buff *cntlr_gen_proxied_encap_dpp(struct controller *c,
 					      uint8_t *frame,
 					      uint16_t hashlen,
 					      uint8_t *hash);
-struct cmdu_buff *cntlr_gen_direct_encap_dpp(struct controller *c);
+struct cmdu_buff *cntlr_gen_direct_encap_dpp(struct controller *c,
+					      uint8_t *dst,
+					      uint8_t *frame,
+					      uint16_t framelen);
 struct cmdu_buff *cntrl_gen_bss_configuration_response(struct controller *c, struct cmdu_buff *request_cmdu);
 struct cmdu_buff *cntlr_gen_dpp_cce_indication(struct controller *c,
 		uint8_t *agent, bool cce_advertise);
diff --git a/src/cntlr_map.c b/src/cntlr_map.c
index 8a77457d7566422c571ee33e26521cb07a901d14..6d27189b2cc74864b8455ae56d29b4939cd8155d 100644
--- a/src/cntlr_map.c
+++ b/src/cntlr_map.c
@@ -45,6 +45,8 @@
 
 #include "timer.h"
 #if (EASYMESH_VERSION > 2)
+#include <dpp_api.h>
+
 #include "dpp.h"
 #include "utils/dpp_sock.h"
 #endif
@@ -957,6 +959,13 @@ int handle_ap_autoconfig_search(void *cntlr, struct cmdu_buff *rx_cmdu,
 	struct controller *c = (struct controller *) cntlr;
 	struct tlv_autoconfig_band *freq;
 	struct tlv_aladdr *aladdr;
+#if (EASYMESH_VERSION > 2)
+	void *event = NULL;
+	bool hash_known = false;
+	bool hash_validity;
+	uint8_t hashlen;
+	uint8_t *hash;
+#endif
 	struct tlv *t;
 	struct cmdu_buff *cmdu;
 	uint8_t almac[6] = {0};
@@ -1003,7 +1012,6 @@ int handle_ap_autoconfig_search(void *cntlr, struct cmdu_buff *rx_cmdu,
 		return -1;
 	}
 
-	// todo: handle tv[6] i.e. MAP_TLV_DPP_CHIRP_VALUE
 	if (tv[1][0]->data[0] != IEEE80211_ROLE_REGISTRAR) {
 		trace("%s: Discard ap-autoconfig search for role != registrar\n",
 			__func__);
@@ -1049,21 +1057,73 @@ int handle_ap_autoconfig_search(void *cntlr, struct cmdu_buff *rx_cmdu,
 	if (tv[3][0])
 		handle_supported_service(c, almac, tv[3][0]);
 
+#if (EASYMESH_VERSION > 2)
+	if (tv[6][0] && c->cfg.map_profile > 2) {
+		int offset = 0;
+		uint8_t flag = 0;
+		bool mac_present;
+		uint8_t *mac;
+
+		flag = tv[6][0]->data[offset++];
+
+		mac_present = (flag & DPP_CHIRP_ENROLLEE_MAC_PRESENT);
+		hash_validity = (flag & DPP_CHIRP_HASH_VALIDITY);
+		UNUSED(hash_validity);
+
+		if (mac_present) {
+			mac = &tv[6][0]->data[offset];
+			UNUSED(mac);
+			offset += 6;
+		}
+
+		hashlen = tv[6][0]->data[offset++];
+		hash = &tv[6][0]->data[offset];
+
+		dump(hash, hashlen, "autoconf search chirp hash");
+
+		hash_known = dpp_is_peer_bootstrap_hash_known(c->dpp, hash, NULL);
+		if (hash_known) {
+			ret = dpp_process_virt_presence_announcement(c->dpp,
+								rx_cmdu->origin,
+								hash, hashlen);
+			if (!ret) {
+				event = dpp_sm_create_event(c->dpp, rx_cmdu->origin,
+								DPP_EVENT_RX_FRAME,
+								0, NULL);
+			} else
+				err("%s: Failed to process virt presence announcement!\n", __func__);
+		} else {
+			err("%s: Hash was not known!\n", __func__);
+		}
+	}
+#endif
+
 	trace("%s: sending autoconfig response for band = %d, node %p\n",
 			__func__, freq->band, n);
-	cmdu = cntlr_gen_ap_autoconfig_response(cntlr, almac,
+
+	cmdu = cntlr_gen_ap_autoconfig_response(cntlr,
+#if (EASYMESH_VERSION > 2)
+			(hash_known ? hash_validity : 0),
+			(hash_known ? hash : NULL),
+			(hash_known ? hashlen : 0),
+#endif
+			almac,
 			freq->band,
 			cmdu_get_mid(rx_cmdu));
 	if (!cmdu)
 		return -1;
 
 	ret = send_cmdu(c, cmdu);
-
 	cmdu_free(cmdu);
 
-	UNUSED(ret);
+#if (EASYMESH_VERSION > 2)
+	if (event) {
+		dbg("|%s:%d| Trigger dpp event\n", __func__, __LINE__);
+		dpp_trigger(c->dpp, rx_cmdu->origin, event);
+	}
+#endif
 
-	return 0;
+	return !!ret;
 }
 
 /* disable and quit on controller response */
@@ -3570,22 +3630,71 @@ int handle_direct_encap_dpp(void *cntlr, struct cmdu_buff *cmdu,
 				     struct node *n)
 {
 	trace("%s: --->\n", __func__);
-
 	struct controller *c = (struct controller *)cntlr;
 	struct tlv *tlv;
 	struct tlv *tlvs[DIRECT_ENCAP_DPP_MAX_NUMBER_OF_TLV_TYPES][TLV_MAXNUM] = { 0 };
+	struct tlv_dpp_message *dpp_msg;
+	uint16_t framelen;
+	uint8_t *frame;
+	int frametype;
+
+	UNUSED(c);
 
 	if (!validate_direct_encap_dpp(cmdu, tlvs)) {
 		dbg("cmdu validation: [DIRECT_ENCAP_DPP] failed\n");
 		return -1;
 	}
 
+	/* POSSIBLY MID CHECK HERE? */
+
 	/* One DPP Message TLV */
 	tlv = tlvs[DIRECT_ENCAP_DPP_MESSAGE_IDX][0];
-	(void) tlv;
-	(void) c;
+	dpp_msg = (struct tlv_dpp_message *) tlv->data;
+
+	frame = dpp_msg->frame;
+	framelen = BUF_GET_BE16(tlv->len);
 
-	// TODO: process DPP Message TLV
+	frametype = dpp_get_frame_type(frame + 1, framelen - 1);
+	if (frametype == 255)
+		return -1;
+
+	/* Encapsulated frame length */
+	dump(frame, framelen, "DIRECT CMDU FRAME");
+
+	switch (frametype) {
+	case DPP_PA_PRESENCE_ANNOUNCEMENT: {
+		int ret;
+
+		ret = dpp_process_presence_announcement(c->dpp, cmdu->origin,
+							frame,
+							framelen);
+		if (ret) {
+			dbg("Failed to build presence announcement frame!\n");
+			break;
+		}
+
+		dbg("%s processing PA\n", (!ret ? "Succeeded" : "Failed"));
+		/* FALLTHROUGH */
+	}
+	case DPP_PA_AUTHENTICATION_RESP:
+	case DPP_PUB_AF_GAS_INITIAL_REQ:
+	case DPP_PA_CONFIGURATION_RESULT:
+	case DPP_PA_PEER_DISCOVERY_REQ:
+	case DPP_PA_CONNECTION_STATUS_RESULT: {
+		void *event =
+			dpp_sm_create_event(c->dpp, cmdu->origin, DPP_EVENT_RX_FRAME, framelen, frame);
+
+		if (event) {
+			dpp_trigger(c->dpp, cmdu->origin, event);
+			dpp_sm_free_event(event);
+		}
+		break;
+
+	}
+	default:
+		dbg("Unknown frame!\n");
+		break;
+	}
 
 	return 0;
 }
diff --git a/src/cntlr_tlv.c b/src/cntlr_tlv.c
index 227045dc697180e119429f8cc8304d3fc0b0a177..2638d1745d7e9cc4ded818bf82e0f0b704c99f9a 100644
--- a/src/cntlr_tlv.c
+++ b/src/cntlr_tlv.c
@@ -1728,29 +1728,20 @@ int cntlr_gen_dpp_cce_indication_tlv(struct controller *c,
 	return 0;
 }
 
-/* TODO: fill the DPP frame field */
-int cntlr_gen_dpp_message_tlv(struct controller *c, struct cmdu_buff *frm)
+int cntlr_gen_dpp_message_tlv(struct controller *c, struct cmdu_buff *frm,
+				uint16_t framelen, uint8_t *frame)
 {
 	struct tlv *t;
-	int offset = 0;
-	/* dummy values */
-	int framelen = 1;
-	uint8_t frame[1] = { 0xff };
 
-	t = cmdu_reserve_tlv(frm, 512);
+	t = cmdu_reserve_tlv(frm, 4700);
 	if (!t)
 		return -1;
 
 	t->type = MAP_TLV_DPP_MESSAGE;
 
-	/* DPP Frame length */
-	t->data[offset++] = framelen;
+	memcpy(&t->data[0], frame, framelen);
 
-	/* DPP Frame */
-	memcpy(&t->data[offset], frame, framelen);
-	offset += framelen;
-
-	t->len = offset;
+	t->len = framelen;
 	if (cmdu_put_tlv(frm, t))
 		return -1;
 
@@ -1804,12 +1795,9 @@ int cntlr_gen_1905_encap_dpp_tlv(struct controller *c, struct cmdu_buff *frm,
 	return 0;
 }
 
-/* TODO: fill the following fields
- * DPP flag (Hash Validity & MAC addr present)
- * Enrollee MAC & hash
- */
 int cntlr_gen_chirp_value_tlv(struct controller *c, struct cmdu_buff *frm,
-			uint8_t *enrollee, uint16_t hashlen, uint8_t *hash)
+			      uint8_t *enrollee, bool hash_validity,
+			      uint16_t hashlen, uint8_t *hash)
 {
 	struct tlv *t;
 	int offset = 0;
@@ -1824,7 +1812,7 @@ int cntlr_gen_chirp_value_tlv(struct controller *c, struct cmdu_buff *frm,
 	if (enrollee)
 		flags |= 1 << 7;
 
-	flags |= 1 << 6; /* TODO:  0: purge (when?) -- 1: establish */
+	flags |= hash_validity << 6; /* TODO:  0: purge (when?) -- 1: establish */
 
 	t->data[offset++] = flags;
 
diff --git a/src/cntlr_tlv.h b/src/cntlr_tlv.h
index 741cc3f2165365566a8cd5271120ce4492faba79..c7b3749dc5fc7f83295d6aabdfce769aa201c909 100644
--- a/src/cntlr_tlv.h
+++ b/src/cntlr_tlv.h
@@ -115,13 +115,14 @@ int cntlr_gen_tlv_higher_layer_data(struct controller *c, struct cmdu_buff *frm,
 		uint8_t proto, uint8_t *data, int len);
 
 #if (EASYMESH_VERSION > 2)
-int cntlr_gen_dpp_message_tlv(struct controller *c,
-		struct cmdu_buff *frm);
+int cntlr_gen_dpp_message_tlv(struct controller *c, struct cmdu_buff *frm,
+				uint16_t framelen, uint8_t *frame);
 int cntlr_gen_1905_encap_dpp_tlv(struct controller *c, struct cmdu_buff *frm,
 				 uint8_t *enrollee, uint8_t frametype,
 				 uint16_t framelen, uint8_t *frame);
 int cntlr_gen_chirp_value_tlv(struct controller *c, struct cmdu_buff *frm,
-			uint8_t *enrollee, uint16_t hashlen, uint8_t *hash);
+			      uint8_t *enrollee, bool hash_validity,
+			      uint16_t hashlen, uint8_t *hash);
 int cntlr_gen_bss_config_response_tlv(struct controller *c,
 				      struct cmdu_buff *cmdu);
 int cntlr_gen_dpp_cce_indication_tlv(struct controller *c, struct cmdu_buff *frm,
diff --git a/src/cntlr_ubus.c b/src/cntlr_ubus.c
index 805824cd62aefebdd7da3d024069fb05b8ddc8c5..d4afb4cde4f72106f89d4e2cb36d888a3fa575be 100644
--- a/src/cntlr_ubus.c
+++ b/src/cntlr_ubus.c
@@ -37,6 +37,8 @@
 
 #include "timer.h"
 #if (EASYMESH_VERSION > 2)
+#include <dpp_api.h>
+
 #include "dpp.h"
 #endif
 #include "utils/utils.h"
@@ -835,10 +837,57 @@ static int cntlr_steer_history(struct ubus_context *ctx, struct ubus_object *obj
 }
 
 #if (EASYMESH_VERSION > 2)
+static int cntlr_dpp_uri_eth(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct controller *c = container_of(obj, struct controller, obj);
+	struct blob_attr *tb[__DPP_URI_MAX];
+	struct dpp_bootstrap_info *enrollee_bi;
+	char *uri;
+	int ret;
+
+	blobmsg_parse(dpp_uri_params, __DPP_URI_MAX, tb,
+			blob_data(msg), blob_len(msg));
+
+	if (!tb[DPP_URI]) {
+		dbg("|%s:%d| URI must be provided!\n", __func__, __LINE__);
+		return UBUS_STATUS_INVALID_ARGUMENT;
+	}
+
+	uri = blobmsg_data(tb[DPP_URI]);
+	if (!uri)
+		return UBUS_STATUS_UNKNOWN_ERROR;
+
+
+	enrollee_bi = calloc(1, sizeof(*enrollee_bi));
+	if (!enrollee_bi) {
+		fprintf(stderr, "Failed to allocate enrollee_bi\n");
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	ret = dpp_build_bootstrap_info_from_uri(uri, enrollee_bi);
+	if (ret) {
+		fprintf(stderr, "Failed to build bootstrap info\n");
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	ret = dpp_bootstrap_add(c->dpp, enrollee_bi);
+	if (ret) {
+		fprintf(stderr, "Failed to add bootstrap\n");
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	//dpp_append_uri_file(c, uri);
+
+	return UBUS_STATUS_OK;
+}
+
 static int cntlr_dpp_uri(struct ubus_context *ctx, struct ubus_object *obj,
 			struct ubus_request_data *req, const char *method,
 			struct blob_attr *msg)
 {
+
 	struct controller *c = container_of(obj, struct controller, obj);
 	struct blob_attr *tb[__DPP_URI_MAX];
 	struct dpp_enrollee *e;
@@ -870,9 +919,9 @@ DPP:C:81/1;M:b0dd74001c32;V:2;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACtPpZTi2FPf1e
 
 	/* TODO: parse correctly */
 	if (tb[DPP_URI_TYPE])
-		e->type = DPP_BOOTSTRAP_QR_CODE;
+		e->type = DPP_BOOTSTRAP_QR_CODE_WIFI;
 	else
-		e->type = DPP_BOOTSTRAP_QR_CODE;
+		e->type = DPP_BOOTSTRAP_QR_CODE_WIFI;
 
 	dbg("|%s:%d| MAC "MACFMT" has URI %s\n", __func__, __LINE__, MAC2STR(e->mac), e->uri);
 
@@ -3538,6 +3587,8 @@ int cntlr_publish_object(struct controller *c, const char *objname)
 #if (EASYMESH_VERSION > 2)
 		UBUS_METHOD("dpp_enrollee_uri", cntlr_dpp_uri,
 				dpp_uri_params),
+		UBUS_METHOD("dpp_enrollee_uri_eth", cntlr_dpp_uri_eth,
+				dpp_uri_params),
 #endif /* DPP */
 		UBUS_METHOD("steer_summary", cntlr_steer_summary,
 				steer_summary_params),
diff --git a/src/config.c b/src/config.c
index 55c7d468384ea51a2b4942ee1f044dc7334cdef3..01a7a539a2cd8eae40161b0f98d13a0716cf111a 100644
--- a/src/config.c
+++ b/src/config.c
@@ -36,6 +36,8 @@
 #include "config.h"
 #include "timer.h"
 #if (EASYMESH_VERSION > 2)
+#include <dpp_api.h>
+
 #include "dpp.h"
 #endif
 #include "cntlr.h"
@@ -1230,6 +1232,24 @@ static int cntlr_config_get_credentials(struct controller_config *c,
 
 	c->num_bss++;
 	list_add_tail(&cred->list, &c->aplist);
+
+#if (EASYMESH_VERSION > 2)
+	if (cred->multi_ap & 0x01) {
+		struct controller *cntlr = container_of(c, struct controller, cfg);
+		const char *sec;
+
+		if (tb[CRED_SEC])
+			sec =  tb[CRED_SEC]->v.string;
+		else
+			sec = "none";
+
+		dpp_set_configuration(cntlr->dpp, DPP_NETROLE_MAP_BH_STA,
+				      dpp_akm_from_str(sec),
+				      (char *) cred->ssid,
+				      (char *) cred->key,
+				      cred->band);
+	}
+#endif
 	return 0;
 }
 
diff --git a/src/dpp.c b/src/dpp.c
index 2f9e2894ce80482bb5bf028698fda9110da3b430..927845364b19a5690be278f3963ca49670af1324 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -49,7 +49,10 @@
 #include "utils/debug.h"
 #include "utils/dpp_sock.h"
 #if (EASYMESH_VERSION > 2)
+#include <dpp_api.h>
+
 #include "dpp.h"
+#include <math.h>
 #endif
 //#include "config.h"
 #include "cntlr.h"
@@ -62,33 +65,9 @@
 static void dpp_fd_timeout(atimer_t *t);
 
 
-uint8_t *dpp_get_attr(uint8_t *buf, size_t len, uint16_t req_id,
-		      uint16_t *ret_len)
-{
-	uint16_t id, alen;
-	uint8_t *pos = buf, *end = buf + len;
-
-	while (end - pos >= 4) {
-		id = buf_get_le16(pos);
-		pos += 2;
-		alen = buf_get_le16(pos);
-		pos += 2;
-		if (alen > end - pos)
-			return NULL;
-		if (id == req_id) {
-			*ret_len = alen;
-			return pos;
-		}
-		pos += alen;
-	}
-
-	return NULL;
-}
-
-
 const char *dpp_type2str(enum dpp_bootstrap_type type)
 {
-	if (type == DPP_BOOTSTRAP_QR_CODE)
+	if (type == DPP_BOOTSTRAP_QR_CODE_WIFI)
 		return "qrcode";
 	else if (type == DPP_BOOTSTRAP_PKEX)
 		return "pkex";
@@ -157,23 +136,6 @@ const char *dpp_frame_type2str(uint8_t type)
 	return "Unknown";
 }
 
-uint8_t dpp_get_pub_af_type(uint8_t *frame, uint16_t framelen)
-{
-	if (framelen < 7)
-		return 255;
-
-	return *(frame + 6);
-}
-
-uint8_t dpp_get_gas_frame_type(const uint8_t *frame, uint16_t framelen)
-{
-	if (framelen < 1)
-		return 255;
-
-	return *frame;
-}
-
-
 struct dpp_enrollee *dpp_enrollee_get(struct controller *c, uint8_t *mac)
 {
 	struct dpp_enrollee *e;
@@ -193,6 +155,9 @@ struct dpp_enrollee *dpp_enrollee_get_hash(struct controller *c, uint8_t *hash)
 	list_for_each_entry(e, &c->dpp_ctx.enrolleelist, list) {
 		struct dpp_chirp *p = e->chirp;
 
+		if (!memcmp(e->hash, hash, 32))
+			return e;
+
 		if (!p)
 			continue;
 
@@ -214,6 +179,7 @@ struct dpp_enrollee *dpp_enrollee_alloc(struct controller *c, uint8_t *mac)
 		return NULL;
 	}
 
+	e->band = BAND_UNKNOWN;
 	e->c = c; /* TODO: deprecate */
 	memcpy(e->mac, mac, 6);
 	INIT_LIST_HEAD(&e->framelist);
@@ -605,6 +571,8 @@ struct dpp_enrollee *dpp_process_new_uri(struct controller *c, char *uri)
 	char *macstr;
 	uint8_t enrollee[6] = {0};
 	struct dpp_enrollee *e;
+	char *hashstr;
+	char *hashend;
 	int rc;
 
 	if (strncmp(uri, "DPP:", 4)) {
@@ -614,16 +582,22 @@ struct dpp_enrollee *dpp_process_new_uri(struct controller *c, char *uri)
 
 	macstr = strstr(uri, ";M:"); // find mac address in URI
 	if (!macstr) {
-		dbg("|%s:%d| URI has invalid format! (Right now) MAC is mandated\n", __func__, __LINE__);
-		return NULL;
+		macstr = strstr(uri, "DPP:M:"); // find mac address in URI
+		if (!macstr) {
+			dbg("|%s:%d| URI has invalid format! (Right now) MAC is mandated\n", __func__, __LINE__);
+			return NULL;
+		}
+		macstr += 3; /* step past DPP identifier */
 	}
 
-	if (*(macstr + 15) != ';') {
+	macstr += 3; /* step past mac identifier */
+
+
+	if (*(macstr + 12) != ';') {
 		dbg("|%s:%d| URI MAC has invalid format!\n", __func__, __LINE__);
 		return NULL;
 	}
 
-	macstr += 3; /* step past mac identifier */
 	strtob(macstr, 6, enrollee);
 
 	e = dpp_enrollee_get(c, enrollee);
@@ -640,15 +614,30 @@ struct dpp_enrollee *dpp_process_new_uri(struct controller *c, char *uri)
 
 	strncpy(e->uri, uri, sizeof(e->uri) - 1);
 
+	hashstr = strstr(uri, ";K:");
+	hashstr += 3 + 36; /* TODO: probably step 36 is not correct, but gives correct bytes in hashb output */
+	hashend = strstr(hashstr, ";");
+
+	if (hashstr && hashend) {
+		uint8_t len = 0;
+		uint8_t hashb[128] = {0};
+		size_t hlen = 128;
+
+		len = abs(hashend - hashstr);
+		rc = base64_decode((unsigned char *) hashstr, (size_t)len, (unsigned char *) hashb, &hlen);
+		memcpy(e->hash, hashb, hlen);
+		dump(e->hash, hlen, "enrollee hash");
+	}
+
 	dbg("|%s:%d| MAC "MACFMT" has URI %s\n", __func__, __LINE__, MAC2STR(e->mac), e->uri);
 
 	send_dpp_cce_indication_all(c, true);
 
 	rc = dpp_parse_uri_chan_list(c, e, e->uri);
 	if (rc < 0) {
-		dbg("|%s:%d| URI MAC has invalid format! (Right now) Opclass/Channel list is mandated\n", __func__, __LINE__);
-		dpp_enrollee_free(e);
-		return NULL;
+		dbg("|%s:%d| URI chanlist has invalid format! (Right now) Opclass/Channel list is mandated\n", __func__, __LINE__);
+	//	dpp_enrollee_free(e);
+	//	return NULL;
 	}
 	if (e->num_chan) {
 		e->band = wifi_channel_to_band(e->chan[0].channel);
@@ -658,26 +647,26 @@ struct dpp_enrollee *dpp_process_new_uri(struct controller *c, char *uri)
 	}
 
 
-	{
-		/* THIS IS A HACK */
-		uint8_t bssid[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-		uint8_t radio[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-		struct cmdu_buff *cmdu;
-		int len = 0;
-
-		len = strlen(e->uri);
-		cmdu = cntlr_gen_dpp_bootstrapping_uri_notification(c, radio, bssid,
-				enrollee, len, e->uri);
-		if (cmdu) {
-			struct node *n;
-
-			list_for_each_entry(n, &c->nodelist, list) {
-				memcpy(cmdu->origin, n->alid, 6);
-				send_cmdu(c, cmdu);
-			}
-			cmdu_free(cmdu);
-		}
-	}
+//	{
+//		/* THIS IS A HACK */
+//		uint8_t bssid[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+//		uint8_t radio[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+//		struct cmdu_buff *cmdu;
+//		int len = 0;
+//
+//		len = strlen(e->uri);
+//		cmdu = cntlr_gen_dpp_bootstrapping_uri_notification(c, radio, bssid,
+//				enrollee, len, e->uri);
+//		if (cmdu) {
+//			struct node *n;
+//
+//			list_for_each_entry(n, &c->nodelist, list) {
+//				memcpy(cmdu->origin, n->alid, 6);
+//				send_cmdu(c, cmdu);
+//			}
+//			cmdu_free(cmdu);
+//		}
+//	}
 
 	return e;
 }
@@ -726,15 +715,101 @@ int dpp_cntlr_read_uris(struct controller *c)
 			continue;
 
 		if (strcmp("qr", blobmsg_data(tb1[1])))
-			e->type = DPP_BOOTSTRAP_QR_CODE;
+			e->type = DPP_BOOTSTRAP_QR_CODE_WIFI;
 		else
-			e->type = DPP_BOOTSTRAP_QR_CODE;
+			e->type = DPP_BOOTSTRAP_QR_CODE_WIFI;
 	}
 
 out:
 	blob_buf_free(&uris);
 	return rc;
 }
+int dpp_frame_handler(void *dpp, uint8_t *smac, enum dpp_event ev,
+		      uint8_t *frame, size_t framelen)
+{
+	struct controller *c;
+
+	err("%s: ----->\n", __func__);
+
+	if (!smac) {
+		warn("%s: Error: smac = NULL\n", __func__);
+		return -1;
+	}
+
+	err("%s: DPP_EVENT: event = %d smac = " MACFMT", frame = %p, len = %zu\n",
+		__func__, ev, MAC2STR(smac), frame, framelen);
+
+	switch (ev) {
+	case DPP_EVENT_TX_FRAME: {
+		struct cmdu_buff *resp;
+		int frametype = 0;
+
+		frametype = dpp_get_frame_type(frame + 1, framelen - 1);
+		if (frametype == 255) {
+			warn("Invalid frametype\n");
+			return -1;
+		}
+
+		c = dpp_get_ctx_private_data(dpp);
+		if (!c)
+			return -1;
+
+		dbg("DPP frametype %s\n", dpp_frame_type2str(frametype));
+		resp = cntlr_gen_direct_encap_dpp(c, smac, frame, framelen);
+		if (!resp) {
+			warn("|%s:%d| DPP: ----> Error generating proxy encap\n",
+			__func__, __LINE__);
+			return -1;
+		}
+
+		switch (frametype) {
+		case DPP_PA_AUTHENTICATION_REQ: {
+#if 0 /* TODO: will be needed for proxied encap */
+			struct node *n;
+
+			list_for_each_entry(n, &c->nodelist, list) {
+				memcpy(resp->origin, smac, 6);
+				send_cmdu(c, resp);
+			}
+			cmdu_free(resp);
+
+			break;
+#else
+			/* FALLTHROUGH */
+#endif
+		}
+		case DPP_PA_AUTHENTICATION_CONF:
+		case DPP_PUB_AF_GAS_INITIAL_RESP:
+		case DPP_PA_PEER_DISCOVERY_RESP:
+			memcpy(resp->origin, smac, 6);
+			send_cmdu(c, resp);
+			cmdu_free(resp);
+			break;
+		default:
+			warn("|%s:%d| DPP: ----> Unknown frame\n", __func__, __LINE__);
+			break;
+		}
+		break;
+	}
+	case DPP_EVENT_BAD_AUTH:
+		err("DPP: BAD AUTH!\n");
+		/* FALLTHROUGH */
+	case DPP_EVENT_TIMEOUT: {
+		struct dpp_peer *peer = dpp_lookup_peer(dpp, smac);
+
+		err("DPP: EVENT TIMEOUT!\n");
+
+		if (peer) {
+			list_del(&peer->list);
+			dpp_free_peer(dpp, peer);
+		}
+		break;
+	}
+	default:
+		break;
+	}
+	return 0;
+}
 
 
 static void dpp_fd_timeout(atimer_t *t)
diff --git a/src/dpp.h b/src/dpp.h
index a32f58c6bc00aafe77509885e654f9f51c15b7e5..0ab2eacd40276d7f80c17d7aa588a2cae6daf678 100644
--- a/src/dpp.h
+++ b/src/dpp.h
@@ -1,21 +1,7 @@
 #ifndef DPP_H
 #define DPP_H
 
-#define PUB_AF_CATEGORY		0x04
-#define DPP_PUB_AF_ACTION		0x09
-#define DPP_PUB_AF_ACTION_OUI_TYPE	0x1A
-#define DPP_PUB_AF_GAS_INITIAL_REQ	0x0A
-#define DPP_PUB_AF_GAS_INITIAL_RESP	0x0B
-
-#define FRAME_IS_DPP_PUB_AF(frame) \
-		((*(frame) == DPP_PUB_AF_ACTION) && \
-		(memcmp((frame + 1), "\x50\x6F\x9A", 3) == 0) && \
-		((*(frame + 4)) == DPP_PUB_AF_ACTION_OUI_TYPE))
-
-#define FRAME_IS_DPP_GAS_FRAME(frame) \
-		((*(frame) == DPP_PUB_AF_GAS_INITIAL_REQ) || \
-		(*(frame) == DPP_PUB_AF_GAS_INITIAL_RESP))
-
+#include <dpputils.h>
 
 #define FRAME_DST_ENROLLEE(type) \
 		((type == DPP_PA_AUTHENTICATION_REQ) || \
@@ -23,63 +9,6 @@
 
 #define DPP_URI_FILE "/etc/multiap/dpp_uris.json"
 
-enum dpp_public_action_frame_type {
-	DPP_PA_AUTHENTICATION_REQ = 0,
-	DPP_PA_AUTHENTICATION_RESP = 1,
-	DPP_PA_AUTHENTICATION_CONF = 2,
-	DPP_PA_PEER_DISCOVERY_REQ = 5,
-	DPP_PA_PEER_DISCOVERY_RESP = 6,
-	DPP_PA_PKEX_V1_EXCHANGE_REQ = 7,
-	DPP_PA_PKEX_EXCHANGE_RESP = 8,
-	DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
-	DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
-	DPP_PA_CONFIGURATION_RESULT = 11,
-	DPP_PA_CONNECTION_STATUS_RESULT = 12,
-	DPP_PA_PRESENCE_ANNOUNCEMENT = 13,
-	DPP_PA_RECONFIG_ANNOUNCEMENT = 14,
-	DPP_PA_RECONFIG_AUTH_REQ = 15,
-	DPP_PA_RECONFIG_AUTH_RESP = 16,
-	DPP_PA_RECONFIG_AUTH_CONF = 17,
-	DPP_PA_PKEX_EXCHANGE_REQ = 18,
-};
-
-enum dpp_attribute_id {
-	DPP_ATTR_STATUS = 0x1000,
-	DPP_ATTR_I_BOOTSTRAP_KEY_HASH = 0x1001,
-	DPP_ATTR_R_BOOTSTRAP_KEY_HASH = 0x1002,
-	DPP_ATTR_I_PROTOCOL_KEY = 0x1003,
-	DPP_ATTR_WRAPPED_DATA = 0x1004,
-	DPP_ATTR_I_NONCE = 0x1005,
-	DPP_ATTR_I_CAPABILITIES = 0x1006,
-	DPP_ATTR_R_NONCE = 0x1007,
-	DPP_ATTR_R_CAPABILITIES = 0x1008,
-	DPP_ATTR_R_PROTOCOL_KEY = 0x1009,
-	DPP_ATTR_I_AUTH_TAG = 0x100A,
-	DPP_ATTR_R_AUTH_TAG = 0x100B,
-	DPP_ATTR_CONFIG_OBJ = 0x100C,
-	DPP_ATTR_CONNECTOR = 0x100D,
-	DPP_ATTR_CONFIG_ATTR_OBJ = 0x100E,
-	DPP_ATTR_BOOTSTRAP_KEY = 0x100F,
-	DPP_ATTR_OWN_NET_NK_HASH = 0x1011,
-	DPP_ATTR_FINITE_CYCLIC_GROUP = 0x1012,
-	DPP_ATTR_ENCRYPTED_KEY = 0x1013,
-	DPP_ATTR_ENROLLEE_NONCE = 0x1014,
-	DPP_ATTR_CODE_IDENTIFIER = 0x1015,
-	DPP_ATTR_TRANSACTION_ID = 0x1016,
-	DPP_ATTR_BOOTSTRAP_INFO = 0x1017,
-	DPP_ATTR_CHANNEL = 0x1018,
-	DPP_ATTR_PROTOCOL_VERSION = 0x1019,
-	DPP_ATTR_ENVELOPED_DATA = 0x101A,
-	DPP_ATTR_SEND_CONN_STATUS = 0x101B,
-	DPP_ATTR_CONN_STATUS = 0x101C,
-	DPP_ATTR_RECONFIG_FLAGS = 0x101D,
-	DPP_ATTR_C_SIGN_KEY_HASH = 0x101E,
-	DPP_ATTR_CSR_ATTR_REQ = 0x101F,
-	DPP_ATTR_A_NONCE = 0x1020,
-	DPP_ATTR_E_PRIME_ID = 0x1021,
-	DPP_ATTR_CONFIGURATOR_NONCE = 0x1022,
-};
-
 enum dpp_responder_state {
 	DPP_BOOSTRAPPING,
 	DPP_AUTHENTICATING,
@@ -88,7 +17,7 @@ enum dpp_responder_state {
 
 /* taken from dpp.h */
 enum dpp_bootstrap_type {
-	DPP_BOOTSTRAP_QR_CODE,
+	DPP_BOOTSTRAP_QR_CODE_WIFI,
 	DPP_BOOTSTRAP_PKEX,
 	DPP_BOOTSTRAP_NFC_URI,
 };
@@ -125,8 +54,10 @@ struct dpp_chan {
 struct dpp_enrollee {
 	struct controller *c; /* TODO: lazy, should all be part of some dpp_ctx which can be traced back to cntlr */
 
+	uint8_t almac[6];
 	uint8_t mac[6];
 	char uri[128];
+	uint8_t hash[32];
 
 	bool onboarded;
 	uint8_t bootstrap_id;
@@ -142,28 +73,24 @@ struct dpp_enrollee {
 	struct list_head list;
 };
 
-struct dpp_context {
+struct dpp_context_wifi {
 	struct list_head enrolleelist;
 	struct list_head chirplist;
 };
 
 struct controller;
-
-uint8_t *dpp_get_attr(uint8_t *buf, size_t len, uint16_t req_id,
-		      uint16_t *ret_len);
+enum dpp_event;
 
 const char *dpp_type2str(enum dpp_bootstrap_type type);
 const char *dpp_frame_type2str(uint8_t type);
 const char *dpp_state2str(enum dpp_responder_state state);
 
-uint8_t dpp_get_pub_af_type(uint8_t *frame, uint16_t framelen);
-uint8_t dpp_get_gas_frame_type(const uint8_t *frame, uint16_t framelen);
-
 struct dpp_chirp *dpp_chirp_get(struct controller *c, uint8_t *hash);
 struct dpp_chirp *dpp_chirp_alloc(struct controller *c, uint8_t *hash);
 
 
 struct dpp_enrollee *dpp_enrollee_get(struct controller *c, uint8_t *mac);
+struct dpp_enrollee *dpp_enrollee_get_hash(struct controller *c, uint8_t *hash);
 struct dpp_enrollee *dpp_enrollee_alloc(struct controller *c, uint8_t *mac);
 void dpp_enrollee_free(struct dpp_enrollee *e);
 
@@ -192,4 +119,7 @@ struct dpp_enrollee *dpp_process_new_uri(struct controller *c, char *uri);
 int dpp_cntlr_read_uris(struct controller *c);
 
 void dpp_event_uloop_cb(struct uloop_fd *fd, unsigned int events);
+
+int dpp_frame_handler(void *dpp, uint8_t *smac, enum dpp_event ev,
+		      uint8_t *frame, size_t framelen);
 #endif