From b456984731b1e6c485fb828e22288bf1cc706420 Mon Sep 17 00:00:00 2001
From: Kamil Zulewski <kamil.zulewski@iopsys.eu>
Date: Fri, 19 May 2023 16:01:07 +0200
Subject: [PATCH] Limiting length of Wi-Fi BH links chains

* Don't send BH BSS WSC TLV for nodes exceeding max_node_bh_hops limit
---
 src/cntlr.c      | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/cntlr.h      |  2 ++
 src/cntlr_cmdu.c |  4 ++++
 src/cntlr_ubus.c |  9 ++++---
 src/cntlr_ubus.h |  4 ++--
 5 files changed, 76 insertions(+), 5 deletions(-)

diff --git a/src/cntlr.c b/src/cntlr.c
index c419a367..2be39cfd 100644
--- a/src/cntlr.c
+++ b/src/cntlr.c
@@ -915,6 +915,67 @@ struct sta *cntlr_add_sta(struct controller *c, uint8_t *macaddr)
 	return s;
 }
 
+bool is_bh_bss_allowed_on_node(struct controller *c, uint8_t *al_mac)
+{
+	bool bh_bss_allowed = false;
+	bool is_root_node = false;
+
+	if (c->cfg.max_node_bh_hops == 0) {
+		dbg("%s: No Max Node BH Hops limitation configured, \
+		     BH BSS allowed on all nodes.\n", __func__);
+
+		return true;
+	}
+
+	if (hwaddr_is_zero(c->almac)) {
+		err("%s: unknown controller AL mac\n", __func__);
+		return true;
+	}
+
+	is_root_node = hwaddr_equal(c->almac, al_mac);
+
+	switch (c->cfg.max_node_bh_hops) {
+	case 1: {
+		/* BH BSS allowed only on root node */
+		bh_bss_allowed = is_root_node;
+
+	} break;
+	case 2: {
+		/* BH BSS allowed on root node and immediate neighbors */
+		if (is_root_node) {
+			bh_bss_allowed = true;
+		} else {
+			struct ieee1905_neighbor_dyn_array neighbors = { 0 };
+			int i;
+
+			if (!cntrl_get_ieee1905_neighbors(c, &neighbors)) {
+				err("%s: unsuccessfull ieee1905 neighbors ubus call.\n", __func__);
+				return true;
+			}
+
+			for (i = 0; i < neighbors.neighbors_size; ++i) {
+				if (neighbors.neighbors[i].is_immediate &&
+				    hwaddr_equal(neighbors.neighbors[i].al_mac, al_mac)) {
+					bh_bss_allowed = true;
+					break;
+				}
+			}
+
+			free(neighbors.neighbors);
+		}
+	} break;
+	default: {
+		/* For 3 and higher values BH BSS allowed on all nodes currently */
+		bh_bss_allowed = true;
+	} break;
+	}
+
+	info("%s: BH BSS allowed on node[" MACFMT "]: %s\n", __func__,
+	     MAC2STR(al_mac), bh_bss_allowed ? "yes" : "no");
+
+	return bh_bss_allowed;
+}
+
 static void forall_node_get_sta_metrics(struct controller *c)
 {
 	struct sta *s = NULL;
@@ -2103,3 +2164,4 @@ out_exit:
 	uloop_done();
 	free(c);
 }
+
diff --git a/src/cntlr.h b/src/cntlr.h
index e7510ba4..fed6570a 100644
--- a/src/cntlr.h
+++ b/src/cntlr.h
@@ -422,4 +422,6 @@ int cntlr_sync_dyn_controller_config(struct controller *c, uint8_t *agent);
 void cntlr_load_steer_modules(struct controller *c);
 void cntlr_unload_steer_modules(struct controller *c);
 
+bool is_bh_bss_allowed_on_node(struct controller *c, uint8_t *al_mac);
+
 #endif /* CNTLR_H */
diff --git a/src/cntlr_cmdu.c b/src/cntlr_cmdu.c
index 24cc9051..2cc11ec0 100644
--- a/src/cntlr_cmdu.c
+++ b/src/cntlr_cmdu.c
@@ -635,6 +635,10 @@ struct cmdu_buff *cntlr_gen_ap_autoconfig_wsc(struct controller *c,
 		if (cred->band != e_band)
 			continue;
 
+		if (cred->mode == AP_WIFI_BBSS &&
+		    !is_bh_bss_allowed_on_node(c, rx_cmdu->origin))
+			continue;
+
 		/* Will return non-zero if band did not match OR on failure */
 		cntlr_gen_wsc(c, resp, cred, msg, msglen, e_band, e_auth);
 	}
diff --git a/src/cntlr_ubus.c b/src/cntlr_ubus.c
index 11a20d55..54836316 100644
--- a/src/cntlr_ubus.c
+++ b/src/cntlr_ubus.c
@@ -3733,8 +3733,8 @@ static void ieee1905_cb_get_neighbors(struct ubus_request *req, int type,
 		[NEIGHBOR_ARRAY] = { .name = "neighbors", .type = BLOBMSG_TYPE_ARRAY },
 	};
 	struct blob_attr *tb[POLICY_LEN];
-	struct ieee1905_neighbor_array *output_array =
-		(struct ieee1905_neighbor_array *)req->priv;
+	struct ieee1905_neighbor_dyn_array *output_array =
+		(struct ieee1905_neighbor_dyn_array *)req->priv;
 
 	blobmsg_parse(policy, POLICY_LEN, tb, blob_data(msg), blob_len(msg));
 
@@ -3784,7 +3784,7 @@ static void ieee1905_cb_get_neighbors(struct ubus_request *req, int type,
 }
 
 int cntrl_get_ieee1905_neighbors(struct controller *c,
-				 struct ieee1905_neighbor_array *neighbors)
+				 struct ieee1905_neighbor_dyn_array *neighbors)
 {
 	uint32_t obj;
 	int ret;
@@ -3798,5 +3798,8 @@ int cntrl_get_ieee1905_neighbors(struct controller *c,
 				       ieee1905_cb_get_neighbors,
 				       neighbors);
 
+	if (neighbors->neighbors_size > 0 && !neighbors->neighbors)
+		ret = -1;
+
 	return ret;
 }
diff --git a/src/cntlr_ubus.h b/src/cntlr_ubus.h
index 6acbb3fc..223e0dd3 100644
--- a/src/cntlr_ubus.h
+++ b/src/cntlr_ubus.h
@@ -38,12 +38,12 @@ struct ieee1905_neighbor {
 	bool is_immediate;
 };
 
-struct ieee1905_neighbor_array {
+struct ieee1905_neighbor_dyn_array {
 	struct ieee1905_neighbor *neighbors;
 	uint32_t neighbors_size;
 };
 
 int cntrl_get_ieee1905_neighbors(struct controller *c,
-				 struct ieee1905_neighbor_array *neighbors);
+				 struct ieee1905_neighbor_dyn_array *neighbors);
 
 #endif /* CNTLR_UBUS_H */
-- 
GitLab