diff --git a/src/core/agent.h b/src/core/agent.h index 59a8701b8bf5a953eba7ebf634b462d8be2fd7fc..ae08dda63741d961f0b48269a723a968a84b954d 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 3c55d713586d6d62eeb415f31ae478eae6844690..d783a3a1eca2170c0a1814e749a315974d0465d8 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 99e752a95331a5bf01e9ba7c3a20f47be532f6be..e9bbd1ab1011a56a95a301e6a1d39ccd99d939c8 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 04e132a986c1383ce407f66d2455c254f0219d06..32956e3dfd36a24d95ba52fb5207a6039aaa53e4 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);