diff --git a/src/cmdu_ackq.c b/src/cmdu_ackq.c
index 1ae6a8aa77a2c15afcc2ee8a8621ca992e38b0d7..7b2b8293bbc0c42e0412ac216afe88b25005d965 100644
--- a/src/cmdu_ackq.c
+++ b/src/cmdu_ackq.c
@@ -18,6 +18,7 @@
 
 #include "timer.h"
 #include "cmdu_ackq.h"
+#include "debug.h"
 
 static int timeradd_msecs(struct timeval *a, unsigned long msecs,
 			  struct timeval *res)
@@ -48,7 +49,7 @@ struct cmdu_ackq_entry *cmdu_ackq_create_msg(uint16_t type, uint16_t mid,
 
 	msg = calloc(1, sizeof(*msg));
 	if (!msg) {
-		fprintf(stderr, "calloc failed. err = NOMEM\n");
+		err("calloc failed! -ENOMEM\n");
 		return NULL;
 	}
 
@@ -62,9 +63,9 @@ struct cmdu_ackq_entry *cmdu_ackq_create_msg(uint16_t type, uint16_t mid,
 	msg->ageing_tmo.tv_usec = (msg->ageing_tmo.tv_usec / 1000) * 1000;
 	memcpy(msg->origin, dest, 6);
 	msg->cookie = cookie;
-	fprintf(stderr,
-		"    CREATE msg: type = 0x%04x  mid = %hu origin = " MACFMT " timeout = { %u (%lu:%lu) }\n",
-		type, mid, MAC2STR(dest), msg->ageing_time, msg->ageing_tmo.tv_sec, msg->ageing_tmo.tv_usec / 1000);
+	loud("    CREATE msg: type = 0x%04x  mid = %hu origin = " MACFMT " timeout = { %u (%lu:%lu) }\n",
+		type, mid, MAC2STR(dest), msg->ageing_time,
+		msg->ageing_tmo.tv_sec, msg->ageing_tmo.tv_usec / 1000);
 
 	return msg;
 }
@@ -92,16 +93,16 @@ static void cmdu_ackq_ageout_entry(struct cmdu_ackq *st, struct hlist_head *head
 
 
 	hlist_for_each_entry_safe(msg, tmp, head, hlist) {
-		fprintf(stderr, "%s(): Entry msg->ageout = (%lu.%lu), now = (%lu.%lu)\n",
-				__func__,
-				msg->ageing_tmo.tv_sec, msg->ageing_tmo.tv_usec,
-				now.tv_sec, now.tv_usec);
+		loud("%s(): Entry msg->ageout = (%lu.%lu), now = (%lu.%lu)\n",
+		     __func__, msg->ageing_tmo.tv_sec, msg->ageing_tmo.tv_usec,
+		     now.tv_sec, now.tv_usec);
 
 		if (timercmp(&msg->ageing_tmo, &now, <=)) {
 			st->pending_cnt--;
 			hlist_del(&msg->hlist, head);
-			fprintf(stderr, "No response from " MACFMT " for CMDU 0x%x with mid = %hu\n",
-				MAC2STR(msg->origin), msg->type, msg->mid);
+			loud("No response from " MACFMT " for CMDU 0x%x with mid = %hu\n",
+			     MAC2STR(msg->origin), msg->type, msg->mid);
+
 			cmdu_ackq_delete_msg(msg);	//TODO: user decides timeout action
 		} else {
 			struct timeval new_next_tmo = { 0 };
@@ -130,15 +131,15 @@ static void cmdu_ackq_ageing_timer_run(atimer_t *t)
 
 	gettimeofday(&nu, NULL);
 
-	fprintf(stderr, "\n ----Timer now = %lu.%lu  --- cnt = %d---\n",
-		nu.tv_sec, nu.tv_usec, st->pending_cnt);
+	/* fprintf(stderr, "\n ----Timer now = %lu.%lu  --- cnt = %d---\n",
+		nu.tv_sec, nu.tv_usec, st->pending_cnt); */
 
 	//spin_lock(&st->hash_lock);
 	for (i = 0; i < CMDU_BACKLOG_MAX; i++) {
 		if (hlist_empty(&st->table[i]))
 			continue;
 
-		fprintf(stderr, "i = %d\t", i);
+		//fprintf(stderr, "i = %d\t", i);
 		cmdu_ackq_ageout_entry(st, &st->table[i], &min_next_tmo);
 	}
 
@@ -227,10 +228,8 @@ int cmdu_ackq_enqueue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *dest,
 
 	msg = cmdu_ackq_lookup(cmdu_q, type, mid, dest);
 	if (msg) {
-		fprintf(stderr,
-			"Duplicate: type = 0x%04x  mid = %hu origin = " MACFMT "\n",
-			type, mid, MAC2STR(dest));
-
+		loud("Duplicate: type = 0x%04x  mid = %hu origin = " MACFMT "\n",
+		     type, mid, MAC2STR(dest));
 		return -1;
 	}
 
@@ -242,10 +241,8 @@ int cmdu_ackq_enqueue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *dest,
 		hlist_add_head(&msg->hlist, &q->table[idx]);
 
 		q->pending_cnt++;
-		fprintf(stderr,
-			"    ENQ:        type = 0x%04x  mid = %hu origin = " MACFMT "\n",
-			type, mid, MAC2STR(dest));
-
+		loud("    ENQ:        type = 0x%04x  mid = %hu origin = " MACFMT "\n",
+		     type, mid, MAC2STR(dest));
 
 		if (timer_pending(&q->ageing_timer)) {
 			if (timercmp(&q->next_tmo, &msg->ageing_tmo, >)) {
@@ -253,10 +250,10 @@ int cmdu_ackq_enqueue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *dest,
 				q->next_tmo.tv_usec = msg->ageing_tmo.tv_usec;
 
 				timer_set(&q->ageing_timer, msg->ageing_time);
-				fprintf(stderr, "Adjust ageout timer ========>\n");
+				//fprintf(stderr, "Adjust ageout timer ===\n");
 			}
 		} else {
-			fprintf(stderr, "Start ageout timer ========>\n");
+			//fprintf(stderr, "Start ageout timer ===\n");
 			q->next_tmo.tv_sec = msg->ageing_tmo.tv_sec;
 			q->next_tmo.tv_usec = msg->ageing_tmo.tv_usec;
 			timer_set(&q->ageing_timer, msg->ageing_time);
@@ -277,10 +274,8 @@ int cmdu_ackq_dequeue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *src, v
 
 	msg = cmdu_ackq_lookup(cmdu_q, type, mid, src);
 	if (!msg) {
-		fprintf(stderr,
-			"DROP! CMDU not found: type = 0x%04x  mid = %hu origin = " MACFMT "\n",
-			type, mid, MAC2STR(src));
-
+		loud("DROP! CMDU not found: type = 0x%04x  mid = %hu origin = " MACFMT "\n",
+		     type, mid, MAC2STR(src));
 		return -1;
 	}
 
@@ -291,9 +286,8 @@ int cmdu_ackq_dequeue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *src, v
 	q->pending_cnt--;
 	pthread_mutex_unlock(&q->qlock);
 
-	fprintf(stderr,
-		"DEQ: type = 0x%04x  mid = %hu origin = " MACFMT "\n",
-		type, mid, MAC2STR(src));
+	loud("DEQ: type = 0x%04x  mid = %hu origin = " MACFMT "\n",
+	     type, mid, MAC2STR(src));
 
 
 	/* After returning cookie back to user, we can safely delete the msg */
diff --git a/src/cmduqueue.c b/src/cmduqueue.c
index 3ca4d976520e5ee4ad003c6cb2f9a4ffc47af908..cab3f04db774cf1b12e87b7aa30d428867a55ca9 100644
--- a/src/cmduqueue.c
+++ b/src/cmduqueue.c
@@ -74,8 +74,8 @@ void cmdu_enqueue(struct cmdu_queue *q, struct cmdu_buff *m)
 {
 	pthread_mutex_lock(&q->lock);
 	list_add_tail(&m->list, &q->q);
-	fprintf(stderr, "After enqueue msg (%p),  qlen =%d\n",
-					m, __cmdu_queue_length(q));
+	/* fprintf(stderr, "After enqueue msg (%p),  qlen =%d\n",
+		m, __cmdu_queue_length(q)); */
 	pthread_mutex_unlock(&q->lock);
 }
 
@@ -99,8 +99,8 @@ struct cmdu_buff *cmdu_dequeue(struct cmdu_queue *q)
 		pthread_cond_wait(&q->empty, &q->lock);
 
 	m = __cmdu_dequeue(q);
-	fprintf(stderr, "After dequeue msg (%p),  qlen =%d\n",
-					m, __cmdu_queue_length(q));
+	/* fprintf(stderr, "After dequeue msg (%p),  qlen =%d\n",
+		m, __cmdu_queue_length(q)); */
 
 	pthread_mutex_unlock(&q->lock);
 
diff --git a/src/debug.c b/src/debug.c
index 3a69db5870cdd20875a60d8dee3c13c78c9d7853..c0ae9f97042093162fac133638ce3d716a06cdde 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -90,23 +90,25 @@ void log_message(int level, const char *fmt, ...)
 {
 	va_list args;
 
-	if (level > verbose) {
-		if (logfile_isfifo && ffd) {
-			time_t now = time(NULL);
-			struct tm *tm_now = localtime(&now);
-			const char *tm_fmt = "[%d-%02d-%02d %02d:%02d:%02d] ";
-
-			va_start(args, fmt);
-			dprintf(ffd, tm_fmt,
-				tm_now->tm_year + 1900,
-				tm_now->tm_mon + 1,
-				tm_now->tm_mday,
-				tm_now->tm_hour,
-				tm_now->tm_min,
-				tm_now->tm_sec);
-			vdprintf(ffd, fmt, args);
-			va_end(args);
-		}
+	if (level > verbose)
+		return;
+
+	if (logfile_isfifo && ffd) {
+		time_t now = time(NULL);
+		struct tm *tm_now = localtime(&now);
+		const char *tm_fmt = "[%d-%02d-%02d %02d:%02d:%02d] ";
+
+		va_start(args, fmt);
+		dprintf(ffd, tm_fmt,
+			tm_now->tm_year + 1900,
+			tm_now->tm_mon + 1,
+			tm_now->tm_mday,
+			tm_now->tm_hour,
+			tm_now->tm_min,
+			tm_now->tm_sec);
+		vdprintf(ffd, fmt, args);
+		va_end(args);
+
 		return;
 	}
 
diff --git a/src/i1905.c b/src/i1905.c
index 227149aea31b576a09e012a4f72d3225a29a11d9..db35e5d58608b020fb6ce8883b91418e4fe0800f 100644
--- a/src/i1905.c
+++ b/src/i1905.c
@@ -36,6 +36,7 @@
 #include <easy/easy.h>
 #include <wifi.h>
 
+#include "debug.h"
 #include "worker.h"
 #include "bufutil.h"
 #include "util.h"
@@ -113,7 +114,7 @@ static void i1905_load_extensions(struct i1905_private *p)
 		if (i1905_lookup_extension(p, e->name))
 			continue;
 
-		fprintf(stderr, "load extension '%s'\n", e->name);
+		dbg("load extension '%s'\n", e->name);
 		mod = i1905_load_extmodule(p, e->name);
 		if (mod)
 			list_add_tail(&mod->list, &p->extlist);
@@ -126,7 +127,7 @@ int i1905_extension_register(struct i1905_private *p, char *name)
 
 
 	if (i1905_lookup_extension(p, name)) {
-		fprintf(stderr, "extension '%s' already registered\n", name);
+		info("extension '%s' already registered\n", name);
 		return 0;
 	}
 
@@ -241,11 +242,11 @@ static struct i1905_interface *i1905_alloc_interface(struct i1905_private *priv,
 		uint8_t s = 0;
 		int ret;
 
-		fprintf(stderr, "%s: is WiFi ", ifname);
+		info("%s: is WiFi ", ifname);
 
 		n->mediainfo = calloc(1, sizeof(struct ieee80211_info));
 		if (!n->mediainfo) {
-			fprintf(stderr, "-ENOMEM\n");
+			err("-ENOMEM\n");
 			free(n);
 			return NULL;
 		}
@@ -258,22 +259,22 @@ static struct i1905_interface *i1905_alloc_interface(struct i1905_private *priv,
 		if (!ret) {
 			if (!!(s & WIFI_AX)) {
 				n->media = I1905_802_11AX;
-				fprintf(stderr, "802.11ax\n");
+				info("802.11ax\n");
 			} else if (!!(s & WIFI_AC)) {
 				n->media = I1905_802_11AC_5_GHZ;
-				fprintf(stderr, "802.11ac\n");
+				info("802.11ac\n");
 			} else if (!!(s & WIFI_N)) {
 				n->media = I1905_802_11N_5_GHZ;	//FIXME: 2.4
-				fprintf(stderr, "802.11n\n");
+				info("802.11n\n");
 			} else if (!!(s & WIFI_A)) {
 				n->media = I1905_802_11AC_5_GHZ;
-				fprintf(stderr, "802.11a\n");
+				info("802.11a\n");
 			} else if (!!(s & WIFI_G)) {
 				n->media = I1905_802_11G_2_4_GHZ;
-				fprintf(stderr, "802.11g\n");
+				info("802.11g\n");
 			} else {
 				n->media = I1905_802_11B_2_4_GHZ;
-				fprintf(stderr, "802.11b\n");
+				info("802.11b\n");
 			}
 		}
 
@@ -313,7 +314,7 @@ static struct i1905_interface *i1905_alloc_interface(struct i1905_private *priv,
 		/* get bssid */
 		ret = wifi_get_bssid(ifname, wifi->bssid);
 		if (ret)
-			fprintf(stderr, "error wifi_get_bssid()\n");
+			warn("error wifi_get_bssid()\n");
 
 
 		/* get ap bandwidth */
@@ -373,7 +374,7 @@ static struct i1905_interface *i1905_alloc_interface(struct i1905_private *priv,
 			n->pbc_ongoing = true;
 
 	} else {
-		fprintf(stderr, "%s: is Ethernet\n", ifname);
+		info("%s: is Ethernet\n", ifname);
 		n->media = MEDIA_TYPE_IEEE_802_3AB_GIGABIT_ETHERNET;	//FIXME
 		n->mediainfo = NULL;
 		n->authenticated = true;
@@ -471,7 +472,7 @@ int i1905_send_cmdu(struct i1905_interface_private *ifpriv,
 	ret = sendto(ifpriv->sock_1905, frm->head, frm->len, 0, (struct sockaddr*)&sa,
 		     sizeof(struct sockaddr_ll));
 	if (ret < 0) {
-		printf("%s: failed to send!!!!!!!\n", __func__);
+		dbg("%s: failed to send!!!!!!!\n", __func__);
 		return -1;
 	}
 
@@ -539,8 +540,8 @@ int i1905_send_cmdu_relay_mcast(struct i1905_private *priv, const char *ifname,
 		ret = sendto(ifpriv->sock_1905, frm->head, frm->len, 0,
 			     (struct sockaddr*)&sa, sizeof(struct sockaddr_ll));
 		if (ret < 0) {
-			fprintf(stderr, "Error sending relay mcast through '%s'\n",
-				ifs->ifname);
+			dbg("Error sending relay mcast through '%s'\n",
+			    ifs->ifname);
 		}
 	}
 
@@ -551,23 +552,29 @@ int i1905_cmdu_tx(struct i1905_interface_private *ifpriv,
 		  uint8_t *dst, uint8_t *src, uint16_t type, uint16_t *mid,
 		  uint8_t *data, int datalen)
 {
-	struct i1905_interface *iface = i1905_interface_priv(ifpriv);
+	struct i1905_interface *iface;
 	struct cmdu_buff *frm = NULL;
 	struct i1905_private *priv;
 	uint16_t resp_type;
+	int pending = 0;
 	int ret = 0;
 
 
+	if (!ifpriv)
+		return -1;
+
+	iface = i1905_interface_priv(ifpriv);
+
 	if (!data && is_cmdu_tlv_required(type)) {
-		fprintf(stderr, "%s: Invalid cmdu. %s requires tlv data\n",
-			__func__, cmdu_type2str(type));
+		err("%s: Invalid cmdu. %s requires tlv data\n", __func__,
+		    cmdu_type2str(type));
 		return -1;
 	}
 
 
 	frm = cmdu_alloc_simple(type, mid);
 	if (!frm) {
-		fprintf(stderr, "%s: -ENOMEM\n", __func__);
+		err("%s: -ENOMEM\n", __func__);
 		return -1;
 	}
 
@@ -634,19 +641,20 @@ int i1905_cmdu_tx(struct i1905_interface_private *ifpriv,
 		if (frmdup) {
 			//dev_macaddr = zero
 			//dev_ifname = ""
-			fprintf(stderr, "@@@@@@@@@@@@@@ TX Clone @@@@>>>>>>>>>>>>>>>>>>>>>>>>\n");
+			err("@@@@@@@@@@@@@@ TX CLONE >>>>>>>>>>>>>>>>>>>>>>>>\n");
 			cmdu_enqueue(&priv->rxqueue, frmdup);
-			cmdu_queue_signal(&priv->rxqueue);
+			pending = 1;
+			//cmdu_queue_signal(&priv->rxqueue);
 		}
 	}
 
 	ret = i1905_send_cmdu(ifpriv, dst, src, ETHERTYPE_1905, frm);
 	if (ret < 0) {
-		fprintf(stderr, "%s: failed!!!!!!!\n", __func__);
+		err("%s: failed!\n", __func__);
 		goto out;
 	}
 
-	fprintf(stderr, "@@@@@@@@@@@@@@ TX @@@@>>>>>>>>>>>>>>>>>>>>>>>>\n");
+	err("@@@@@@@@@@@@@@ TX >>>>>>>>>>>>>>>>>>>>>>>>\n");
 out_enqueue:
 	//TODO: when dst = mcast, skip matching dst on recv'd cmdu in DEQ
 	resp_type = cmdu_expect_response(type);
@@ -656,12 +664,14 @@ out_enqueue:
 				  CMDU_DEFAULT_TIMEOUT, NULL);
 	}
 
+	/* signal rxqueue if pending */
+	if (pending)
+		cmdu_queue_signal(&priv->rxqueue);
 out:
 	cmdu_free(frm);
 	return ret;
 }
 
-
 static void i1905_recv_1905(struct uloop_fd *fd, unsigned int events)
 {
 	struct i1905_interface_private *ifpriv =
@@ -678,7 +688,7 @@ static void i1905_recv_1905(struct uloop_fd *fd, unsigned int events)
 
 		rxf = cmdu_alloc_default();
 		if (!rxf) {
-			fprintf(stderr, "%s: -ENOMEM\n", __func__);
+			err("%s: -ENOMEM\n", __func__);
 			return;
 		}
 
@@ -689,8 +699,8 @@ static void i1905_recv_1905(struct uloop_fd *fd, unsigned int events)
 			break;
 		}
 
-		fprintf(stderr, "%s: Rx 1905 CMDU ifname = %s\n", __func__, iface->ifname);
-		bufprintf(rxf->head, res, "Received 1905 CMDU");
+		dbg("%s: Rx 1905 CMDU ifname = %s\n", __func__, iface->ifname);
+		//bufprintf(rxf->head, res, "Received 1905 CMDU");
 
 		if (*(rxf->head + 12) == 0x81 && *(rxf->head + 13) == 0x00) {
 			/* vlan tagged */
@@ -823,7 +833,7 @@ static void i1905_recv_lldp(struct uloop_fd *fd, unsigned int events)
 			break;
 		}
 
-		bufprintf(rxf->head, res, "Received lldp data");
+		//bufprintf(rxf->head, res, "Received lldp data");
 
 		if (*(rxf->head + 12) == 0x81 && *(rxf->head + 13) == 0x00) {
 			/* vlan tagged */
@@ -1065,7 +1075,7 @@ static int i1905_init_interfaces(struct i1905_private *p)
 		struct i1905_interface *iface;
 
 
-		fprintf(stderr, "%s: ifname = %s\n", __func__, f->ifname);
+		dbg("%s: ifname = %s\n", __func__, f->ifname);
 
 		if (f->is_bridge && if_isbridge(f->ifname)) {
 			char cmd[512] = {0};
@@ -1075,7 +1085,7 @@ static int i1905_init_interfaces(struct i1905_private *p)
 			int ret;
 			int i;
 
-			fprintf(stderr, "%s: %s is bridge\n", __func__, f->ifname);
+			dbg("%s: %s is bridge\n", __func__, f->ifname);
 			br_ifindex = if_nametoindex(f->ifname);
 			ret = br_get_iflist(f->ifname, &n, ifnames);
 			if (ret)
@@ -1096,22 +1106,22 @@ static int i1905_init_interfaces(struct i1905_private *p)
 				list_add_tail(&iface->list, &p->dm.self.iflist);
 				p->dm.self.num_interface++;
 
-				fprintf(stderr, "bypass bridge flow for unicast CMDUs to " MACFMT "\n",
-					MAC2STR(iface->macaddr));
+				loud("bypass bridge flow for unicast CMDUs to " MACFMT "\n",
+				     MAC2STR(iface->macaddr));
 				snprintf(cmd, 511,
 					"ebtables -t broute -I BROUTING 1 -d " MACFMT " -p 0x893a -j DROP",
 					MAC2STR(iface->macaddr));
 				system(cmd);
 			}
 
-			fprintf(stderr, "bypass bridge flow for CMDUs to our AL-address\n");
+			loud("bypass bridge flow for CMDUs to our AL-address\n");
 			snprintf(cmd, 511,
 				"ebtables -t broute -I BROUTING 1 -d " MACFMT " -p 0x893a -j DROP",
 				MAC2STR(cfg->macaddr));
 			system(cmd);
 
 
-			fprintf(stderr, "bypass bridge flow for multicast CMDUs\n");
+			loud("bypass bridge flow for multicast CMDUs\n");
 			snprintf(cmd, 511,
 				"ebtables -t broute -I BROUTING 1 -d " MACFMT " -p 0x893a -j DROP",
 				MAC2STR(MCAST_1905));
@@ -1131,8 +1141,8 @@ static int i1905_init_interfaces(struct i1905_private *p)
 				i1905_init_interface(p, iface, i1905_setup_interface_priv);
 				iface->is_brif = false;
 				iface->brport = 0xffffffff;
-				fprintf(stderr, "%s: aladdr = " MACFMT "\n",
-					__func__, MAC2STR(cfg->macaddr));
+				info("%s: aladdr = " MACFMT "\n", __func__,
+				     MAC2STR(cfg->macaddr));
 
 				list_add_tail(&iface->list, &p->dm.self.iflist);
 				p->dm.self.num_interface++;
@@ -1146,11 +1156,11 @@ static int i1905_init_interfaces(struct i1905_private *p)
 							    NULL);
 					if (!res) {
 						p->al_ifindex = if_nametoindex(p->al_ifname);
-						fprintf(stderr, "Bringing up AL interface ifindex = %d\n",
-							p->al_ifindex);
+						dbg("Bringing up AL interface ifindex = %d\n",
+						    p->al_ifindex);
 						res = if_setflags(p->al_ifname, IFF_UP);
 						if (res) {
-							fprintf(stderr, "Failed to bring up al-interface!!!!!\n");
+							err("Failed to bring up al-interface!!!!!\n");
 						}
 					}
 				}
@@ -1181,7 +1191,7 @@ static int i1905_init_al(struct i1905_private *p)
 	cmdu_ackq_init(&p->txack_q);
 	neigh_queue_init(&p->neigh_q);
 
-	fprintf(stderr, "%s: starting rx worker...\n", __func__);
+	dbg("%s: starting rx worker...\n", __func__);
 	p->rxwork.data = p;
 	p->rxwork.func = i1905_cmdu_rxq_handler;
 	worker_init(&p->rxwork);
@@ -1385,7 +1395,7 @@ int i1905_init(void **priv, void *opts)
 	uloop_init();
 	p->ctx = ubus_connect(uopts->ubus_sockpath);
 	if (!p->ctx) {
-		fprintf(stderr, "Failed to connect to ubus\n");
+		err("Failed to connect to ubus\n");
 		goto out_err;
 	}
 	ubus_add_uloop(p->ctx);
@@ -1395,10 +1405,9 @@ int i1905_init(void **priv, void *opts)
 	i1905_reconfig(&p->cfg, uopts->confpath, uopts->conffile);
 	i1905_dump_config(&p->cfg);
 
-	fprintf(stderr, "%s:  priv = %p  registrar (2G = %d, 5G = %d))\n",
-		__func__, p,
-		!!(p->cfg.registrar & BIT(I1905_CONFIG_REGISTRAR_2G)),
-		!!(p->cfg.registrar & BIT(I1905_CONFIG_REGISTRAR_5G)));
+	dbg("%s:  priv = %p  registrar (2G = %d, 5G = %d))\n", __func__, p,
+	    !!(p->cfg.registrar & BIT(I1905_CONFIG_REGISTRAR_2G)),
+	    !!(p->cfg.registrar & BIT(I1905_CONFIG_REGISTRAR_5G)));
 
 
 	ret = i1905_init_al(p);
diff --git a/src/i1905_netlink.c b/src/i1905_netlink.c
index 0c4bf8a63dcbb3aa75fb0b4cd2ea442bbb5ea762..2c88ccd047ca6915f110b1e82803371c41308591 100644
--- a/src/i1905_netlink.c
+++ b/src/i1905_netlink.c
@@ -167,8 +167,8 @@ int i1905_update_neigh_brport(struct i1905_private *priv, char *brname)
 	for (i = 0; i < num; i++) {
 		struct neigh_entry *t;
 
-		fprintf(stderr, "FDB[%d] : " MACFMT "  port = %hu\n",
-			i, MAC2STR(fdbs[i].macaddr), fdbs[i].port);
+		dbg("FDB[%d] : " MACFMT "  port = %hu\n", i,
+		    MAC2STR(fdbs[i].macaddr), fdbs[i].port);
 
 		t = neigh_lookup(&priv->neigh_q, fdbs[i].macaddr);
 		if (t) {
@@ -185,8 +185,6 @@ int i1905_update_neigh_brport(struct i1905_private *priv, char *brname)
 		}
 	}
 
-	fprintf(stderr, "\n");
-
 	return 0;
 }
 
@@ -307,8 +305,8 @@ static int i1905_handle_nlevents_neigh(struct i1905_private *priv,
 
 	if_indextoname(ndm->ndm_ifindex, ifname);
 
-	err("Netlink neigh %s on %s   state = %s\n", ipbuf, ifname,
-	    rtnl_neigh_state2str(ndm->ndm_state, state, sizeof(state)));
+	loud("Netlink neigh %s on %s   state = %s\n", ipbuf, ifname,
+	     rtnl_neigh_state2str(ndm->ndm_state, state, sizeof(state)));
 
 
 	i1905_handle_neigh_tbl_change(priv, add, ifname, macaddr, &ip,
@@ -391,7 +389,7 @@ int i1905_register_nlevents(struct i1905_private *priv)
 	rtnl_event.sock = sk;
 
 	if (nl_socket_set_buffer_size(rtnl_event.sock, rtnl_event.sock_bufsize, 0)) {
-		fprintf(stderr, "%s: %d\n", __func__, __LINE__);
+		err("%s: %d\n", __func__, __LINE__);
 		goto out_err;
 	}
 
@@ -516,9 +514,11 @@ int i1905_get_known_neighbors(struct i1905_private *priv, char *ifname)
 		i1905_update_neigh_brport(priv, ifname);
 	}
 
+#ifdef NEIGH_DEBUG
 	fprintf(stderr, "-------------------------------\n");
 	neigh_queue_print(&priv->neigh_q);
 	fprintf(stderr, "-------------------------------\n");
+#endif
 
 	return 0;
 }
diff --git a/src/i1905_ubus.c b/src/i1905_ubus.c
index d67e99766c0a2bd2f5b4c88476cc8e89c15f0666..a8efca3941fef229f000642c48c261cb7b17d67f 100644
--- a/src/i1905_ubus.c
+++ b/src/i1905_ubus.c
@@ -736,9 +736,9 @@ static const struct blobmsg_policy cmdu_tx_policy[NUM_CMDU_TX_POLICY] = {
 	[CMDU_TX_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING },
 };
 
-int i1905_ubus_cmdu_tx(struct ubus_context *ctx, struct ubus_object *obj,
-		      struct ubus_request_data *req, const char *method,
-		      struct blob_attr *msg)
+int i1905_ubus_iface_cmdu_tx(struct ubus_context *ctx, struct ubus_object *obj,
+			     struct ubus_request_data *req, const char *method,
+			     struct blob_attr *msg)
 {
 	struct i1905_interface_private *ifp =
 			container_of(obj, struct i1905_interface_private, obj);
@@ -821,6 +821,122 @@ int i1905_ubus_cmdu_tx(struct ubus_context *ctx, struct ubus_object *obj,
 	return 0;
 }
 
+int i1905_ubus_cmdu_tx(struct ubus_context *ctx, struct ubus_object *obj,
+		       struct ubus_request_data *req, const char *method,
+		       struct blob_attr *msg)
+{
+	struct i1905_private *p = container_of(obj, struct i1905_private, obj);
+	struct blob_attr *tb[NUM_CMDU_TX_POLICY];
+	char dst_macstr[18] = {0};
+	char src_macstr[18] = {0};
+	struct blob_buf bb = {};
+	uint8_t dst[6] = {0};
+	uint8_t src[6] = {0};
+	char *data_str = NULL;
+	uint8_t *data = NULL;
+	const char *ifname;
+	uint16_t type = 0;
+	uint16_t mid = 0;
+	int data_len = 0;
+	int ret;
+
+
+
+	blobmsg_parse(cmdu_tx_policy, NUM_CMDU_TX_POLICY, tb,
+		      blob_data(msg), blob_len(msg));
+
+	/* cmdu type and destination macaddress are mandatory */
+	if (!tb[CMDU_TX_DST] || !tb[CMDU_TX_TYPE])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+
+	if (tb[CMDU_TX_DST]) {
+		strncpy(dst_macstr, blobmsg_data(tb[CMDU_TX_DST]),
+			sizeof(dst_macstr)-1);
+
+		if (hwaddr_aton(dst_macstr, dst) == NULL)
+			return UBUS_STATUS_INVALID_ARGUMENT;
+
+		if (hwaddr_is_zero(dst))
+			return UBUS_STATUS_INVALID_ARGUMENT;
+	}
+
+	if (tb[CMDU_TX_SRC]) {
+		strncpy(src_macstr, blobmsg_data(tb[CMDU_TX_SRC]),
+			sizeof(src_macstr)-1);
+
+		if (hwaddr_aton(src_macstr, src) == NULL)
+			return UBUS_STATUS_INVALID_ARGUMENT;
+	}
+
+	if (tb[CMDU_TX_TYPE])
+		type = blobmsg_get_u32(tb[CMDU_TX_TYPE]);
+
+
+	if (tb[CMDU_TX_DATA]) {
+		int data_strlen;
+
+		data_strlen = blobmsg_data_len(tb[CMDU_TX_DATA]);
+		data_len = (data_strlen - 1) / 2;
+		data_str = calloc(1, data_strlen * sizeof(char));
+		data = calloc(1, data_len * sizeof(uint8_t));
+
+		if (data_str && data) {
+			strncpy(data_str, blobmsg_data(tb[CMDU_TX_DATA]), data_strlen);
+			strtob(data_str, data_strlen, data);
+		}
+	}
+
+	if (hwaddr_is_mcast(dst) || hwaddr_is_bcast(dst)) {
+		struct i1905_interface_private *ifpriv;
+		struct i1905_interface *iface;
+
+		/* send out through all interfaces */
+		ret = i1905_cmdu_tx(p, dst, src, type, &mid, data, data_len);
+
+		list_for_each_entry(iface, &p->dm.self.iflist, list) {
+			ifpriv = iface->priv;
+			ret &= i1905_cmdu_tx(ifpriv, dst, src, type, &mid, data, data_len);
+			/* if any ret = 0, return success */
+		}
+	} else {
+		uint16_t brport;
+
+		brport = neigh_get_brport(&p->neigh_q, dst);
+		if (brport != 0xffff) {
+			struct i1905_interface_private *ifpriv;
+			struct i1905_interface *iface;
+
+			ifname = i1905_brport_to_ifname(p, brport);
+			iface = i1905_ifname_to_interface(p, ifname);
+			if (iface) {
+				ifpriv = iface->priv;
+				ret = i1905_cmdu_tx(ifpriv, dst, src, type, &mid, data, data_len);
+			}
+		}
+	}
+
+	//ret = i1905_cmdu_tx(ifpriv, dst, src, type, &mid, data, data_len);
+
+	if (data_str)
+		free(data_str);
+
+	if (data)
+		free(data);
+
+
+	/* reply with mid and status of cmdu tx */
+	blob_buf_init(&bb, 0);
+	blobmsg_add_string(&bb, "status", ret == 0 ? "ok" : "fail");
+	if (!ret)
+		blobmsg_add_u32(&bb, "mid", mid);
+
+	ubus_send_reply(ctx, req, bb.head);
+	blob_buf_free(&bb);
+
+	return 0;
+}
+
 #define MAX_IFACE_METHODS	8
 static int add_iface_methods(struct ubus_object *iface_obj)
 {
@@ -845,7 +961,7 @@ do {									\
 			UBUS_METHOD_NOARG("neighbors", i1905_ubus_iface_neighbors));
 
 	UBUS_METHOD_ADD(iface_methods, n_methods,
-			UBUS_METHOD("cmdu", i1905_ubus_cmdu_tx, cmdu_tx_policy));
+			UBUS_METHOD("cmdu", i1905_ubus_iface_cmdu_tx, cmdu_tx_policy));
 
 #undef UBUS_METHOD_ADD
 
@@ -1026,7 +1142,7 @@ int i1905_publish_object(struct i1905_private *p, const char *objname)
 	struct ubus_object_type *obj_type;
 	struct ubus_method *obj_methods;
 	int ret;
-	struct ubus_method m[7] = {
+	struct ubus_method m[8] = {
 		UBUS_METHOD_NOARG("start", i1905_ubus_start),
 		UBUS_METHOD_NOARG("stop", i1905_ubus_stop),
 		UBUS_METHOD_NOARG("status", i1905_ubus_status),
@@ -1034,6 +1150,7 @@ int i1905_publish_object(struct i1905_private *p, const char *objname)
 		UBUS_METHOD_NOARG("neighbors", i1905_ubus_neighbors),
 		UBUS_METHOD("apconfig", i1905_ubus_apconfig, apconfig_policy),
 		UBUS_METHOD_NOARG("refresh", i1905_ubus_refresh),
+		UBUS_METHOD("cmdu", i1905_ubus_cmdu_tx, cmdu_tx_policy),
 	};
 	int num_methods = ARRAY_SIZE(m);
 
diff --git a/src/neigh.c b/src/neigh.c
index 5a6ca160373d11e720ce23c4787b28e034dc0a4d..a39439de23e2ec38329ab1f96bf1a205e9d81923 100644
--- a/src/neigh.c
+++ b/src/neigh.c
@@ -64,10 +64,10 @@ struct neigh_entry *neigh_entry_create(uint8_t *macaddr, uint16_t state,
 	//e->ageing_tmo.tv_usec = roundup(e->ageing_tmo.tv_usec, 1000);
 	e->ageing_tmo.tv_usec = (e->ageing_tmo.tv_usec / 1000) * 1000;
 	e->cookie = cookie;
-	fprintf(stderr,
+	/* fprintf(stderr,
 		"    CREATE entry: " MACFMT " state = 0x%04x timeout = { %u (%lu:%lu) }\n",
 		MAC2STR(macaddr), state, e->ageing_time,
-		e->ageing_tmo.tv_sec, e->ageing_tmo.tv_usec / 1000);
+		e->ageing_tmo.tv_sec, e->ageing_tmo.tv_usec / 1000); */
 
 	return e;
 }
@@ -104,10 +104,10 @@ static void neigh_entry_ageout(struct neigh_queue *st, struct hlist_head *head,
 
 
 	hlist_for_each_entry_safe(e, tmp, head, hlist) {
-		fprintf(stderr, "%s(): Checking for ageout: e->ageout = (%lu.%lu), now = (%lu.%lu)\n",
-				__func__,
-				e->ageing_tmo.tv_sec, e->ageing_tmo.tv_usec,
-				now.tv_sec, now.tv_usec);
+		/* fprintf(stderr, "%s(): Checking for ageout: e->ageout = (%lu.%lu), now = (%lu.%lu)\n",
+			__func__,
+			e->ageing_tmo.tv_sec, e->ageing_tmo.tv_usec,
+			now.tv_sec, now.tv_usec); */
 
 		if (timercmp(&e->ageing_tmo, &now, <=)) {
 			/* schedule a one-time probing for this entry after 1s.
@@ -125,8 +125,8 @@ static void neigh_entry_ageout(struct neigh_queue *st, struct hlist_head *head,
 			} else {
 				st->pending_cnt--;
 				hlist_del(&e->hlist, head);
-				fprintf(stderr, MACFMT " state = 0x%04x aged out!\n",
-					MAC2STR(e->macaddr), e->state);
+				/* fprintf(stderr, MACFMT " state = 0x%04x aged out!\n",
+					MAC2STR(e->macaddr), e->state); */
 				neigh_entry_delete(e);
 			}
 		} else {
@@ -156,15 +156,15 @@ static void neigh_ageing_timer_run(atimer_t *t)
 
 	gettimeofday(&nu, NULL);
 
-	fprintf(stderr, "\n ----Timer now = %lu.%lu  --- cnt = %d---\n",
-		nu.tv_sec, nu.tv_usec, st->pending_cnt);
+	/* fprintf(stderr, "\n ----Timer now = %lu.%lu  --- cnt = %d---\n",
+		nu.tv_sec, nu.tv_usec, st->pending_cnt); */
 
 	//spin_lock(&st->hash_lock);
 	for (i = 0; i < NEIGH_ENTRIES_MAX; i++) {
 		if (hlist_empty(&st->table[i]))
 			continue;
 
-		fprintf(stderr, "i = %d\t", i);
+		//fprintf(stderr, "i = %d\t", i);
 		neigh_entry_ageout(st, &st->table[i], &min_next_tmo);
 	}
 
@@ -257,20 +257,20 @@ struct neigh_entry *neigh_queue_print(void *nq)
 		hlist_for_each_entry(e, &q->table[idx], hlist) {
 			struct ip_address_entry *t;
 
-			fprintf(stderr, "Entry: " MACFMT " wifi = %d | ifname = %s (port = %hu)   state = %02x ipaddrs: ",
+			/* fprintf(stderr, "Entry: " MACFMT " wifi = %d | ifname = %s (port = %hu)   state = %02x ipaddrs: ",
 				MAC2STR(e->macaddr),
 				e->type == NEIGH_TYPE_WIFI ? 1 : 0,
 				e->ifname,
 				e->brport,
-				e->state);
+				e->state); */
 
 			list_for_each_entry(t, &e->iplist, list) {
 				char ipbuf[256] = {0};
 
 				inet_ntop(t->ip.family, &t->ip.addr, ipbuf, sizeof(ipbuf));
-				fprintf(stderr, "%s ", ipbuf);
+				/* fprintf(stderr, "%s ", ipbuf); */
 			}
-			fprintf(stderr, "\n");
+			/* fprintf(stderr, "\n"); */
 		}
 	}
 	pthread_mutex_unlock(&q->qlock);
@@ -364,9 +364,9 @@ int neigh_enqueue(void *nq, uint8_t *macaddr, uint16_t state, char *ifname,
 		struct ip_address_entry *ipaddr;
 		bool ipknown = false;
 
-		fprintf(stderr,
+		/* fprintf(stderr,
 			"Update: macaddr = " MACFMT " state = 0x%04x\n",
-			MAC2STR(macaddr), state);
+			MAC2STR(macaddr), state); */
 
 		pthread_mutex_lock(&q->qlock);
 		e->state = state;
@@ -375,8 +375,8 @@ int neigh_enqueue(void *nq, uint8_t *macaddr, uint16_t state, char *ifname,
 
 		/* reset probing if state becomes reachable */
 		if (e->probing && timer_pending(&e->probing_timer)) {
-			fprintf(stderr, "**** Resetting PROBING timer for " MACFMT "\n",
-				MAC2STR(e->macaddr));
+			/* fprintf(stderr, "**** Resetting PROBING timer for " MACFMT "\n",
+				MAC2STR(e->macaddr)); */
 			timer_del(&e->probing_timer);
 			e->probing = 0;
 		}
@@ -410,11 +410,11 @@ int neigh_enqueue(void *nq, uint8_t *macaddr, uint16_t state, char *ifname,
 				q->next_tmo.tv_usec = e->ageing_tmo.tv_usec;
 
 				timer_set(&q->ageing_timer, e->ageing_time);
-				fprintf(stderr, "Update ageout timer for " MACFMT "========>\n",
-					MAC2STR(macaddr));
+				//fprintf(stderr, "Update ageout timer for " MACFMT "========>\n",
+				//	MAC2STR(macaddr));
 			}
 		} else {
-			fprintf(stderr, "Start ageout timer ========>\n");
+			//fprintf(stderr, "Start ageout timer ========>\n");
 			q->next_tmo.tv_sec = e->ageing_tmo.tv_sec;
 			q->next_tmo.tv_usec = e->ageing_tmo.tv_usec;
 			timer_set(&q->ageing_timer, e->ageing_time);
@@ -431,9 +431,9 @@ int neigh_enqueue(void *nq, uint8_t *macaddr, uint16_t state, char *ifname,
 		hlist_add_head(&e->hlist, &q->table[idx]);
 
 		q->pending_cnt++;
-		fprintf(stderr,
+		/* fprintf(stderr,
 			"    ENQ:        " MACFMT " state = 0x%04x  ifname = %s\n",
-			MAC2STR(macaddr), state, ifname);
+			MAC2STR(macaddr), state, ifname); */
 
 
 		if (timer_pending(&q->ageing_timer)) {
@@ -444,7 +444,7 @@ int neigh_enqueue(void *nq, uint8_t *macaddr, uint16_t state, char *ifname,
 				timer_set(&q->ageing_timer, e->ageing_time);
 			}
 		} else {
-			fprintf(stderr, "Start ageout timer ========>\n");
+			//fprintf(stderr, "Start ageout timer ========>\n");
 			q->next_tmo.tv_sec = e->ageing_tmo.tv_sec;
 			q->next_tmo.tv_usec = e->ageing_tmo.tv_usec;
 			timer_set(&q->ageing_timer, e->ageing_time);
@@ -466,8 +466,8 @@ int neigh_dequeue(void *nq, uint8_t *macaddr, void **cookie)
 
 	e = neigh_lookup(nq, macaddr);
 	if (!e) {
-		fprintf(stderr, "DEQ: Entry " MACFMT " not found!\n",
-			MAC2STR(macaddr));
+		//fprintf(stderr, "DEQ: Entry " MACFMT " not found!\n",
+		//	MAC2STR(macaddr));
 		return -1;
 	}
 
@@ -478,7 +478,7 @@ int neigh_dequeue(void *nq, uint8_t *macaddr, void **cookie)
 	q->pending_cnt--;
 	pthread_mutex_unlock(&q->qlock);
 
-	fprintf(stderr, "DEQ: Entry " MACFMT "\n", MAC2STR(macaddr));
+	//fprintf(stderr, "DEQ: Entry " MACFMT "\n", MAC2STR(macaddr));
 
 
 	/* After returning cookie back to user, we can safely delete the e */
diff --git a/src/tests/mapclient1.c b/src/tests/mapclient1.c
index fdeba2017fb7f9aa08cc80450a0c6816b0c0e5a1..757b1f8e2507b018ea58c58d536ac9e463afe292 100644
--- a/src/tests/mapclient1.c
+++ b/src/tests/mapclient1.c
@@ -42,6 +42,7 @@ uint32_t i1905cmdus_mask = BIT(CMDU_TYPE_TOPOLOGY_DISCOVERY) |
 			   BIT(CMDU_TYPE_TOPOLOGY_RESPONSE) |
 			   BIT(CMDU_TYPE_VENDOR_SPECIFIC) |
 			   BIT(CMDU_TYPE_AP_AUTOCONFIGURATION_SEARCH) |
+			   BIT(CMDU_TYPE_AP_AUTOCONFIGURATION_RESPONSE) |
 			   BIT(CMDU_TYPE_AP_AUTOCONFIGURATION_WSC);
 
 struct mapclient_private {
diff --git a/src/util.h b/src/util.h
index f07f71d96fee53232828f7c58676276fbe8e834b..abfdf8153fe0093c3e6eb64a827e78f4e37601d8 100644
--- a/src/util.h
+++ b/src/util.h
@@ -51,6 +51,8 @@ int if_getmediatype(const char *ifname, enum if_mediatype *mtype);
 
 int if_brportnum(const char *ifname);
 
+int hwaddr_is_mcast(const uint8_t *a);
+
 #ifndef BIT
 #define BIT(x)	(1 << (x))
 #endif