From e4e7bb9bdadd295734ca4cf0f1e004ba206e51a9 Mon Sep 17 00:00:00 2001
From: Jakob Olsson <jakob.olsson@iopsys.eu>
Date: Fri, 7 May 2021 13:04:47 +0200
Subject: [PATCH] map-agent: separate wsc vendor ext parsing
---
src/core/agent.h | 9 ++++
src/core/agent_map.c | 98 ++++++++++++++++++++++++++++++++++++++++++--
src/core/config.c | 18 ++++----
src/core/config.h | 4 +-
4 files changed, 115 insertions(+), 14 deletions(-)
diff --git a/src/core/agent.h b/src/core/agent.h
index 59a8701b8..ae08dda63 100644
--- a/src/core/agent.h
+++ b/src/core/agent.h
@@ -348,6 +348,15 @@ struct wifi_unassoc_sta_element {
uint8_t rssi;
};
+struct iop_ext {
+ uint8_t bridge[16];
+ uint8_t proto[8];
+ uint8_t vid;
+ uint8_t bk_ssid[33];
+ uint8_t bk_key[65];
+ uint32_t br_ip;
+};
+
struct wsc_key {
uint8_t *key;
uint32_t key_len;
diff --git a/src/core/agent_map.c b/src/core/agent_map.c
index 3c55d7135..d783a3a1e 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -1062,6 +1062,79 @@ char *wifi_gen_first_ifname(struct agent *a, char *device, char *ifname)
return NULL;
}
+int wsc_get_iop_ext(uint8_t *msg, uint16_t msglen, struct iop_ext *exts)
+{
+ uint8_t *p;
+ uint8_t *msg_end;
+
+ if (!msg || msglen == 0 || !exts)
+ return -1;
+
+ p = msg;
+ msg_end = msg + msglen;
+
+ while (abs(p - msg) < msglen - 4) {
+ uint16_t attr_type;
+ uint16_t attr_len;
+
+ attr_type = buf_get_be16(p);
+ p += 2;
+ attr_len = buf_get_be16(p);
+ p += 2;
+
+ if (p + attr_len > msg_end)
+ return -1;
+
+ if (attr_type == ATTR_VENDOR_EXTENSION) {
+ uint8_t id[3] = {0};
+ uint8_t *end_of_ext;
+ uint8_t subelem;
+ uint8_t len;
+
+ /* May be one or more subelements (Section 12 of WSC spec) */
+ end_of_ext = p + attr_len;
+ memcpy(id, p, sizeof(id));
+ p += 3;
+ attr_len -= 3;
+
+ if (id[0] == IOP_VENDOR_ID_1 &&
+ id[1] == IOP_VENDOR_ID_2 &&
+ id[2] == IOP_VENDOR_ID_3) {
+
+ while (p < end_of_ext) {
+ memcpy(&subelem, p, 1);
+ p += 1;
+ attr_len -= 1;
+
+ memcpy(&len, p, 1);
+ p += 1;
+ attr_len -= 1;
+
+ if (subelem == ATTR_BRIDGE)
+ memcpy(exts->bridge, p, len);
+ else if (subelem == ATTR_PROTO)
+ memcpy(exts->proto, p, len);
+ else if (subelem == ATTR_VID)
+ memcpy(&exts->vid, p, len);
+ else if (subelem == ATTR_BR_IP)
+ memcpy(&exts->br_ip, p, len);
+ else if (subelem == ATTR_BK_SSID)
+ memcpy(exts->bk_ssid, p, len);
+ else if (subelem == ATTR_BK_KEY)
+ memcpy(exts->bk_key, p, len);
+
+ p += len;
+ attr_len -= len;
+ }
+ }
+ }
+
+ p += attr_len;
+ }
+
+ return 0;
+}
+
int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
{
struct agent *a = (struct agent *) agent;
@@ -1102,6 +1175,9 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
struct wps_credential out = {0};
char ifname[IFNAMSIZ] = {0};
int rv;
+ uint8_t *ext = NULL;
+ uint16_t extlen = 0;
+ struct iop_ext exts = {0};
if (!wifi_gen_first_ifname(a, radio->name, ifname)) {
err("Failed to find valid interface name, probably "\
@@ -1111,9 +1187,11 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
return -1;
}
- ret = wsc_process_m2(radio->autconfig.m1_frame, radio->autconfig.m1_size,
- radio->autconfig.key, tv[3][num]->data, tlv_length(tv[3][num]),
- &out);
+ ret = wsc_process_m2(radio->autconfig.m1_frame,
+ radio->autconfig.m1_size,
+ radio->autconfig.key, tv[3][num]->data,
+ tlv_length(tv[3][num]),
+ &out, &ext, &extlen);
if (ret) {
err("Failed to process M2 target for interface "\
MACFMT "!\n", MAC2STR(bssid));
@@ -1125,6 +1203,18 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
return -1;
}
+ ret = wsc_get_iop_ext(ext, extlen, &exts);
+ if (ret) {
+ err("Failed to process IOPSYS vendor ext for interface "\
+ MACFMT "!\n", MAC2STR(bssid));
+
+ wifi_teardown_map_ifaces_by_radio(a, radio->name);
+ /* Return rather than freeing because it may belong to
+ * an updated frame
+ */
+ return -1;
+ }
+
if (BIT(4, out.mapie)) {
err("MAP Extension had teardown bit set, tearing down "\
"all MAP interfaces for bssid " MACFMT \
@@ -1137,7 +1227,7 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu)
}
ret = uci_apply_m2(&a->cfg, ifname, radio->name, &out,
- radio->onboarded);
+ radio->onboarded, &exts);
if (ret) {
err("Failure to process M2, tearing down all MAP "\
" interfaces for bssid " MACFMT "\n",
diff --git a/src/core/config.c b/src/core/config.c
index 99e752a95..e9bbd1ab1 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -713,7 +713,7 @@ int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band)
/* TODO: batch the changes arther than commit oneby one */
int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
- struct wps_credential *out, bool onboarded)
+ struct wps_credential *out, bool onboarded, struct iop_ext *exts)
{
bool ret;
char auth_type_str[20] = {0};
@@ -739,7 +739,7 @@ int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
memcpy(ssid, out->ssid, out->ssidlen);
memcpy(network_key, out->key, out->keylen);
- memcpy(bridge, out->bridge, 15);
+ memcpy(bridge, exts->bridge, 15);
inet_ntop(AF_INET, &out->br_ip, ipaddr_str, INET_ADDRSTRLEN);
@@ -750,11 +750,11 @@ int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
dbg(" - NETWORK_KEY : %s\n", network_key);
dbg(" - MAPIE_EXTENSION : 0x%02x\n", out->mapie);
dbg(" - BRIDGE : %s\n", bridge);
- dbg(" - PROTO : %s\n", out->proto);
- dbg(" - VID : 0x%02x\n", out->vid);
+ dbg(" - PROTO : %s\n", exts->proto);
+ dbg(" - VID : 0x%02x\n", exts->vid);
dbg(" - BR_IP : %s\n", ipaddr_str);
- dbg(" - BK_SSID : %s\n", out->bk_ssid);
- dbg(" - BK_KEY : %s\n", out->bk_key);
+ dbg(" - BK_SSID : %s\n", exts->bk_ssid);
+ dbg(" - BK_KEY : %s\n", exts->bk_key);
dbg(" - BAND : %s\n", band_str);
// if teardown bit is set, return
@@ -775,7 +775,7 @@ int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
return M2_PROCESS_ERROR;
}
- ret = uci_set_bridge("network", bridge, out->proto, ipaddr_str);
+ ret = uci_set_bridge("network", bridge, exts->proto, ipaddr_str);
if (ret) {
info("Error seting up bridge from M2!\n");
return M2_PROCESS_ERROR;
@@ -843,9 +843,9 @@ int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
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", out->bk_key);
+ interface_name, "multi_ap_backhaul_key", exts->bk_key);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
- interface_name, "multi_ap_backhaul_ssid", out->bk_ssid);
+ interface_name, "multi_ap_backhaul_ssid", exts->bk_ssid);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "ieee80211k", "1");
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
diff --git a/src/core/config.h b/src/core/config.h
index 04e132a98..32956e3df 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -37,6 +37,8 @@ enum steer_action {
#define CONTROLLER_SELECT_RETRY_INT 3 /* attempts */
#define CONTROLLER_SELECT_AUTOSTART 0 /* don't start cntlr */
+struct iop_ext;
+
struct steer_policy {
char name[16]; /* XXX: maps to struct steer_rule.name in (all)?
* cases otherwise there is no way of knowing how
@@ -257,7 +259,7 @@ void clean_fh(struct netif_fhcfg *p);
int clean_all_fh(struct agent_config *cfg);
int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
- struct wps_credential *out, bool onboarded);
+ struct wps_credential *out, bool onboarded, struct iop_ext *exts);
int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band);
int wifi_reorder_interfaces_by_device(struct agent_config *ac,
struct uci_context *ctx, struct uci_package *pkg, char *device);
--
GitLab