diff --git a/src/cmdu.c b/src/cmdu.c
index 0bf9be037f7ec72f9ab272b7b9c0d21e26d17222..606d18848a7793aebfb29115c7b542692b6dc38e 100644
--- a/src/cmdu.c
+++ b/src/cmdu.c
@@ -261,9 +261,10 @@ int cmdu_put(struct cmdu_buff *c, uint8_t *bytes, int len)
 	return 0;
 }
 
-int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[],
+int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16],
 		    struct tlv_policy *policy, int policy_len)
 {
+	int idx[policy_len];
 	struct tlv *t;
 	int len;
 	int i;
@@ -272,7 +273,10 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[],
 	if (!c)
 		return -1;
 
-	memset(tv, 0, policy_len * sizeof(struct tlv *));
+	for (i = 0; i < policy_len; i++) {
+		memset(tv[i], 0, 16 * sizeof(struct tlv *));
+		idx[i] = 0;
+	}
 	len = c->datalen;
 
 	cmdu_for_each_tlv(t, c->data, len) {
@@ -288,10 +292,12 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[],
 			    tlv_length(t) > policy[i].maxlen)
 				continue;
 
-			if (tv[i])
-				continue;
+			if (tv[i][0]) {
+				if (policy[i].present == TLV_PRESENT_ONE)
+					continue;
+			}
 
-			tv[i] = t;
+			tv[i][idx[i]++] = t;
 		}
 	}
 
diff --git a/src/cmdu.h b/src/cmdu.h
index 67a9558b44101f113282c700ac93475ba69ddd04..5792134fa1bb48feb3d231d07c8686bff7812f52 100644
--- a/src/cmdu.h
+++ b/src/cmdu.h
@@ -45,11 +45,18 @@ struct cmdu_buff {
 	struct list_head list;
 };
 
+enum tlv_presence {
+	TLV_PRESENT_UNDEFINED,
+	TLV_PRESENT_ONE,
+	TLV_PRESENT_MORE,
+	TLV_PRESENT_NUM,
+};
 
 struct tlv_policy {
 	uint8_t type;
 	uint16_t minlen;
 	uint16_t maxlen;
+	enum tlv_presence present;
 };
 
 struct tlv {
@@ -80,7 +87,7 @@ uint16_t cmdu_get_next_mid(void);
 int cmdu_validate(struct cmdu_buff *c, int max_tlvtype,
 		       struct tlv_policy *policy);
 
-int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[],
+int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16],
 		    struct tlv_policy *policy, int policy_len);
 
 
diff --git a/src/cmdu_input.c b/src/cmdu_input.c
index 035c9f3a44dcec6d7e255742c942eca97583c212..208d39553f07da1debf224c6d9da795948e0b4b9 100644
--- a/src/cmdu_input.c
+++ b/src/cmdu_input.c
@@ -45,12 +45,287 @@
 #include "lldp_tlvs.h"
 
 
+#define CMDU_TYPE_1905_START	0x0001
+#define CMDU_TYPE_1905_END	0x0009
+
+
+int i1905_handle_topology_discovery(struct i1905_interface_private *pif,
+				    struct cmdu_buff *rxf)
+{
+	struct tlv_policy a_policy[] = {
+		[0] = { .type = TLV_TYPE_AL_MAC_ADDRESS_TYPE, .present = TLV_PRESENT_ONE },
+		[1] = { .type = TLV_TYPE_MAC_ADDRESS_TYPE, .present = TLV_PRESENT_ONE },
+	};
+	struct tlv *tv[2][16];
+	uint8_t aladdr_origin[6] = {0};
+	uint8_t macaddr_origin[6] = {0};
+	int ret;
+
+
+	cmdu_parse_tlvs(rxf, tv, a_policy, 2);
+
+	if (tv[0][0])
+		memcpy(aladdr_origin, tv[0][0]->data, tlv_length(tv[0][0]));
+
+	if (tv[1][0])
+		memcpy(macaddr_origin, tv[1][0]->data, tlv_length(tv[1][0]));
+
+
+	if (hwaddr_is_zero(macaddr_origin)) {
+		fprintf(stderr, "%s: Discard topo discovery from src = 0!\n",
+			__func__);
+
+		return -1;
+	}
+
+	ret = i1905_dm_neighour_update(i1905_interface_priv(pif),
+					   aladdr_origin, macaddr_origin);
+	if (ret) {
+		fprintf(stderr, "%s: Error updating DM for neighbor " MACFMT"\n",
+			__func__, MAC2STR(macaddr_origin));
+
+		return -1;
+	}
+
+	return 0;
+}
+
+int i1905_handle_topology_notification(struct i1905_interface_private *pif,
+				       struct cmdu_buff *rxf)
+{
+	struct tlv_policy a_policy[] = {
+		[0] = { .type = TLV_TYPE_AL_MAC_ADDRESS_TYPE, .present = TLV_PRESENT_ONE },
+	};
+	struct tlv *tv[1][16];
+	uint8_t aladdr_origin[6] = {0};
+	int ret;
+
+
+	cmdu_parse_tlvs(rxf, tv, a_policy, 1);
+
+	if (tv[0][0])
+		memcpy(aladdr_origin, tv[0][0]->data, tlv_length(tv[0][0]));
+
+
+	if (hwaddr_is_zero(aladdr_origin)) {
+		fprintf(stderr, "%s: Discard topo notification from aladdr = 0!\n",
+			__func__);
+
+		return -1;
+	}
+
+	ret = i1905_dm_neighour_update(i1905_interface_priv(pif),
+					   aladdr_origin, NULL);
+	if (ret) {
+		fprintf(stderr, "%s: Error updating DM for neighbor " MACFMT"\n",
+			__func__, MAC2STR(aladdr_origin));
+
+		return -1;
+	}
+
+	return 0;
+}
+
+int i1905_handle_topology_query(struct i1905_interface_private *pif,
+				struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_topology_response(struct i1905_interface_private *pif,
+				   struct cmdu_buff *rxf)
+{
+	struct tlv_policy a_policy[] = {
+		[0] = { .type = TLV_TYPE_DEVICE_INFORMATION_TYPE, .present = TLV_PRESENT_ONE },
+		[1] = { .type = TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES, .present = TLV_PRESENT_MORE },
+		[2] = { .type = TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST, .present = TLV_PRESENT_MORE },
+		[3] = { .type = TLV_TYPE_NEIGHBOR_DEVICE_LIST, .present = TLV_PRESENT_MORE },
+		[4] = { .type = TLV_TYPE_POWER_OFF_INTERFACE, .present = TLV_PRESENT_MORE},
+		[5] = { .type = TLV_TYPE_L2_NEIGHBOR_DEVICE, .present = TLV_PRESENT_MORE },
+	};
+	struct tlv *tv[6][16];
+	uint8_t aladdr_origin[6] = {0};
+	uint8_t macaddr_origin[6] = {0};
+	int ret;
+
+
+	cmdu_parse_tlvs(rxf, tv, a_policy, 6);
+
+
+#if 0
+	if (hwaddr_is_zero(macaddr_origin)) {
+		fprintf(stderr, "%s: Discard topo discovery from src = 0!\n",
+			__func__);
+
+		return -1;
+	}
+
+	ret = i1905_dm_neighour_update(i1905_interface_priv(pif),
+					   aladdr_origin, macaddr_origin);
+	if (ret) {
+		fprintf(stderr, "%s: Error updating DM for neighbor " MACFMT"\n",
+			__func__, MAC2STR(macaddr_origin));
+
+		return -1;
+	}
+#endif
+
+
+	return 0;
+}
+
+int i1905_handle_vendor_request(struct i1905_interface_private *pif,
+				struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_link_metric_query(struct i1905_interface_private *pif,
+				   struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_link_metric_response(struct i1905_interface_private *pif,
+				      struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_ap_autoconfig_search(struct i1905_interface_private *pif,
+				      struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_ap_autoconfig_response(struct i1905_interface_private *pif,
+				        struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_ap_autoconfig_renew(struct i1905_interface_private *pif,
+				     struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_ap_autoconfig_wsc(struct i1905_interface_private *pif,
+				   struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_pbc_notification(struct i1905_interface_private *pif,
+				  struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_pbc_join_notification(struct i1905_interface_private *pif,
+				   struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_higherlayer_query(struct i1905_interface_private *pif,
+				   struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_higherlayer_response(struct i1905_interface_private *pif,
+				      struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_interface_power_request(struct i1905_interface_private *pif,
+					 struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_interface_power_response(struct i1905_interface_private *pif,
+					  struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_generic_phy_query(struct i1905_interface_private *pif,
+				   struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+int i1905_handle_generic_phy_response(struct i1905_interface_private *pif,
+				      struct cmdu_buff *rxf)
+{
+	//TODO
+	return 0;
+}
+
+
+typedef int (*cmdu_handler_t)(struct i1905_interface_private *ifp,
+			      struct cmdu_buff *rxf);
+
+static const cmdu_handler_t i1905ftable[] = {
+	[0x00] = i1905_handle_topology_discovery,
+	[0x01] = i1905_handle_topology_notification,
+	[0x02] = i1905_handle_topology_query,
+	[0x03] = i1905_handle_topology_response,
+	[0x04] = i1905_handle_vendor_request,
+	[0x05] = i1905_handle_link_metric_query,
+	[0x06] = i1905_handle_link_metric_response,
+	[0x07] = i1905_handle_ap_autoconfig_search,
+	[0x08] = i1905_handle_ap_autoconfig_response,
+	[0x09] = i1905_handle_ap_autoconfig_wsc,
+	[0x0a] = i1905_handle_ap_autoconfig_renew,
+	[0x0b] = i1905_handle_pbc_notification,
+	[0x0c] = i1905_handle_pbc_join_notification,
+	[0x0d] = i1905_handle_higherlayer_query,
+	[0x0e] = i1905_handle_higherlayer_response,
+	[0x0f] = i1905_handle_interface_power_request,
+	[0x10] = i1905_handle_interface_power_response,
+	[0x11] = i1905_handle_generic_phy_query,
+	[0x11] = i1905_handle_generic_phy_response,
+};
+
+
 int i1905_process_cmdu(struct i1905_interface_private *pif, struct cmdu_buff *rxf)
 {
+	uint16_t type;
+	int ret;
+
+	if (!rxf->cdata)
+		return -1;
+
+	// TODO: discard duplicates
+
+	type = buf_get_be16(rxf->cdata->hdr.type);
+
+	if (i1905ftable[type]) {
+		ret = i1905ftable[type](pif, rxf);
+	}
 
 	fprintf(stderr, "%s: ----->\n", __func__);
 
-	return 0;
+	return ret;
 }
 
 
diff --git a/src/i1905.h b/src/i1905.h
index 6fdab0da5a4245582e8412cc6acf4d27b9c37ace..d12e372fbf608a12053a7cc934c73a675ffb8eb0 100644
--- a/src/i1905.h
+++ b/src/i1905.h
@@ -71,6 +71,7 @@ extern struct i1905_dm *i1905_dm_get();
 extern int i1905_dm_init(struct i1905_dm *dm);
 extern int i1905_dm_free(struct i1905_dm *dm);
 
-
+extern int i1905_dm_neighour_update(struct i1905_interface *iface,
+				    uint8_t *aladdr, uint8_t *macaddr);
 
 #endif /* I1905_H */
diff --git a/src/i1905_dm.c b/src/i1905_dm.c
index 1b6e20c6fbb68b96f3da7de61fbd281ee631ae5b..b8951e7c06d6a6f52adcb9be60977ad17f039e51 100644
--- a/src/i1905_dm.c
+++ b/src/i1905_dm.c
@@ -30,6 +30,19 @@
 
 
 
+int i1905_dm_neighour_update(struct i1905_interface *iface, uint8_t *aladdr,
+			     uint8_t *macaddr)
+{
+
+	//TODO: lookup aladdr/macaddr in DM
+	//	if not available, add to DM
+	//	if available, update tsp
+	//
+	//	if tsp_lastupdated = 0 or > 10 secs, send topo query
+
+	return 0;
+}
+
 int i1905_dm_init(struct i1905_dm *dm)
 {