diff --git a/src/cmdu.c b/src/cmdu.c
index 114313d11b97450b9e4453fc36359d06236dfc92..fa5aa37b8040e6b12e729f0e51d11aae2c0faf58 100644
--- a/src/cmdu.c
+++ b/src/cmdu.c
@@ -172,6 +172,37 @@ static size_t tlv_minsize(struct tlv *t)
 	return 0;
 }
 
+__thread int ieee1905_errval;
+
+int *ieee1905_get_errval(void)
+{
+	return &ieee1905_errval;
+}
+
+#define ieee1905_set_error(v)	(ieee1905_errval = (v))
+
+static const char *ieee1905_errlist[IEEE1905_ERROR_MAXNUM] = {
+	"Ok",
+	[CMDU_STATUS_ERR_TLV_MALFORMED] = "TLV is malformed",
+	[CMDU_STATUS_ERR_TLV_NUM_LESS] = "Number of TLVs less than required",
+	[CMDU_STATUS_ERR_TLV_NUM_MORE] = "Number of TLVs more than required",
+	[CMDU_STATUS_ERR_TLV_NO_EOM] = "EOM TLV is not present",
+	[CMDU_STATUS_ERR_TLV_RESIDUE_DATA] = "Stray non-zero bytes after EOM",
+	[CMDU_STATUS_ERR_TLV_LEN_INSUFFICIENT] = "TLV length insufficient",
+	[CMDU_STATUS_ERR_TLV_LEN_OVERFLOW] = "TLV length points to beyond CMDU",
+	[CMDU_STATUS_ERR_MISC] = "Misc cmdu error",
+};
+
+const char *ieee1905_strerror(int err)
+{
+	int last_err = err;
+
+	if (last_err >= 0 && last_err <= IEEE1905_ERROR_LAST)
+		return ieee1905_errlist[last_err];
+
+	return "";
+}
+
 void cmdu_set_type(struct cmdu_buff *c, uint16_t type)
 {
 	if (c && c->cdata)
@@ -691,6 +722,7 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16],
 	int i;
 
 
+	ieee1905_set_error(CMDU_STATUS_OK);
 	if (!c || !c->data || !c->datalen)
 		return -1;
 
@@ -705,24 +737,32 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16],
 			if (policy[i].type != t->type)
 				continue;
 
-			if (policy[i].len && tlv_length(t) != policy[i].len)
+			if (policy[i].len && tlv_length(t) != policy[i].len) {
+				ieee1905_set_error(CMDU_STATUS_ERR_TLV_MALFORMED);
 				return -1;
+			}
 
 			if (policy[i].minlen > 0 &&
-			    tlv_length(t) < policy[i].minlen)
-				continue;
+			    tlv_length(t) < policy[i].minlen) {
+				ieee1905_set_error(CMDU_STATUS_ERR_TLV_LEN_INSUFFICIENT);
+				return -1;
+			}
 
 			if (policy[i].maxlen > 0 &&
-			    tlv_length(t) > policy[i].maxlen)
-				continue;
+			    tlv_length(t) > policy[i].maxlen) {
+				ieee1905_set_error(CMDU_STATUS_ERR_TLV_LEN_OVERFLOW);
+				return -1;
+			}
 
 			if (tlv_length(t) < tlv_minsize(t))
 				continue;
 
 			if (tv[i][0]) {
 				if (policy[i].present == TLV_PRESENT_ONE ||
-				    policy[i].present == TLV_PRESENT_OPTIONAL_ONE)
+				    policy[i].present == TLV_PRESENT_OPTIONAL_ONE) {
+					ieee1905_set_error(CMDU_STATUS_ERR_TLV_NUM_MORE);
 					return -1;
+				}
 			}
 
 			tv[i][idx[i]++] = t;
@@ -734,16 +774,20 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16],
 		int k = 0;
 
 		while (k < len) {
-			if (c->data[c->datalen - len + k++] != 0)
+			if (c->data[c->datalen - len + k++] != 0) {
+				ieee1905_set_error(CMDU_STATUS_ERR_TLV_RESIDUE_DATA);
 				return -1;
+			}
 		}
 	}
 
 	/* strictly check against tlv policies */
 	for (i = 0; i < policy_len; i++) {
 		if ((policy[i].present == TLV_PRESENT_ONE ||
-		    policy[i].present == TLV_PRESENT_MORE) && !tv[i][0])
+		    policy[i].present == TLV_PRESENT_MORE) && !tv[i][0]) {
+			ieee1905_set_error(CMDU_STATUS_ERR_TLV_NUM_LESS);
 			return -1;
+		}
 	}
 
 	return 0;
diff --git a/src/cmdu.h b/src/cmdu.h
index 9dac85265d353baa1dc155a21ab717255ba87acb..9c970586122b098c069356fc1a9355a76ee799d4 100644
--- a/src/cmdu.h
+++ b/src/cmdu.h
@@ -241,6 +241,27 @@ int is_cmdu_type_response(uint16_t type);
 /** Function to check if a CMDU type must include atleast one TLV */
 int is_cmdu_tlv_required(uint16_t type);
 
+/** Parsing status of received CMDU */
+enum CMDU_STATUS {
+	CMDU_STATUS_OK,
+	CMDU_STATUS_ERR_TLV_MALFORMED,
+	CMDU_STATUS_ERR_TLV_NUM_LESS,	/* mandatory tlv(s) absent */
+	CMDU_STATUS_ERR_TLV_NUM_MORE,
+	CMDU_STATUS_ERR_TLV_NO_EOM,
+	CMDU_STATUS_ERR_TLV_RESIDUE_DATA,
+	CMDU_STATUS_ERR_TLV_LEN_INSUFFICIENT,
+	CMDU_STATUS_ERR_TLV_LEN_OVERFLOW,
+	CMDU_STATUS_ERR_MISC,
+
+	IEEE1905_ERROR_MAXNUM,
+	IEEE1905_ERROR_LAST = IEEE1905_ERROR_MAXNUM - 1,
+};
+
+
+extern int *ieee1905_get_errval(void);
+#define ieee1905_error	(*ieee1905_get_errval())
+
+const char *ieee1905_strerror(int err);
 
 /** Parse a CMDU to get list of the TLVs present in it
  *