From cab15b0b76602f5565f125b15da90ef27a149ca3 Mon Sep 17 00:00:00 2001
From: Kamil Zulewski <kamil.zulewski@iopsys.eu>
Date: Mon, 2 Jan 2023 14:59:37 +0000
Subject: [PATCH] Enhanced error handling for map_cmdu_parse_tlvs and
 cmdu_parse_tlvs

---
 src/cmdu.c                      |  9 ++++++---
 src/cmdu.h                      |  1 +
 src/extensions/map/map_module.h | 30 ++++++++++++++++++++++++++++++
 src/extensions/map/maputil.c    | 32 ++++++++++++++++++++++++++++++++
 src/extensions/map/policy.c     | 31 +++++++++++++++++++++++++------
 5 files changed, 94 insertions(+), 9 deletions(-)

diff --git a/src/cmdu.c b/src/cmdu.c
index fa5aa37b..4c17be26 100644
--- a/src/cmdu.c
+++ b/src/cmdu.c
@@ -182,7 +182,7 @@ int *ieee1905_get_errval(void)
 #define ieee1905_set_error(v)	(ieee1905_errval = (v))
 
 static const char *ieee1905_errlist[IEEE1905_ERROR_MAXNUM] = {
-	"Ok",
+	[CMDU_STATUS_OK] = "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",
@@ -190,6 +190,7 @@ static const char *ieee1905_errlist[IEEE1905_ERROR_MAXNUM] = {
 	[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_CMDU_MALFORMED] = "CMDU input structure malformed",
 	[CMDU_STATUS_ERR_MISC] = "Misc cmdu error",
 };
 
@@ -197,7 +198,7 @@ const char *ieee1905_strerror(int err)
 {
 	int last_err = err;
 
-	if (last_err >= 0 && last_err <= IEEE1905_ERROR_LAST)
+	if (last_err >= 0 && last_err <= IEEE1905_ERROR_LAST && ieee1905_errlist[last_err])
 		return ieee1905_errlist[last_err];
 
 	return "";
@@ -723,8 +724,10 @@ int cmdu_parse_tlvs(struct cmdu_buff *c, struct tlv *tv[][16],
 
 
 	ieee1905_set_error(CMDU_STATUS_OK);
-	if (!c || !c->data || !c->datalen)
+	if (!c || !c->data || !c->datalen) {
+		ieee1905_set_error(CMDU_STATUS_ERR_CMDU_MALFORMED);
 		return -1;
+	}
 
 	for (i = 0; i < policy_len; i++) {
 		memset(tv[i], 0, 16 * sizeof(struct tlv *));
diff --git a/src/cmdu.h b/src/cmdu.h
index 6c34fa3a..34c17191 100644
--- a/src/cmdu.h
+++ b/src/cmdu.h
@@ -258,6 +258,7 @@ enum CMDU_STATUS {
 	CMDU_STATUS_ERR_TLV_RESIDUE_DATA,
 	CMDU_STATUS_ERR_TLV_LEN_INSUFFICIENT,
 	CMDU_STATUS_ERR_TLV_LEN_OVERFLOW,
+	CMDU_STATUS_ERR_CMDU_MALFORMED,
 	CMDU_STATUS_ERR_MISC,
 
 	IEEE1905_ERROR_MAXNUM,
diff --git a/src/extensions/map/map_module.h b/src/extensions/map/map_module.h
index 5cf46bdc..cc0a4b30 100644
--- a/src/extensions/map/map_module.h
+++ b/src/extensions/map/map_module.h
@@ -10,6 +10,7 @@
 #ifndef MAP_MODULE_H
 #define MAP_MODULE_H
 
+#include <cmdu.h>
 
 typedef uint32_t mapmodule_object_t;
 typedef uint8_t mapmodule_cmdu_mask_t[16];
@@ -40,6 +41,35 @@ int map_subscribe(void *bus, void *publisher,
 
 int map_unsubscribe(void *bus, void *subscriber);
 
+enum MAP_STATUS {
+	/* Existing ieee1905 error codes start at 0 offset */
+	MAP_STATUS_OK = CMDU_STATUS_OK,
+	MAP_STATUS_ERR_TLV_MALFORMED = CMDU_STATUS_ERR_TLV_MALFORMED,
+	MAP_STATUS_ERR_TLV_NUM_LESS = CMDU_STATUS_ERR_TLV_NUM_LESS,
+	MAP_STATUS_ERR_TLV_NUM_MORE = CMDU_STATUS_ERR_TLV_NUM_MORE,
+	MAP_STATUS_ERR_TLV_NO_EOM = CMDU_STATUS_ERR_TLV_NO_EOM,
+	MAP_STATUS_ERR_TLV_RESIDUE_DATA = CMDU_STATUS_ERR_TLV_RESIDUE_DATA,
+	MAP_STATUS_ERR_TLV_LEN_INSUFFICIENT = CMDU_STATUS_ERR_TLV_LEN_INSUFFICIENT,
+	MAP_STATUS_ERR_TLV_LEN_OVERFLOW = CMDU_STATUS_ERR_TLV_LEN_OVERFLOW,
+	MAP_STATUS_ERR_CMDU_MALFORMED = CMDU_STATUS_ERR_CMDU_MALFORMED,
+	MAP_STATUS_ERR_MISC = CMDU_STATUS_ERR_MISC,
+
+	/* MAP plugin specific error codes start at 10000 offset */
+	MAP_STATUS_ERR_FIRST = 10000,
+
+	MAP_STATUS_ERR_CMDU_TYPE_NOT_SUPPORTED = MAP_STATUS_ERR_FIRST,
+	MAP_STATUS_ERR_MAP_PROFILE_NOT_SUPPORTED,
+	MAP_STATUS_ERR_MAP_POLICY_NOT_FOUND,
+	MAP_STATUS_ERR_TLVS_OUTPUT_ARRAY_INSUFFICIENT,
+
+	MAP_STATUS_ERR_AFTER_LAST
+};
+
+int *map_get_errval(void);
+#define map_error (*map_get_errval())
+
+const char *map_strerror(int err);
+
 int map_cmdu_parse_tlvs(struct cmdu_buff *cmdu, struct tlv *tv[][16], int num_tvi, int revision);
 
 #endif /* MAP_MODULE_H */
diff --git a/src/extensions/map/maputil.c b/src/extensions/map/maputil.c
index 7f612f28..9528380f 100644
--- a/src/extensions/map/maputil.c
+++ b/src/extensions/map/maputil.c
@@ -25,6 +25,38 @@
 #include "easymesh.h"
 #include "map_module.h"
 
+static __thread int map_errval;
+
+int *map_get_errval(void)
+{
+	return &map_errval;
+}
+
+static const char *map_status_to_string(enum MAP_STATUS err)
+{
+	switch (err) {
+	case MAP_STATUS_ERR_CMDU_TYPE_NOT_SUPPORTED:
+		return "MAP: CMDU type not supported";
+	case MAP_STATUS_ERR_MAP_PROFILE_NOT_SUPPORTED:
+		return "MAP: Multi-AP Profile not supported";
+	case MAP_STATUS_ERR_MAP_POLICY_NOT_FOUND:
+		return "MAP: Policy required to parse CMDU not found";
+	case MAP_STATUS_ERR_TLVS_OUTPUT_ARRAY_INSUFFICIENT:
+		return "MAP: TLVs output array insufficient";
+
+	default:
+		return "MAP: error description not provided";
+	}
+}
+
+const char *map_strerror(int err)
+{
+	if (err >= MAP_STATUS_ERR_FIRST && err < MAP_STATUS_ERR_AFTER_LAST)
+		return map_status_to_string(err);
+
+	return ieee1905_strerror(err);
+}
+
 #define cmdu_mask_setbit(m, f)						\
 do {									\
 	if (f >= 0x8000)						\
diff --git a/src/extensions/map/policy.c b/src/extensions/map/policy.c
index 40373b6a..0ce80516 100644
--- a/src/extensions/map/policy.c
+++ b/src/extensions/map/policy.c
@@ -40,9 +40,12 @@ int map_cmdu_parse_tlvs(struct cmdu_buff *cmdu, struct tlv *tv[][16], int num_tv
 	int idx = 0;
 	int i;
 
+	map_error = MAP_STATUS_OK;
 
-	if (!cmdu)
+	if (!cmdu || !cmdu->cdata) {
+		map_error =  MAP_STATUS_ERR_CMDU_MALFORMED;
 		return -1;
+	}
 
 	type = cmdu_get_type(cmdu);
 
@@ -50,36 +53,47 @@ int map_cmdu_parse_tlvs(struct cmdu_buff *cmdu, struct tlv *tv[][16], int num_tv
 		idx = type;
 	} else if (type >= CMDU_TYPE_MAP_START && type <= CMDU_TYPE_MAP_END) {
 		idx = type - CMDU_TYPE_MAP_START + CMDU_TYPE_1905_END + 1;
-	} else
+	} else {
+		map_error = MAP_STATUS_ERR_CMDU_TYPE_NOT_SUPPORTED;
 		return -1;
+	}
 
 	switch (revision) {
 	case 2:
-		if (idx > ARRAY_SIZE(easymesh_policy_r2))
+		if (idx > ARRAY_SIZE(easymesh_policy_r2)) {
+			map_error = MAP_STATUS_ERR_MAP_POLICY_NOT_FOUND;
 			return -1;
+		}
 
 		pol = &easymesh_policy_r2[idx];
 		break;
 #if (EASYMESH_VERSION > 2)
 	case 4:
-		if (idx > ARRAY_SIZE(easymesh_policy_r4))
+		if (idx > ARRAY_SIZE(easymesh_policy_r4)) {
+			map_error = MAP_STATUS_ERR_MAP_POLICY_NOT_FOUND;
 			return -1;
+		}
 
 		pol = &easymesh_policy_r4[idx];
 		break;
 #endif
 	default:
+
+		map_error = MAP_STATUS_ERR_MAP_PROFILE_NOT_SUPPORTED;
 		return -1;
 	}
 
-	if (pol->pol == NULL)
+	if (pol->pol == NULL) {
+		map_error = MAP_STATUS_ERR_MAP_POLICY_NOT_FOUND;
 		return -1;
+	}
 
 	if (pol->num == 0)
 		return 0;
 
 	if (num_tv < pol->num) {
 		fprintf(stderr, "%s: minimum %zu tv needed!\n", __func__, pol->num);
+		map_error = MAP_STATUS_ERR_TLVS_OUTPUT_ARRAY_INSUFFICIENT;
 		return -1;
 	}
 
@@ -87,5 +101,10 @@ int map_cmdu_parse_tlvs(struct cmdu_buff *cmdu, struct tlv *tv[][16], int num_tv
 	for (i = 0; i < num_tv; i++)
 		memset(tv[i], 0, 16 * sizeof(struct tlv *));
 
-	return cmdu_parse_tlvs(cmdu, tv, pol->pol, pol->num);
+	if (cmdu_parse_tlvs(cmdu, tv, pol->pol, pol->num)) {
+		map_error = ieee1905_error;
+		return -1;
+	}
+
+	return 0;
 }
-- 
GitLab