From 7a86382fb13a87c7afcb4401b2325bfbe03713a4 Mon Sep 17 00:00:00 2001
From: Jakob Olsson <jakob.olsson@iopsys.eu>
Date: Fri, 29 Jan 2021 13:24:43 +0100
Subject: [PATCH] map-agent: autoconfig: parse IOPSYS vendor extensions in m2

---
 src/core/agent.c     |  22 +++++--
 src/core/agent.h     |   1 +
 src/core/agent_map.c |  13 ++--
 src/core/config.c    | 141 +++++++++++++++++++++++++++++++++++--------
 src/core/config.h    |   8 ++-
 5 files changed, 150 insertions(+), 35 deletions(-)

diff --git a/src/core/agent.c b/src/core/agent.c
index b5bf5841e..68ebaeb55 100644
--- a/src/core/agent.c
+++ b/src/core/agent.c
@@ -2033,8 +2033,6 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 		if (!ret)
 			return;
 	}
-	uci_set_wireless_interface_option("mapagent", "bk-iface", ifname,
-			"onboarded", "1");
 
 	uci_reload_services();
 
@@ -2043,6 +2041,8 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
 		return;
 
 	radio->onboarded = 1;
+	uci_set_wireless_interface_option("mapagent", "wifi-radio", "device",
+			radio->name, "onboarded", "1");
 }
 
 static void ubus_wifi_event_handler(struct ubus_context *ctx,
@@ -2761,13 +2761,27 @@ static void _enumerate_wifi_objects(struct ubus_request *req, int type,
 		char r_objname[32] = {0};
 		const char *r_fmt = "wifi.radio.%s";
 		wifi_object_t r_wobj = WIFI_OBJECT_INVALID;
-
+		struct agent_config_radio *r_cfg;
 		radio_obj = json_object_array_get_idx(radio_array, i);
 		json_object_object_get_ex(radio_obj, "name", &radio_obj_name);
 		radio_name = json_object_get_string(radio_obj_name);
 		strncpy(a->ifs[i].radio, radio_name, 15);
 		strncpy(a->radios[i].name, radio_name, 15);
 
+		list_for_each_entry(r_cfg, &a->cfg.radiolist, list) {
+			if (strncmp(r_cfg->name, a->radios[i].name, 15))
+				continue;
+
+			a->radios[i].onboarded = r_cfg->onboarded;
+			a->radios[i].configured = r_cfg->configured;
+			break;
+		}
+
+		// parse channel range
+		// if channel range is stricly beneath <= 64, assign low
+		// else if channel rangei stricly above 100, >= 100, assign high
+		// else if both ranges, no assignation
+
 		json_object_object_get_ex(radio_obj, "accesspoints", &fh_array);
 		fh_len = json_object_array_length(fh_array);
 		for (j = 0; j < fh_len; j++) {
@@ -3366,7 +3380,7 @@ static void agent_dispatch_autoconfig(struct uloop_timeout *t)
 		struct cmdu_cstruct *cmdu;
 		struct wifi_radio_element *radio = &a->radios[i];
 
-		if (radio->onboarded) {
+		if (radio->onboarded || radio->configured) {
 			dbg("radio %s has been onboarded, don't trigger search\n",
 					radio->name);
 			continue;
diff --git a/src/core/agent.h b/src/core/agent.h
index ab9c2e13b..599608b9f 100644
--- a/src/core/agent.h
+++ b/src/core/agent.h
@@ -338,6 +338,7 @@ struct wifi_radio_element {
 	uint8_t macaddr[6];
 	uint8_t country_code[2];
 	bool onboarded;
+	bool configured;
 	enum wifi_band band;
 	bool enabled;
 	int anpi;
diff --git a/src/core/agent_map.c b/src/core/agent_map.c
index a3c90ac4f..1ea5925e7 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -826,7 +826,10 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
 					out.output.auth_types,
 					out.output.encryption_types,
 					out.output.network_key,
-					out.output.mapie, radio->band);
+					out.output.mapie, radio->band,
+					out.output.bridge, out.output.proto,
+					out.output.vid, out.output.br_ip,
+					out.output.bk_ssid, out.output.bk_key);
 			break;
 		}
 		default:
@@ -834,11 +837,13 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
 
 		}
 	}
-
-	a->configured = true;
+	uci_set_wireless_interface_option("mapagent", "wifi-radio", "device",
+			radio->name, "configured", "1");
+	radio->configured = 1;
+	//a->configured = true;
 	wifi_reorder_interfaces(&a->cfg);
 	agent_config_reload(&a->cfg);
-	uci_apply_wps_credentials(&a->cfg, radio->band);
+	//uci_apply_wps_credentials(&a->cfg, radio->band);
 teardown:
 	// TODO: freeing from here risks freeing an updated frame
 	agent_free_wsc_data(&radio->autconfig);
diff --git a/src/core/config.c b/src/core/config.c
index 66916719c..14508cdba 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -437,13 +437,14 @@ bool uci_check_wifi_iface(char *package_name, char *ifname,
 }
 
 bool uci_set_wireless_interface_option(char *package_name,
-		char *section_type, char *ifname, char *option, char *value)
+		char *section_type, char *search_key, char *search_val,
+		char *option, char *value)
 {
 	struct uci_context *ctx;
 	struct uci_package *pkg;
 	struct uci_element *e;
 
-	if (!package_name || !ifname || !option || !value)
+	if (!package_name || !search_val || !option || !value)
 		return false;
 
 	ctx = uci_alloc_context();
@@ -460,11 +461,11 @@ bool uci_set_wireless_interface_option(char *package_name,
 
 		if (!strcmp(s->type, section_type)) {
 			struct uci_option *opt = uci_lookup_option(ctx, s,
-					"ifname");
+					search_key);
 
 			if (!opt || opt->type != UCI_TYPE_STRING)
 				continue;
-			if (strcmp(opt->v.string, ifname) == 0) {
+			if (strcmp(opt->v.string, search_val) == 0) {
 				struct uci_ptr ptr = {0};
 
 				ptr.value = value;
@@ -611,6 +612,7 @@ bool uci_reload_services(void)
 	return false;
 }
 
+#if 0 /* Deprecated for 6.1 - Possibly bring back in 6.2 with modifications */
 /* TODO: introduce option and vendor extension to make this logic redundant */
 int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band)
 {
@@ -631,18 +633,20 @@ int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band)
 
 			uci_set_wireless_interface_option(UCI_WIRELESS,
 					UCI_WLAN_IFACE,
+					"ifname",
 					fh->name,
 					"multi_ap_backhaul_ssid",
 					bk->ssid);
 			uci_set_wireless_interface_option(UCI_WIRELESS,
 					UCI_WLAN_IFACE,
+					"ifname",
 					fh->name,
 					"multi_ap_backhaul_key",
 					bk->key);
 			uci_set_wireless_interface_option(UCI_WIRELESS,
-					UCI_WLAN_IFACE,	fh->name, "wps", "1");
+					UCI_WLAN_IFACE,	"ifname", fh->name, "wps", "1");
 			uci_set_wireless_interface_option(UCI_WIRELESS,
-					UCI_WLAN_IFACE,	fh->name,
+					UCI_WLAN_IFACE,	"ifname", fh->name,
 					"wps_pushbutton", "1");
 		}
 
@@ -651,12 +655,15 @@ int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band)
 
 	return 0;
 }
+#endif
 
 
 /* TODO: batch the changes arther than commit oneby one */
 int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 		uint16_t auth_type, uint16_t encryption_type,
-		uint8_t *network_key, uint8_t mapie, uint8_t band)
+		uint8_t *network_key, uint8_t mapie, uint8_t band,
+		uint8_t *bridge, uint8_t *proto, uint8_t vid, uint32_t br_ip,
+		uint8_t *bk_ssid, uint8_t *bk_key)
 {
 	bool ret;
 	char auth_type_str[20] = {0};
@@ -665,6 +672,10 @@ int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 	bool bk_mode;
 	char band_str[2] = {0};
 	char agent_section[16] = {0};
+	char ipaddr_str[INET_ADDRSTRLEN] = {0};
+
+	inet_ntop(AF_INET, &br_ip, ipaddr_str, INET_ADDRSTRLEN);
+
 
 	dbg("Applying WSC configuration (%s):\n", interface_name);
 	dbg("  - SSID            : %s\n", ssid);
@@ -672,7 +683,12 @@ int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 	dbg("  - ENCRYPTION_TYPE : 0x%04x\n", encryption_type);
 	dbg("  - NETWORK_KEY     : %s\n", network_key);
 	dbg("  - MAPIE_EXTENSION : 0x%02x\n", mapie);
-
+	dbg("  - BRIDGE          : %s\n", bridge);
+	dbg("  - PROTO           : %s\n", proto);
+	dbg("  - VID             : 0x%02x\n", vid);
+	dbg("  - BR_IP           : %s\n", ipaddr_str);
+	dbg("  - BK_SSID         : %s\n", bk_ssid);
+	dbg("  - BK_KEY          : %s\n", bk_key);
 	// if teardown bit is set, return
 	if (BIT(3, mapie))
 		return M2_PROCESS_TEARDOWN;
@@ -683,12 +699,22 @@ int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 
 	snprintf(multiap_str, sizeof(multiap_str), "%d", multi_ap);
 
+	//snprintf(ipaddr_str, sizeof(ipaddr_str), "%d.%d.%d.%d", br_ip[0],
+	//		br_ip[1], br_ip[2], br_ip[3]);
+
 	if (!get_encryption_value(auth_type, encryption_type,
 			auth_type_str, 20)) {
 		info("Unsupported encryption or cipher received!!\n");
 		return M2_PROCESS_ERROR;
 	}
 
+	ret = uci_set_bridge("network", bridge, proto, ipaddr_str);
+	if (ret) {
+		info("Error seting up bridge from M2!\n");
+		return M2_PROCESS_ERROR;
+	}
+
+
 	strncpy(agent_section, (bk_mode ? UCI_BK_AGENT : UCI_FH_AGENT),
 			sizeof(agent_section));
 
@@ -709,17 +735,17 @@ int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 	else /* TODO: 60 */
 		return M2_PROCESS_ERROR;
 
-	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section, "ifname",
 			interface_name, "band",	band_str);
-	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section, "ifname",
 			interface_name, "band",	band_str);
-	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section, "ifname",
 			interface_name,	"device", device);
-	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section, "ifname",
 			interface_name,	"ssid", ssid);
-	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section, "ifname",
 			interface_name,	"key", network_key);
-	uci_set_wireless_interface_option(UCI_AGENT, agent_section,
+	uci_set_wireless_interface_option(UCI_AGENT, agent_section, "ifname",
 			interface_name,	"encryption", auth_type_str);
 	if (bk_mode) {
 		char disallow_str[2] = {0};
@@ -727,7 +753,7 @@ int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 		snprintf(disallow_str, sizeof(disallow_str), "%d",
 				((mapie >> 2) & 0x03));
 		uci_set_wireless_interface_option(UCI_AGENT,
-				UCI_BK_AGENT,
+				UCI_BK_AGENT, "ifname",
 				interface_name,
 				"disallow_bsta", disallow_str);
 	}
@@ -742,23 +768,34 @@ int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 			return M2_PROCESS_ERROR;
 	}
 
-	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
-			interface_name, "network", "lan");
-	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
+			interface_name, "network", bridge);
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
 			interface_name, "ssid", (char *) ssid);
-	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
 			interface_name, "key", (char *) network_key);
-	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
 			interface_name, "encryption", auth_type_str);
-	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
 			interface_name, "mode", "ap");
-	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
 			interface_name, "device", device);
-	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
 			interface_name, "multi_ap", multiap_str);
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
+			interface_name, "multi_ap_backhaul_key", bk_key);
+	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
+			interface_name, "multi_ap_backhaul_ssid", bk_ssid);
+
 	if (bk_mode) {
 		uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
-			interface_name, "hidden", "1");
+			"ifname", interface_name, "hidden", "1");
+	} else {
+		uci_set_wireless_interface_option(UCI_WIRELESS,
+			UCI_WLAN_IFACE,	"ifname", interface_name, "wps", "1");
+		uci_set_wireless_interface_option(UCI_WIRELESS,
+			UCI_WLAN_IFACE,	"ifname", interface_name,
+			"wps_pushbutton", "1");
 	}
 	return M2_PROCESS_OK;
 }
@@ -1983,4 +2020,58 @@ int wifi_reorder_interfaces(struct agent_config *a)
 	uci_commit(ctx, &pkg, false);
 	uci_free_context(ctx);
 	return 0;
-}
\ No newline at end of file
+}
+
+int uci_set_bridge(char *config, char *bridge, char *proto, char *ipaddress)
+{
+	struct uci_context *ctx = NULL;
+	struct uci_package *pkg;
+	struct uci_element *e;
+	struct uci_section *section = NULL;
+
+	/** if bridge starts with br prefix, step past */
+	if (!strncmp(bridge, "br-", 3))
+		bridge += 3;
+
+	pkg = uci_load_pkg(&ctx, "network");
+	if (!pkg)
+		return -1;
+
+	uci_foreach_element(&pkg->sections, e) {
+		struct uci_section *s = uci_to_section(e);
+
+		if (strncmp(s->e.name, bridge, 16))
+			continue;
+
+		section = s;
+		break;
+	}
+
+	if (!section) {
+		struct uci_ptr ptr = {0};
+
+		ptr.p = pkg;
+		ptr.section = bridge;
+		ptr.value = "interface";
+		ptr.option = NULL;
+		uci_set(ctx, &ptr);
+		section = ptr.s;
+	}
+
+	set_value(ctx, pkg, section, "type", "bridge", UCI_TYPE_STRING);
+	set_value(ctx, pkg, section, "is_lan", "1", UCI_TYPE_STRING);
+	if (strlen(proto))
+		set_value(ctx, pkg, section, "proto", proto, UCI_TYPE_STRING);
+	if (!strcmp(proto, "static")) {
+		set_value(ctx, pkg, section, "ipaddr", ipaddress,
+				UCI_TYPE_STRING);
+		set_value(ctx, pkg, section, "netmask", "255.255.255.0",
+				UCI_TYPE_STRING);
+	}
+
+	uci_commit(ctx, &pkg, false);
+out:
+	uci_unload(ctx, pkg);
+	uci_free_context(ctx);
+	return false;
+}
diff --git a/src/core/config.h b/src/core/config.h
index 283725d7a..c13ddbadb 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -198,7 +198,8 @@ int config_add_default_wifi_iface(const char *config, const char *type,
 bool uci_check_wifi_iface(char *package_name, char *ifname,
 		char *section);
 bool uci_set_wireless_interface_option(char *package_name,
-		char *section_type, char *ifname, char *option, char *value);
+		char *section_type, char *search_key, char *search_val,
+		char *option, char *value);
 bool uci_add_wireless_iface_sec(char *package_name, char *interface_name,
 		char *section_name);
 
@@ -209,9 +210,12 @@ int clean_all_fh(struct agent_config *cfg);
 
 int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid,
 		uint16_t auth_type, uint16_t encryption_type,
-		uint8_t *network_key, uint8_t mapie, uint8_t band);
+		uint8_t *network_key, uint8_t mapie, uint8_t band,
+		uint8_t *bridge, uint8_t *proto, uint8_t vid, uint32_t br_ip,
+		uint8_t *bk_ssid, uint8_t *bk_key);
 int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band);
 int wifi_reorder_interfaces_by_device(struct agent_config *a,
 		struct uci_context *ctx, struct uci_package *pkg, char *device);
 int wifi_reorder_interfaces(struct agent_config *a);
+int uci_set_bridge(char *config, char *bridge, char *proto, char *ipaddress);
 #endif
-- 
GitLab