From acf03d97ada0b3875b3e17bc296554d96e322fc8 Mon Sep 17 00:00:00 2001
From: sverma <saurabh.verma@iopsys.eu>
Date: Wed, 16 Feb 2022 13:11:54 +0530
Subject: [PATCH] added validation for channal_scan_report CMDU

---
 src/Makefile        |   1 +
 src/cmdu_validate.c | 112 ++++++++++++++++++++++++++++++++++++++++++++
 src/cmdu_validate.h |  10 ++++
 src/cntlr_map.c     |  45 +++++++-----------
 4 files changed, 139 insertions(+), 29 deletions(-)
 create mode 100644 src/cmdu_validate.c
 create mode 100644 src/cmdu_validate.h

diff --git a/src/Makefile b/src/Makefile
index 92b8d0b3..a94b659d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -15,6 +15,7 @@ OBJS = \
 	cntlr_cmdu.o \
 	cntlr_acs.o \
 	cntlr_map_debug.o \
+	cmdu_validate.o \
 	config.o \
 	main.o
 
diff --git a/src/cmdu_validate.c b/src/cmdu_validate.c
new file mode 100644
index 00000000..868c0a6d
--- /dev/null
+++ b/src/cmdu_validate.c
@@ -0,0 +1,112 @@
+
+#include <map2.h>
+#include <cmdu.h>
+#include "cmdu_validate.h"
+
+
+bool validate_channel_scan_report(struct cmdu_buff *cmdu, struct tlv *tv_tsp[][16],
+		struct tlv *tv_scan[], int *num)
+{
+	int i, j;
+	struct tlv_policy d_policy_tsp[] = {
+		[0] = {
+			.type = MAP_TLV_TIMESTAMP,
+			.present = TLV_PRESENT_ONE,
+			.minlen = 1
+		}
+	};
+	struct tlv_policy d_policy_scan[] = {
+		[0] = {
+			.type = MAP_TLV_CHANNEL_SCAN_RES,
+			.present = TLV_PRESENT_MORE,
+			.minlen = 9
+		}
+	};
+
+	cmdu_parse_tlvs(cmdu, tv_tsp, d_policy_tsp, 1);
+	cmdu_parse_tlv_single(cmdu, tv_scan, d_policy_scan, num);
+
+	if (tv_tsp[0][0]) {
+		int offset = 0;
+		int tsp_len = 0;
+		uint8_t *t = (uint8_t *)tv_tsp[0][0]->data;
+		uint16_t tlv_len = tlv_length(tv_tsp[0][0]);
+
+		tsp_len = t[offset];
+		offset += 1;
+		if (offset+tsp_len > tlv_len)
+			return false;
+	}
+
+	for (i = 0; i < *num; i++) {
+		int offset = 0;
+		uint8_t status = 0x00;
+		uint8_t *t = (uint8_t *)tv_scan[i]->data;
+		uint16_t tlv_len = tlv_length(tv_scan[i]);
+
+		offset += 6;	/* radio id */
+		offset += 1;	/* opclass */
+		offset += 1;	/* channel */
+		status = t[offset];
+		offset += 1;	/* status */
+
+		if (status == CH_SCAN_STATUS_SUCCESS) {
+			int ts_len = 0;
+			uint16_t num_nb = 0;
+
+			if (offset+1 > tlv_len)
+				return false;
+
+			ts_len = t[offset];
+			offset += 1;	/* timestamp len */
+			if (offset+ts_len+4 > tlv_len)
+				return false;
+
+			offset += ts_len;	/* timestamp */
+			offset += 1;		/* utilization */
+			offset += 1;		/* noise */
+			num_nb = BUF_GET_BE16(t[offset]);
+			offset += 2;		/* num neightbors */
+
+			for (j = 0; j < num_nb; j++) {
+				int ssid_len = 0;
+				int bw_len = 0;
+				uint8_t info = 0x00;
+
+				if (offset+7 > tlv_len)
+					return false;
+
+				offset += 6;	/* bssid */
+				ssid_len = t[offset];
+				offset += 1;	/* ssid len */
+				if (offset+ssid_len+2 > tlv_len)
+					return false;
+
+				offset += ssid_len;	/* ssid */
+				offset += 1;		/* rcpi */
+				bw_len = t[offset];
+				offset += 1;		/* bw len */
+				if (offset+bw_len+1 > tlv_len)
+					return false;
+
+				offset += bw_len;	/* bandwidth */
+				info = t[offset];
+				offset += 1;		/* info */
+
+				if (info & CH_SCAN_RESULT_BSSLOAD_PRESENT) {
+					if (offset+3 > tlv_len)
+						return false;
+
+					offset += 1;	/* channel utilization */
+					offset += 2;	/* station count */
+				}
+			}
+
+			if (offset+5 > tlv_len)
+				return false;
+		}
+	}
+
+	return true;
+}
+
diff --git a/src/cmdu_validate.h b/src/cmdu_validate.h
new file mode 100644
index 00000000..3c029a12
--- /dev/null
+++ b/src/cmdu_validate.h
@@ -0,0 +1,10 @@
+
+
+#ifndef CMDU_VALIDATE
+#define CMDU_VALIDATE
+
+bool validate_channel_scan_report(struct cmdu_buff *cmdu, struct tlv *tv_tsp[][16],
+		struct tlv *tv_scan[], int *num);
+
+
+#endif	// CMDU_VALIDATE
diff --git a/src/cntlr_map.c b/src/cntlr_map.c
index cb85f26d..c0716218 100644
--- a/src/cntlr_map.c
+++ b/src/cntlr_map.c
@@ -48,6 +48,7 @@
 #include "cntlr_map_debug.h"
 #include "cntlr_cmdu.h"
 #include "cntlr_tlv.h"
+#include "cmdu_validate.h"
 
 #define TIMESTAMP_MAX_LEN 256
 
@@ -2039,24 +2040,14 @@ int handle_channel_scan_report(void *cntlr, struct cmdu_buff *cmdu)
 	uint8_t *tv_data;
 	struct tlv *tv_tsp[1][16];
 	struct tlv *tv_scan[256];
-	struct tlv_policy d_policy_tsp[] = {
-		[0] = {
-			.type = MAP_TLV_TIMESTAMP,
-			.present = TLV_PRESENT_ONE
-		}
-	};
-	struct tlv_policy d_policy_scan[] = {
-		[0] = {
-			.type = MAP_TLV_CHANNEL_SCAN_RES,
-			.present = TLV_PRESENT_MORE
-		}
-	};
 	char timestamp[TIMESTAMP_MAX_LEN] = {0};
 	struct tlv_timestamp *p;
 
 
-	cmdu_parse_tlvs(cmdu, tv_tsp, d_policy_tsp, 1);
-	cmdu_parse_tlv_single(cmdu, tv_scan, d_policy_scan, &num);
+	if (!validate_channel_scan_report(cmdu, tv_tsp, tv_scan, &num)) {
+		dbg("cmdu validation: [CHANNEL_SCAN_REPORT] failed\n");
+		return -1;
+	}
 
 	if (!tv_tsp[0][0]) {
 		dbg("No TIMESTAMP_TLV received!\n");
@@ -2067,10 +2058,6 @@ int handle_channel_scan_report(void *cntlr, struct cmdu_buff *cmdu)
 		dbg("No RESULT_TLV received!\n");
 		return -1;
 	}
-	if (tv_tsp[0][0]->type != MAP_TLV_TIMESTAMP) {
-		dbg("Wrong received TLV type!\n");
-		return -1;
-	}
 
 	dbg("\nTLV type: MAP_TLV_TIMESTAMP\n");
 	tv_data = (uint8_t *)tv_tsp[0][0]->data;
@@ -2089,11 +2076,6 @@ int handle_channel_scan_report(void *cntlr, struct cmdu_buff *cmdu)
 	dbg("\n");
 
 	for (i = 0; i < num; i++) {
-		if (tv_scan[i]->type != MAP_TLV_CHANNEL_SCAN_RES) {
-			dbg("Wrong received TLV type!\n");
-			return -1;
-		}
-
 		dbg("\nTLV type: MAP_TLV_CHANNEL_SCAN_RES\n");
 		tv_data = (uint8_t *)tv_scan[i]->data;
 		struct tlv_channel_scan_result *p1 = (struct tlv_channel_scan_result *)tv_data;
@@ -2123,6 +2105,8 @@ int handle_channel_scan_report(void *cntlr, struct cmdu_buff *cmdu)
 			dbg("\tnum_neighbor: %d\n", num_neightbor);
 			offset += 2;
 			for (j = 0; j < num_neightbor; j++) {
+				uint8_t info = 0x00;
+
 				dbg("\n\t\tbssid: " MACFMT "\n", MAC2STR(&tv_data[offset]));
 				offset += 6;
 				ssid_len = tv_data[offset++];
@@ -2137,13 +2121,16 @@ int handle_channel_scan_report(void *cntlr, struct cmdu_buff *cmdu)
 				dbg("\t\tlen: %d\n", bw_len);
 				dbg("\t\tbwstr: %d\n", atoi((char *)&tv_data[offset]));
 				offset += bw_len;
-				dbg("\t\tinfo: %d\n", tv_data[offset]);
-				offset++;
-				dbg("\t\tch_util: %d\n", tv_data[offset]);
-				offset++;
-				dbg("\t\tsta_count: %d\n", tv_data[offset]);
+				info = tv_data[offset];
+				dbg("\t\tinfo: %d\n", offset);
 				offset++;
-				offset++; /* sta_count is 2 byte*/
+
+				if (info & CH_SCAN_RESULT_BSSLOAD_PRESENT) {
+					dbg("\t\t\tch_util: %d\n", tv_data[offset]);
+					offset++;
+					dbg("\t\t\tsta_count: %d\n", tv_data[offset]);
+					offset += 2;
+				}
 			}
 		}
 		dbg("\n");
-- 
GitLab