diff --git a/src/Makefile b/src/Makefile
index a65caf028ce7c41da8ff1533bbdc64cce84c64d0..2b0381448fa1fee33849ac21770e79d3832ce161 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -20,6 +20,7 @@ CNTLR_OBJS = \
 	core/cntlr_ubus.o \
 	core/cntlr.o \
 	core/cntlr_map.o \
+	core/cntlr_map_debug.o \
 	core/config.o \
 	core/main.o
 
diff --git a/src/core/cntlr.c b/src/core/cntlr.c
index 3d698687d1d02cc07fedea6e0505422cefcc1cf5..a8eb71f38b66b5261537a9a40f0d0fef3c165a5a 100644
--- a/src/core/cntlr.c
+++ b/src/core/cntlr.c
@@ -31,6 +31,7 @@
 
 #include "debug.h"
 #include "utils.h"
+#include "config.h"
 #include "cntlr.h"
 #include "comm.h"
 #include "hlist.h"
@@ -1957,6 +1958,8 @@ int start_controller(void)
 	as_init_table(&c->as_table);
 	ubus_add_uloop(ctx);
 
+	cntlr_config_reload(&c->cfg);
+
 	c->topology = ubus_get_topology_object(c->ubus_ctx);
 	info("topology object: %d\n", c->topology);
 	if (c->topology != OBJECT_INVALID) {
diff --git a/src/core/cntlr.h b/src/core/cntlr.h
index d8f57f3bd2ecc003fa383b28db1167cc2f1464c8..525f9aa504c9d0e50f84b099898cd7d662394942 100644
--- a/src/core/cntlr.h
+++ b/src/core/cntlr.h
@@ -124,6 +124,7 @@ struct controller {
 	struct list_head watchlist;
 	struct uloop_timeout radar_timer;
 	struct hlist_head *as_table; /** active sta hash table */
+	struct controller_config cfg;
 };
 
 #define COMM_HANDLE(c)	((struct controller *)(c))->ubus_ctx
diff --git a/src/core/cntlr_map.c b/src/core/cntlr_map.c
index 9c1c2224d165fb9e2b0d4e8d987704361ed24e58..21cd943033dec63252b9cc0641f4e9840284109f 100644
--- a/src/core/cntlr_map.c
+++ b/src/core/cntlr_map.c
@@ -28,6 +28,7 @@
 #include <libubus.h>
 
 #include <easy/easy.h>
+#include <wifi.h> // TODO: remove wifi.h
 
 #include "map_module.h"
 #include "utils.h"
@@ -42,6 +43,9 @@
 #include <map1905/map2.h>
 #include <map1905/maputils.h>
 
+#include "cntlr_map_debug.h"
+
+
 #define for_each_tlv(e, _buf, _len)					  \
 for ((e) = (struct tlv *)(_buf);					  \
 	(e)->len && (_buf) + (_len) - (uint8_t *)(e) - 3 - (e)->len >= 0; \
@@ -56,119 +60,45 @@ struct tlv {
 
 typedef int (*map_cmdu_handler_t)(void *cntlr, struct cmdu_cstruct *cmdu);
 
+struct map_cmdu_calltable_t {
+    map_cmdu_handler_t handle;
+	map_cmdu_handler_t debug;
+};
 
 int handle_topology_notification(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_topology_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_ap_autoconfig_search(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_ap_autoconfig_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_ap_autoconfig_wsc(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 
 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: %d\n", p->max_tx_streams_supported);
-				trace("\tmax_tx_streams_supported: ");
-				print_bits(p->max_tx_streams_supported, 2, 2);
-				trace("\tmax_rx_streams_supported: ");
-				print_bits(p->max_rx_streams_supported, 2, 2);
-				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: ");
-				print_bits(p->vht_tx_mcs_supported, 16, 2);
-				trace("\tvht_rx_mcs_supported: ");
-				print_bits(p->vht_rx_mcs_supported, 16, 2);
-				trace("\tmax_tx_streams_supported: ");
-				print_bits(p->max_tx_streams_supported, 3, 3);
-				trace("\tmax_rx_streams_supported: ");
-				print_bits(p->max_rx_streams_supported, 3, 3);
-				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");
-	}
-
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
@@ -176,156 +106,111 @@ 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;
 }
 
 
 int handle_channel_pref_report(void *cntlr, struct cmdu_cstruct *cmdu)
 {
-
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_channel_sel_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
-
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_oper_channel_report(void *cntlr, struct cmdu_cstruct *cmdu)
 {
-
-	return 0;
-}
-
-static bool sta_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_CLIENT_INFO:
-			{
-				struct tlv_client_info *p = (struct tlv_client_info *)tlv;
-
-				trace("\tbssid: " MACFMT "\n", MAC2STR(p->bssid));
-				trace("\tclient_addr: " MACFMT "\n", MAC2STR(p->client_addr));
-				break;
-			}
-		case MAP_TLV_CLIENT_CAPABILITY_REPORT:
-			{
-				struct tlv_client_cap_report *p = (struct tlv_client_cap_report *)tlv;
-				char *frame;
-				int offset = 1 + 2 + 1;
-
-				frame = calloc(1, (2 * (p->tlv_len - offset)) + 1);
-				if (!frame)
-					continue;
-
-				btostr(p->frame_body + offset, p->tlv_len - offset, frame);
-
-				trace("\tresult_code: 0x%02x\n", p->result_code);
-				trace("\tframe: 0x%s\n", frame);
-				break;
-			}
-		case MAP_TLV_ERROR_CODE:
-			{
-				struct tlv_error_code *p = (struct tlv_error_code *)tlv;
-
-				trace("\treason_code: 0x%02x\n", p->reason_code);
-				if (p->reason_code == 0x02)
-					trace("\tclient_addr: " MACFMT "\n", MAC2STR(p->addr));
-
-				break;
-			}
-		default:
-			fprintf(stdout, "unknown TLV in CMDU:|%s|", map_stringify_cmdu_type(cmdu_data->message_type));
-			break;
-		}
-		trace("\n");
-	}
-
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_sta_caps_report(void *cntlr, struct cmdu_cstruct *cmdu)
 {
-	trace("received sta caps report!\n");
-	sta_caps_info_from_tlv(cntlr, cmdu);
+	trace("%s: --->\n", __func__);
+	trace("parsing AP capabilities of |%s:" MACFMT "|\n", cmdu->intf_name, MAC2STR(cmdu->origin));
 	return 0;
 }
 
 int handle_ap_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_sta_link_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_unassoc_sta_link_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_beacon_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_sta_steer_btm_report(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_sta_steer_complete(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_backhaul_sta_steer_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_channel_scan_report(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_sta_disassoc_stats(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_assoc_status_notification(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_tunneled_message(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 int handle_backhaul_sta_caps_report(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
 
 int handle_failed_connection_msg(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	trace("%s: --->\n", __func__);
 	return 0;
 }
 
@@ -338,34 +223,106 @@ int handle_failed_connection_msg(void *cntlr, struct cmdu_cstruct *cmdu)
 #define CMDU_TYPE_MAP_END	0x8033
 
 /* mind the holes in the following two tables */
-static const map_cmdu_handler_t i1905ftable[] = {
-	[0x01] = handle_topology_notification,
-	[0x03] = handle_topology_response,
-	[0x07] = handle_ap_autoconfig_search,
-	[0x08] = handle_ap_autoconfig_response,
-	[0x09] = handle_ap_autoconfig_wsc,
+static const struct map_cmdu_calltable_t i1905ftable[] = {
+	[0x01] = {
+		.handle = handle_topology_notification,
+		.debug = debug_topology_notification
+	},
+	[0x03] = {
+		.handle = handle_topology_response,
+		.debug = debug_topology_response
+	},
+	[0x07] = {
+		.handle = handle_ap_autoconfig_search,
+		.debug = debug_ap_autoconfig_search
+	},
+	[0x08] = {
+		.handle = handle_ap_autoconfig_response,
+		.debug = debug_ap_autoconfig_response
+	},
+	[0x09] = {
+		.handle = handle_ap_autoconfig_wsc,
+		.debug = debug_ap_autoconfig_wsc
+	},
 };
 
-static const map_cmdu_handler_t cntlr_mapftable[] = {
-	[0x00] = handle_1905_ack,
-	[0x02] = handle_ap_caps_report,
-	[0x05] = handle_channel_pref_report,
-	[0x07] = handle_channel_sel_response,
-	[0x08] = handle_oper_channel_report,
-	[0x0a] = handle_sta_caps_report,
-	[0x0c] = handle_ap_metrics_response,
-	[0x0e] = handle_sta_link_metrics_response,
-	[0x10] = handle_unassoc_sta_link_metrics_response,
-	[0x12] = handle_beacon_metrics_response,
-	[0x15] = handle_sta_steer_btm_report,
-	[0x17] = handle_sta_steer_complete,
-	[0x1a] = handle_backhaul_sta_steer_response,
-	[0x1c] = handle_channel_scan_report,
-	[0x22] = handle_sta_disassoc_stats,
-	[0x25] = handle_assoc_status_notification,
-	[0x26] = handle_tunneled_message,
-	[0x28] = handle_backhaul_sta_caps_report,
-	[0x33] = handle_failed_connection_msg,
+static const struct map_cmdu_calltable_t cntlr_mapftable[] = {
+	[0x00] = {
+		.handle = handle_1905_ack,
+		.debug = debug_1905_ack
+	},
+	[0x02] = {
+		.handle = handle_ap_caps_report,
+		.debug = debug_ap_caps_report
+	},
+	[0x05] = {
+		.handle = handle_channel_pref_report,
+		.debug = debug_channel_pref_report
+	},
+	[0x07] = {
+		.handle = handle_channel_sel_response,
+		.debug = debug_channel_sel_response
+	},
+	[0x08] = {
+		.handle = handle_oper_channel_report,
+		.debug = debug_oper_channel_report
+	},
+	[0x0a] = {
+		.handle = handle_sta_caps_report,
+		.debug = debug_sta_caps_report
+	},
+	[0x0c] = {
+		.handle = handle_ap_metrics_response,
+		.debug = debug_ap_metrics_response
+	},
+	[0x0e] = {
+		.handle = handle_sta_link_metrics_response,
+		.debug = debug_sta_link_metrics_response
+	},
+	[0x10] = {
+		.handle = handle_unassoc_sta_link_metrics_response,
+		.debug = debug_unassoc_sta_link_metrics_response
+	},
+	[0x12] = {
+		.handle = handle_beacon_metrics_response,
+		.debug = debug_beacon_metrics_response
+	},
+	[0x15] = {
+		.handle = handle_sta_steer_btm_report,
+		.debug = debug_sta_steer_btm_report
+	},
+	[0x17] = {
+		.handle = handle_sta_steer_complete,
+		.debug = debug_sta_steer_complete
+	},
+	[0x1a] = {
+		.handle = handle_backhaul_sta_steer_response,
+		.debug = debug_backhaul_sta_steer_response
+	},
+	[0x1c] = {
+		.handle = handle_channel_scan_report,
+		.debug = debug_channel_scan_report
+	},
+	[0x22] = {
+		.handle = handle_sta_disassoc_stats,
+		.debug = debug_sta_disassoc_stats
+	},
+	[0x25] = {
+		.handle = handle_assoc_status_notification,
+		.debug = debug_assoc_status_notification
+	},
+	[0x26] = {
+		.handle = handle_tunneled_message,
+		.debug = debug_tunneled_message
+	},
+	[0x28] = {
+		.handle = handle_backhaul_sta_caps_report,
+		.debug = debug_backhaul_sta_caps_report
+	},
+	[0x33] = {
+		.handle = handle_failed_connection_msg,
+		.debug = debug_failed_connection_msg
+	},
 };
 
 
@@ -376,10 +333,10 @@ bool is_cmdu_for_us(void *module, uint16_t type)
 	/* TODO: handle cmdu types relevant for operating profile. */
 
 	if (type >= CMDU_TYPE_1905_START && type <= CMDU_TYPE_MAP_START) {
-		if (i1905ftable[type])
+		if (i1905ftable[type].handle)
 			return true;
 	} else if (type >= CMDU_TYPE_MAP_START && type <= CMDU_TYPE_MAP_END) {
-		if (cntlr_mapftable[type - CMDU_TYPE_MAP_START])
+		if (cntlr_mapftable[type - CMDU_TYPE_MAP_START].handle)
 			return true;
 	}
 
@@ -390,7 +347,7 @@ int cntlr_handle_map_event(void *module, uint16_t cmdutype, uint16_t mid,
 			   char *rxif, uint8_t *src, uint8_t *tlvs, int len)
 {
 	struct controller *c = (struct controller *)module;
-	const map_cmdu_handler_t *f;
+	const struct map_cmdu_calltable_t *f;
 	struct cmdu_cstruct *cmdu;
 	int ret = 0;
 	int idx;
@@ -405,16 +362,21 @@ int cntlr_handle_map_event(void *module, uint16_t cmdutype, uint16_t mid,
 		f = i1905ftable;
 	}
 
-	if (f[idx]) {
-		cmdu = map_build_cmdu(cmdutype, mid, rxif, src, tlvs);
-		if (cmdu) {
-			ret = f[idx](c, cmdu);
-			map_free_cmdu(cmdu);
-		} else {
-			dbg("%s: map_build_cmdu() failed!\n", __func__);
-		}
+	cmdu = map_build_cmdu(cmdutype, mid, rxif, src, tlvs);
+	if (!cmdu) {
+		dbg("%s: map_build_cmdu() failed!\n", __func__);
+		return -1;
 	}
 
+	if (f[idx].handle)
+		ret = f[idx].handle(c, cmdu);
+
+	if (c->cfg.debug_level >= 3 && f[idx].debug)
+		f[idx].debug(c, cmdu);
+
+
+	map_free_cmdu(cmdu);
+
 	//TODO: check ret
 
 	return ret;
diff --git a/src/core/cntlr_map_debug.c b/src/core/cntlr_map_debug.c
new file mode 100644
index 0000000000000000000000000000000000000000..4985ca3f974918c8fdc50fe6f1c78e080fbfc617
--- /dev/null
+++ b/src/core/cntlr_map_debug.c
@@ -0,0 +1,299 @@
+/*
+ * cntlr_map_debug.c - implements MAP2 CMDUs debug/test handling
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: jakob.olsson@iopsys.eu
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <easy/easy.h>
+
+#include "utils.h"
+#include "debug.h"
+
+#include <map1905/map2.h>
+#include <map1905/maputils.h>
+
+#include "cntlr_map_debug.h"
+
+int debug_topology_notification(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_topology_response(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_ap_autoconfig_search(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_ap_autoconfig_response(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_ap_autoconfig_wsc(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+
+int debug_1905_ack(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_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));
+
+	int i, j, k;
+	int radio_index, bss_index;
+	uint8_t *tlv = NULL;
+
+	for (i = 0; i < cmdu->num_tlvs; i++) {
+		tlv = (uint8_t *) cmdu->tlvs[i];
+		trace("CMDU type: %s, len = %04x %d %d\n", map_stringify_tlv_type(*tlv), *(tlv + 1), (uint16_t) *(tlv+2), map_get_first_tlv_length(cmdu->tlvs));
+		switch (*tlv) {
+		case MAP_TLV_AP_CAPABILITY:
+			{
+				struct tlv_ap_cap *p = (struct tlv_ap_cap *)tlv;
+				trace("len = %d\n", p->tlv_len);
+				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("len = %d\n", p->tlv_len);
+				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("len = %d\n", p->tlv_len);
+				trace("\tradio_id: " MACFMT "\n", MAC2STR(p->radio_id));
+				trace("\tmax_tx_streams_supported: %d\n", p->max_tx_streams_supported);
+				trace("\tmax_tx_streams_supported: ");
+				print_bits(p->max_tx_streams_supported, 2, 2);
+				trace("\tmax_rx_streams_supported: ");
+				print_bits(p->max_rx_streams_supported, 2, 2);
+				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("len = %d\n", p->tlv_len);
+				trace("\tradio_id: " MACFMT "\n", MAC2STR(p->radio_id));
+				trace("\tvht_tx_mcs_supported: ");
+				print_bits(p->vht_tx_mcs_supported, 16, 2);
+				trace("\tvht_rx_mcs_supported: ");
+				print_bits(p->vht_rx_mcs_supported, 16, 2);
+				trace("\tmax_tx_streams_supported: ");
+				print_bits(p->max_tx_streams_supported, 3, 3);
+				trace("\tmax_rx_streams_supported: ");
+				print_bits(p->max_rx_streams_supported, 3, 3);
+				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->message_type));
+			break;
+		}
+		trace("\n");
+	}
+	return 0;
+}
+
+
+int debug_channel_pref_report(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_channel_sel_response(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_oper_channel_report(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_sta_caps_report(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	int i, j, k;
+	int radio_index, bss_index;
+	uint8_t *tlv = NULL;
+
+	trace("%s: --->\n", __func__);
+	trace("parsing AP capabilities of |%s:" MACFMT "|\n", cmdu->intf_name, MAC2STR(cmdu->origin));
+
+	for (i = 0; i < cmdu->num_tlvs; i++) {
+		tlv = cmdu->tlvs[i];
+		trace("CMDU type: %s\n", map_stringify_tlv_type(*tlv));
+		switch (*tlv) {
+		case MAP_TLV_CLIENT_INFO:
+			{
+				struct tlv_client_info *p = (struct tlv_client_info *)tlv;
+
+				trace("\tbssid: " MACFMT "\n", MAC2STR(p->bssid));
+				trace("\tclient_addr: " MACFMT "\n", MAC2STR(p->client_addr));
+				break;
+			}
+		case MAP_TLV_CLIENT_CAPABILITY_REPORT:
+			{
+				struct tlv_client_cap_report *p = (struct tlv_client_cap_report *)tlv;
+				char *frame;
+				int offset = 1 + 2 + 1;
+
+				frame = calloc(1, (2 * (p->tlv_len - offset)) + 1);
+				if (!frame)
+					continue;
+
+				btostr(p->frame_body + offset, p->tlv_len - offset, frame);
+
+				trace("\tresult_code: 0x%02x\n", p->result_code);
+				trace("\tframe: 0x%s\n", frame);
+				break;
+			}
+		case MAP_TLV_ERROR_CODE:
+			{
+				struct tlv_error_code *p = (struct tlv_error_code *)tlv;
+
+				trace("\treason_code: 0x%02x\n", p->reason_code);
+				if (p->reason_code == 0x02)
+					trace("\tclient_addr: " MACFMT "\n", MAC2STR(p->addr));
+
+				break;
+			}
+		default:
+			fprintf(stdout, "unknown TLV in CMDU:|%s|", map_stringify_cmdu_type(cmdu->message_type));
+			break;
+		}
+		trace("\n");
+	}
+
+	return 0;
+}
+
+int debug_ap_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_sta_link_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_unassoc_sta_link_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_beacon_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_sta_steer_btm_report(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_sta_steer_complete(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_backhaul_sta_steer_response(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_channel_scan_report(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_sta_disassoc_stats(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_assoc_status_notification(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_tunneled_message(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+int debug_backhaul_sta_caps_report(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	trace("%s: --->\n", __func__);
+	return 0;
+}
+
+
+int debug_failed_connection_msg(void *cntlr, struct cmdu_cstruct *cmdu)
+{
+	return 0;
+}
\ No newline at end of file
diff --git a/src/core/cntlr_map_debug.h b/src/core/cntlr_map_debug.h
new file mode 100644
index 0000000000000000000000000000000000000000..4b2003d4101ac16bfdd9bd6b7702dfadb6380b12
--- /dev/null
+++ b/src/core/cntlr_map_debug.h
@@ -0,0 +1,37 @@
+/*
+ * cntlr_map_debug.h - debug function declarations
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: jakob.olsson@iopsys.eu
+ *
+ */
+
+#ifndef CNTLR_MAP_DEBUG_H
+#define CNTLR_MAP_DEBUG_H
+
+int debug_topology_notification(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_topology_response(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_ap_autoconfig_search(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_ap_autoconfig_response(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_ap_autoconfig_wsc(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_1905_ack(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_ap_caps_report(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_channel_pref_report(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_channel_sel_response(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_oper_channel_report(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_sta_caps_report(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_ap_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_sta_link_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_unassoc_sta_link_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_beacon_metrics_response(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_sta_steer_btm_report(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_sta_steer_complete(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_backhaul_sta_steer_response(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_channel_scan_report(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_sta_disassoc_stats(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_assoc_status_notification(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_tunneled_message(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_backhaul_sta_caps_report(void *cntlr, struct cmdu_cstruct *cmdu);
+int debug_failed_connection_msg(void *cntlr, struct cmdu_cstruct *cmdu);
+#endif
\ No newline at end of file
diff --git a/src/core/cntlr_ubus.c b/src/core/cntlr_ubus.c
index a4ce4d03cbba7bbee95c2901fff807bb021ead21..7af67ba559b3e3f0d0e907476c0652a87ba7ca7b 100644
--- a/src/core/cntlr_ubus.c
+++ b/src/core/cntlr_ubus.c
@@ -20,7 +20,8 @@
 #include <uci.h>
 
 #include <easy/easy.h>
-//#include <wifi.h>
+#include <wifi.h> // TODO: remove wifi.h
+
 #include "utils.h"
 #include "debug.h"
 #include "config.h"
diff --git a/src/core/config.c b/src/core/config.c
index 1ce3210024f2bcb3c430e60313bebb634c09a18f..407cf1406c94b6abb664876052acf5ce89016624 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -27,6 +27,9 @@
 #include <libubus.h>
 #include <uci.h>
 
+#include <easy/easy.h> // TODO: remove wifi.h
+#include <wifi.h> // TODO: remove wifi.h
+
 #include "debug.h"
 #include "utils.h"
 #include "config.h"
@@ -97,11 +100,13 @@ static int cntlr_config_get_base(struct controller_config *c,
 	enum {
 		CNTLR_ENABLED,
 		CNTLR_REGISTRAR,
+		CNTLR_DEBUG,
 		NUM_CNTLR_ATTRS,
 	};
 	const struct uci_parse_option opts[] = {
 		{ .name = "enabled", .type = UCI_TYPE_STRING },
 		{ .name = "registrar", .type = UCI_TYPE_STRING },
+		{ .name = "debug", .type = UCI_TYPE_STRING },
 	};
 	struct uci_option *tb[NUM_CNTLR_ATTRS];
 
@@ -121,6 +126,12 @@ static int cntlr_config_get_base(struct controller_config *c,
 		c->has_registrar_2g = !strstr(val, "2") ? false : true;
 	}
 
+	if (tb[CNTLR_ENABLED]) {
+		const char *debug = tb[CNTLR_DEBUG]->v.string;
+
+		c->debug_level = atoi(debug);
+	}
+
 	return 0;
 }
 
@@ -162,9 +173,9 @@ static int cntlr_config_get_credentials(struct controller_config *c,
 
 	if (tb[CRED_BAND]) {
 		if (atoi(tb[CRED_BAND]->v.string) == 5)
-			cred->band = WIFI_BAND_5;
+			cred->band = BAND_5;
 		else if (atoi(tb[CRED_BAND]->v.string) == 2)
-			cred->band = WIFI_BAND_2;
+			cred->band = BAND_2;
 	}
 
 	if (tb[CRED_SSID])
diff --git a/src/core/config.h b/src/core/config.h
index d8270878f362057d76358755595e91a9ff02f974..0e90e9158ac0ef50bb2c2a3b8a607debd79afb15 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -10,16 +10,18 @@
 #ifndef CONFIG_H
 #define CONFIG_H
 
-
+/*
 // TODO: use wifi.h definitions??
 enum wifi_band {
 	WIFI_BAND_NONE,
-	WIFI_BAND_2       = 1 << 0,        /**< 0x1 for 2.4Ghz band. */
-	WIFI_BAND_5       = 1 << 1,        /**< 0x2 for 5Ghz band. */
-	WIFI_BAND_60      = 1 << 2,        /**< 0x4 for 60Ghz band. */
-	WIFI_BAND_6       = 1 << 3,        /**< 0x8 for 6Ghz */
+	WIFI_BAND_2       = 1 << 0,
+	WIFI_BAND_5       = 1 << 1,
+	WIFI_BAND_60      = 1 << 2,
+	WIFI_BAND_6       = 1 << 3,
 };
+*/
 
+/*
 // TODO: use wifi.h definitions??
 enum wifi_security {
 	WIFI_SECURITY_NONE,
@@ -33,7 +35,7 @@ enum wifi_security {
 	WIFI_SECURITY_WPA2,
 	WIFI_SECURITY_WPA3,
 };
-
+*/
 
 struct iface_credential {
 	enum wifi_band band;
@@ -78,6 +80,7 @@ struct controller_config {
 	bool enabled;
 	bool has_registrar_5g;
 	bool has_registrar_2g;
+	int debug_level;
 	int num_fh;
 	int num_bk;
 	struct iface_credential fh[2];