diff --git a/src/cntlr_map.c b/src/cntlr_map.c
index f4bca669b50eb01f056b7b1941d60c15e2f3fb66..e417c74e1d6637aea89d5d8874c93e030c307296 100644
--- a/src/cntlr_map.c
+++ b/src/cntlr_map.c
@@ -3303,6 +3303,7 @@ int handle_proxied_encap_dpp(void *cntlr, struct cmdu_buff *cmdu,
 		switch (frm->type) {
 		case DPP_PA_PRESENCE_ANNOUNCEMENT: {
 			int ret;
+			uint16_t port;
 
 			if (p->chirp_fd.fd > 0) {
 				err("|%s:%d| chirp already has an open fd:%d!\n",
@@ -3310,9 +3311,12 @@ int handle_proxied_encap_dpp(void *cntlr, struct cmdu_buff *cmdu,
 				break;
 			}
 
+			port = dpp_get_controller_tcp_port(c, e->band);
+
+			/* find band based on QR */
 			/* open socket */
 			/* TODO: read ip and port from cfg */
-			p->chirp_fd.fd = connect_to_server("0.0.0.0", 8910);
+			p->chirp_fd.fd = connect_to_server("0.0.0.0", port);
 			if (p->chirp_fd.fd <= 0)
 				break;
 
diff --git a/src/cntlr_ubus.c b/src/cntlr_ubus.c
index 36e66baa108044a58cdfc891bd4bfe8749ae1d24..31f4437a951cdb3812c95bc1d0526fac005ac776 100644
--- a/src/cntlr_ubus.c
+++ b/src/cntlr_ubus.c
@@ -836,7 +836,7 @@ static int cntlr_dpp_uri(struct ubus_context *ctx, struct ubus_object *obj,
 	char *uri;
 	uint8_t enrollee[6] = {0};
 	struct dpp_enrollee *e;
-
+	int rc;
 /*
 DPP:C:81/1;M:b0dd74001c32;V:2;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACtPpZTi2FPf1eMeu6hvPHVMmxam4iHPvmekZXnACsqNA=;;
 */
@@ -862,7 +862,7 @@ DPP:C:81/1;M:b0dd74001c32;V:2;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACtPpZTi2FPf1e
 
 	macstr = strstr(uri, ";M:"); // find mac address in URI
 	if (!macstr) {
-		dbg("|%s:%d| URI has invalid format!\n", __func__, __LINE__);
+		dbg("|%s:%d| URI has invalid format! (Right now) MAC is mandated\n", __func__, __LINE__);
 		return UBUS_STATUS_INVALID_ARGUMENT;
 	}
 
@@ -898,12 +898,16 @@ DPP:C:81/1;M:b0dd74001c32;V:2;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACtPpZTi2FPf1e
 
 	send_dpp_cce_indication_all(c, true);
 
-	dpp_parse_uri_chan_list(c, e, e->uri);
+	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 UBUS_STATUS_INVALID_ARGUMENT;
+	}
 	if (e->num_chan) {
 		struct node *n = NULL;
 
 		e->band = wifi_channel_to_band(e->chan[0].channel);
-
 		/* need to swap to a channel that is supported in chanlist
 		 * off-operating channel dpp_listen is not supported
 		 */
diff --git a/src/config.c b/src/config.c
index 2ba370292a3c5b191ef5f5d8dd66ab694d528a93..eb3a55eac02caf598c3c42f5c2225c951e817535 100644
--- a/src/config.c
+++ b/src/config.c
@@ -105,6 +105,54 @@ static int clean_agentlist(struct node_policy *p)
 	return 0;
 }
 
+#if (EASYMESH_VERSION > 2)
+struct dpp_controller_cfg *get_dpp_controller_by_band(struct controller_config *c,
+		enum wifi_band band)
+{
+	struct dpp_controller_cfg *p;
+
+	list_for_each_entry(p, &c->dpp_cntlrlist, list) {
+		if (band == p->band)
+			return p;
+	}
+
+	return NULL;
+}
+
+/* create ap config and initialize with default values */
+struct dpp_controller_cfg *create_dpp_controller_config(struct controller_config *cfg,
+							enum wifi_band band)
+{
+	struct dpp_controller_cfg *new;
+
+	if (!cfg)
+		return NULL;
+
+	new = calloc(1, sizeof(struct dpp_controller_cfg));
+	if (!new) {
+		warn("OOM! config\n");
+		return NULL;
+	}
+	new->band = band;
+
+	if (new->band == BAND_2)
+		new->port = 8902;
+	else if (new->band == BAND_5)
+		new->port = 8905;
+#if 0 /* TOOD: BAND_6 not yet supported */
+	else if (new->band == BAND_6)
+		new->port = 8906;
+#endif
+	else
+		new->port = 8910; /* default */
+
+	dbg("%s: %s dpp_controller->cfg = %p\n", __func__, new->ifname, new);
+
+	list_add(&new->list, &cfg->dpp_cntlrlist);
+	return new;
+}
+#endif
+
 static int clean_steer_btm_excl(struct node_policy *p)
 {
 	struct stax *n = NULL, *tmp;
@@ -562,6 +610,9 @@ int cntlr_config_defaults(struct controller *cntlr, struct controller_config *cf
 	INIT_LIST_HEAD(&cfg->nodelist);
 	INIT_LIST_HEAD(&cfg->aplist);
 	INIT_LIST_HEAD(&cfg->scclist);
+#if (EASYMESH_VERSION > 2)
+	INIT_LIST_HEAD(&cfg->dpp_cntlrlist);
+#endif
 	return 0;
 }
 
@@ -1499,6 +1550,86 @@ static int cntlr_config_get_agent_radio(struct controller_config *cc,
 	return 0;
 }
 
+#if (EASYMESH_VERSION > 2)
+static int cntlr_config_get_dpp_controller(struct controller_config *a,
+		struct uci_section *s)
+{
+	enum {
+		DPP_IFNAME,
+		DPP_DEVICE,
+		DPP_BAND,
+		DPP_TCP_PORT,
+		NUM_POLICIES
+	};
+	const struct uci_parse_option opts[] = {
+		{ .name = "ifname", .type = UCI_TYPE_STRING },
+		{ .name = "device", .type = UCI_TYPE_STRING },
+		{ .name = "band", .type = UCI_TYPE_STRING },
+		{ .name = "tcp_port", .type = UCI_TYPE_STRING },
+	};
+	struct uci_option *tb[NUM_POLICIES];
+	struct dpp_controller_cfg *dpp_cntlr;
+
+/*
+config dpp_dpp_cntlr
+	option device 'wl1'
+	option band '2'
+	option ifname 'wl1'
+	option tcp_dpp_cntlr '8902'
+*/
+
+	uci_parse_section(s, opts, NUM_POLICIES, tb);
+
+	if (tb[DPP_BAND]) {
+		int bandval = atoi(tb[DPP_BAND]->v.string);
+		enum wifi_band band = BAND_UNKNOWN;
+
+		if (bandval == 2)
+			band = BAND_2;
+		else if (bandval == 5)
+			band = BAND_5;
+		else if (bandval == 6)
+			band = BAND_6;
+
+		dpp_cntlr = get_dpp_controller_by_band(a, band);
+		if (!dpp_cntlr) {
+			dpp_cntlr = create_dpp_controller_config(a, band);
+			if (!dpp_cntlr) {
+				warn("%s: OOM!\n", __func__);
+				return -1;
+			}
+		} else {
+			warn("Duplicate 'dpp dpp_cntlr %d' config!! ignore\n",
+					bandval);
+		}
+	} else
+		return -1;
+
+	if (tb[DPP_IFNAME]) {
+		const char *ifname;
+
+		ifname = tb[DPP_IFNAME]->v.string;
+		strncpy(dpp_cntlr->ifname, ifname, sizeof(dpp_cntlr->ifname) - 1);
+	}
+
+	if (tb[DPP_DEVICE]) {
+		const char *device;
+
+		device = tb[DPP_DEVICE]->v.string;
+		strncpy(dpp_cntlr->device, device, sizeof(dpp_cntlr->device) - 1);
+	}
+
+	if (tb[DPP_TCP_PORT]) {
+		int port = atoi(tb[DPP_TCP_PORT]->v.string);
+
+		dpp_cntlr->port = (uint16_t) port;
+	}
+
+	return 0;
+}
+#endif
+
+
 static void config_map_radios_to_node(struct controller_config *cfg)
 {
 	struct radio_policy *r = NULL, *tmp;
@@ -1690,6 +1821,10 @@ uint8_t cntlr_config_reload(struct controller_config *cfg)
 		} else if (!strcmp(s->type, "radio")) {
 			cntlr_config_get_agent_radio(cfg, s);
 		}
+#if (EASYMESH_VERSION > 2)
+		else if (!strcmp(s->type, "dpp_controller"))
+			cntlr_config_get_dpp_controller(cfg, s);
+#endif
 	}
 
 	config_map_radios_to_node(cfg);
diff --git a/src/config.h b/src/config.h
index 0477db783af06bd3b9fe13098ae3377e485f3a06..eae8d1b562649dc5d25f4c478b242f63370f0689 100644
--- a/src/config.h
+++ b/src/config.h
@@ -139,6 +139,16 @@ struct steer_control_config {
 	struct list_head list;
 };
 
+#if (EASYMESH_VERSION > 2)
+struct dpp_controller_cfg {
+	char ifname[16];
+	enum wifi_band band;
+	char device[16];
+	uint16_t port;
+	struct list_head list;
+};
+#endif
+
 struct controller_config {
 	bool enabled;
 	bool has_registrar_6g;
@@ -161,9 +171,14 @@ struct controller_config {
 	struct list_head aplist;
 	struct list_head radiolist;
 	struct list_head scclist;		/* list of steer_control_config */
+#if (EASYMESH_VERSION > 2)
+	struct list_head dpp_cntlrlist;
+#endif
 };
 
 struct controller;
+struct dpp_controller_cfg *get_dpp_controller_by_band(struct controller_config *c,
+		enum wifi_band band);
 
 int set_value_by_string(const char *package, const char *section,
 		const char *key, const char *value, enum uci_option_type type);
diff --git a/src/dpp.c b/src/dpp.c
index c4f61bb59468bf751dd1f15bde2b3c70770e0891..cf12f02ad9daec916fac99e2e395da05cc3be84f 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -222,6 +222,20 @@ struct dpp_enrollee *dpp_enrollee_alloc(struct controller *c, uint8_t *mac)
 	return e;
 }
 
+void dpp_enrollee_free(struct dpp_enrollee *e)
+{
+	struct dpp_frame *f;
+
+	list_for_each_entry(f, &e->framelist, list) {
+		list_del(&f->list);
+		free(f->data);
+		free(f);
+	}
+
+	list_del(&e->list);
+	free(e);
+}
+
 struct dpp_chirp *dpp_chirp_get(struct controller *c, uint8_t *hash)
 {
 	struct dpp_chirp *p;
@@ -587,6 +601,23 @@ fail:
 	return 0;
 }
 
+uint16_t dpp_get_controller_tcp_port(struct controller *c, enum wifi_band band)
+{
+	struct dpp_controller_cfg *dpp_cntlr;
+
+	dpp_cntlr = get_dpp_controller_by_band(&c->cfg, band);
+	if (dpp_cntlr)
+		return dpp_cntlr->port;
+	else {
+		if (band == BAND_2)
+			return 8902;
+		else if (band == BAND_5)
+			return 8905;
+	}
+
+	return 8910;
+}
+
 static void dpp_fd_timeout(atimer_t *t)
 {
 	struct dpp_chirp *c = container_of(t, struct dpp_chirp, timeout);
diff --git a/src/dpp.h b/src/dpp.h
index bdc2d42501471501c7b49e687ab3f680b7f3d48e..344dcd6f27ff7b141748cc3468f0cef6da5ad4cb 100644
--- a/src/dpp.h
+++ b/src/dpp.h
@@ -163,6 +163,7 @@ 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_alloc(struct controller *c, uint8_t *mac);
+void dpp_enrollee_free(struct dpp_enrollee *e);
 
 int cntlr_dpp_gen_uri(struct controller *c);
 int cntlr_dpp_del_uri(struct controller *c);
@@ -182,6 +183,7 @@ int dpp_parse_uri_chan_list(struct controller *c, struct dpp_enrollee *e,
 			    char *uri);
 enum wifi_band wifi_channel_to_band(uint8_t channel);
 
+uint16_t dpp_get_controller_tcp_port(struct controller *c, enum wifi_band band);
 /* this is a test */
 void dpp_event_uloop_cb(struct uloop_fd *fd, unsigned int events);
 #endif