Import the initial version of sigma_dut open source project
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
diff --git a/sta.c b/sta.c
new file mode 100644
index 0000000..7f8d16b
--- /dev/null
+++ b/sta.c
@@ -0,0 +1,7555 @@
+/*
+ * Sigma Control API DUT (station/AP)
+ * Copyright (c) 2010-2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2015, Qualcomm Atheros, Inc.
+ * All Rights Reserved.
+ * Licensed under the Clear BSD license. See README for more details.
+ */
+
+#include "sigma_dut.h"
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#ifdef __linux__
+#include <sys/time.h>
+#include <netpacket/packet.h>
+#include <linux/if_ether.h>
+#ifdef ANDROID
+#include <cutils/properties.h>
+#include <android/log.h>
+#include "keystore_get.h"
+#else /* ANDROID */
+#include <ifaddrs.h>
+#endif /* ANDROID */
+#include <netdb.h>
+#endif /* __linux__ */
+#ifdef __QNXNTO__
+#include <net/if_dl.h>
+#endif /* __QNXNTO__ */
+#include "wpa_ctrl.h"
+#include "wpa_helpers.h"
+
+/* Temporary files for sta_send_addba */
+#define VI_QOS_TMP_FILE "/tmp/vi-qos.tmp"
+#define VI_QOS_FILE "/tmp/vi-qos.txt"
+#define VI_QOS_REFFILE "/etc/vi-qos.txt"
+
+/*
+ * MTU for Ethernet need to take into account 8-byte SNAP header
+ * to be added when encapsulating Ethernet frame into 802.11
+ */
+#ifndef IEEE80211_MAX_DATA_LEN_DMG
+#define IEEE80211_MAX_DATA_LEN_DMG 7920
+#endif
+#ifndef IEEE80211_SNAP_LEN_DMG
+#define IEEE80211_SNAP_LEN_DMG 8
+#endif
+
+extern char *sigma_wpas_ctrl;
+extern char *sigma_cert_path;
+extern enum driver_type wifi_chip_type;
+extern char *sigma_radio_ifname[];
+
+
+#ifdef ANDROID
+
+static int add_ipv6_rule(struct sigma_dut *dut, const char *ifname);
+
+#define ANDROID_KEYSTORE_GET 'g'
+#define ANDROID_KEYSTORE_GET_PUBKEY 'b'
+
+static int android_keystore_get(char cmd, const char *key, unsigned char *val)
+{
+#ifdef ANDROID43
+ /* Android 4.3 changed keystore design, so need to use keystore_get() */
+#ifndef KEYSTORE_MESSAGE_SIZE
+#define KEYSTORE_MESSAGE_SIZE 65535
+#endif /* KEYSTORE_MESSAGE_SIZE */
+
+ ssize_t len;
+ uint8_t *value = NULL;
+
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "keystore command '%c' key '%s' --> keystore_get",
+ cmd, key);
+
+ len = keystore_get(key, strlen(key), &value);
+ if (len < 0) {
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "keystore_get() failed");
+ return -1;
+ }
+
+ if (len > KEYSTORE_MESSAGE_SIZE)
+ len = KEYSTORE_MESSAGE_SIZE;
+ memcpy(val, value, len);
+ free(value);
+ return len;
+#else /* ANDROID43 */
+ int s, res, reslen = -1, received;
+ size_t keylen;
+ unsigned char hdr[3];
+
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "keystore command '%c' key '%s'", cmd, key);
+ keylen = strlen(key);
+ if (keylen > KEYSTORE_MESSAGE_SIZE)
+ return -1;
+
+ s = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (s < 0) {
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "could not connect to keystore");
+ return -1;
+ }
+
+ hdr[0] = cmd;
+ hdr[1] = keylen >> 8;
+ hdr[2] = keylen & 0xff;
+
+ if (send(s, hdr, sizeof(hdr), MSG_NOSIGNAL) != sizeof(hdr) ||
+ send(s, key, keylen, MSG_NOSIGNAL) != (int) keylen ||
+ shutdown(s, SHUT_WR) != 0) {
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "could not send keystore command");
+ goto fail;
+ }
+
+ if (recv(s, hdr, 1, 0) != 1)
+ goto fail;
+ if (hdr[0] != 1) {
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "unexpected keystore response %u", hdr[0]);
+ goto fail;
+ }
+ if (recv(s, hdr + 1, 2, 0) != 2)
+ goto fail;
+ reslen = hdr[1] * 256 + hdr[2];
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "keystore response length %d", reslen);
+ if (reslen > KEYSTORE_MESSAGE_SIZE) {
+ reslen = -1;
+ goto fail;
+ }
+
+ received = 0;
+ while (received < reslen) {
+ res = recv(s, val + received, reslen - received, 0);
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "keystore recv -> %d", res);
+ if (res <= 0) {
+ reslen = -1;
+ break;
+ }
+ received += res;
+ }
+
+fail:
+ close(s);
+ __android_log_print(ANDROID_LOG_DEBUG, "sigma_dut",
+ "keystore get -> %d", reslen);
+ return reslen;
+#endif /* ANDROID43 */
+}
+#endif /* ANDROID */
+
+
+int set_ps(const char *intf, struct sigma_dut *dut, int enabled)
+{
+#ifdef __linux__
+ char buf[100];
+
+ if (wifi_chip_type == DRIVER_WCN) {
+ if (enabled) {
+ snprintf(buf, sizeof(buf), "iwpriv wlan0 dump 906");
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to enable power save");
+ return -1;
+ }
+ } else {
+ snprintf(buf, sizeof(buf), "iwpriv wlan0 dump 905");
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to stop power save timer");
+ return -1;
+ }
+ snprintf(buf, sizeof(buf), "iwpriv wlan0 dump 912");
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to disable power save");
+ return -1;
+ }
+ }
+
+ return 0;
+ }
+
+ snprintf(buf, sizeof(buf), "./iw dev %s set power_save %s",
+ intf, enabled ? "on" : "off");
+ if (system(buf) != 0) {
+ snprintf(buf, sizeof(buf), "iw dev %s set power_save %s",
+ intf, enabled ? "on" : "off");
+ if (system(buf) != 0)
+ return -1;
+ }
+
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+static void static_ip_file(int proto, const char *addr, const char *mask,
+ const char *gw)
+{
+ if (proto) {
+ FILE *f = fopen("static-ip", "w");
+ if (f) {
+ fprintf(f, "%d %s %s %s\n", proto, addr,
+ mask ? mask : "N/A",
+ gw ? gw : "N/A");
+ fclose(f);
+ }
+ } else {
+ unlink("static-ip");
+ }
+}
+
+
+static int send_neighbor_request(struct sigma_dut *dut, const char *intf,
+ const char *ssid)
+{
+#ifdef __linux__
+ char buf[100];
+
+ snprintf(buf, sizeof(buf), "iwpriv %s neighbor %s",
+ intf, ssid);
+ sigma_dut_print(dut, DUT_MSG_INFO, "Request: %s", buf);
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv neighbor request failed");
+ return -1;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_INFO, "iwpriv neighbor request send");
+
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+static int send_trans_mgmt_query(struct sigma_dut *dut, const char *intf,
+ const char *ssid)
+{
+ /*
+ * In the earlier builds we used WNM_QUERY and in later
+ * builds used WNM_BSS_QUERY.
+ */
+
+ if (wpa_command(intf, "WNM_BSS_QUERY 0") != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "transition management query failed");
+ return -1;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "transition management query sent");
+
+ return 0;
+}
+
+
+int is_ip_addr(const char *str)
+{
+ const char *pos = str;
+ struct in_addr addr;
+
+ while (*pos) {
+ if (*pos != '.' && (*pos < '0' || *pos > '9'))
+ return 0;
+ pos++;
+ }
+
+ return inet_aton(str, &addr);
+}
+
+
+int is_ipv6_addr(const char *str)
+{
+ struct sockaddr_in6 addr;
+
+ return inet_pton(AF_INET6, str, &(addr.sin6_addr));
+}
+
+
+int get_ip_config(struct sigma_dut *dut, const char *ifname, char *buf,
+ size_t buf_len)
+{
+ char tmp[256], *pos, *pos2;
+ FILE *f;
+ char ip[16], mask[15], dns[16], sec_dns[16];
+ int is_dhcp = 0;
+ int s;
+#ifdef ANDROID
+ char prop[PROPERTY_VALUE_MAX];
+#endif /* ANDROID */
+
+ ip[0] = '\0';
+ mask[0] = '\0';
+ dns[0] = '\0';
+ sec_dns[0] = '\0';
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s >= 0) {
+ struct ifreq ifr;
+ struct sockaddr_in saddr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to get "
+ "%s IP address: %s",
+ ifname, strerror(errno));
+ } else {
+ memcpy(&saddr, &ifr.ifr_addr,
+ sizeof(struct sockaddr_in));
+ strncpy(ip, inet_ntoa(saddr.sin_addr), sizeof(ip));
+ }
+
+ if (ioctl(s, SIOCGIFNETMASK, &ifr) == 0) {
+ memcpy(&saddr, &ifr.ifr_addr,
+ sizeof(struct sockaddr_in));
+ strncpy(mask, inet_ntoa(saddr.sin_addr), sizeof(mask));
+ }
+ close(s);
+ }
+
+#ifdef ANDROID
+ snprintf(tmp, sizeof(tmp), "dhcp.%s.pid", ifname);
+ if (property_get(tmp, prop, NULL) != 0 && atoi(prop) > 0) {
+ snprintf(tmp, sizeof(tmp), "dhcp.%s.result", ifname);
+ if (property_get(tmp, prop, NULL) != 0 &&
+ strcmp(prop, "ok") == 0) {
+ snprintf(tmp, sizeof(tmp), "dhcp.%s.ipaddress",
+ ifname);
+ if (property_get(tmp, prop, NULL) != 0 &&
+ strcmp(ip, prop) == 0)
+ is_dhcp = 1;
+ }
+ }
+
+ snprintf(tmp, sizeof(tmp), "dhcp.%s.dns1", ifname);
+ if (property_get(tmp, prop, NULL) != 0) {
+ strncpy(dns, prop, sizeof(dns));
+ dns[sizeof(dns) - 1] = '\0';
+ } else {
+ if (property_get("net.dns1", prop, NULL) != 0) {
+ strncpy(dns, prop, sizeof(dns));
+ dns[sizeof(dns) - 1] = '\0';
+ }
+ }
+
+ snprintf(tmp, sizeof(tmp), "dhcp.%s.dns2", ifname);
+ if (property_get(tmp, prop, NULL) != 0) {
+ strncpy(sec_dns, prop, sizeof(sec_dns));
+ sec_dns[sizeof(sec_dns) - 1] = '\0';
+ }
+#else /* ANDROID */
+#ifdef __linux__
+ snprintf(tmp, sizeof(tmp), "ps ax | grep dhclient | grep -v grep | "
+ "grep -q %s", ifname);
+ if (system(tmp) == 0)
+ is_dhcp = 1;
+ else {
+ snprintf(tmp, sizeof(tmp), "ps ax | grep udhcpc | "
+ "grep -v grep | grep -q %s", ifname);
+ if (system(tmp) == 0)
+ is_dhcp = 1;
+ else {
+ snprintf(tmp, sizeof(tmp), "ps ax | grep dhcpcd | "
+ "grep -v grep | grep -q %s", ifname);
+ if (system(tmp) == 0)
+ is_dhcp = 1;
+ }
+ }
+#endif /* __linux__ */
+
+ f = fopen("/etc/resolv.conf", "r");
+ if (f) {
+ while (fgets(tmp, sizeof(tmp), f)) {
+ if (strncmp(tmp, "nameserver", 10) != 0)
+ continue;
+ pos = tmp + 10;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ pos2 = pos;
+ while (*pos2) {
+ if (*pos2 == '\n' || *pos2 == '\r') {
+ *pos2 = '\0';
+ break;
+ }
+ pos2++;
+ }
+ if (!dns[0]) {
+ strncpy(dns, pos, sizeof(dns));
+ dns[sizeof(dns) - 1] = '\0';
+ } else if (!sec_dns[0]) {
+ strncpy(sec_dns, pos, sizeof(sec_dns));
+ sec_dns[sizeof(sec_dns) - 1] = '\0';
+ }
+ }
+ fclose(f);
+ }
+#endif /* ANDROID */
+
+ snprintf(buf, buf_len, "dhcp,%d,ip,%s,mask,%s,primary-dns,%s",
+ is_dhcp, ip, mask, dns);
+ buf[buf_len - 1] = '\0';
+
+ return 0;
+}
+
+
+
+
+int get_ipv6_config(struct sigma_dut *dut, const char *ifname, char *buf,
+ size_t buf_len)
+{
+#ifdef __linux__
+#ifdef ANDROID
+ char cmd[200], result[1000], *pos, *end;
+ FILE *f;
+ size_t len;
+
+ snprintf(cmd, sizeof(cmd), "ip addr show dev %s scope global", ifname);
+ f = popen(cmd, "r");
+ if (f == NULL)
+ return -1;
+ len = fread(result, 1, sizeof(result) - 1, f);
+ pclose(f);
+ if (len == 0)
+ return -1;
+ result[len] = '\0';
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "%s result: %s\n", cmd, result);
+
+ pos = strstr(result, "inet6 ");
+ if (pos == NULL)
+ return -1;
+ pos += 6;
+ end = strchr(pos, ' ');
+ if (end)
+ *end = '\0';
+ end = strchr(pos, '/');
+ if (end)
+ *end = '\0';
+ snprintf(buf, buf_len, "ip,%s", pos);
+ buf[buf_len - 1] = '\0';
+ return 0;
+#else /* ANDROID */
+ struct ifaddrs *ifaddr, *ifa;
+ int res, found = 0;
+ char host[NI_MAXHOST];
+
+ if (getifaddrs(&ifaddr) < 0) {
+ perror("getifaddrs");
+ return -1;
+ }
+
+ for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+ if (strcasecmp(ifname, ifa->ifa_name) != 0)
+ continue;
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+
+ res = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6),
+ host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ if (res != 0) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "getnameinfo: %s",
+ gai_strerror(res));
+ continue;
+ }
+ if (strncmp(host, "fe80::", 6) == 0)
+ continue; /* skip link-local */
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "ifaddr: %s", host);
+ found = 1;
+ break;
+ }
+
+ freeifaddrs(ifaddr);
+
+ if (found) {
+ char *pos;
+ pos = strchr(host, '%');
+ if (pos)
+ *pos = '\0';
+ snprintf(buf, buf_len, "ip,%s", host);
+ buf[buf_len - 1] = '\0';
+ return 0;
+ }
+
+#endif /* ANDROID */
+#endif /* __linux__ */
+ return -1;
+}
+
+
+static int cmd_sta_get_ip_config(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname;
+ char buf[200];
+ const char *val;
+ int type = 1;
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ /*
+ * UCC may assume the IP address to be available immediately after
+ * association without trying to run sta_get_ip_config multiple times.
+ * Sigma CAPI does not specify this command as a block command that
+ * would wait for the address to become available, but to pass tests
+ * more reliably, it looks like such a wait may be needed here.
+ */
+ if (wait_ip_addr(dut, ifname, 15) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Could not get IP address "
+ "for sta_get_ip_config");
+ /*
+ * Try to continue anyway since many UCC tests do not really
+ * care about the return value from here..
+ */
+ }
+
+ val = get_param(cmd, "Type");
+ if (val)
+ type = atoi(val);
+ if (type == 2 || dut->last_set_ip_config_ipv6) {
+ int i;
+
+ /*
+ * Since we do not have proper wait for IPv6 addresses, use a
+ * fixed two second delay here as a workaround for UCC script
+ * assuming IPv6 address is available when this command returns.
+ * Some scripts did not use Type,2 properly for IPv6, so include
+ * also the cases where the previous sta_set_ip_config indicated
+ * use of IPv6.
+ */
+ sigma_dut_print(dut, DUT_MSG_INFO, "Wait up to extra ten seconds in sta_get_ip_config for IPv6 address");
+ for (i = 0; i < 10; i++) {
+ sleep(1);
+ if (get_ipv6_config(dut, ifname, buf, sizeof(buf)) == 0)
+ {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Found IPv6 address");
+ send_resp(dut, conn, SIGMA_COMPLETE, buf);
+#ifdef ANDROID
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Adding IPv6 rule on Android");
+ add_ipv6_rule(dut, intf);
+#endif /* ANDROID */
+
+ return 0;
+ }
+ }
+ }
+ if (type == 1) {
+ if (get_ip_config(dut, ifname, buf, sizeof(buf)) < 0)
+ return -2;
+ } else if (type == 2) {
+ if (get_ipv6_config(dut, ifname, buf, sizeof(buf)) < 0)
+ return -2;
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unsupported address type");
+ return 0;
+ }
+
+ send_resp(dut, conn, SIGMA_COMPLETE, buf);
+ return 0;
+}
+
+
+static void kill_dhcp_client(struct sigma_dut *dut, const char *ifname)
+{
+#ifdef __linux__
+ char buf[200];
+ char path[128];
+ struct stat s;
+
+#ifdef ANDROID
+ snprintf(path, sizeof(path), "/data/misc/dhcp/dhcpcd-%s.pid", ifname);
+#else /* ANDROID */
+ snprintf(path, sizeof(path), "/var/run/dhclient-%s.pid", ifname);
+#endif /* ANDROID */
+ if (stat(path, &s) == 0) {
+ snprintf(buf, sizeof(buf), "kill `cat %s`", path);
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Kill previous DHCP client: %s", buf);
+ if (system(buf) != 0)
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to kill DHCP client");
+ unlink(path);
+ sleep(1);
+ } else {
+ snprintf(path, sizeof(path), "/var/run/dhcpcd-%s.pid", ifname);
+
+ if (stat(path, &s) == 0) {
+ snprintf(buf, sizeof(buf), "kill `cat %s`", path);
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Kill previous DHCP client: %s", buf);
+ if (system(buf) != 0)
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to kill DHCP client");
+ unlink(path);
+ sleep(1);
+ }
+ }
+#endif /* __linux__ */
+}
+
+
+static int start_dhcp_client(struct sigma_dut *dut, const char *ifname)
+{
+#ifdef __linux__
+ char buf[200];
+
+#ifdef ANDROID
+ snprintf(buf, sizeof(buf),
+ "/system/bin/dhcpcd -b %s", ifname);
+#else /* ANDROID */
+ snprintf(buf, sizeof(buf),
+ "dhclient -nw -pf /var/run/dhclient-%s.pid %s",
+ ifname, ifname);
+#endif /* ANDROID */
+ sigma_dut_print(dut, DUT_MSG_INFO, "Start DHCP client: %s", buf);
+ if (system(buf) != 0) {
+ snprintf(buf, sizeof(buf), "dhcpcd -t 0 %s &", ifname);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to start DHCP client");
+#ifndef ANDROID
+ return -1;
+#endif /* ANDROID */
+ }
+ }
+#endif /* __linux__ */
+
+ return 0;
+}
+
+
+static int clear_ip_addr(struct sigma_dut *dut, const char *ifname)
+{
+#ifdef __linux__
+ char buf[200];
+
+ snprintf(buf, sizeof(buf), "ip addr flush dev %s", ifname);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to clear IP addresses");
+ return -1;
+ }
+#endif /* __linux__ */
+
+ return 0;
+}
+
+
+#ifdef ANDROID
+static int add_ipv6_rule(struct sigma_dut *dut, const char *ifname)
+{
+ char cmd[200], *result, *pos;
+ FILE *fp;
+ int len, tableid, result_len = 1000;
+
+ snprintf(cmd, sizeof(cmd), "ip -6 route list table all | grep %s",
+ ifname);
+ fp = popen(cmd, "r");
+ if (fp == NULL)
+ return -1;
+
+ result = malloc(result_len);
+ if (result == NULL)
+ return -1;
+
+ len = fread(result, 1, result_len, fp);
+ fclose(fp);
+
+ if (len == 0) {
+ free(result);
+ return -1;
+ }
+
+ pos = strstr(result, "table ");
+ if (pos == NULL) {
+ free(result);
+ return -1;
+ }
+
+ pos += strlen("table ");
+ tableid = atoi(pos);
+ if (tableid != 0) {
+ if (system("ip -6 rule del prio 22000") != 0) {
+ /* ignore any error */
+ }
+ snprintf(cmd, sizeof(cmd),
+ "ip -6 rule add from all lookup %d prio 22000",
+ tableid);
+ if (system(cmd) != 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to run %s", cmd);
+ free(result);
+ return -1;
+ }
+ } else {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "No Valid Table Id found %s", pos);
+ free(result);
+ return -1;
+ }
+ free(result);
+
+ return 0;
+}
+#endif /* ANDROID */
+
+
+static int cmd_sta_set_ip_config(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname;
+ char buf[200];
+ const char *val, *ip, *mask, *gw;
+ int type = 1;
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ if (if_nametoindex(ifname) == 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unknown interface");
+ return 0;
+ }
+
+ val = get_param(cmd, "Type");
+ if (val) {
+ type = atoi(val);
+ if (type != 1 && type != 2) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported address type");
+ return 0;
+ }
+ }
+
+ dut->last_set_ip_config_ipv6 = 0;
+
+ val = get_param(cmd, "dhcp");
+ if (val && (strcmp(val, "1") == 0 || strcasecmp(val, "true") == 0)) {
+ static_ip_file(0, NULL, NULL, NULL);
+#ifdef __linux__
+ if (type == 2) {
+ dut->last_set_ip_config_ipv6 = 1;
+ sigma_dut_print(dut, DUT_MSG_INFO, "Using IPv6 "
+ "stateless address autoconfiguration");
+#ifdef ANDROID
+ /*
+ * This sleep is required as the assignment in case of
+ * Android is taking time and is done by the kernel.
+ * The subsequent ping for IPv6 is impacting HS20 test
+ * case.
+ */
+ sleep(2);
+ add_ipv6_rule(dut, intf);
+#endif /* ANDROID */
+ /* Assume this happens by default */
+ return 1;
+ }
+
+ kill_dhcp_client(dut, ifname);
+ if (start_dhcp_client(dut, ifname) < 0)
+ return -2;
+ return 1;
+#endif /* __linux__ */
+ return -2;
+ }
+
+ ip = get_param(cmd, "ip");
+ mask = get_param(cmd, "mask");
+
+ if (type == 2) {
+ int net = atoi(mask);
+
+ if ((net < 0 && net > 64) || !is_ipv6_addr(ip))
+ return -1;
+
+ if (dut->no_ip_addr_set) {
+ snprintf(buf, sizeof(buf),
+ "sysctl net.ipv6.conf.%s.disable_ipv6=1",
+ ifname);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Failed to disable IPv6 address before association");
+ }
+ } else {
+ snprintf(buf, sizeof(buf),
+ "ip -6 addr del %s/%s dev %s",
+ ip, mask, ifname);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ /*
+ * This command may fail if the address being
+ * deleted does not exist. Inaction here is
+ * intentional.
+ */
+ }
+
+ snprintf(buf, sizeof(buf),
+ "ip -6 addr add %s/%s dev %s",
+ ip, mask, ifname);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set IPv6 address");
+ return 0;
+ }
+ }
+
+ dut->last_set_ip_config_ipv6 = 1;
+ static_ip_file(6, ip, mask, NULL);
+ return 1;
+ } else if (type == 1) {
+ if (ip == NULL || !is_ip_addr(ip) ||
+ mask == NULL || !is_ip_addr(mask))
+ return -1;
+ }
+
+ kill_dhcp_client(dut, ifname);
+
+ if (!dut->no_ip_addr_set) {
+ snprintf(buf, sizeof(buf), "ifconfig %s %s netmask %s",
+ ifname, ip, mask);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set IP address");
+ return 0;
+ }
+ }
+
+ gw = get_param(cmd, "defaultGateway");
+ if (gw) {
+ if (!is_ip_addr(gw))
+ return -1;
+ snprintf(buf, sizeof(buf), "route add default gw %s", gw);
+ if (!dut->no_ip_addr_set && system(buf) != 0) {
+ snprintf(buf, sizeof(buf), "ip ro re default via %s",
+ gw);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed "
+ "to set default gateway");
+ return 0;
+ }
+ }
+ }
+
+ val = get_param(cmd, "primary-dns");
+ if (val) {
+ /* TODO */
+ sigma_dut_print(dut, DUT_MSG_INFO, "Ignored primary-dns %s "
+ "setting", val);
+ }
+
+ val = get_param(cmd, "secondary-dns");
+ if (val) {
+ /* TODO */
+ sigma_dut_print(dut, DUT_MSG_INFO, "Ignored secondary-dns %s "
+ "setting", val);
+ }
+
+ static_ip_file(4, ip, mask, gw);
+
+ return 1;
+}
+
+
+static int cmd_sta_get_info(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ /* const char *intf = get_param(cmd, "Interface"); */
+ /* TODO: could report more details here */
+ send_resp(dut, conn, SIGMA_COMPLETE, "vendor,Atheros");
+ return 0;
+}
+
+
+static int cmd_sta_get_mac_address(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ /* const char *intf = get_param(cmd, "Interface"); */
+ char addr[20], resp[50];
+
+ if (get_wpa_status(get_station_ifname(), "address", addr, sizeof(addr))
+ < 0)
+ return -2;
+
+ snprintf(resp, sizeof(resp), "mac,%s", addr);
+ send_resp(dut, conn, SIGMA_COMPLETE, resp);
+ return 0;
+}
+
+
+static int cmd_sta_is_connected(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ /* const char *intf = get_param(cmd, "Interface"); */
+ int connected = 0;
+ char result[32];
+ if (get_wpa_status(get_station_ifname(), "wpa_state", result,
+ sizeof(result)) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Could not get interface "
+ "%s status", get_station_ifname());
+ return -2;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "wpa_state=%s", result);
+ if (strncmp(result, "COMPLETED", 9) == 0)
+ connected = 1;
+
+ if (connected)
+ send_resp(dut, conn, SIGMA_COMPLETE, "connected,1");
+ else
+ send_resp(dut, conn, SIGMA_COMPLETE, "connected,0");
+
+ return 0;
+}
+
+
+static int cmd_sta_verify_ip_connection(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ /* const char *intf = get_param(cmd, "Interface"); */
+ const char *dst, *timeout;
+ int wait_time = 90;
+ char buf[100];
+ int res;
+
+ dst = get_param(cmd, "destination");
+ if (dst == NULL || !is_ip_addr(dst))
+ return -1;
+
+ timeout = get_param(cmd, "timeout");
+ if (timeout) {
+ wait_time = atoi(timeout);
+ if (wait_time < 1)
+ wait_time = 1;
+ }
+
+ /* TODO: force renewal of IP lease if DHCP is enabled */
+
+ snprintf(buf, sizeof(buf), "ping %s -c 3 -W %d", dst, wait_time);
+ res = system(buf);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "ping returned: %d", res);
+ if (res == 0)
+ send_resp(dut, conn, SIGMA_COMPLETE, "connected,1");
+ else if (res == 256)
+ send_resp(dut, conn, SIGMA_COMPLETE, "connected,0");
+ else
+ return -2;
+
+ return 0;
+}
+
+
+static int cmd_sta_get_bssid(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ /* const char *intf = get_param(cmd, "Interface"); */
+ char bssid[20], resp[50];
+
+ if (get_wpa_status(get_station_ifname(), "bssid", bssid, sizeof(bssid))
+ < 0)
+ strncpy(bssid, "00:00:00:00:00:00", sizeof(bssid));
+
+ snprintf(resp, sizeof(resp), "bssid,%s", bssid);
+ send_resp(dut, conn, SIGMA_COMPLETE, resp);
+ return 0;
+}
+
+
+#ifdef __SAMSUNG__
+static int add_use_network(const char *ifname)
+{
+ char buf[100];
+
+ snprintf(buf, sizeof(buf), "USE_NETWORK ON");
+ wpa_command(ifname, buf);
+ return 0;
+}
+#endif /* __SAMSUNG__ */
+
+
+static int add_network_common(struct sigma_dut *dut, struct sigma_conn *conn,
+ const char *ifname, struct sigma_cmd *cmd)
+{
+ const char *ssid = get_param(cmd, "ssid");
+ int id;
+ const char *val;
+
+ if (ssid == NULL)
+ return -1;
+
+ start_sta_mode(dut);
+
+#ifdef __SAMSUNG__
+ add_use_network(ifname);
+#endif /* __SAMSUNG__ */
+
+ id = add_network(ifname);
+ if (id < 0)
+ return -2;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Adding network %d", id);
+
+ if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
+ return -2;
+
+ dut->infra_network_id = id;
+ snprintf(dut->infra_ssid, sizeof(dut->infra_ssid), "%s", ssid);
+
+ val = get_param(cmd, "program");
+ if (!val)
+ val = get_param(cmd, "prog");
+ if (val && strcasecmp(val, "hs2") == 0) {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "ENABLE_NETWORK %d no-connect", id);
+ wpa_command(ifname, buf);
+
+ val = get_param(cmd, "prefer");
+ if (val && atoi(val) > 0)
+ set_network(ifname, id, "priority", "1");
+ }
+
+ return id;
+}
+
+
+static int cmd_sta_set_encryption(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ssid = get_param(cmd, "ssid");
+ const char *type = get_param(cmd, "encpType");
+ const char *ifname;
+ char buf[200];
+ int id;
+
+ if (intf == NULL || ssid == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = add_network_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
+ return -2;
+
+ if (type && strcasecmp(type, "wep") == 0) {
+ const char *val;
+ int i;
+
+ val = get_param(cmd, "activeKey");
+ if (val) {
+ int keyid;
+ keyid = atoi(val);
+ if (keyid < 1 || keyid > 4)
+ return -1;
+ snprintf(buf, sizeof(buf), "%d", keyid - 1);
+ if (set_network(ifname, id, "wep_tx_keyidx", buf) < 0)
+ return -2;
+ }
+
+ for (i = 0; i < 4; i++) {
+ snprintf(buf, sizeof(buf), "key%d", i + 1);
+ val = get_param(cmd, buf);
+ if (val == NULL)
+ continue;
+ snprintf(buf, sizeof(buf), "wep_key%d", i);
+ if (set_network(ifname, id, buf, val) < 0)
+ return -2;
+ }
+ }
+
+ return 1;
+}
+
+
+static int set_wpa_common(struct sigma_dut *dut, struct sigma_conn *conn,
+ const char *ifname, struct sigma_cmd *cmd)
+{
+ const char *val;
+ int id;
+
+ id = add_network_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ val = get_param(cmd, "keyMgmtType");
+ if (val == NULL) {
+ send_resp(dut, conn, SIGMA_INVALID, "errorCode,Missing keyMgmtType");
+ return 0;
+ }
+ if (strcasecmp(val, "wpa") == 0 ||
+ strcasecmp(val, "wpa-psk") == 0) {
+ if (set_network(ifname, id, "proto", "WPA") < 0)
+ return -2;
+ } else if (strcasecmp(val, "wpa2") == 0 ||
+ strcasecmp(val, "wpa2-psk") == 0 ||
+ strcasecmp(val, "wpa2-ft") == 0 ||
+ strcasecmp(val, "wpa2-sha256") == 0) {
+ if (set_network(ifname, id, "proto", "WPA2") < 0)
+ return -2;
+ } else if (strcasecmp(val, "wpa2-wpa-psk") == 0) {
+ if (set_network(ifname, id, "proto", "WPA WPA2") < 0)
+ return -2;
+ } else {
+ send_resp(dut, conn, SIGMA_INVALID, "errorCode,Unrecognized keyMgmtType value");
+ return 0;
+ }
+
+ val = get_param(cmd, "encpType");
+ if (val == NULL) {
+ send_resp(dut, conn, SIGMA_INVALID, "errorCode,Missing encpType");
+ return 0;
+ }
+ if (strcasecmp(val, "tkip") == 0) {
+ if (set_network(ifname, id, "pairwise", "TKIP") < 0)
+ return -2;
+ } else if (strcasecmp(val, "aes-ccmp") == 0) {
+ if (set_network(ifname, id, "pairwise", "CCMP") < 0)
+ return -2;
+ } else if (strcasecmp(val, "aes-ccmp-tkip") == 0) {
+ if (set_network(ifname, id, "pairwise", "CCMP TKIP") < 0)
+ return -2;
+ } else if (strcasecmp(val, "aes-gcmp") == 0) {
+ if (set_network(ifname, id, "pairwise", "GCMP") < 0)
+ return -2;
+ if (set_network(ifname, id, "group", "GCMP") < 0)
+ return -2;
+ } else {
+ send_resp(dut, conn, SIGMA_INVALID, "errorCode,Unrecognized encpType value");
+ return 0;
+ }
+
+ dut->sta_pmf = STA_PMF_DISABLED;
+ val = get_param(cmd, "PMF");
+ if (val) {
+ if (strcasecmp(val, "Required") == 0 ||
+ strcasecmp(val, "Forced_Required") == 0) {
+ dut->sta_pmf = STA_PMF_REQUIRED;
+ if (set_network(ifname, id, "ieee80211w", "2") < 0)
+ return -2;
+ } else if (strcasecmp(val, "Optional") == 0) {
+ dut->sta_pmf = STA_PMF_OPTIONAL;
+ if (set_network(ifname, id, "ieee80211w", "1") < 0)
+ return -2;
+ } else if (strcasecmp(val, "Disabled") == 0 ||
+ strcasecmp(val, "Forced_Disabled") == 0) {
+ dut->sta_pmf = STA_PMF_DISABLED;
+ } else {
+ send_resp(dut, conn, SIGMA_INVALID, "errorCode,Unrecognized PMF value");
+ return 0;
+ }
+ }
+
+ return id;
+}
+
+
+static int cmd_sta_set_psk(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname, *val, *alg;
+ int id;
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = set_wpa_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ val = get_param(cmd, "keyMgmtType");
+ alg = get_param(cmd, "micAlg");
+
+ if (alg && strcasecmp(alg, "SHA-256") == 0) {
+ if (set_network(ifname, id, "key_mgmt", "WPA-PSK-SHA256") < 0)
+ return -2;
+ } else if (alg && strcasecmp(alg, "SHA-1") == 0) {
+ if (set_network(ifname, id, "key_mgmt", "WPA-PSK") < 0)
+ return -2;
+ } else if ((val && strcasecmp(val, "wpa2-sha256") == 0) ||
+ dut->sta_pmf == STA_PMF_REQUIRED) {
+ if (set_network(ifname, id, "key_mgmt",
+ "WPA-PSK WPA-PSK-SHA256") < 0)
+ return -2;
+ } else if (dut->sta_pmf == STA_PMF_OPTIONAL) {
+ if (set_network(ifname, id, "key_mgmt",
+ "WPA-PSK WPA-PSK-SHA256") < 0)
+ return -2;
+ } else {
+ if (set_network(ifname, id, "key_mgmt", "WPA-PSK") < 0)
+ return -2;
+ }
+
+ val = get_param(cmd, "passPhrase");
+ if (val == NULL)
+ return -1;
+ if (set_network_quoted(ifname, id, "psk", val) < 0)
+ return -2;
+
+ return 1;
+}
+
+
+static int set_eap_common(struct sigma_dut *dut, struct sigma_conn *conn,
+ const char *ifname, struct sigma_cmd *cmd)
+{
+ const char *val, *alg;
+ int id;
+ char buf[200];
+#ifdef ANDROID
+ unsigned char kvalue[KEYSTORE_MESSAGE_SIZE];
+ int length;
+#endif /* ANDROID */
+
+ id = set_wpa_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ val = get_param(cmd, "keyMgmtType");
+ alg = get_param(cmd, "micAlg");
+
+ if (alg && strcasecmp(alg, "SHA-256") == 0) {
+ if (set_network(ifname, id, "key_mgmt", "WPA-EAP-SHA256") < 0)
+ return -2;
+ } else if (alg && strcasecmp(alg, "SHA-1") == 0) {
+ if (set_network(ifname, id, "key_mgmt", "WPA-EAP") < 0)
+ return -2;
+ } else if (val && strcasecmp(val, "wpa2-ft") == 0) {
+ if (set_network(ifname, id, "key_mgmt", "FT-EAP") < 0)
+ return -2;
+ } else if ((val && strcasecmp(val, "wpa2-sha256") == 0) ||
+ dut->sta_pmf == STA_PMF_REQUIRED) {
+ if (set_network(ifname, id, "key_mgmt",
+ "WPA-EAP WPA-EAP-SHA256") < 0)
+ return -2;
+ } else if (dut->sta_pmf == STA_PMF_OPTIONAL) {
+ if (set_network(ifname, id, "key_mgmt",
+ "WPA-EAP WPA-EAP-SHA256") < 0)
+ return -2;
+ } else {
+ if (set_network(ifname, id, "key_mgmt", "WPA-EAP") < 0)
+ return -2;
+ }
+
+ val = get_param(cmd, "trustedRootCA");
+ if (val) {
+#ifdef ANDROID
+ snprintf(buf, sizeof(buf), "CACERT_%s", val);
+ length = android_keystore_get(ANDROID_KEYSTORE_GET, buf,
+ kvalue);
+ if (length > 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Use Android keystore [%s]", buf);
+ snprintf(buf, sizeof(buf), "keystore://CACERT_%s",
+ val);
+ goto ca_cert_selected;
+ }
+#endif /* ANDROID */
+
+ snprintf(buf, sizeof(buf), "%s/%s", sigma_cert_path, val);
+#ifdef __linux__
+ if (!file_exists(buf)) {
+ char msg[300];
+ snprintf(msg, sizeof(msg), "ErrorCode,trustedRootCA "
+ "file (%s) not found", buf);
+ send_resp(dut, conn, SIGMA_ERROR, msg);
+ return -3;
+ }
+#endif /* __linux__ */
+#ifdef ANDROID
+ca_cert_selected:
+#endif /* ANDROID */
+ if (set_network_quoted(ifname, id, "ca_cert", buf) < 0)
+ return -2;
+ }
+
+ val = get_param(cmd, "username");
+ if (val) {
+ if (set_network_quoted(ifname, id, "identity", val) < 0)
+ return -2;
+ }
+
+ val = get_param(cmd, "password");
+ if (val) {
+ if (set_network_quoted(ifname, id, "password", val) < 0)
+ return -2;
+ }
+
+ return id;
+}
+
+
+static int cmd_sta_set_eaptls(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname, *val;
+ int id;
+ char buf[200];
+#ifdef ANDROID
+ unsigned char kvalue[KEYSTORE_MESSAGE_SIZE];
+ int length;
+ int jb_or_newer = 0;
+ char prop[PROPERTY_VALUE_MAX];
+#endif /* ANDROID */
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = set_eap_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "eap", "TLS") < 0)
+ return -2;
+
+ if (set_network_quoted(ifname, id, "identity",
+ "wifi-user@wifilabs.local") < 0)
+ return -2;
+
+ val = get_param(cmd, "clientCertificate");
+ if (val == NULL)
+ return -1;
+#ifdef ANDROID
+ snprintf(buf, sizeof(buf), "USRPKEY_%s", val);
+ length = android_keystore_get(ANDROID_KEYSTORE_GET, buf, kvalue);
+ if (length < 0) {
+ /*
+ * JB started reporting keystore type mismatches, so retry with
+ * the GET_PUBKEY command if the generic GET fails.
+ */
+ length = android_keystore_get(ANDROID_KEYSTORE_GET_PUBKEY,
+ buf, kvalue);
+ }
+
+ if (property_get("ro.build.version.release", prop, NULL) != 0) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Android release %s", prop);
+ if (strncmp(prop, "4.0", 3) != 0)
+ jb_or_newer = 1;
+ } else
+ jb_or_newer = 1; /* assume newer */
+
+ if (jb_or_newer && length > 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Use Android keystore [%s]", buf);
+ if (set_network(ifname, id, "engine", "1") < 0)
+ return -2;
+ if (set_network_quoted(ifname, id, "engine_id", "keystore") < 0)
+ return -2;
+ snprintf(buf, sizeof(buf), "USRPKEY_%s", val);
+ if (set_network_quoted(ifname, id, "key_id", buf) < 0)
+ return -2;
+ snprintf(buf, sizeof(buf), "keystore://USRCERT_%s", val);
+ if (set_network_quoted(ifname, id, "client_cert", buf) < 0)
+ return -2;
+ return 1;
+ } else if (length > 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Use Android keystore [%s]", buf);
+ snprintf(buf, sizeof(buf), "keystore://USRPKEY_%s", val);
+ if (set_network_quoted(ifname, id, "private_key", buf) < 0)
+ return -2;
+ snprintf(buf, sizeof(buf), "keystore://USRCERT_%s", val);
+ if (set_network_quoted(ifname, id, "client_cert", buf) < 0)
+ return -2;
+ return 1;
+ }
+#endif /* ANDROID */
+
+ snprintf(buf, sizeof(buf), "%s/%s", sigma_cert_path, val);
+#ifdef __linux__
+ if (!file_exists(buf)) {
+ char msg[300];
+ snprintf(msg, sizeof(msg), "ErrorCode,clientCertificate file "
+ "(%s) not found", buf);
+ send_resp(dut, conn, SIGMA_ERROR, msg);
+ return -3;
+ }
+#endif /* __linux__ */
+ if (set_network_quoted(ifname, id, "private_key", buf) < 0)
+ return -2;
+ if (set_network_quoted(ifname, id, "client_cert", buf) < 0)
+ return -2;
+
+ if (set_network_quoted(ifname, id, "private_key_passwd", "wifi") < 0)
+ return -2;
+
+ return 1;
+}
+
+
+static int cmd_sta_set_eapttls(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname;
+ int id;
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = set_eap_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "eap", "TTLS") < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set TTLS method");
+ return 0;
+ }
+
+ if (set_network_quoted(ifname, id, "phase2", "auth=MSCHAPV2") < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set MSCHAPv2 for TTLS Phase 2");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_set_eapsim(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname;
+ int id;
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = set_eap_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "eap", "SIM") < 0)
+ return -2;
+
+ return 1;
+}
+
+
+static int cmd_sta_set_peap(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname, *val;
+ int id;
+ char buf[100];
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = set_eap_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "eap", "PEAP") < 0)
+ return -2;
+
+ val = get_param(cmd, "innerEAP");
+ if (val) {
+ if (strcasecmp(val, "MSCHAPv2") == 0) {
+ if (set_network_quoted(ifname, id, "phase2",
+ "auth=MSCHAPV2") < 0)
+ return -2;
+ } else if (strcasecmp(val, "GTC") == 0) {
+ if (set_network_quoted(ifname, id, "phase2",
+ "auth=GTC") < 0)
+ return -2;
+ } else
+ return -1;
+ }
+
+ val = get_param(cmd, "peapVersion");
+ if (val) {
+ int ver = atoi(val);
+ if (ver < 0 || ver > 1)
+ return -1;
+ snprintf(buf, sizeof(buf), "peapver=%d", ver);
+ if (set_network_quoted(ifname, id, "phase1", buf) < 0)
+ return -2;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_set_eapfast(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname, *val;
+ int id;
+ char buf[100];
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = set_eap_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "eap", "FAST") < 0)
+ return -2;
+
+ val = get_param(cmd, "innerEAP");
+ if (val) {
+ if (strcasecmp(val, "MSCHAPV2") == 0) {
+ if (set_network_quoted(ifname, id, "phase2",
+ "auth=MSCHAPV2") < 0)
+ return -2;
+ } else if (strcasecmp(val, "GTC") == 0) {
+ if (set_network_quoted(ifname, id, "phase2",
+ "auth=GTC") < 0)
+ return -2;
+ } else
+ return -1;
+ }
+
+ val = get_param(cmd, "validateServer");
+ if (val) {
+ /* TODO */
+ sigma_dut_print(dut, DUT_MSG_INFO, "Ignored EAP-FAST "
+ "validateServer=%s", val);
+ }
+
+ val = get_param(cmd, "pacFile");
+ if (val) {
+ snprintf(buf, sizeof(buf), "blob://%s", val);
+ if (set_network_quoted(ifname, id, "pac_file", buf) < 0)
+ return -2;
+ }
+
+ if (set_network_quoted(ifname, id, "phase1", "fast_provisioning=2") <
+ 0)
+ return -2;
+
+ return 1;
+}
+
+
+static int cmd_sta_set_eapaka(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname;
+ int id;
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = set_eap_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "eap", "AKA") < 0)
+ return -2;
+
+ return 1;
+}
+
+
+static int cmd_sta_set_eapakaprime(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname;
+ int id;
+
+ if (intf == NULL)
+ return -1;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = set_eap_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "eap", "AKA'") < 0)
+ return -2;
+
+ return 1;
+}
+
+
+static int sta_set_open(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *ifname;
+ int id;
+
+ if (strcmp(intf, get_main_ifname()) == 0)
+ ifname = get_station_ifname();
+ else
+ ifname = intf;
+
+ id = add_network_common(dut, conn, ifname, cmd);
+ if (id < 0)
+ return id;
+
+ if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
+ return -2;
+
+ return 1;
+}
+
+
+static int cmd_sta_set_security(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *type = get_param(cmd, "Type");
+
+ if (type == NULL) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing Type argument");
+ return 0;
+ }
+
+ if (strcasecmp(type, "OPEN") == 0)
+ return sta_set_open(dut, conn, cmd);
+ if (strcasecmp(type, "PSK") == 0)
+ return cmd_sta_set_psk(dut, conn, cmd);
+ if (strcasecmp(type, "EAPTLS") == 0)
+ return cmd_sta_set_eaptls(dut, conn, cmd);
+ if (strcasecmp(type, "EAPTTLS") == 0)
+ return cmd_sta_set_eapttls(dut, conn, cmd);
+ if (strcasecmp(type, "EAPPEAP") == 0)
+ return cmd_sta_set_peap(dut, conn, cmd);
+ if (strcasecmp(type, "EAPSIM") == 0)
+ return cmd_sta_set_eapsim(dut, conn, cmd);
+ if (strcasecmp(type, "EAPFAST") == 0)
+ return cmd_sta_set_eapfast(dut, conn, cmd);
+ if (strcasecmp(type, "EAPAKA") == 0)
+ return cmd_sta_set_eapaka(dut, conn, cmd);
+ if (strcasecmp(type, "EAPAKAPRIME") == 0)
+ return cmd_sta_set_eapakaprime(dut, conn, cmd);
+
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported Type value");
+ return 0;
+}
+
+
+int ath6kl_client_uapsd(struct sigma_dut *dut, const char *intf, int uapsd)
+{
+#ifdef __linux__
+ /* special handling for ath6kl */
+ char path[128], fname[128], *pos;
+ ssize_t res;
+ FILE *f;
+
+ snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", intf);
+ res = readlink(path, path, sizeof(path));
+ if (res < 0)
+ return 0; /* not ath6kl */
+
+ if (res >= (int) sizeof(path))
+ res = sizeof(path) - 1;
+ path[res] = '\0';
+ pos = strrchr(path, '/');
+ if (pos == NULL)
+ pos = path;
+ else
+ pos++;
+ snprintf(fname, sizeof(fname),
+ "/sys/kernel/debug/ieee80211/%s/ath6kl/"
+ "create_qos", pos);
+ if (!file_exists(fname))
+ return 0; /* not ath6kl */
+
+ if (uapsd) {
+ f = fopen(fname, "w");
+ if (f == NULL)
+ return -1;
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Use ath6kl create_qos");
+ fprintf(f, "4 2 2 1 2 9999999 9999999 9999999 7777777 0 4 "
+ "45000 200 56789000 56789000 5678900 0 0 9999999 "
+ "20000 0\n");
+ fclose(f);
+ } else {
+ snprintf(fname, sizeof(fname),
+ "/sys/kernel/debug/ieee80211/%s/ath6kl/"
+ "delete_qos", pos);
+
+ f = fopen(fname, "w");
+ if (f == NULL)
+ return -1;
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Use ath6kl delete_qos");
+ fprintf(f, "2 4\n");
+ fclose(f);
+ }
+#endif /* __linux__ */
+
+ return 0;
+}
+
+
+static int cmd_sta_set_uapsd(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ /* const char *ssid = get_param(cmd, "ssid"); */
+ const char *val;
+ int max_sp_len = 4;
+ int ac_be = 1, ac_bk = 1, ac_vi = 1, ac_vo = 1;
+ char buf[100];
+ int ret1, ret2;
+
+ val = get_param(cmd, "maxSPLength");
+ if (val) {
+ max_sp_len = atoi(val);
+ if (max_sp_len != 0 && max_sp_len != 1 && max_sp_len != 2 &&
+ max_sp_len != 4)
+ return -1;
+ }
+
+ val = get_param(cmd, "acBE");
+ if (val)
+ ac_be = atoi(val);
+
+ val = get_param(cmd, "acBK");
+ if (val)
+ ac_bk = atoi(val);
+
+ val = get_param(cmd, "acVI");
+ if (val)
+ ac_vi = atoi(val);
+
+ val = get_param(cmd, "acVO");
+ if (val)
+ ac_vo = atoi(val);
+
+ dut->client_uapsd = ac_be || ac_bk || ac_vi || ac_vo;
+
+ snprintf(buf, sizeof(buf), "P2P_SET client_apsd %d,%d,%d,%d;%d",
+ ac_be, ac_bk, ac_vi, ac_vo, max_sp_len);
+ ret1 = wpa_command(intf, buf);
+
+ snprintf(buf, sizeof(buf), "SET uapsd %d,%d,%d,%d;%d",
+ ac_be, ac_bk, ac_vi, ac_vo, max_sp_len);
+ ret2 = wpa_command(intf, buf);
+
+ if (ret1 && ret2) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to set client mode "
+ "UAPSD parameters.");
+ return -2;
+ }
+
+ if (ath6kl_client_uapsd(dut, intf, dut->client_uapsd) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set ath6kl QoS parameters");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_set_wmm(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ char buf[1000];
+ const char *intf = get_param(cmd, "Interface");
+ const char *grp = get_param(cmd, "Group");
+ const char *act = get_param(cmd, "Action");
+ const char *tid = get_param(cmd, "Tid");
+ const char *dir = get_param(cmd, "Direction");
+ const char *psb = get_param(cmd, "Psb");
+ const char *up = get_param(cmd, "Up");
+ const char *fixed = get_param(cmd, "Fixed");
+ const char *size = get_param(cmd, "Size");
+ const char *msize = get_param(cmd, "Maxsize");
+ const char *minsi = get_param(cmd, "Min_srvc_intrvl");
+ const char *maxsi = get_param(cmd, "Max_srvc_intrvl");
+ const char *inact = get_param(cmd, "Inactivity");
+ const char *sus = get_param(cmd, "Suspension");
+ const char *mindr = get_param(cmd, "Mindatarate");
+ const char *meandr = get_param(cmd, "Meandatarate");
+ const char *peakdr = get_param(cmd, "Peakdatarate");
+ const char *phyrate = get_param(cmd, "Phyrate");
+ const char *burstsize = get_param(cmd, "Burstsize");
+ const char *sba = get_param(cmd, "Sba");
+ int direction;
+ int handle;
+ float sba_fv;
+ int fixed_int;
+ int psb_ts;
+
+ if (intf == NULL || grp == NULL || act == NULL )
+ return -1;
+
+ if (strcasecmp(act, "addts") == 0) {
+ if (tid == NULL || dir == NULL || psb == NULL ||
+ up == NULL || fixed == NULL || size == NULL)
+ return -1;
+
+ /*
+ * Note: Sigma CAPI spec lists uplink, downlink, and bidi as the
+ * possible values, but WMM-AC and V-E test scripts use "UP,
+ * "DOWN", and "BIDI".
+ */
+ if (strcasecmp(dir, "uplink") == 0 ||
+ strcasecmp(dir, "up") == 0) {
+ direction = 0;
+ } else if (strcasecmp(dir, "downlink") == 0 ||
+ strcasecmp(dir, "down") == 0) {
+ direction = 1;
+ } else if (strcasecmp(dir, "bidi") == 0) {
+ direction = 2;
+ } else {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Direction %s not supported", dir);
+ return -1;
+ }
+
+ if (strcasecmp(psb, "legacy") == 0) {
+ psb_ts = 0;
+ } else if (strcasecmp(psb, "uapsd") == 0) {
+ psb_ts = 1;
+ } else {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "PSB %s not supported", psb);
+ return -1;
+ }
+
+ if (atoi(tid) < 0 || atoi(tid) > 7) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "TID %s not supported", tid);
+ return -1;
+ }
+
+ if (strcasecmp(fixed, "true") == 0) {
+ fixed_int = 1;
+ } else {
+ fixed_int = 0;
+ }
+
+ sba_fv = atof(sba);
+
+ dut->dialog_token++;
+ handle = 7000 + dut->dialog_token;
+
+ /*
+ * size: convert to hex
+ * maxsi: convert to hex
+ * mindr: convert to hex
+ * meandr: convert to hex
+ * peakdr: convert to hex
+ * burstsize: convert to hex
+ * phyrate: convert to hex
+ * sba: convert to hex with modification
+ * minsi: convert to integer
+ * sus: convert to integer
+ * inact: convert to integer
+ * maxsi: convert to integer
+ */
+
+ /*
+ * The Nominal MSDU Size field is 2 octets long and contains an
+ * unsigned integer that specifies the nominal size, in octets,
+ * of MSDUs belonging to the traffic under this traffic
+ * specification and is defined in Figure 16. If the Fixed
+ * subfield is set to 1, then the size of the MSDU is fixed and
+ * is indicated by the Size Subfield. If the Fixed subfield is
+ * set to 0, then the size of the MSDU might not be fixed and
+ * the Size indicates the nominal MSDU size.
+ *
+ * The Surplus Bandwidth Allowance Factor field is 2 octets long
+ * and specifies the excess allocation of time (and bandwidth)
+ * over and above the stated rates required to transport an MSDU
+ * belonging to the traffic in this TSPEC. This field is
+ * represented as an unsigned binary number with an implicit
+ * binary point after the leftmost 3 bits. For example, an SBA
+ * of 1.75 is represented as 0x3800. This field is included to
+ * account for retransmissions. As such, the value of this field
+ * must be greater than unity.
+ */
+
+ snprintf(buf, sizeof(buf),
+ "iwpriv %s addTspec %d %s %d %d %s 0x%X"
+ " 0x%X 0x%X 0x%X"
+ " 0x%X 0x%X 0x%X"
+ " 0x%X %d %d %d %d"
+ " %d %d",
+ intf, handle, tid, direction, psb_ts, up,
+ (unsigned int) ((fixed_int << 15) | atoi(size)),
+ msize ? atoi(msize) : 0,
+ mindr ? atoi(mindr) : 0,
+ meandr ? atoi(meandr) : 0,
+ peakdr ? atoi(peakdr) : 0,
+ burstsize ? atoi(burstsize) : 0,
+ phyrate ? atoi(phyrate) : 0,
+ sba ? ((unsigned int) (((int) sba_fv << 13) |
+ (int)((sba_fv - (int) sba_fv) *
+ 8192))) : 0,
+ minsi ? atoi(minsi) : 0,
+ sus ? atoi(sus) : 0,
+ 0, 0,
+ inact ? atoi(inact) : 0,
+ maxsi ? atoi(maxsi) : 0);
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv addtspec request failed");
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to execute addTspec command");
+ return 0;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "iwpriv addtspec request send");
+
+ /* Mapping handle to a TID */
+ dut->tid_to_handle[atoi(tid)] = handle;
+ } else if (strcasecmp(act, "delts") == 0) {
+ if (tid == NULL)
+ return -1;
+
+ if (atoi(tid) < 0 || atoi(tid) > 7) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "TID %s not supported", tid);
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unsupported TID");
+ return 0;
+ }
+
+ handle = dut->tid_to_handle[atoi(tid)];
+
+ if (handle < 7000 || handle > 7255) {
+ /* Invalid handle ie no mapping for that TID */
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "handle-> %d not found", handle);
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s delTspec %d",
+ intf, handle);
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv deltspec request failed");
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to execute delTspec command");
+ return 0;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "iwpriv deltspec request send");
+
+ dut->tid_to_handle[atoi(tid)] = 0;
+ } else {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Action type %s not supported", act);
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unsupported Action");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_associate(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ /* const char *intf = get_param(cmd, "Interface"); */
+ const char *ssid = get_param(cmd, "ssid");
+ const char *wps_param = get_param(cmd, "WPS");
+ const char *bssid = get_param(cmd, "bssid");
+ int wps = 0;
+ char buf[100];
+
+ if (ssid == NULL)
+ return -1;
+
+ if (wps_param &&
+ (strcmp(wps_param, "1") == 0 || strcasecmp(wps_param, "On") == 0))
+ wps = 1;
+
+ if (wps) {
+ if (dut->wps_method == WFA_CS_WPS_NOT_READY) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,WPS "
+ "parameters not yet set");
+ return 0;
+ }
+ if (dut->wps_method == WFA_CS_WPS_PBC) {
+ if (wpa_command(get_station_ifname(), "WPS_PBC") < 0)
+ return -2;
+ } else {
+ snprintf(buf, sizeof(buf), "WPS_PIN any %s",
+ dut->wps_pin);
+ if (wpa_command(get_station_ifname(), buf) < 0)
+ return -2;
+ }
+ } else {
+ if (strcmp(ssid, dut->infra_ssid) != 0) {
+ printf("No network parameters known for network "
+ "(ssid='%s')", ssid);
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,"
+ "No network parameters known for network");
+ return 0;
+ }
+
+ if (bssid &&
+ set_network(get_station_ifname(), dut->infra_network_id,
+ "bssid", bssid) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,"
+ "Invalid bssid argument");
+ return 0;
+ }
+
+ snprintf(buf, sizeof(buf), "SELECT_NETWORK %d",
+ dut->infra_network_id);
+ if (wpa_command(get_station_ifname(), buf) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to select "
+ "network id %d on %s",
+ dut->infra_network_id,
+ get_station_ifname());
+ return -2;
+ }
+ }
+
+ return 1;
+}
+
+
+static int run_hs20_osu(struct sigma_dut *dut, const char *params)
+{
+ char buf[500], cmd[200];
+ int res;
+
+ /* Use hs20-osu-client file at the current dir, if found; otherwise use
+ * default path */
+ res = snprintf(cmd, sizeof(cmd),
+ "%s -w \"%s\" -r hs20-osu-client.res %s%s -dddKt -f Logs/hs20-osu-client.txt",
+ file_exists("./hs20-osu-client") ?
+ "./hs20-osu-client" : "hs20-osu-client",
+ sigma_wpas_ctrl,
+ dut->summary_log ? "-s " : "",
+ dut->summary_log ? dut->summary_log : "");
+ if (res < 0 || res >= (int) sizeof(cmd))
+ return -1;
+
+ res = snprintf(buf, sizeof(buf), "%s %s", cmd, params);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to run: %s", buf);
+ return -1;
+ }
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Completed hs20-osu-client operation");
+
+ return 0;
+}
+
+
+static int download_ppsmo(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *intf,
+ struct sigma_cmd *cmd)
+{
+ const char *name, *path, *val;
+ char url[500], buf[600], fbuf[100];
+ char *fqdn = NULL;
+
+ name = get_param(cmd, "FileName");
+ path = get_param(cmd, "FilePath");
+ if (name == NULL || path == NULL)
+ return -1;
+
+ if (strcasecmp(path, "VendorSpecific") == 0) {
+ snprintf(url, sizeof(url), "PPS/%s", name);
+ sigma_dut_print(dut, DUT_MSG_INFO, "Use pre-configured PPS MO "
+ "from the device (%s)", url);
+ if (!file_exists(url)) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Requested "
+ "PPS MO file does not exist");
+ return 0;
+ }
+ snprintf(buf, sizeof(buf), "cp %s pps-tnds.xml", url);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to copy PPS MO");
+ return 0;
+ }
+ } else if (strncasecmp(path, "http:", 5) != 0 &&
+ strncasecmp(path, "https:", 6) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,"
+ "Unsupported FilePath value");
+ return 0;
+ } else {
+ snprintf(url, sizeof(url), "%s/%s", path, name);
+ sigma_dut_print(dut, DUT_MSG_INFO, "Downloading PPS MO from %s",
+ url);
+ snprintf(buf, sizeof(buf), "wget -T 10 -t 3 -O pps-tnds.xml '%s'", url);
+ remove("pps-tnds.xml");
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to download PPS MO");
+ return 0;
+ }
+ }
+
+ if (run_hs20_osu(dut, "from_tnds pps-tnds.xml pps.xml") < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to parse downloaded PPSMO");
+ return 0;
+ }
+ unlink("pps-tnds.xml");
+
+ val = get_param(cmd, "managementTreeURI");
+ if (val) {
+ const char *pos, *end;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "managementTreeURI: %s",
+ val);
+ if (strncmp(val, "./Wi-Fi/", 8) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Invalid managementTreeURI prefix");
+ return 0;
+ }
+ pos = val + 8;
+ end = strchr(pos, '/');
+ if (end == NULL ||
+ strcmp(end, "/PerProviderSubscription") != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Invalid managementTreeURI postfix");
+ return 0;
+ }
+ if (end - pos >= (int) sizeof(fbuf)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Too long FQDN in managementTreeURI");
+ return 0;
+ }
+ memcpy(fbuf, pos, end - pos);
+ fbuf[end - pos] = '\0';
+ fqdn = fbuf;
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "FQDN from managementTreeURI: %s", fqdn);
+ } else if (run_hs20_osu(dut, "get_fqdn pps.xml") == 0) {
+ FILE *f = fopen("pps-fqdn", "r");
+ if (f) {
+ if (fgets(fbuf, sizeof(fbuf), f)) {
+ fbuf[sizeof(fbuf) - 1] = '\0';
+ fqdn = fbuf;
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Use FQDN %s", fqdn);
+ }
+ fclose(f);
+ }
+ }
+
+ if (fqdn == NULL) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,No FQDN specified");
+ return 0;
+ }
+
+ mkdir("SP", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ snprintf(buf, sizeof(buf), "SP/%s", fqdn);
+ mkdir(buf, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+
+ snprintf(buf, sizeof(buf), "SP/%s/pps.xml", fqdn);
+ if (rename("pps.xml", buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not move PPS MO");
+ return 0;
+ }
+
+ if (strcasecmp(path, "VendorSpecific") == 0) {
+ snprintf(buf, sizeof(buf), "cp Certs/ca.pem SP/%s/ca.pem",
+ fqdn);
+ if (system(buf)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to copy OSU CA cert");
+ return 0;
+ }
+
+ snprintf(buf, sizeof(buf),
+ "cp Certs/aaa-ca.pem SP/%s/aaa-ca.pem",
+ fqdn);
+ if (system(buf)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to copy AAA CA cert");
+ return 0;
+ }
+ } else {
+ snprintf(buf, sizeof(buf),
+ "dl_osu_ca SP/%s/pps.xml SP/%s/ca.pem",
+ fqdn, fqdn);
+ if (run_hs20_osu(dut, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to download OSU CA cert");
+ return 0;
+ }
+
+ snprintf(buf, sizeof(buf),
+ "dl_aaa_ca SP/%s/pps.xml SP/%s/aaa-ca.pem",
+ fqdn, fqdn);
+ if (run_hs20_osu(dut, buf) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to download AAA CA cert");
+ }
+ }
+
+ if (file_exists("next-client-cert.pem")) {
+ snprintf(buf, sizeof(buf), "SP/%s/client-cert.pem", fqdn);
+ if (rename("next-client-cert.pem", buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not move client certificate");
+ return 0;
+ }
+ }
+
+ if (file_exists("next-client-key.pem")) {
+ snprintf(buf, sizeof(buf), "SP/%s/client-key.pem", fqdn);
+ if (rename("next-client-key.pem", buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not move client key");
+ return 0;
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "set_pps SP/%s/pps.xml", fqdn);
+ if (run_hs20_osu(dut, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to configure credential from "
+ "PPSMO");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int download_cert(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *intf,
+ struct sigma_cmd *cmd)
+{
+ const char *name, *path;
+ char url[500], buf[600];
+
+ name = get_param(cmd, "FileName");
+ path = get_param(cmd, "FilePath");
+ if (name == NULL || path == NULL)
+ return -1;
+
+ if (strcasecmp(path, "VendorSpecific") == 0) {
+ snprintf(url, sizeof(url), "Certs/%s-cert.pem", name);
+ sigma_dut_print(dut, DUT_MSG_INFO, "Use pre-configured client "
+ "certificate from the device (%s)", url);
+ if (!file_exists(url)) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Requested "
+ "certificate file does not exist");
+ return 0;
+ }
+ snprintf(buf, sizeof(buf), "cp %s next-client-cert.pem", url);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to copy client "
+ "certificate");
+ return 0;
+ }
+
+ snprintf(url, sizeof(url), "Certs/%s-key.pem", name);
+ sigma_dut_print(dut, DUT_MSG_INFO, "Use pre-configured client "
+ "private key from the device (%s)", url);
+ if (!file_exists(url)) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Requested "
+ "private key file does not exist");
+ return 0;
+ }
+ snprintf(buf, sizeof(buf), "cp %s next-client-key.pem", url);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to copy client key");
+ return 0;
+ }
+ } else if (strncasecmp(path, "http:", 5) != 0 &&
+ strncasecmp(path, "https:", 6) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,"
+ "Unsupported FilePath value");
+ return 0;
+ } else {
+ snprintf(url, sizeof(url), "%s/%s.pem", path, name);
+ sigma_dut_print(dut, DUT_MSG_INFO, "Downloading client "
+ "certificate/key from %s", url);
+ snprintf(buf, sizeof(buf),
+ "wget -T 10 -t 3 -O next-client-cert.pem '%s'", url);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to download client "
+ "certificate");
+ return 0;
+ }
+
+ if (system("cp next-client-cert.pem next-client-key.pem") != 0)
+ {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to copy client key");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_preset_testparameters_hs2_r2(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *intf,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+
+ val = get_param(cmd, "FileType");
+ if (val && strcasecmp(val, "PPSMO") == 0)
+ return download_ppsmo(dut, conn, intf, cmd);
+ if (val && strcasecmp(val, "CERT") == 0)
+ return download_cert(dut, conn, intf, cmd);
+ if (val) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported FileType");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void ath_sta_set_noack(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ int counter = 0;
+ char token[50];
+ char *result;
+ char buf[100];
+
+ strncpy(token, val, sizeof(token));
+ token[sizeof(token) - 1] = '\0';
+ result = strtok(token, ":");
+ while (result) {
+ if (strcmp(result, "disable") == 0) {
+ snprintf(buf, sizeof(buf),
+ "iwpriv %s noackpolicy %d 1 0",
+ intf, counter);
+ } else {
+ snprintf(buf, sizeof(buf),
+ "iwpriv %s noackpolicy %d 1 1",
+ intf, counter);
+ }
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv noackpolicy failed");
+ }
+ result = strtok(NULL, ":");
+ counter++;
+ }
+}
+
+
+static void ath_sta_set_rts(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[100];
+
+ snprintf(buf, sizeof(buf), "iwconfig %s rts %s", intf, val);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "iwconfig RTS failed");
+ }
+}
+
+
+static void ath_sta_set_wmm(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[100];
+
+ if (strcasecmp(val, "off") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s wmm 0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to turn off WMM");
+ }
+ }
+}
+
+
+static void ath_sta_set_sgi(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[100];
+ int sgi20;
+
+ sgi20 = strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0;
+
+ snprintf(buf, sizeof(buf), "iwpriv %s shortgi %d", intf, sgi20);
+ if (system(buf) != 0)
+ sigma_dut_print(dut, DUT_MSG_ERROR, "iwpriv shortgi failed");
+}
+
+
+static void ath_sta_set_11nrates(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[100];
+ int rate_code;
+
+ /* Disable Tx Beam forming when using a fixed rate */
+ ath_disable_txbf(dut, intf);
+
+ rate_code = 0x80 + atoi(val);
+
+ snprintf(buf, sizeof(buf), "iwpriv %s set11NRates 0x%x",
+ intf, rate_code);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv set11NRates failed");
+ }
+
+ /* Channel width gets messed up, fix this */
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth %d", intf, dut->chwidth);
+ if (system(buf) != 0)
+ sigma_dut_print(dut, DUT_MSG_ERROR, "iwpriv chwidth failed");
+}
+
+
+static void ath_sta_set_amsdu(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[60];
+
+ if (strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0)
+ snprintf(buf, sizeof(buf), "iwpriv %s amsdu 2", intf);
+ else
+ snprintf(buf, sizeof(buf), "iwpriv %s amsdu 1", intf);
+
+ if (system(buf) != 0)
+ sigma_dut_print(dut, DUT_MSG_ERROR, "iwpriv amsdu failed");
+}
+
+
+static void ath_sta_set_stbc(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[60];
+
+ snprintf(buf, sizeof(buf), "iwpriv %s tx_stbc %s", intf, val);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv tx_stbc failed");
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s rx_stbc %s", intf, val);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv rx_stbc failed");
+ }
+}
+
+
+static int wcn_sta_set_cts_width(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[60];
+
+ if (strcmp(val, "80") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s cts_cbw 3", intf);
+ } else if (strcmp(val, "40") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s cts_cbw 2", intf);
+ } else if (strcmp(val, "20") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s cts_cbw 1", intf);
+ } else if (strcasecmp(val, "Auto") == 0) {
+ buf[0] = '\0';
+ } else {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "WIDTH/CTS_WIDTH value not supported");
+ return -1;
+ }
+
+ if (buf[0] != '\0' && system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set WIDTH/CTS_WIDTH");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int ath_set_width(struct sigma_dut *dut, struct sigma_conn *conn,
+ const char *intf, const char *val)
+{
+ char buf[60];
+
+ if (strcasecmp(val, "Auto") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth 0", intf);
+ dut->chwidth = 0;
+ } else if (strcasecmp(val, "20") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth 0", intf);
+ dut->chwidth = 0;
+ } else if (strcasecmp(val, "40") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth 1", intf);
+ dut->chwidth = 1;
+ } else if (strcasecmp(val, "80") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth 2", intf);
+ dut->chwidth = 2;
+ } else if (strcasecmp(val, "160") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth 3", intf);
+ dut->chwidth = 3;
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,WIDTH not supported");
+ return -1;
+ }
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv chwidth failed");
+ }
+
+ return 0;
+}
+
+
+static int wcn_sta_set_sp_stream(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[60];
+
+ if (strcmp(val, "1SS") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s nss 1", intf);
+ } else if (strcmp(val, "2SS") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s nss 2", intf);
+ } else {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "SP_STREAM value not supported");
+ return -1;
+ }
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set SP_STREAM");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int cmd_sta_preset_testparameters(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val;
+
+ val = get_param(cmd, "Program");
+ if (val && strcasecmp(val, "HS2-R2") == 0) {
+ if (intf == NULL)
+ return -1;
+ return cmd_sta_preset_testparameters_hs2_r2(dut, conn, intf,
+ cmd);
+ }
+
+#ifdef ANDROID_NAN
+ if (val && strcasecmp(val, "NAN") == 0)
+ return nan_cmd_sta_preset_testparameters(dut, conn, cmd);
+#endif /* ANDROID_NAN */
+
+#if 0
+ val = get_param(cmd, "Supplicant");
+ if (val && strcasecmp(val, "Default") != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Only default(Vendor) supplicant "
+ "supported");
+ return 0;
+ }
+#endif
+
+ val = get_param(cmd, "RTS");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_sta_set_rts(dut, intf, val);
+ break;
+ default:
+#if 0
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Setting RTS not supported");
+ return 0;
+#else
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Setting RTS not supported");
+ break;
+#endif
+ }
+ }
+
+#if 0
+ val = get_param(cmd, "FRGMNT");
+ if (val) {
+ /* TODO */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Setting FRGMNT not supported");
+ return 0;
+ }
+#endif
+
+#if 0
+ val = get_param(cmd, "Preamble");
+ if (val) {
+ /* TODO: Long/Short */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Setting Preamble not supported");
+ return 0;
+ }
+#endif
+
+ val = get_param(cmd, "Mode");
+ if (val) {
+ if (strcmp(val, "11b") == 0 ||
+ strcmp(val, "11g") == 0 ||
+ strcmp(val, "11a") == 0 ||
+ strcmp(val, "11n") == 0 ||
+ strcmp(val, "11ng") == 0 ||
+ strcmp(val, "11nl") == 0 ||
+ strcmp(val, "11nl(nabg)") == 0 ||
+ strcmp(val, "AC") == 0 ||
+ strcmp(val, "11AC") == 0 ||
+ strcmp(val, "11ac") == 0 ||
+ strcmp(val, "11na") == 0 ||
+ strcmp(val, "11an") == 0) {
+ /* STA supports all modes by default */
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Setting Mode not supported");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "wmm");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_sta_set_wmm(dut, intf, val);
+ break;
+ default:
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Setting wmm not supported");
+ break;
+ }
+ }
+
+ val = get_param(cmd, "Powersave");
+ if (val) {
+ if (strcmp(val, "0") == 0 || strcasecmp(val, "off") == 0) {
+ if (wpa_command(get_station_ifname(),
+ "P2P_SET ps 0") < 0)
+ return -2;
+ /* Make sure test modes are disabled */
+ wpa_command(get_station_ifname(), "P2P_SET ps 98");
+ wpa_command(get_station_ifname(), "P2P_SET ps 96");
+ } else if (strcmp(val, "1") == 0 ||
+ strcasecmp(val, "PSPoll") == 0 ||
+ strcasecmp(val, "on") == 0) {
+ /* Disable default power save mode */
+ wpa_command(get_station_ifname(), "P2P_SET ps 0");
+ /* Enable PS-Poll test mode */
+ if (wpa_command(get_station_ifname(),
+ "P2P_SET ps 97") < 0 ||
+ wpa_command(get_station_ifname(),
+ "P2P_SET ps 99") < 0)
+ return -2;
+ } else if (strcmp(val, "2") == 0 ||
+ strcasecmp(val, "Fast") == 0) {
+ /* TODO */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Powersave=Fast not supported");
+ return 0;
+ } else if (strcmp(val, "3") == 0 ||
+ strcasecmp(val, "PSNonPoll") == 0) {
+ /* Make sure test modes are disabled */
+ wpa_command(get_station_ifname(), "P2P_SET ps 98");
+ wpa_command(get_station_ifname(), "P2P_SET ps 96");
+
+ /* Enable default power save mode */
+ if (wpa_command(get_station_ifname(),
+ "P2P_SET ps 1") < 0)
+ return -2;
+ } else
+ return -1;
+ }
+
+ val = get_param(cmd, "NoAck");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_sta_set_noack(dut, intf, val);
+ break;
+ default:
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Setting NoAck not supported");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "IgnoreChswitchProhibit");
+ if (val) {
+ /* TODO: Enabled/disabled */
+ if (strcasecmp(val, "Enabled") == 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Enabling IgnoreChswitchProhibit "
+ "not supported");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "TDLS");
+ if (val) {
+ if (strcasecmp(val, "Disabled") == 0) {
+ if (wpa_command(intf, "SET tdls_disabled 1")) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to disable TDLS");
+ return 0;
+ }
+ } else if (strcasecmp(val, "Enabled") == 0) {
+ if (wpa_command(intf, "SET tdls_disabled 0")) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to enable TDLS");
+ return 0;
+ }
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported TDLS value");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "TDLSmode");
+ if (val) {
+ if (strcasecmp(val, "Default") == 0) {
+ wpa_command(intf, "SET tdls_testing 0");
+ } else if (strcasecmp(val, "APProhibit") == 0) {
+ if (wpa_command(intf, "SET tdls_testing 0x400")) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to enable ignore "
+ "APProhibit TDLS mode");
+ return 0;
+ }
+ } else if (strcasecmp(val, "HiLoMac") == 0) {
+ /* STA should respond with TDLS setup req for a TDLS
+ * setup req */
+ if (wpa_command(intf, "SET tdls_testing 0x80")) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to enable HiLoMac "
+ "TDLS mode");
+ return 0;
+ }
+ } else if (strcasecmp(val, "WeakSecurity") == 0) {
+ /*
+ * Since all security modes are enabled by default when
+ * Sigma control is used, there is no need to do
+ * anything here.
+ */
+ } else if (strcasecmp(val, "ExistLink") == 0) {
+ /*
+ * Since we allow new TDLS Setup Request even if there
+ * is an existing link, nothing needs to be done for
+ * this.
+ */
+ } else {
+ /* TODO:
+ * ExistLink: STA should send TDLS setup req even if
+ * direct link already exists
+ */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported TDLSmode value");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "FakePubKey");
+ if (val && atoi(val) && wpa_command(intf, "SET wps_corrupt_pkhash 1")) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to enable FakePubKey");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static const char * ath_get_radio_name(const char *radio_name)
+{
+ if (radio_name == NULL)
+ return "wifi0";
+ if (strcmp(radio_name, "wifi1") == 0)
+ return "wifi1";
+ if (strcmp(radio_name, "wifi2") == 0)
+ return "wifi2";
+ return "wifi0";
+}
+
+
+static void ath_sta_set_txsp_stream(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[60];
+ unsigned int vht_mcsmap = 0;
+ int txchainmask = 0;
+ const char *basedev = ath_get_radio_name(sigma_radio_ifname[0]);
+
+ if (strcasecmp(val, "1") == 0 || strcasecmp(val, "1SS") == 0) {
+ if (dut->testbed_flag_txsp == 1) {
+ vht_mcsmap = 0xfffc;
+ dut->testbed_flag_txsp = 0;
+ } else {
+ vht_mcsmap = 0xfffe;
+ }
+ txchainmask = 1;
+ } else if (strcasecmp(val, "2") == 0 || strcasecmp(val, "2SS") == 0) {
+ if (dut->testbed_flag_txsp == 1) {
+ vht_mcsmap = 0xfff0;
+ dut->testbed_flag_txsp = 0;
+ } else {
+ vht_mcsmap = 0xfffa;
+ }
+ txchainmask = 3;
+ } else if (strcasecmp(val, "3") == 0 || strcasecmp(val, "3SS") == 0) {
+ if (dut->testbed_flag_txsp == 1) {
+ vht_mcsmap = 0xffc0;
+ dut->testbed_flag_txsp = 0;
+ } else {
+ vht_mcsmap = 0xffea;
+ }
+ txchainmask = 7;
+ } else if (strcasecmp(val, "4") == 0 || strcasecmp(val, "4SS") == 0) {
+ if (dut->testbed_flag_txsp == 1) {
+ vht_mcsmap = 0xff00;
+ dut->testbed_flag_txsp = 0;
+ } else {
+ vht_mcsmap = 0xffaa;
+ }
+ txchainmask = 15;
+ } else {
+ if (dut->testbed_flag_txsp == 1) {
+ vht_mcsmap = 0xffc0;
+ dut->testbed_flag_txsp = 0;
+ } else {
+ vht_mcsmap = 0xffea;
+ }
+ }
+
+ if (txchainmask) {
+ snprintf(buf, sizeof(buf), "iwpriv %s txchainmask %d",
+ basedev, txchainmask);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv txchainmask failed");
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s vht_mcsmap 0x%04x",
+ intf, vht_mcsmap);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s vht_mcsmap 0x%04x failed",
+ intf, vht_mcsmap);
+ }
+}
+
+
+static void ath_sta_set_rxsp_stream(struct sigma_dut *dut, const char *intf,
+ const char *val)
+{
+ char buf[60];
+ unsigned int vht_mcsmap = 0;
+ int rxchainmask = 0;
+ const char *basedev = ath_get_radio_name(sigma_radio_ifname[0]);
+
+ if (strcasecmp(val, "1") == 0 || strcasecmp(val, "1SS") == 0) {
+ if (dut->testbed_flag_rxsp == 1) {
+ vht_mcsmap = 0xfffc;
+ dut->testbed_flag_rxsp = 0;
+ } else {
+ vht_mcsmap = 0xfffe;
+ }
+ rxchainmask = 1;
+ } else if (strcasecmp(val, "2") == 0 || strcasecmp(val, "2SS") == 0) {
+ if (dut->testbed_flag_rxsp == 1) {
+ vht_mcsmap = 0xfff0;
+ dut->testbed_flag_rxsp = 0;
+ } else {
+ vht_mcsmap = 0xfffa;
+ }
+ rxchainmask = 3;
+ } else if (strcasecmp(val, "3") == 0 || strcasecmp(val, "3SS") == 0) {
+ if (dut->testbed_flag_rxsp == 1) {
+ vht_mcsmap = 0xffc0;
+ dut->testbed_flag_rxsp = 0;
+ } else {
+ vht_mcsmap = 0xffea;
+ }
+ rxchainmask = 7;
+ } else if (strcasecmp(val, "4") == 0 || strcasecmp(val, "4SS") == 0) {
+ if (dut->testbed_flag_rxsp == 1) {
+ vht_mcsmap = 0xff00;
+ dut->testbed_flag_rxsp = 0;
+ } else {
+ vht_mcsmap = 0xffaa;
+ }
+ rxchainmask = 15;
+ } else {
+ if (dut->testbed_flag_rxsp == 1) {
+ vht_mcsmap = 0xffc0;
+ dut->testbed_flag_rxsp = 0;
+ } else {
+ vht_mcsmap = 0xffea;
+ }
+ }
+
+ if (rxchainmask) {
+ snprintf(buf, sizeof(buf), "iwpriv %s rxchainmask %d",
+ basedev, rxchainmask);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv rxchainmask failed");
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s vht_mcsmap 0x%04x",
+ intf, vht_mcsmap);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s vht_mcsmap 0x%04x",
+ intf, vht_mcsmap);
+ }
+}
+
+
+void ath_set_zero_crc(struct sigma_dut *dut, const char *val)
+{
+ if (strcasecmp(val, "enable") == 0) {
+ if (system("athdiag --set --address=0x2a204 --and=0xbfffffff")
+ != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Disable BB_VHTSIGB_CRC_CALC failed");
+ }
+
+ if (system("athdiag --set --address=0x2a204 --or=0x80000000")
+ != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Enable FORCE_VHT_SIGB_CRC_VALUE_ZERO failed");
+ }
+ } else {
+ if (system("athdiag --set --address=0x2a204 --and=0x7fffffff")
+ != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Disable FORCE_VHT_SIGB_CRC_VALUE_ZERO failed");
+ }
+
+ if (system("athdiag --set --address=0x2a204 --or=0x40000000")
+ != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Enable BB_VHTSIGB_CRC_CALC failed");
+ }
+ }
+}
+
+
+static int cmd_sta_set_wireless_common(const char *intf, struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ int ampdu = -1;
+ char buf[30];
+
+ val = get_param(cmd, "40_INTOLERANT");
+ if (val) {
+ if (strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0) {
+ /* TODO: iwpriv ht40intol through wpa_supplicant */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,40_INTOLERANT not supported");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "ADDBA_REJECT");
+ if (val) {
+ if (strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0) {
+ /* reject any ADDBA with status "decline" */
+ ampdu = 0;
+ } else {
+ /* accept ADDBA */
+ ampdu = 1;
+ }
+ }
+
+ val = get_param(cmd, "AMPDU");
+ if (val) {
+ if (strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0) {
+ /* enable AMPDU Aggregation */
+ if (ampdu == 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Mismatch in "
+ "addba_reject/ampdu - "
+ "not supported");
+ return 0;
+ }
+ ampdu = 1;
+ } else {
+ /* disable AMPDU Aggregation */
+ if (ampdu == 1) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Mismatch in "
+ "addba_reject/ampdu - "
+ "not supported");
+ return 0;
+ }
+ ampdu = 0;
+ }
+ }
+
+ if (ampdu >= 0) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "%s A-MPDU aggregation",
+ ampdu ? "Enabling" : "Disabling");
+ snprintf(buf, sizeof(buf), "SET ampdu %d", ampdu);
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,set aggr failed");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "AMSDU");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_sta_set_amsdu(dut, intf, val);
+ break;
+ default:
+ if (strcmp(val, "1") == 0 ||
+ strcasecmp(val, "Enable") == 0) {
+ /* Enable AMSDU Aggregation */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,AMSDU aggregation not supported");
+ return 0;
+ }
+ break;
+ }
+ }
+
+ val = get_param(cmd, "STBC_RX");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_sta_set_stbc(dut, intf, val);
+ break;
+ default:
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,STBC_RX not supported");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "WIDTH");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_WCN:
+ if (wcn_sta_set_cts_width(dut, intf, val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set WIDTH");
+ return 0;
+ }
+ break;
+ case DRIVER_ATHEROS:
+ if (ath_set_width(dut, conn, intf, val) < 0)
+ return 0;
+ break;
+ default:
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Setting WIDTH not supported");
+ break;
+ }
+ }
+
+ val = get_param(cmd, "SMPS");
+ if (val) {
+ /* TODO: Dynamic/0, Static/1, No Limit/2 */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,SMPS not supported");
+ return 0;
+ }
+
+ val = get_param(cmd, "TXSP_STREAM");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_WCN:
+ if (wcn_sta_set_sp_stream(dut, intf, val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set TXSP_STREAM");
+ return 0;
+ }
+ break;
+ case DRIVER_ATHEROS:
+ ath_sta_set_txsp_stream(dut, intf, val);
+ break;
+ default:
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Setting TXSP_STREAM not supported");
+ break;
+ }
+ }
+
+ val = get_param(cmd, "RXSP_STREAM");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_WCN:
+ if (wcn_sta_set_sp_stream(dut, intf, val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set RXSP_STREAM");
+ return 0;
+ }
+ break;
+ case DRIVER_ATHEROS:
+ ath_sta_set_rxsp_stream(dut, intf, val);
+ break;
+ default:
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Setting RXSP_STREAM not supported");
+ break;
+ }
+ }
+
+ val = get_param(cmd, "DYN_BW_SGNL");
+ if (val) {
+ if (strcasecmp(val, "Enable") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s cwmenable 1",
+ intf);
+ } else if (strcasecmp(val, "Disable") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s cwmenable 0",
+ intf);
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,DYN_BW_SGNL value not supported");
+ return 0;
+ }
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set DYN_BW_SGNL");
+ }
+
+ if (get_driver_type() == DRIVER_WCN) {
+ snprintf(buf, sizeof(buf), "iwpriv %s cts_cbw 3", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set cts_cbw in DYN_BW_SGNL");
+ return 0;
+ }
+ }
+
+ }
+
+ val = get_param(cmd, "RTS_FORCE");
+ if (val) {
+ if (strcasecmp(val, "Enable") == 0) {
+ snprintf(buf, sizeof(buf), "iwconfig %s rts 64", intf);
+ } else if (strcasecmp(val, "Disable") == 0) {
+ snprintf(buf, sizeof(buf), "iwconfig %s rts 2347",
+ intf);
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,RTS_FORCE value not supported");
+ return 0;
+ }
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set RTS_FORCE");
+ }
+ }
+
+ val = get_param(cmd, "CTS_WIDTH");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_WCN:
+ if (wcn_sta_set_cts_width(dut, intf, val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set CTS_WIDTH");
+ return 0;
+ }
+ break;
+ case DRIVER_ATHEROS:
+ ath_set_cts_width(dut, intf, val);
+ break;
+ default:
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Setting CTS_WIDTH not supported");
+ break;
+ }
+ }
+
+ val = get_param(cmd, "BW_SGNL");
+ if (val) {
+ if (strcasecmp(val, "Enable") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s cwmenable 1",
+ intf);
+ } else if (strcasecmp(val, "Disable") == 0) {
+ /* TODO: Disable */
+ buf[0] = '\0';
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,BW_SGNL value not supported");
+ return 0;
+ }
+
+ if (buf[0] != '\0' && system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set BW_SGNL");
+ }
+ }
+
+ val = get_param(cmd, "Band");
+ if (val) {
+ if (strcmp(val, "2.4") == 0 || strcmp(val, "5") == 0) {
+ /* STA supports all bands by default */
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported Band");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "zero_crc");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_set_zero_crc(dut, val);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 1;
+}
+
+
+static int sta_set_60g_common(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ char buf[100];
+
+ val = get_param(cmd, "MSDUSize");
+ if (val) {
+ int mtu;
+
+ dut->amsdu_size = atoi(val);
+ if (dut->amsdu_size > IEEE80211_MAX_DATA_LEN_DMG ||
+ dut->amsdu_size < IEEE80211_SNAP_LEN_DMG) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "MSDUSize %d is above max %d or below min %d",
+ dut->amsdu_size,
+ IEEE80211_MAX_DATA_LEN_DMG,
+ IEEE80211_SNAP_LEN_DMG);
+ dut->amsdu_size = 0;
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ mtu = dut->amsdu_size - IEEE80211_SNAP_LEN_DMG;
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Setting amsdu_size to %d", mtu);
+ snprintf(buf, sizeof(buf), "ifconfig %s mtu %d",
+ get_station_ifname(), mtu);
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to set %s",
+ buf);
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+ }
+
+ val = get_param(cmd, "BAckRcvBuf");
+ if (val) {
+ dut->back_rcv_buf = atoi(val);
+ if (dut->back_rcv_buf == 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to convert %s or value is 0",
+ val);
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Setting BAckRcvBuf to %s", val);
+ }
+
+ return SIGMA_DUT_SUCCESS_CALLER_SEND_STATUS;
+}
+
+
+static int sta_pcp_start(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ int net_id;
+ char *ifname;
+ const char *val;
+ char buf[100];
+
+ dut->mode = SIGMA_MODE_STATION;
+ ifname = get_main_ifname();
+ if (wpa_command(ifname, "PING") != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Supplicant not running");
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ wpa_command(ifname, "FLUSH");
+ net_id = add_network_common(dut, conn, ifname, cmd);
+ if (net_id < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to add network");
+ return net_id;
+ }
+
+ /* TODO: mode=2 for the AP; in the future, replace for mode PCP */
+ if (set_network(ifname, net_id, "mode", "2") < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set supplicant network mode");
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Supplicant set network with mode 2");
+
+ val = get_param(cmd, "Security");
+ if (val && strcasecmp(val, "OPEN") == 0) {
+ dut->ap_key_mgmt = AP_OPEN;
+ if (set_network(ifname, net_id, "key_mgmt", "NONE") < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set supplicant to %s security",
+ val);
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+ } else if (val && strcasecmp(val, "WPA2-PSK") == 0) {
+ dut->ap_key_mgmt = AP_WPA2_PSK;
+ if (set_network(ifname, net_id, "key_mgmt", "WPA-PSK") < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set supplicant to %s security",
+ val);
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ if (set_network(ifname, net_id, "proto", "RSN") < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set supplicant to proto RSN");
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+ } else if (val) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Requested Security %s is not supported on 60GHz",
+ val);
+ return SIGMA_DUT_INVALID_CALLER_SEND_STATUS;
+ }
+
+ val = get_param(cmd, "Encrypt");
+ if (val && strcasecmp(val, "AES-GCMP") == 0) {
+ if (set_network(ifname, net_id, "pairwise", "GCMP") < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set supplicant to pairwise GCMP");
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+ if (set_network(ifname, net_id, "group", "GCMP") < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set supplicant to group GCMP");
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+ } else if (val) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Requested Encrypt %s is not supported on 60 GHz",
+ val);
+ return SIGMA_DUT_INVALID_CALLER_SEND_STATUS;
+ }
+
+ val = get_param(cmd, "PSK");
+ if (val && set_network_quoted(ifname, net_id, "psk", val) < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to set psk %s",
+ val);
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ /* Convert 60G channel to freq */
+ switch (dut->ap_channel) {
+ case 1:
+ val = "58320";
+ break;
+ case 2:
+ val = "60480";
+ break;
+ case 3:
+ val = "62640";
+ break;
+ default:
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to configure channel %d. Not supported",
+ dut->ap_channel);
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ if (set_network(ifname, net_id, "frequency", val) < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to set supplicant network frequency");
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Supplicant set network with frequency");
+
+ snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", net_id);
+ if (wpa_command(ifname, buf) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to select network id %d on %s",
+ net_id, ifname);
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Selected network");
+
+ return SIGMA_DUT_SUCCESS_CALLER_SEND_STATUS;
+}
+
+
+static int sta_set_60g_pcp(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+
+ if (dut->dev_role != DEVROLE_PCP) {
+ send_resp(dut, conn, SIGMA_INVALID,
+ "ErrorCode,Invalid DevRole");
+ return 0;
+ }
+
+ val = get_param(cmd, "SSID");
+ if (val) {
+ if (strlen(val) > sizeof(dut->ap_ssid) - 1) {
+ send_resp(dut, conn, SIGMA_INVALID,
+ "ErrorCode,Invalid SSID");
+ return -1;
+ }
+
+ strncpy(dut->ap_ssid, val, sizeof(dut->ap_ssid));
+ }
+
+ val = get_param(cmd, "CHANNEL");
+ if (val) {
+ const char *pos;
+
+ dut->ap_channel = atoi(val);
+ pos = strchr(val, ';');
+ if (pos) {
+ pos++;
+ dut->ap_channel_1 = atoi(pos);
+ }
+ }
+
+ switch (dut->ap_channel) {
+ case 1:
+ case 2:
+ case 3:
+ break;
+ default:
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Channel %d is not supported", dut->ap_channel);
+ send_resp(dut, conn, SIGMA_ERROR,
+ "Requested channel is not supported");
+ return -1;
+ }
+
+ val = get_param(cmd, "BCNINT");
+ if (val)
+ dut->ap_bcnint = atoi(val);
+
+
+ val = get_param(cmd, "ExtSchIE");
+ if (val) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,ExtSchIE is not supported yet");
+ return -1;
+ }
+
+ val = get_param(cmd, "AllocType");
+ if (val) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,AllocType is not supported yet");
+ return -1;
+ }
+
+ val = get_param(cmd, "PercentBI");
+ if (val) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,PercentBI is not supported yet");
+ return -1;
+ }
+
+ val = get_param(cmd, "CBAPOnly");
+ if (val) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,CBAPOnly is not supported yet");
+ return -1;
+ }
+
+ val = get_param(cmd, "AMPDU");
+ if (val) {
+ if (strcasecmp(val, "Enable") == 0)
+ dut->ap_ampdu = 1;
+ else if (strcasecmp(val, "Disable") == 0)
+ dut->ap_ampdu = 2;
+ else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,AMPDU value is not Enable nor Disabled");
+ return -1;
+ }
+ }
+
+ val = get_param(cmd, "AMSDU");
+ if (val) {
+ if (strcasecmp(val, "Enable") == 0)
+ dut->ap_amsdu = 1;
+ else if (strcasecmp(val, "Disable") == 0)
+ dut->ap_amsdu = 2;
+ }
+
+ val = get_param(cmd, "NumMSDU");
+ if (val) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode, NumMSDU is not supported yet");
+ return -1;
+ }
+
+ val = get_param(cmd, "ABFTLRang");
+ if (val) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Ignoring ABFTLRang parameter since FW default is greater than 1");
+ }
+
+ if (sta_pcp_start(dut, conn, cmd) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode, Can't start PCP role");
+ return -1;
+ }
+
+ return sta_set_60g_common(dut, conn, cmd);
+}
+
+
+static int sta_set_60g_sta(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val = get_param(cmd, "DiscoveryMode");
+
+ if (dut->dev_role != DEVROLE_STA) {
+ send_resp(dut, conn, SIGMA_INVALID,
+ "ErrorCode,Invalid DevRole");
+ return 0;
+ }
+
+ if (val) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Discovery: %s", val);
+ /* Ignore Discovery mode till Driver expose API. */
+#if 0
+ if (strcasecmp(val, "1") == 0) {
+ send_resp(dut, conn, SIGMA_INVALID,
+ "ErrorCode,DiscoveryMode 1 not supported");
+ return 0;
+ }
+
+ if (strcasecmp(val, "0") == 0) {
+ /* OK */
+ } else {
+ send_resp(dut, conn, SIGMA_INVALID,
+ "ErrorCode,DiscoveryMode not supported");
+ return 0;
+ }
+#endif
+ }
+
+ if (start_sta_mode(dut) != 0)
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ return sta_set_60g_common(dut, conn, cmd);
+}
+
+
+static int cmd_sta_disconnect(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ disconnect_station(dut);
+ /* Try to ignore old scan results to avoid HS 2.0R2 test case failures
+ * due to cached results. */
+ wpa_command(intf, "SET ignore_old_scan_res 1");
+ wpa_command(intf, "BSS_FLUSH");
+ return 1;
+}
+
+
+static int cmd_sta_reassoc(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *bssid = get_param(cmd, "bssid");
+ const char *val = get_param(cmd, "CHANNEL");
+ struct wpa_ctrl *ctrl;
+ char buf[100];
+ int res;
+ int chan = 0;
+
+ if (bssid == NULL) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Missing bssid "
+ "argument");
+ return 0;
+ }
+
+ if (val)
+ chan = atoi(val);
+
+ if (wifi_chip_type != DRIVER_WCN && wifi_chip_type != DRIVER_AR6003) {
+ /* The current network may be from sta_associate or
+ * sta_hs2_associate
+ */
+ if (set_network(intf, dut->infra_network_id, "bssid", bssid) <
+ 0 ||
+ set_network(intf, 0, "bssid", bssid) < 0)
+ return -2;
+ }
+
+ ctrl = open_wpa_mon(intf);
+ if (ctrl == NULL) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to open "
+ "wpa_supplicant monitor connection");
+ return -1;
+ }
+
+ if (wifi_chip_type == DRIVER_WCN) {
+#ifdef ANDROID
+ if (set_network(intf, dut->infra_network_id, "bssid", "any")
+ < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to set "
+ "bssid to any during FASTREASSOC");
+ return -2;
+ }
+ res = snprintf(buf, sizeof(buf), "DRIVER FASTREASSOC %s %d",
+ bssid, chan);
+ if (res > 0 && res < (int) sizeof(buf))
+ res = wpa_command(intf, buf);
+
+ if (res < 0 || res >= (int) sizeof(buf)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to run DRIVER FASTREASSOC");
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ return 0;
+ }
+#else /* ANDROID */
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Reassoc using iwpriv - skip chan=%d info",
+ chan);
+ snprintf(buf, sizeof(buf), "iwpriv %s reassoc", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "%s failed", buf);
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ return 0;
+ }
+#endif /* ANDROID */
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "sta_reassoc: Run %s successful", buf);
+ } else if (wpa_command(intf, "REASSOCIATE")) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to "
+ "request reassociation");
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ return 0;
+ }
+
+ res = get_wpa_cli_event(dut, ctrl, "CTRL-EVENT-CONNECTED",
+ buf, sizeof(buf));
+
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+
+ if (res < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Scan did not complete");
+ return -1;
+ }
+
+ return 1;
+}
+
+
+static void hs2_clear_credentials(const char *intf)
+{
+ wpa_command(intf, "REMOVE_CRED all");
+}
+
+
+static int sta_get_parameter_60g(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ char buf[MAX_CMD_LEN];
+ char bss_list[MAX_CMD_LEN];
+ const char *parameter = get_param(cmd, "Parameter");
+
+ if (parameter == NULL)
+ return -1;
+
+ if (strcasecmp(parameter, "DiscoveredDevList") == 0) {
+ char *bss_line;
+ char *bss_id = NULL;
+ const char *ifname = get_param(cmd, "Interface");
+
+ if (ifname == NULL) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "For get DiscoveredDevList need Interface name.");
+ return -1;
+ }
+
+ /*
+ * Use "BSS RANGE=ALL MASK=0x2" which provides a list
+ * of BSSIDs in "bssid=<BSSID>\n"
+ */
+ if (wpa_command_resp(ifname, "BSS RANGE=ALL MASK=0x2",
+ bss_list,
+ sizeof(bss_list)) < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to get bss list");
+ return -1;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "bss list for ifname:%s is:%s",
+ ifname, bss_list);
+
+ snprintf(buf, sizeof(buf), "DeviceList");
+ bss_line = strtok(bss_list, "\n");
+ while (bss_line) {
+ if (sscanf(bss_line, "bssid=%ms", &bss_id) > 0 &&
+ bss_id) {
+ int len;
+
+ len = snprintf(buf + strlen(buf),
+ sizeof(buf) - strlen(buf),
+ ",%s", bss_id);
+ free(bss_id);
+ bss_id = NULL;
+ if (len < 0) {
+ sigma_dut_print(dut,
+ DUT_MSG_ERROR,
+ "Failed to read BSSID");
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to read BSS ID");
+ return 0;
+ }
+
+ if ((size_t) len >= sizeof(buf) - strlen(buf)) {
+ sigma_dut_print(dut,
+ DUT_MSG_ERROR,
+ "Response buf too small for list");
+ send_resp(dut, conn,
+ SIGMA_ERROR,
+ "ErrorCode,Response buf too small for list");
+ return 0;
+ }
+ }
+
+ bss_line = strtok(NULL, "\n");
+ }
+
+ sigma_dut_print(dut, DUT_MSG_INFO, "DiscoveredDevList is %s",
+ buf);
+ send_resp(dut, conn, SIGMA_COMPLETE, buf);
+ return 0;
+ }
+
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Unsupported parameter");
+ return 0;
+}
+
+
+static int cmd_sta_get_parameter(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *program = get_param(cmd, "Program");
+
+ if (program == NULL)
+ return -1;
+
+ if (strcasecmp(program, "P2PNFC") == 0)
+ return p2p_cmd_sta_get_parameter(dut, conn, cmd);
+
+ if (strcasecmp(program, "60ghz") == 0)
+ return sta_get_parameter_60g(dut, conn, cmd);
+
+#ifdef ANDROID_NAN
+ if (strcasecmp(program, "NAN") == 0)
+ return nan_cmd_sta_exec_action(dut, conn, cmd);
+#endif /* ANDROID_NAN */
+
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Unsupported parameter");
+ return 0;
+}
+
+
+static void sta_reset_default_ath(struct sigma_dut *dut, const char *intf,
+ const char *type)
+{
+ char buf[100];
+
+ if (dut->program == PROGRAM_VHT) {
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth 2", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s chwidth failed", intf);
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s mode 11ACVHT80", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s mode 11ACVHT80 failed",
+ intf);
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s vhtmcs -1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s vhtmcs -1 failed", intf);
+ }
+ }
+
+ if (dut->program == PROGRAM_HT) {
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth 0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s chwidth failed", intf);
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s mode 11naht40", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s mode 11naht40 failed",
+ intf);
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s set11NRates 0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv set11NRates failed");
+ }
+ }
+
+ if (dut->program == PROGRAM_VHT || dut->program == PROGRAM_HT) {
+ snprintf(buf, sizeof(buf), "iwpriv %s powersave 0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "disabling powersave failed");
+ }
+
+ /* Reset CTS width */
+ snprintf(buf, sizeof(buf), "wifitool %s beeliner_fw_test 54 0",
+ intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "wifitool %s beeliner_fw_test 54 0 failed",
+ intf);
+ }
+
+ /* Enable Dynamic Bandwidth signalling by default */
+ snprintf(buf, sizeof(buf), "iwpriv %s cwmenable 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s cwmenable 1 failed", intf);
+ }
+
+ snprintf(buf, sizeof(buf), "iwconfig %s rts 2347", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv rts failed");
+ }
+ }
+
+ if (type && strcasecmp(type, "Testbed") == 0) {
+ dut->testbed_flag_txsp = 1;
+ dut->testbed_flag_rxsp = 1;
+ /* STA has to set spatial stream to 2 per Appendix H */
+ snprintf(buf, sizeof(buf), "iwpriv %s vht_mcsmap 0xfff0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv vht_mcsmap failed");
+ }
+
+ /* Disable LDPC per Appendix H */
+ snprintf(buf, sizeof(buf), "iwpriv %s ldpc 0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s ldpc 0 failed", intf);
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s amsdu 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv amsdu failed");
+ }
+
+ /* TODO: Disable STBC 2x1 transmit and receive */
+ snprintf(buf, sizeof(buf), "iwpriv %s tx_stbc 0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Disable tx_stbc 0 failed");
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s rx_stbc 0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Disable rx_stbc 0 failed");
+ }
+
+ /* STA has to disable Short GI per Appendix H */
+ snprintf(buf, sizeof(buf), "iwpriv %s shortgi 0", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s shortgi 0 failed", intf);
+ }
+ }
+
+ if (type && strcasecmp(type, "DUT") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s nss 3", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s nss 3 failed", intf);
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s shortgi 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv %s shortgi 1 failed", intf);
+ }
+ }
+}
+
+
+static int cmd_sta_reset_default(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ int cmd_sta_p2p_reset(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd);
+ const char *intf = get_param(cmd, "Interface");
+ const char *type;
+
+ dut->program = sigma_program_to_enum(get_param(cmd, "prog"));
+ dut->device_type = STA_unknown;
+ type = get_param(cmd, "type");
+ if (type && strcasecmp(type, "Testbed") == 0)
+ dut->device_type = STA_testbed;
+ if (type && strcasecmp(type, "DUT") == 0)
+ dut->device_type = STA_dut;
+
+ if (dut->program == PROGRAM_TDLS) {
+ /* Clear TDLS testing mode */
+ wpa_command(intf, "SET tdls_disabled 0");
+ wpa_command(intf, "SET tdls_testing 0");
+ dut->no_tpk_expiration = 0;
+ }
+
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ sta_reset_default_ath(dut, intf, type);
+ break;
+ default:
+ break;
+ }
+
+#ifdef ANDROID_NAN
+ if (dut->program == PROGRAM_NAN)
+ nan_cmd_sta_reset_default(dut, conn, cmd);
+#endif /* ANDROID_NAN */
+
+ if (dut->program == PROGRAM_HS2_R2) {
+ unlink("SP/wi-fi.org/pps.xml");
+ if (system("rm -r SP/*") != 0) {
+ }
+ unlink("next-client-cert.pem");
+ unlink("next-client-key.pem");
+ }
+
+ if (dut->program == PROGRAM_60GHZ) {
+ const char *dev_role = get_param(cmd, "DevRole");
+
+ if (!dev_role) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Missing DevRole argument");
+ return 0;
+ }
+
+ if (strcasecmp(dev_role, "STA") == 0)
+ dut->dev_role = DEVROLE_STA;
+ else if (strcasecmp(dev_role, "PCP") == 0)
+ dut->dev_role = DEVROLE_PCP;
+ else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unknown DevRole");
+ return 0;
+ }
+
+ if (dut->device_type == STA_unknown) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Device type is not STA testbed or DUT");
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unknown device type");
+ return 0;
+ }
+ }
+
+ wpa_command(intf, "WPS_ER_STOP");
+ wpa_command(intf, "FLUSH");
+ wpa_command(intf, "SET radio_disabled 0");
+
+ if (dut->tmp_mac_addr && dut->set_macaddr) {
+ dut->tmp_mac_addr = 0;
+ if (system(dut->set_macaddr) != 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to clear "
+ "temporary MAC address");
+ }
+ }
+
+ set_ps(intf, dut, 0);
+
+ if (dut->program == PROGRAM_HS2 || dut->program == PROGRAM_HS2_R2) {
+ wpa_command(intf, "SET interworking 1");
+ wpa_command(intf, "SET hs20 1");
+ }
+
+ if (dut->program == PROGRAM_HS2_R2) {
+ wpa_command(intf, "SET pmf 1");
+ } else {
+ wpa_command(intf, "SET pmf 0");
+ }
+
+ hs2_clear_credentials(intf);
+ wpa_command(intf, "SET hessid 00:00:00:00:00:00");
+ wpa_command(intf, "SET access_network_type 15");
+
+ static_ip_file(0, NULL, NULL, NULL);
+ kill_dhcp_client(dut, intf);
+ clear_ip_addr(dut, intf);
+
+ dut->er_oper_performed = 0;
+ dut->er_oper_bssid[0] = '\0';
+
+ return cmd_sta_p2p_reset(dut, conn, cmd);
+}
+
+
+static int cmd_sta_get_events(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *program = get_param(cmd, "Program");
+
+ if (program == NULL)
+ return -1;
+#ifdef ANDROID_NAN
+ if (strcasecmp(program, "NAN") == 0)
+ return nan_cmd_sta_get_events(dut, conn, cmd);
+#endif /* ANDROID_NAN */
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Unsupported parameter");
+ return 0;
+}
+
+
+static int cmd_sta_exec_action(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *program = get_param(cmd, "Prog");
+
+ if (program == NULL)
+ return -1;
+#ifdef ANDROID_NAN
+ if (strcasecmp(program, "NAN") == 0)
+ return nan_cmd_sta_exec_action(dut, conn, cmd);
+#endif /* ANDROID_NAN */
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Unsupported parameter");
+ return 0;
+}
+
+
+static int cmd_sta_set_11n(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val, *mcs32, *rate;
+
+ val = get_param(cmd, "GREENFIELD");
+ if (val) {
+ if (strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0) {
+ /* Enable GD */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,GF not supported");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "SGI20");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_sta_set_sgi(dut, intf, val);
+ break;
+ default:
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,SGI20 not supported");
+ return 0;
+ }
+ }
+
+ mcs32 = get_param(cmd, "MCS32"); /* HT Duplicate Mode Enable/Disable */
+ rate = get_param(cmd, "MCS_FIXEDRATE"); /* Fixed MCS rate (0..31) */
+ if (mcs32 && rate) {
+ /* TODO */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,MCS32,MCS_FIXEDRATE not supported");
+ return 0;
+ } else if (mcs32 && !rate) {
+ /* TODO */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,MCS32 not supported");
+ return 0;
+ } else if (!mcs32 && rate) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_sta_set_11nrates(dut, intf, rate);
+ break;
+ default:
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,MCS32_FIXEDRATE not supported");
+ return 0;
+ }
+ }
+
+ return cmd_sta_set_wireless_common(intf, dut, conn, cmd);
+}
+
+
+static int cmd_sta_set_wireless_vht(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val;
+ char buf[30];
+ int tkip = -1;
+ int wep = -1;
+
+ val = get_param(cmd, "SGI80");
+ if (val) {
+ int sgi80;
+
+ sgi80 = strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0;
+ snprintf(buf, sizeof(buf), "iwpriv %s shortgi %d", intf, sgi80);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv shortgi failed");
+ }
+ }
+
+ val = get_param(cmd, "TxBF");
+ if (val && (strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0)) {
+ snprintf(buf, sizeof(buf), "iwpriv %s vhtsubfee 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv vhtsubfee failed");
+ }
+ snprintf(buf, sizeof(buf), "iwpriv %s vhtsubfer 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv vhtsubfer failed");
+ }
+ }
+
+ val = get_param(cmd, "MU_TxBF");
+ if (val && (strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0)) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ ath_sta_set_txsp_stream(dut, intf, "1SS");
+ ath_sta_set_rxsp_stream(dut, intf, "1SS");
+ case DRIVER_WCN:
+ if (wcn_sta_set_sp_stream(dut, intf, "1SS") < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set RX/TXSP_STREAM");
+ return 0;
+ }
+ default:
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Setting SP_STREAM not supported");
+ break;
+ }
+ snprintf(buf, sizeof(buf), "iwpriv %s vhtmubfee 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv vhtmubfee failed");
+ }
+ snprintf(buf, sizeof(buf), "iwpriv %s vhtmubfer 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv vhtmubfer failed");
+ }
+ }
+
+ val = get_param(cmd, "LDPC");
+ if (val) {
+ int ldpc;
+
+ ldpc = strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0;
+ snprintf(buf, sizeof(buf), "iwpriv %s ldpc %d", intf, ldpc);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv ldpc failed");
+ }
+ }
+
+ val = get_param(cmd, "opt_md_notif_ie");
+ if (val) {
+ char *result = NULL;
+ char delim[] = ";";
+ char token[30];
+ int value, config_val = 0;
+
+ strncpy(token, val, sizeof(token));
+ token[sizeof(token) - 1] = '\0';
+ result = strtok(token, delim);
+
+ /* Extract the NSS information */
+ if (result) {
+ value = atoi(result);
+ switch (value) {
+ case 1:
+ config_val = 1;
+ break;
+ case 2:
+ config_val = 3;
+ break;
+ case 3:
+ config_val = 7;
+ break;
+ case 4:
+ config_val = 15;
+ break;
+ default:
+ config_val = 3;
+ break;
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s rxchainmask %d",
+ intf, config_val);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv rxchainmask failed");
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s txchainmask %d",
+ intf, config_val);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv txchainmask failed");
+ }
+ }
+
+ /* Extract the channel width information */
+ result = strtok(NULL, delim);
+ if (result) {
+ value = atoi(result);
+ switch (value) {
+ case 20:
+ config_val = 0;
+ break;
+ case 40:
+ config_val = 1;
+ break;
+ case 80:
+ config_val = 2;
+ break;
+ case 160:
+ config_val = 3;
+ break;
+ default:
+ config_val = 2;
+ break;
+ }
+
+ dut->chwidth = config_val;
+
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth %d",
+ intf, config_val);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv chwidth failed");
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s opmode_notify 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv opmode_notify failed");
+ }
+ }
+
+ val = get_param(cmd, "nss_mcs_cap");
+ if (val) {
+ int nss, mcs;
+ char token[20];
+ char *result = NULL;
+ unsigned int vht_mcsmap = 0;
+
+ strncpy(token, val, sizeof(token));
+ token[sizeof(token) - 1] = '\0';
+ result = strtok(token, ";");
+ nss = atoi(result);
+
+ snprintf(buf, sizeof(buf), "iwpriv %s nss %d", intf, nss);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv nss failed");
+ }
+
+ result = strtok(NULL, ";");
+ if (result == NULL) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "VHTMCS NOT SPECIFIED!");
+ return 0;
+ }
+ result = strtok(result, "-");
+ result = strtok(NULL, "-");
+ mcs = atoi(result);
+
+ snprintf(buf, sizeof(buf), "iwpriv %s vhtmcs %d", intf, mcs);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv mcs failed");
+ }
+
+ switch (nss) {
+ case 1:
+ switch (mcs) {
+ case 7:
+ vht_mcsmap = 0xfffc;
+ break;
+ case 8:
+ vht_mcsmap = 0xfffd;
+ break;
+ case 9:
+ vht_mcsmap = 0xfffe;
+ break;
+ default:
+ vht_mcsmap = 0xfffe;
+ break;
+ }
+ break;
+ case 2:
+ switch (mcs) {
+ case 7:
+ vht_mcsmap = 0xfff0;
+ break;
+ case 8:
+ vht_mcsmap = 0xfff5;
+ break;
+ case 9:
+ vht_mcsmap = 0xfffa;
+ break;
+ default:
+ vht_mcsmap = 0xfffa;
+ break;
+ }
+ break;
+ case 3:
+ switch (mcs) {
+ case 7:
+ vht_mcsmap = 0xffc0;
+ break;
+ case 8:
+ vht_mcsmap = 0xffd5;
+ break;
+ case 9:
+ vht_mcsmap = 0xffea;
+ break;
+ default:
+ vht_mcsmap = 0xffea;
+ break;
+ }
+ break;
+ default:
+ vht_mcsmap = 0xffea;
+ break;
+ }
+ snprintf(buf, sizeof(buf), "iwpriv %s vht_mcsmap 0x%04x",
+ intf, vht_mcsmap);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv vht_mcsmap failed");
+ }
+ }
+
+ /* UNSUPPORTED: val = get_param(cmd, "Tx_lgi_rate"); */
+
+ val = get_param(cmd, "Vht_tkip");
+ if (val)
+ tkip = strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0;
+
+ val = get_param(cmd, "Vht_wep");
+ if (val)
+ wep = strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0;
+
+ if (tkip != -1 || wep != -1) {
+ if ((tkip == 1 && wep != 0) || (wep == 1 && tkip != 0)) {
+ snprintf(buf, sizeof(buf), "iwpriv %s htweptkip 1",
+ intf);
+ } else if ((tkip == 0 && wep != 1) || (wep == 0 && tkip != 1)) {
+ snprintf(buf, sizeof(buf), "iwpriv %s htweptkip 0",
+ intf);
+ } else {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "ErrorCode,mixed mode of VHT TKIP/WEP not supported");
+ return 0;
+ }
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv htweptkip failed");
+ }
+ }
+
+ val = get_param(cmd, "txBandwidth");
+ if (val) {
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ if (ath_set_width(dut, conn, intf, val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set txBandwidth");
+ return 0;
+ }
+ break;
+ default:
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Setting txBandwidth not supported");
+ break;
+ }
+ }
+
+ return cmd_sta_set_wireless_common(intf, dut, conn, cmd);
+}
+
+
+static int sta_set_wireless_60g(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *dev_role = get_param(cmd, "DevRole");
+
+ if (!dev_role) {
+ send_resp(dut, conn, SIGMA_INVALID,
+ "ErrorCode,DevRole not specified");
+ return 0;
+ }
+
+ if (strcasecmp(dev_role, "PCP") == 0)
+ return sta_set_60g_pcp(dut, conn, cmd);
+ if (strcasecmp(dev_role, "STA") == 0)
+ return sta_set_60g_sta(dut, conn, cmd);
+ send_resp(dut, conn, SIGMA_INVALID,
+ "ErrorCode,DevRole not supported");
+ return 0;
+}
+
+
+static int cmd_sta_set_wireless(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+
+ val = get_param(cmd, "Program");
+ if (val) {
+ if (strcasecmp(val, "11n") == 0)
+ return cmd_sta_set_11n(dut, conn, cmd);
+ if (strcasecmp(val, "VHT") == 0)
+ return cmd_sta_set_wireless_vht(dut, conn, cmd);
+ if (strcasecmp(val, "60ghz") == 0)
+ return sta_set_wireless_60g(dut, conn, cmd);
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Program value not supported");
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Program argument not available");
+ }
+
+ return 0;
+}
+
+
+static void ath_sta_inject_frame(struct sigma_dut *dut, const char *intf,
+ int tid)
+{
+ char buf[100];
+ int tid_to_dscp [] = { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0 };
+
+ /*
+ * Two ways to ensure that addba request with a
+ * non zero TID could be sent out. EV 117296
+ */
+ snprintf(buf, sizeof(buf),
+ "ping -c 8 -Q %d `arp -a | grep wlan0 | awk '{print $2}' | tr -d '()'`",
+ tid);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Ping did not send out");
+ }
+
+ snprintf(buf, sizeof(buf),
+ "iwconfig %s | grep Access | awk '{print $6}' > %s",
+ intf, VI_QOS_TMP_FILE);
+ if (system(buf) != 0)
+ return;
+
+ snprintf(buf, sizeof(buf),
+ "ifconfig %s | grep HWaddr | cut -b 39-56 >> %s",
+ intf, VI_QOS_TMP_FILE);
+ if (system(buf) != 0)
+ sigma_dut_print(dut, DUT_MSG_ERROR, "HWaddr matching failed");
+
+ snprintf(buf,sizeof(buf), "sed -n '3,$p' %s >> %s",
+ VI_QOS_REFFILE, VI_QOS_TMP_FILE);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "VI_QOS_TEMP_FILE generation error failed");
+ }
+ snprintf(buf, sizeof(buf), "sed '5 c %x' %s > %s",
+ tid_to_dscp[tid], VI_QOS_TMP_FILE, VI_QOS_FILE);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "VI_QOS_FILE generation failed");
+ }
+
+ snprintf(buf, sizeof(buf), "sed '5 c %x' %s > %s",
+ tid_to_dscp[tid], VI_QOS_TMP_FILE, VI_QOS_FILE);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "VI_QOS_FILE generation failed");
+ }
+
+ snprintf(buf, sizeof(buf), "ethinject %s %s", intf, VI_QOS_FILE);
+ if (system(buf) != 0) {
+ }
+}
+
+
+static int ath_sta_send_addba(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val;
+ int tid = 0;
+ char buf[100];
+
+ val = get_param(cmd, "TID");
+ if (val) {
+ tid = atoi(val);
+ if (tid)
+ ath_sta_inject_frame(dut, intf, tid);
+ }
+
+ /* Command sequence for ADDBA request on Peregrine based devices */
+ snprintf(buf, sizeof(buf), "iwpriv %s setaddbaoper 1", intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv setaddbaoper failed");
+ }
+
+ snprintf(buf, sizeof(buf), "wifitool %s senddelba 1 %d 1 4", intf, tid);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "wifitool senddelba failed");
+ }
+
+ snprintf(buf, sizeof(buf), "wifitool %s sendaddba 1 %d 64", intf, tid);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "wifitool sendaddba failed");
+ }
+
+ /* UNSUPPORTED: val = get_param(cmd, "Dest_mac"); */
+
+ return 1;
+}
+
+
+static int send_addba_60g(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ int tid = 0;
+ char buf[100];
+
+ val = get_param(cmd, "TID");
+ if (val) {
+ tid = atoi(val);
+ if (tid != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Ignore TID %d for send_addba use TID 0 for 60g since only 0 required on TX",
+ tid);
+ }
+ }
+
+ val = get_param(cmd, "Dest_mac");
+ if (!val) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Currently not supporting addba for 60G without Dest_mac");
+ return SIGMA_DUT_ERROR_CALLER_SEND_STATUS;
+ }
+
+ snprintf(buf, sizeof(buf), "wil6210_addba_req.py %s %d",
+ val, dut->back_rcv_buf);
+ sigma_dut_print(dut, DUT_MSG_INFO, "Run: %s", buf);
+
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to send addba");
+ return -1;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_send_addba(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ return ath_sta_send_addba(dut, conn, cmd);
+ case DRIVER_WIL6210:
+ return send_addba_60g(dut, conn, cmd);
+ default:
+ /*
+ * There is no driver specific implementation for other drivers.
+ * Ignore the command and report COMPLETE since the following
+ * throughput test operation will end up sending ADDBA anyway.
+ */
+ return 1;
+ }
+}
+
+
+int inject_eth_frame(int s, const void *data, size_t len,
+ unsigned short ethtype, char *dst, char *src)
+{
+ struct iovec iov[4] = {
+ {
+ .iov_base = dst,
+ .iov_len = ETH_ALEN,
+ },
+ {
+ .iov_base = src,
+ .iov_len = ETH_ALEN,
+ },
+ {
+ .iov_base = ðtype,
+ .iov_len = sizeof(unsigned short),
+ },
+ {
+ .iov_base = (void *) data,
+ .iov_len = len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 4,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+
+ return sendmsg(s, &msg, 0);
+}
+
+#if defined(__linux__) || defined(__QNXNTO__)
+
+int inject_frame(int s, const void *data, size_t len, int encrypt)
+{
+#define IEEE80211_RADIOTAP_F_WEP 0x04
+#define IEEE80211_RADIOTAP_F_FRAG 0x08
+ unsigned char rtap_hdr[] = {
+ 0x00, 0x00, /* radiotap version */
+ 0x0e, 0x00, /* radiotap length */
+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
+ 0x00, /* padding */
+ 0x00, 0x00, /* RX and TX flags to indicate that */
+ 0x00, 0x00, /* this is the injected frame directly */
+ };
+ struct iovec iov[2] = {
+ {
+ .iov_base = &rtap_hdr,
+ .iov_len = sizeof(rtap_hdr),
+ },
+ {
+ .iov_base = (void *) data,
+ .iov_len = len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+
+ if (encrypt)
+ rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
+
+ return sendmsg(s, &msg, 0);
+}
+
+
+int open_monitor(const char *ifname)
+{
+#ifdef __QNXNTO__
+ struct sockaddr_dl ll;
+ int s;
+
+ memset(&ll, 0, sizeof(ll));
+ ll.sdl_family = AF_LINK;
+ ll.sdl_index = if_nametoindex(ifname);
+ if (ll.sdl_index == 0) {
+ perror("if_nametoindex");
+ return -1;
+ }
+ s = socket(PF_INET, SOCK_RAW, 0);
+#else /* __QNXNTO__ */
+ struct sockaddr_ll ll;
+ int s;
+
+ memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = if_nametoindex(ifname);
+ if (ll.sll_ifindex == 0) {
+ perror("if_nametoindex");
+ return -1;
+ }
+ s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+#endif /* __QNXNTO__ */
+ if (s < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ perror("monitor socket bind");
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+
+static int hex2num(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+
+int hwaddr_aton(const char *txt, unsigned char *addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ int a, b;
+
+ a = hex2num(*txt++);
+ if (a < 0)
+ return -1;
+ b = hex2num(*txt++);
+ if (b < 0)
+ return -1;
+ *addr++ = (a << 4) | b;
+ if (i < 5 && *txt++ != ':')
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* defined(__linux__) || defined(__QNXNTO__) */
+
+enum send_frame_type {
+ DISASSOC, DEAUTH, SAQUERY, AUTH, ASSOCREQ, REASSOCREQ, DLS_REQ
+};
+enum send_frame_protection {
+ CORRECT_KEY, INCORRECT_KEY, UNPROTECTED
+};
+
+
+static int sta_inject_frame(struct sigma_dut *dut, struct sigma_conn *conn,
+ enum send_frame_type frame,
+ enum send_frame_protection protected,
+ const char *dest)
+{
+#ifdef __linux__
+ unsigned char buf[1000], *pos;
+ int s, res;
+ char bssid[20], addr[20];
+ char result[32], ssid[100];
+ size_t ssid_len;
+
+ if (get_wpa_status(get_station_ifname(), "wpa_state", result,
+ sizeof(result)) < 0 ||
+ strncmp(result, "COMPLETED", 9) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Not connected");
+ return 0;
+ }
+
+ if (get_wpa_status(get_station_ifname(), "bssid", bssid, sizeof(bssid))
+ < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not get "
+ "current BSSID");
+ return 0;
+ }
+
+ if (get_wpa_status(get_station_ifname(), "address", addr, sizeof(addr))
+ < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not get "
+ "own MAC address");
+ return 0;
+ }
+
+ if (get_wpa_status(get_station_ifname(), "ssid", ssid, sizeof(ssid))
+ < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not get "
+ "current SSID");
+ return 0;
+ }
+ ssid_len = strlen(ssid);
+
+ pos = buf;
+
+ /* Frame Control */
+ switch (frame) {
+ case DISASSOC:
+ *pos++ = 0xa0;
+ break;
+ case DEAUTH:
+ *pos++ = 0xc0;
+ break;
+ case SAQUERY:
+ *pos++ = 0xd0;
+ break;
+ case AUTH:
+ *pos++ = 0xb0;
+ break;
+ case ASSOCREQ:
+ *pos++ = 0x00;
+ break;
+ case REASSOCREQ:
+ *pos++ = 0x20;
+ break;
+ case DLS_REQ:
+ *pos++ = 0xd0;
+ break;
+ }
+
+ if (protected == INCORRECT_KEY)
+ *pos++ = 0x40; /* Set Protected field to 1 */
+ else
+ *pos++ = 0x00;
+
+ /* Duration */
+ *pos++ = 0x00;
+ *pos++ = 0x00;
+
+ /* addr1 = DA (current AP) */
+ hwaddr_aton(bssid, pos);
+ pos += 6;
+ /* addr2 = SA (own address) */
+ hwaddr_aton(addr, pos);
+ pos += 6;
+ /* addr3 = BSSID (current AP) */
+ hwaddr_aton(bssid, pos);
+ pos += 6;
+
+ /* Seq# (to be filled by driver/mac80211) */
+ *pos++ = 0x00;
+ *pos++ = 0x00;
+
+ if (protected == INCORRECT_KEY) {
+ /* CCMP parameters */
+ memcpy(pos, "\x61\x01\x00\x20\x00\x10\x00\x00", 8);
+ pos += 8;
+ }
+
+ if (protected == INCORRECT_KEY) {
+ switch (frame) {
+ case DEAUTH:
+ /* Reason code (encrypted) */
+ memcpy(pos, "\xa7\x39", 2);
+ pos += 2;
+ break;
+ case DISASSOC:
+ /* Reason code (encrypted) */
+ memcpy(pos, "\xa7\x39", 2);
+ pos += 2;
+ break;
+ case SAQUERY:
+ /* Category|Action|TransID (encrypted) */
+ memcpy(pos, "\x6f\xbd\xe9\x4d", 4);
+ pos += 4;
+ break;
+ default:
+ return -1;
+ }
+
+ /* CCMP MIC */
+ memcpy(pos, "\xc8\xd8\x3b\x06\x5d\xb7\x25\x68", 8);
+ pos += 8;
+ } else {
+ switch (frame) {
+ case DEAUTH:
+ /* reason code = 8 */
+ *pos++ = 0x08;
+ *pos++ = 0x00;
+ break;
+ case DISASSOC:
+ /* reason code = 8 */
+ *pos++ = 0x08;
+ *pos++ = 0x00;
+ break;
+ case SAQUERY:
+ /* Category - SA Query */
+ *pos++ = 0x08;
+ /* SA query Action - Request */
+ *pos++ = 0x00;
+ /* Transaction ID */
+ *pos++ = 0x12;
+ *pos++ = 0x34;
+ break;
+ case AUTH:
+ /* Auth Alg (Open) */
+ *pos++ = 0x00;
+ *pos++ = 0x00;
+ /* Seq# */
+ *pos++ = 0x01;
+ *pos++ = 0x00;
+ /* Status code */
+ *pos++ = 0x00;
+ *pos++ = 0x00;
+ break;
+ case ASSOCREQ:
+ /* Capability Information */
+ *pos++ = 0x31;
+ *pos++ = 0x04;
+ /* Listen Interval */
+ *pos++ = 0x0a;
+ *pos++ = 0x00;
+ /* SSID */
+ *pos++ = 0x00;
+ *pos++ = ssid_len;
+ memcpy(pos, ssid, ssid_len);
+ pos += ssid_len;
+ /* Supported Rates */
+ memcpy(pos, "\x01\x08\x02\x04\x0b\x16\x0c\x12\x18\x24",
+ 10);
+ pos += 10;
+ /* Extended Supported Rates */
+ memcpy(pos, "\x32\x04\x30\x48\x60\x6c", 6);
+ pos += 6;
+ /* RSN */
+ memcpy(pos, "\x30\x1a\x01\x00\x00\x0f\xac\x04\x01\x00"
+ "\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x02\xc0"
+ "\x00\x00\x00\x00\x0f\xac\x06", 28);
+ pos += 28;
+ break;
+ case REASSOCREQ:
+ /* Capability Information */
+ *pos++ = 0x31;
+ *pos++ = 0x04;
+ /* Listen Interval */
+ *pos++ = 0x0a;
+ *pos++ = 0x00;
+ /* Current AP */
+ hwaddr_aton(bssid, pos);
+ pos += 6;
+ /* SSID */
+ *pos++ = 0x00;
+ *pos++ = ssid_len;
+ memcpy(pos, ssid, ssid_len);
+ pos += ssid_len;
+ /* Supported Rates */
+ memcpy(pos, "\x01\x08\x02\x04\x0b\x16\x0c\x12\x18\x24",
+ 10);
+ pos += 10;
+ /* Extended Supported Rates */
+ memcpy(pos, "\x32\x04\x30\x48\x60\x6c", 6);
+ pos += 6;
+ /* RSN */
+ memcpy(pos, "\x30\x1a\x01\x00\x00\x0f\xac\x04\x01\x00"
+ "\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x02\xc0"
+ "\x00\x00\x00\x00\x0f\xac\x06", 28);
+ pos += 28;
+ break;
+ case DLS_REQ:
+ /* Category - DLS */
+ *pos++ = 0x02;
+ /* DLS Action - Request */
+ *pos++ = 0x00;
+ /* Destination MACAddress */
+ if (dest)
+ hwaddr_aton(dest, pos);
+ else
+ memset(pos, 0, 6);
+ pos += 6;
+ /* Source MACAddress */
+ hwaddr_aton(addr, pos);
+ pos += 6;
+ /* Capability Information */
+ *pos++ = 0x10; /* Privacy */
+ *pos++ = 0x06; /* QoS */
+ /* DLS Timeout Value */
+ *pos++ = 0x00;
+ *pos++ = 0x01;
+ /* Supported rates */
+ *pos++ = 0x01;
+ *pos++ = 0x08;
+ *pos++ = 0x0c; /* 6 Mbps */
+ *pos++ = 0x12; /* 9 Mbps */
+ *pos++ = 0x18; /* 12 Mbps */
+ *pos++ = 0x24; /* 18 Mbps */
+ *pos++ = 0x30; /* 24 Mbps */
+ *pos++ = 0x48; /* 36 Mbps */
+ *pos++ = 0x60; /* 48 Mbps */
+ *pos++ = 0x6c; /* 54 Mbps */
+ /* TODO: Extended Supported Rates */
+ /* TODO: HT Capabilities */
+ break;
+ }
+ }
+
+ s = open_monitor("sigmadut");
+ if (s < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to open "
+ "monitor socket");
+ return 0;
+ }
+
+ res = inject_frame(s, buf, pos - buf, protected == CORRECT_KEY);
+ if (res < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to "
+ "inject frame");
+ return 0;
+ }
+ if (res < pos - buf) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Only partial "
+ "frame sent");
+ return 0;
+ }
+
+ close(s);
+
+ return 1;
+#else /* __linux__ */
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,sta_send_frame not "
+ "yet supported");
+ return 0;
+#endif /* __linux__ */
+}
+
+
+static int cmd_sta_send_frame_tdls(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *sta, *val;
+ unsigned char addr[ETH_ALEN];
+ char buf[100];
+
+ sta = get_param(cmd, "peer");
+ if (sta == NULL)
+ sta = get_param(cmd, "station");
+ if (sta == NULL) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing peer address");
+ return 0;
+ }
+ if (hwaddr_aton(sta, addr) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Invalid peer address");
+ return 0;
+ }
+
+ val = get_param(cmd, "type");
+ if (val == NULL)
+ return -1;
+
+ if (strcasecmp(val, "DISCOVERY") == 0) {
+ snprintf(buf, sizeof(buf), "TDLS_DISCOVER %s", sta);
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to send TDLS discovery");
+ return 0;
+ }
+ return 1;
+ }
+
+ if (strcasecmp(val, "SETUP") == 0) {
+ int status = 0, timeout = 0;
+
+ val = get_param(cmd, "Status");
+ if (val)
+ status = atoi(val);
+
+ val = get_param(cmd, "Timeout");
+ if (val)
+ timeout = atoi(val);
+
+ if (status != 0 && status != 37) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported status value");
+ return 0;
+ }
+
+ if (timeout != 0 && timeout != 301) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported timeout value");
+ return 0;
+ }
+
+ if (status && timeout) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported timeout+status "
+ "combination");
+ return 0;
+ }
+
+ if (status == 37 &&
+ wpa_command(intf, "SET tdls_testing 0x200")) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to enable "
+ "decline setup response test mode");
+ return 0;
+ }
+
+ if (timeout == 301) {
+ int res;
+ if (dut->no_tpk_expiration)
+ res = wpa_command(intf,
+ "SET tdls_testing 0x108");
+ else
+ res = wpa_command(intf,
+ "SET tdls_testing 0x8");
+ if (res) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set short TPK "
+ "lifetime");
+ return 0;
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "TDLS_SETUP %s", sta);
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to send TDLS setup");
+ return 0;
+ }
+ return 1;
+ }
+
+ if (strcasecmp(val, "TEARDOWN") == 0) {
+ snprintf(buf, sizeof(buf), "TDLS_TEARDOWN %s", sta);
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to send TDLS teardown");
+ return 0;
+ }
+ return 1;
+ }
+
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported TDLS frame");
+ return 0;
+}
+
+
+static int sta_ap_known(const char *ifname, const char *bssid)
+{
+ char buf[4096];
+
+ snprintf(buf, sizeof(buf), "BSS %s", bssid);
+ if (wpa_command_resp(ifname, buf, buf, sizeof(buf)) < 0)
+ return 0;
+ if (strncmp(buf, "id=", 3) != 0)
+ return 0;
+ return 1;
+}
+
+
+static int sta_scan_ap(struct sigma_dut *dut, const char *ifname,
+ const char *bssid)
+{
+ int res;
+ struct wpa_ctrl *ctrl;
+ char buf[256];
+
+ if (sta_ap_known(ifname, bssid))
+ return 0;
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "AP not in BSS table - start scan");
+
+ ctrl = open_wpa_mon(ifname);
+ if (ctrl == NULL) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to open "
+ "wpa_supplicant monitor connection");
+ return -1;
+ }
+
+ if (wpa_command(ifname, "SCAN") < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to start scan");
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ return -1;
+ }
+
+ res = get_wpa_cli_event(dut, ctrl, "CTRL-EVENT-SCAN-RESULTS",
+ buf, sizeof(buf));
+
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+
+ if (res < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Scan did not complete");
+ return -1;
+ }
+
+ if (sta_ap_known(ifname, bssid))
+ return 0;
+ sigma_dut_print(dut, DUT_MSG_INFO, "AP not in BSS table");
+ return -1;
+}
+
+
+static int cmd_sta_send_frame_hs2_neighadv(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *intf)
+{
+ char buf[200];
+
+ snprintf(buf, sizeof(buf), "ndsend 2001:DB8::1 %s", intf);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Failed to run "
+ "ndsend");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_send_frame_hs2_neighsolreq(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *intf)
+{
+ char buf[200];
+ const char *ip = get_param(cmd, "SenderIP");
+
+ snprintf(buf, sizeof(buf), "ndisc6 -nm %s %s -r 4", ip, intf);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) == 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Neighbor Solicitation got a response "
+ "for %s@%s", ip, intf);
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_send_frame_hs2_arpprobe(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *ifname)
+{
+ char buf[200];
+ const char *ip = get_param(cmd, "SenderIP");
+
+ if (ip == NULL) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing SenderIP parameter");
+ return 0;
+ }
+ snprintf(buf, sizeof(buf), "arping -I %s -D %s -c 4", ifname, ip);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "arping DAD got a response "
+ "for %s@%s", ip, ifname);
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_send_frame_hs2_arpannounce(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *ifname)
+{
+ char buf[200];
+ char ip[16];
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s >= 0) {
+ struct ifreq ifr;
+ struct sockaddr_in saddr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to get "
+ "%s IP address: %s",
+ ifname, strerror(errno));
+ return -1;
+ } else {
+ memcpy(&saddr, &ifr.ifr_addr,
+ sizeof(struct sockaddr_in));
+ strncpy(ip, inet_ntoa(saddr.sin_addr), sizeof(ip));
+ }
+ close(s);
+
+ }
+
+ snprintf(buf, sizeof(buf), "arping -I %s -s %s %s -c 4", ifname, ip,
+ ip);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_send_frame_hs2_arpreply(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *ifname)
+{
+ char buf[200], addr[20];
+ char dst[ETH_ALEN], src[ETH_ALEN];
+ short ethtype = htons(ETH_P_ARP);
+ char *pos;
+ int s, res;
+ const char *val;
+ struct sockaddr_in taddr;
+
+ val = get_param(cmd, "dest");
+ if (val)
+ hwaddr_aton(val, (unsigned char *) dst);
+
+ val = get_param(cmd, "DestIP");
+ if (val)
+ inet_aton(val, &taddr.sin_addr);
+
+ if (get_wpa_status(get_station_ifname(), "address", addr,
+ sizeof(addr)) < 0)
+ return -2;
+ hwaddr_aton(addr, (unsigned char *) src);
+
+ pos = buf;
+ *pos++ = 0x00;
+ *pos++ = 0x01;
+ *pos++ = 0x08;
+ *pos++ = 0x00;
+ *pos++ = 0x06;
+ *pos++ = 0x04;
+ *pos++ = 0x00;
+ *pos++ = 0x02;
+ memcpy(pos, src, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &taddr.sin_addr, 4);
+ pos += 4;
+ memcpy(pos, dst, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &taddr.sin_addr, 4);
+ pos += 4;
+
+ s = open_monitor(get_station_ifname());
+ if (s < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to open "
+ "monitor socket");
+ return 0;
+ }
+
+ res = inject_eth_frame(s, buf, pos - buf, ethtype, dst, src);
+ if (res < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to "
+ "inject frame");
+ return 0;
+ }
+
+ close(s);
+
+ return 1;
+}
+
+
+static int cmd_sta_send_frame_hs2_dls_req(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *intf, const char *dest)
+{
+ char buf[100];
+
+ if (if_nametoindex("sigmadut") == 0) {
+ snprintf(buf, sizeof(buf),
+ "iw dev %s interface add sigmadut type monitor",
+ get_station_ifname());
+ if (system(buf) != 0 ||
+ if_nametoindex("sigmadut") == 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to add "
+ "monitor interface with '%s'", buf);
+ return -2;
+ }
+ }
+
+ if (system("ifconfig sigmadut up") != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to set "
+ "monitor interface up");
+ return -2;
+ }
+
+ return sta_inject_frame(dut, conn, DLS_REQ, UNPROTECTED, dest);
+}
+
+
+static int cmd_sta_send_frame_hs2(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *dest = get_param(cmd, "Dest");
+ const char *type = get_param(cmd, "FrameName");
+ const char *val;
+ char buf[200], *pos, *end;
+ int count, count2;
+
+ if (type == NULL)
+ type = get_param(cmd, "Type");
+
+ if (intf == NULL || dest == NULL || type == NULL)
+ return -1;
+
+ if (strcasecmp(type, "NeighAdv") == 0)
+ return cmd_sta_send_frame_hs2_neighadv(dut, conn, cmd, intf);
+
+ if (strcasecmp(type, "NeighSolicitReq") == 0)
+ return cmd_sta_send_frame_hs2_neighsolreq(dut, conn, cmd, intf);
+
+ if (strcasecmp(type, "ARPProbe") == 0)
+ return cmd_sta_send_frame_hs2_arpprobe(dut, conn, cmd, intf);
+
+ if (strcasecmp(type, "ARPAnnounce") == 0)
+ return cmd_sta_send_frame_hs2_arpannounce(dut, conn, cmd, intf);
+
+ if (strcasecmp(type, "ARPReply") == 0)
+ return cmd_sta_send_frame_hs2_arpreply(dut, conn, cmd, intf);
+
+ if (strcasecmp(type, "DLS-request") == 0 ||
+ strcasecmp(type, "DLSrequest") == 0)
+ return cmd_sta_send_frame_hs2_dls_req(dut, conn, cmd, intf,
+ dest);
+
+ if (strcasecmp(type, "ANQPQuery") != 0 &&
+ strcasecmp(type, "Query") != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported HS 2.0 send frame type");
+ return 0;
+ }
+
+ if (sta_scan_ap(dut, intf, dest) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Could not find "
+ "the requested AP");
+ return 0;
+ }
+
+ pos = buf;
+ end = buf + sizeof(buf);
+ count = 0;
+ pos += snprintf(pos, end - pos, "ANQP_GET %s ", dest);
+
+ val = get_param(cmd, "ANQP_CAP_LIST");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s257", count > 0 ? "," : "");
+ count++;
+ }
+
+ val = get_param(cmd, "VENUE_NAME");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s258", count > 0 ? "," : "");
+ count++;
+ }
+
+ val = get_param(cmd, "NETWORK_AUTH_TYPE");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s260", count > 0 ? "," : "");
+ count++;
+ }
+
+ val = get_param(cmd, "ROAMING_CONS");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s261", count > 0 ? "," : "");
+ count++;
+ }
+
+ val = get_param(cmd, "IP_ADDR_TYPE_AVAILABILITY");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s262", count > 0 ? "," : "");
+ count++;
+ }
+
+ val = get_param(cmd, "NAI_REALM_LIST");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s263", count > 0 ? "," : "");
+ count++;
+ }
+
+ val = get_param(cmd, "3GPP_INFO");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s264", count > 0 ? "," : "");
+ count++;
+ }
+
+ val = get_param(cmd, "DOMAIN_LIST");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s268", count > 0 ? "," : "");
+ count++;
+ }
+
+ if (count && wpa_command(intf, buf)) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,ANQP_GET failed");
+ return 0;
+ }
+
+ pos = buf;
+ end = buf + sizeof(buf);
+ count2 = 0;
+ pos += snprintf(pos, end - pos, "HS20_ANQP_GET %s ", dest);
+
+ val = get_param(cmd, "HS_CAP_LIST");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s2", count2 > 0 ? "," : "");
+ count2++;
+ }
+
+ val = get_param(cmd, "OPER_NAME");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s3", count2 > 0 ? "," : "");
+ count2++;
+ }
+
+ val = get_param(cmd, "WAN_METRICS");
+ if (!val)
+ val = get_param(cmd, "WAN_MAT");
+ if (!val)
+ val = get_param(cmd, "WAN_MET");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s4", count2 > 0 ? "," : "");
+ count2++;
+ }
+
+ val = get_param(cmd, "CONNECTION_CAPABILITY");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s5", count2 > 0 ? "," : "");
+ count2++;
+ }
+
+ val = get_param(cmd, "OP_CLASS");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s7", count2 > 0 ? "," : "");
+ count2++;
+ }
+
+ val = get_param(cmd, "OSU_PROVIDER_LIST");
+ if (val && atoi(val)) {
+ pos += snprintf(pos, end - pos, "%s8", count2 > 0 ? "," : "");
+ count2++;
+ }
+
+ if (count && count2) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Wait before sending out "
+ "second query");
+ sleep(1);
+ }
+
+ if (count2 && wpa_command(intf, buf)) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,HS20_ANQP_GET "
+ "failed");
+ return 0;
+ }
+
+ val = get_param(cmd, "NAI_HOME_REALM_LIST");
+ if (val) {
+ if (count || count2) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Wait before "
+ "sending out second query");
+ sleep(1);
+ }
+
+ if (strcmp(val, "1") == 0)
+ val = "mail.example.com";
+ snprintf(buf, end - pos,
+ "HS20_GET_NAI_HOME_REALM_LIST %s realm=%s",
+ dest, val);
+ if (wpa_command(intf, buf)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,HS20_GET_NAI_HOME_REALM_LIST "
+ "failed");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "ICON_REQUEST");
+ if (val) {
+ if (count || count2) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Wait before "
+ "sending out second query");
+ sleep(1);
+ }
+
+ snprintf(buf, end - pos,
+ "HS20_ICON_REQUEST %s %s", dest, val);
+ if (wpa_command(intf, buf)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,HS20_ICON_REQUEST failed");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+static int ath_sta_send_frame_vht(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ char *ifname;
+ char buf[100];
+ int chwidth, nss;
+
+ val = get_param(cmd, "framename");
+ if (!val)
+ return -1;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "framename is %s", val);
+
+ /* Command sequence to generate Op mode notification */
+ if (val && strcasecmp(val, "Op_md_notif_frm") == 0) {
+ ifname = get_station_ifname();
+
+ /* Disable STBC */
+ snprintf(buf, sizeof(buf),
+ "iwpriv %s tx_stbc 0", ifname);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv tx_stbc 0 failed!");
+ }
+
+ /* Extract Channel width */
+ val = get_param(cmd, "Channel_width");
+ if (val) {
+ switch (atoi(val)) {
+ case 20:
+ chwidth = 0;
+ break;
+ case 40:
+ chwidth = 1;
+ break;
+ case 80:
+ chwidth = 2;
+ break;
+ case 160:
+ chwidth = 3;
+ break;
+ default:
+ chwidth = 2;
+ break;
+ }
+
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth %d",
+ ifname, chwidth);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv chwidth failed!");
+ }
+ }
+
+ /* Extract NSS */
+ val = get_param(cmd, "NSS");
+ if (val) {
+ switch (atoi(val)) {
+ case 1:
+ nss = 1;
+ break;
+ case 2:
+ nss = 3;
+ break;
+ case 3:
+ nss = 7;
+ break;
+ default:
+ /* We do not support NSS > 3 */
+ nss = 3;
+ break;
+ }
+ snprintf(buf, sizeof(buf),
+ "iwpriv %s rxchainmask %d", ifname, nss);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv rxchainmask failed!");
+ }
+ }
+
+ /* Opmode notify */
+ snprintf(buf, sizeof(buf), "iwpriv %s opmode_notify 1", ifname);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv opmode_notify failed!");
+ } else {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Sent out the notify frame!");
+ }
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_send_frame_vht(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ return ath_sta_send_frame_vht(dut, conn, cmd);
+ default:
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unsupported sta_set_frame(VHT) with the current driver");
+ return 0;
+ }
+}
+
+
+int cmd_sta_send_frame(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val;
+ enum send_frame_type frame;
+ enum send_frame_protection protected;
+ char buf[100];
+ unsigned char addr[ETH_ALEN];
+ int res;
+
+ val = get_param(cmd, "program");
+ if (val == NULL)
+ val = get_param(cmd, "frame");
+ if (val && strcasecmp(val, "TDLS") == 0)
+ return cmd_sta_send_frame_tdls(dut, conn, cmd);
+ if (val && (strcasecmp(val, "HS2") == 0 ||
+ strcasecmp(val, "HS2-R2") == 0))
+ return cmd_sta_send_frame_hs2(dut, conn, cmd);
+ if (val && strcasecmp(val, "VHT") == 0)
+ return cmd_sta_send_frame_vht(dut, conn, cmd);
+
+ val = get_param(cmd, "TD_DISC");
+ if (val) {
+ if (hwaddr_aton(val, addr) < 0)
+ return -1;
+ snprintf(buf, sizeof(buf), "TDLS_DISCOVER %s", val);
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to send TDLS discovery");
+ return 0;
+ }
+ return 1;
+ }
+
+ val = get_param(cmd, "TD_Setup");
+ if (val) {
+ if (hwaddr_aton(val, addr) < 0)
+ return -1;
+ snprintf(buf, sizeof(buf), "TDLS_SETUP %s", val);
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to start TDLS setup");
+ return 0;
+ }
+ return 1;
+ }
+
+ val = get_param(cmd, "TD_TearDown");
+ if (val) {
+ if (hwaddr_aton(val, addr) < 0)
+ return -1;
+ snprintf(buf, sizeof(buf), "TDLS_TEARDOWN %s", val);
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to tear down TDLS link");
+ return 0;
+ }
+ return 1;
+ }
+
+ val = get_param(cmd, "TD_ChannelSwitch");
+ if (val) {
+ /* TODO */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,TD_ChannelSwitch not yet supported");
+ return 0;
+ }
+
+ val = get_param(cmd, "TD_NF");
+ if (val) {
+ /* TODO */
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,TD_NF not yet supported");
+ return 0;
+ }
+
+ val = get_param(cmd, "PMFFrameType");
+ if (val == NULL)
+ val = get_param(cmd, "FrameName");
+ if (val == NULL)
+ val = get_param(cmd, "Type");
+ if (val == NULL)
+ return -1;
+ if (strcasecmp(val, "disassoc") == 0)
+ frame = DISASSOC;
+ else if (strcasecmp(val, "deauth") == 0)
+ frame = DEAUTH;
+ else if (strcasecmp(val, "saquery") == 0)
+ frame = SAQUERY;
+ else if (strcasecmp(val, "auth") == 0)
+ frame = AUTH;
+ else if (strcasecmp(val, "assocreq") == 0)
+ frame = ASSOCREQ;
+ else if (strcasecmp(val, "reassocreq") == 0)
+ frame = REASSOCREQ;
+ else if (strcasecmp(val, "neigreq") == 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Got neighbor request");
+
+ val = get_param(cmd, "ssid");
+ if (val == NULL)
+ return -1;
+
+ res = send_neighbor_request(dut, intf, val);
+ if (res) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,"
+ "Failed to send neighbor report request");
+ return 0;
+ }
+
+ return 1;
+ } else if (strcasecmp(val, "transmgmtquery") == 0) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Got Transition Management Query");
+
+ val = get_param(cmd, "ssid");
+ res = send_trans_mgmt_query(dut, intf, val);
+ if (res) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,"
+ "Failed to send Transition Management Query");
+ return 0;
+ }
+
+ return 1;
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported "
+ "PMFFrameType");
+ return 0;
+ }
+
+ val = get_param(cmd, "PMFProtected");
+ if (val == NULL)
+ val = get_param(cmd, "Protected");
+ if (val == NULL)
+ return -1;
+ if (strcasecmp(val, "Correct-key") == 0 ||
+ strcasecmp(val, "CorrectKey") == 0)
+ protected = CORRECT_KEY;
+ else if (strcasecmp(val, "IncorrectKey") == 0)
+ protected = INCORRECT_KEY;
+ else if (strcasecmp(val, "Unprotected") == 0)
+ protected = UNPROTECTED;
+ else {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported "
+ "PMFProtected");
+ return 0;
+ }
+
+ if (protected != UNPROTECTED &&
+ (frame == AUTH || frame == ASSOCREQ || frame == REASSOCREQ)) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Impossible "
+ "PMFProtected for auth/assocreq/reassocreq");
+ return 0;
+ }
+
+ if (if_nametoindex("sigmadut") == 0) {
+ snprintf(buf, sizeof(buf),
+ "iw dev %s interface add sigmadut type monitor",
+ get_station_ifname());
+ if (system(buf) != 0 ||
+ if_nametoindex("sigmadut") == 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to add "
+ "monitor interface with '%s'", buf);
+ return -2;
+ }
+ }
+
+ if (system("ifconfig sigmadut up") != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to set "
+ "monitor interface up");
+ return -2;
+ }
+
+ return sta_inject_frame(dut, conn, frame, protected, NULL);
+}
+
+
+static int cmd_sta_set_parameter_hs2(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *ifname)
+{
+ char buf[200];
+ const char *val;
+
+ val = get_param(cmd, "ClearARP");
+ if (val && atoi(val) == 1) {
+ snprintf(buf, sizeof(buf), "ip neigh flush dev %s", ifname);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to clear ARP cache");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+int cmd_sta_set_parameter(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val;
+
+ if (intf == NULL)
+ return -1;
+
+ val = get_param(cmd, "program");
+ if (val && (strcasecmp(val, "HS2") == 0 ||
+ strcasecmp(val, "HS2-R2") == 0))
+ return cmd_sta_set_parameter_hs2(dut, conn, cmd, intf);
+
+ return -1;
+}
+
+
+static int cmd_sta_set_macaddr(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *mac = get_param(cmd, "MAC");
+
+ if (intf == NULL || mac == NULL)
+ return -1;
+
+ sigma_dut_print(dut, DUT_MSG_INFO, "Change local MAC address for "
+ "interface %s to %s", intf, mac);
+
+ if (dut->set_macaddr) {
+ char buf[128];
+ int res;
+ if (strcasecmp(mac, "default") == 0) {
+ res = snprintf(buf, sizeof(buf), "%s",
+ dut->set_macaddr);
+ dut->tmp_mac_addr = 0;
+ } else {
+ res = snprintf(buf, sizeof(buf), "%s %s",
+ dut->set_macaddr, mac);
+ dut->tmp_mac_addr = 1;
+ }
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set MAC "
+ "address");
+ return 0;
+ }
+ return 1;
+ }
+
+ if (strcasecmp(mac, "default") == 0)
+ return 1;
+
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported "
+ "command");
+ return 0;
+}
+
+
+static int iwpriv_tdlsoffchnmode(struct sigma_dut *dut,
+ struct sigma_conn *conn, const char *intf,
+ int val)
+{
+ char buf[200];
+ int res;
+
+ res = snprintf(buf, sizeof(buf), "iwpriv %s tdlsoffchnmode %d",
+ intf, val);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to configure offchannel mode");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+enum sec_ch_offset {
+ SEC_CH_NO,
+ SEC_CH_40ABOVE,
+ SEC_CH_40BELOW
+};
+
+
+static int off_chan_val(enum sec_ch_offset off)
+{
+ switch (off) {
+ case SEC_CH_NO:
+ return 0;
+ case SEC_CH_40ABOVE:
+ return 40;
+ case SEC_CH_40BELOW:
+ return -40;
+ }
+
+ return 0;
+}
+
+
+static int iwpriv_set_offchan(struct sigma_dut *dut, struct sigma_conn *conn,
+ const char *intf, int off_ch_num,
+ enum sec_ch_offset sec)
+{
+ char buf[200];
+ int res;
+
+ res = snprintf(buf, sizeof(buf), "iwpriv %s tdlsoffchan %d",
+ intf, off_ch_num);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set offchan");
+ return 0;
+ }
+
+ res = snprintf(buf, sizeof(buf), "iwpriv %s tdlsecchnoffst %d",
+ intf, off_chan_val(sec));
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set sec chan offset");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int tdls_set_offchannel_offset(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *intf, int off_ch_num,
+ enum sec_ch_offset sec)
+{
+ char buf[200];
+ int res;
+
+ res = snprintf(buf, sizeof(buf), "DRIVER TDLSOFFCHANNEL %d",
+ off_ch_num);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set offchan");
+ return 0;
+ }
+ res = snprintf(buf, sizeof(buf), "DRIVER TDLSSECONDARYCHANNELOFFSET %d",
+ off_chan_val(sec));
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set sec chan offset");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int tdls_set_offchannel_mode(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *intf, int val)
+{
+ char buf[200];
+ int res;
+
+ res = snprintf(buf, sizeof(buf), "DRIVER TDLSOFFCHANNELMODE %d",
+ val);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to configure offchannel mode");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_set_rfeature_tdls(const char *intf, struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ enum {
+ CHSM_NOT_SET,
+ CHSM_ENABLE,
+ CHSM_DISABLE,
+ CHSM_REJREQ,
+ CHSM_UNSOLRESP
+ } chsm = CHSM_NOT_SET;
+ int off_ch_num = -1;
+ enum sec_ch_offset sec_ch = SEC_CH_NO;
+ int res;
+
+ val = get_param(cmd, "Uapsd");
+ if (val) {
+ char buf[100];
+ if (strcasecmp(val, "Enable") == 0)
+ snprintf(buf, sizeof(buf), "SET ps 99");
+ else if (strcasecmp(val, "Disable") == 0)
+ snprintf(buf, sizeof(buf), "SET ps 98");
+ else {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,"
+ "Unsupported uapsd parameter value");
+ return 0;
+ }
+ if (wpa_command(intf, buf)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to change U-APSD "
+ "powersave mode");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "TPKTIMER");
+ if (val && strcasecmp(val, "DISABLE") == 0) {
+ if (wpa_command(intf, "SET tdls_testing 0x100")) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to enable no TPK "
+ "expiration test mode");
+ return 0;
+ }
+ dut->no_tpk_expiration = 1;
+ }
+
+ val = get_param(cmd, "ChSwitchMode");
+ if (val) {
+ if (strcasecmp(val, "Enable") == 0 ||
+ strcasecmp(val, "Initiate") == 0)
+ chsm = CHSM_ENABLE;
+ else if (strcasecmp(val, "Disable") == 0 ||
+ strcasecmp(val, "passive") == 0)
+ chsm = CHSM_DISABLE;
+ else if (strcasecmp(val, "RejReq") == 0)
+ chsm = CHSM_REJREQ;
+ else if (strcasecmp(val, "UnSolResp") == 0)
+ chsm = CHSM_UNSOLRESP;
+ else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unknown ChSwitchMode value");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "OffChNum");
+ if (val) {
+ off_ch_num = atoi(val);
+ if (off_ch_num == 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Invalid OffChNum");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "SecChOffset");
+ if (val) {
+ if (strcmp(val, "20") == 0)
+ sec_ch = SEC_CH_NO;
+ else if (strcasecmp(val, "40above") == 0)
+ sec_ch = SEC_CH_40ABOVE;
+ else if (strcasecmp(val, "40below") == 0)
+ sec_ch = SEC_CH_40BELOW;
+ else {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unknown SecChOffset value");
+ return 0;
+ }
+ }
+
+ if (chsm == CHSM_NOT_SET) {
+ /* no offchannel changes requested */
+ return 1;
+ }
+
+ if (strcmp(intf, get_main_ifname()) != 0 &&
+ strcmp(intf, get_station_ifname()) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unknown interface");
+ return 0;
+ }
+
+ switch (chsm) {
+ case CHSM_NOT_SET:
+ break;
+ case CHSM_ENABLE:
+ if (off_ch_num < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing OffChNum argument");
+ return 0;
+ }
+ if (wifi_chip_type == DRIVER_WCN) {
+ res = tdls_set_offchannel_offset(dut, conn, intf,
+ off_ch_num, sec_ch);
+ } else {
+ res = iwpriv_set_offchan(dut, conn, intf, off_ch_num,
+ sec_ch);
+ }
+ if (res != 1)
+ return res;
+ if (wifi_chip_type == DRIVER_WCN)
+ res = tdls_set_offchannel_mode(dut, conn, intf, 1);
+ else
+ res = iwpriv_tdlsoffchnmode(dut, conn, intf, 1);
+ break;
+ case CHSM_DISABLE:
+ if (wifi_chip_type == DRIVER_WCN)
+ res = tdls_set_offchannel_mode(dut, conn, intf, 2);
+ else
+ res = iwpriv_tdlsoffchnmode(dut, conn, intf, 2);
+ break;
+ case CHSM_REJREQ:
+ if (wifi_chip_type == DRIVER_WCN)
+ res = tdls_set_offchannel_mode(dut, conn, intf, 3);
+ else
+ res = iwpriv_tdlsoffchnmode(dut, conn, intf, 3);
+ break;
+ case CHSM_UNSOLRESP:
+ if (off_ch_num < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing OffChNum argument");
+ return 0;
+ }
+ if (wifi_chip_type == DRIVER_WCN) {
+ res = tdls_set_offchannel_offset(dut, conn, intf,
+ off_ch_num, sec_ch);
+ } else {
+ res = iwpriv_set_offchan(dut, conn, intf, off_ch_num,
+ sec_ch);
+ }
+ if (res != 1)
+ return res;
+ if (wifi_chip_type == DRIVER_WCN)
+ res = tdls_set_offchannel_mode(dut, conn, intf, 4);
+ else
+ res = iwpriv_tdlsoffchnmode(dut, conn, intf, 4);
+ break;
+ }
+
+ return res;
+}
+
+
+static int ath_sta_set_rfeature_vht(const char *intf, struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ char *token, *result;
+
+ val = get_param(cmd, "nss_mcs_opt");
+ if (val) {
+ /* String (nss_operating_mode; mcs_operating_mode) */
+ int nss, mcs;
+ char buf[50];
+
+ token = strdup(val);
+ if (!token)
+ return 0;
+ result = strtok(token, ";");
+ if (strcasecmp(result, "def") != 0) {
+ nss = atoi(result);
+ if (nss == 4)
+ ath_disable_txbf(dut, intf);
+ snprintf(buf, sizeof(buf), "iwpriv %s nss %d",
+ intf, nss);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv nss failed");
+ goto failed;
+ }
+ }
+
+ result = strtok(NULL, ";");
+ if (strcasecmp(result, "def") == 0) {
+ snprintf(buf, sizeof(buf), "iwpriv %s set11NRates 0",
+ intf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv set11NRates failed");
+ goto failed;
+ }
+
+ } else {
+ mcs = atoi(result);
+ snprintf(buf, sizeof(buf), "iwpriv %s vhtmcs %d",
+ intf, mcs);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv vhtmcs failed");
+ goto failed;
+ }
+ }
+ /* Channel width gets messed up, fix this */
+ snprintf(buf, sizeof(buf), "iwpriv %s chwidth %d",
+ intf, dut->chwidth);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "iwpriv chwidth failed");
+ }
+ }
+
+ return 1;
+failed:
+ free(token);
+ return 0;
+}
+
+
+static int cmd_sta_set_rfeature_vht(const char *intf, struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ switch (get_driver_type()) {
+ case DRIVER_ATHEROS:
+ return ath_sta_set_rfeature_vht(intf, dut, conn, cmd);
+ default:
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unsupported sta_set_rfeature(VHT) with the current driver");
+ return 0;
+ }
+}
+
+
+static int cmd_sta_set_rfeature(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *prog = get_param(cmd, "Prog");
+
+ if (intf == NULL || prog == NULL)
+ return -1;
+
+ if (strcasecmp(prog, "TDLS") == 0)
+ return cmd_sta_set_rfeature_tdls(intf, dut, conn, cmd);
+
+ if (strcasecmp(prog, "VHT") == 0)
+ return cmd_sta_set_rfeature_vht(intf, dut, conn, cmd);
+
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported Prog");
+ return 0;
+}
+
+
+static int cmd_sta_set_radio(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *mode = get_param(cmd, "Mode");
+ int res;
+
+ if (intf == NULL || mode == NULL)
+ return -1;
+
+ if (strcasecmp(mode, "On") == 0)
+ res = wpa_command(intf, "SET radio_disabled 0");
+ else if (strcasecmp(mode, "Off") == 0)
+ res = wpa_command(intf, "SET radio_disabled 1");
+ else
+ return -1;
+
+ if (res) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to change "
+ "radio mode");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_set_pwrsave(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *mode = get_param(cmd, "Mode");
+ int res;
+
+ if (intf == NULL || mode == NULL)
+ return -1;
+
+ if (strcasecmp(mode, "On") == 0)
+ res = set_ps(intf, dut, 1);
+ else if (strcasecmp(mode, "Off") == 0)
+ res = set_ps(intf, dut, 0);
+ else
+ return -1;
+
+ if (res) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to change "
+ "power save mode");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_bssid_pool(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val, *bssid;
+ int res;
+ char *buf;
+ size_t buf_len;
+
+ val = get_param(cmd, "BSSID_FILTER");
+ if (val == NULL)
+ return -1;
+
+ bssid = get_param(cmd, "BSSID_List");
+ if (atoi(val) == 0 || bssid == NULL) {
+ /* Disable BSSID filter */
+ if (wpa_command(intf, "SET bssid_filter ")) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed "
+ "to disable BSSID filter");
+ return 0;
+ }
+
+ return 1;
+ }
+
+ buf_len = 100 + strlen(bssid);
+ buf = malloc(buf_len);
+ if (buf == NULL)
+ return -1;
+
+ snprintf(buf, buf_len, "SET bssid_filter %s", bssid);
+ res = wpa_command(intf, buf);
+ free(buf);
+ if (res) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to enable "
+ "BSSID filter");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_reset_parm(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val;
+
+ /* TODO: ARP */
+
+ val = get_param(cmd, "HS2_CACHE_PROFILE");
+ if (val && strcasecmp(val, "All") == 0)
+ hs2_clear_credentials(intf);
+
+ return 1;
+}
+
+
+static int cmd_sta_get_key(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *key_type = get_param(cmd, "KeyType");
+ char buf[100], resp[200];
+
+ if (key_type == NULL)
+ return -1;
+
+ if (strcasecmp(key_type, "GTK") == 0) {
+ if (wpa_command_resp(intf, "GET gtk", buf, sizeof(buf)) < 0 ||
+ strncmp(buf, "FAIL", 4) == 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could "
+ "not fetch current GTK");
+ return 0;
+ }
+ snprintf(resp, sizeof(resp), "KeyValue,%s", buf);
+ send_resp(dut, conn, SIGMA_COMPLETE, resp);
+ return 0;
+ } else {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported "
+ "KeyType");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int hs2_set_policy(struct sigma_dut *dut)
+{
+#ifdef ANDROID
+ system("ip rule del prio 23000");
+ if (system("ip rule add from all lookup main prio 23000") != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to run:ip rule add from all lookup main prio");
+ return -1;
+ }
+ if (system("ip route flush cache") != 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to run ip route flush cache");
+ return -1;
+ }
+ return 1;
+#else /* ANDROID */
+ return 0;
+#endif /* ANDROID */
+}
+
+
+static int cmd_sta_hs2_associate(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val = get_param(cmd, "Ignore_blacklist");
+ struct wpa_ctrl *ctrl;
+ int res;
+ char bssid[20], ssid[40], resp[100], buf[100], blacklisted[100];
+ int tries = 0;
+ int ignore_blacklist = 0;
+ const char *events[] = {
+ "CTRL-EVENT-CONNECTED",
+ "INTERWORKING-BLACKLISTED",
+ "INTERWORKING-NO-MATCH",
+ NULL
+ };
+
+ start_sta_mode(dut);
+
+ blacklisted[0] = '\0';
+ if (val && atoi(val))
+ ignore_blacklist = 1;
+
+try_again:
+ ctrl = open_wpa_mon(intf);
+ if (ctrl == NULL) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to open "
+ "wpa_supplicant monitor connection");
+ return -2;
+ }
+
+ tries++;
+ if (wpa_command(intf, "INTERWORKING_SELECT auto")) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to start "
+ "Interworking connection");
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ return 0;
+ }
+
+ buf[0] = '\0';
+ while (1) {
+ char *pos;
+ res = get_wpa_cli_events(dut, ctrl, events, buf, sizeof(buf));
+ pos = strstr(buf, "INTERWORKING-BLACKLISTED");
+ if (!pos)
+ break;
+ pos += 25;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Found blacklisted AP: %s",
+ pos);
+ if (!blacklisted[0])
+ memcpy(blacklisted, pos, strlen(pos) + 1);
+ }
+
+ if (ignore_blacklist && blacklisted[0]) {
+ char *end;
+ end = strchr(blacklisted, ' ');
+ if (end)
+ *end = '\0';
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Try to connect to a blacklisted network: %s",
+ blacklisted);
+ snprintf(buf, sizeof(buf), "INTERWORKING_CONNECT %s",
+ blacklisted);
+ if (wpa_command(intf, buf)) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Failed to start Interworking connection to blacklisted network");
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ return 0;
+ }
+ res = get_wpa_cli_event(dut, ctrl, "CTRL-EVENT-CONNECTED",
+ buf, sizeof(buf));
+ }
+
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+
+ if (res < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Could not "
+ "connect");
+ return 0;
+ }
+
+ if (strstr(buf, "INTERWORKING-NO-MATCH") ||
+ strstr(buf, "INTERWORKING-BLACKLISTED")) {
+ if (tries < 2) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "No match found - try again to verify no APs were missed in the scan");
+ goto try_again;
+ }
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,No network with "
+ "matching credentials found");
+ return 0;
+ }
+
+ if (get_wpa_status(intf, "bssid", bssid, sizeof(bssid)) < 0 ||
+ get_wpa_status(intf, "ssid", ssid, sizeof(ssid)) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Could not "
+ "get current BSSID/SSID");
+ return 0;
+ }
+
+ snprintf(resp, sizeof(resp), "SSID,%s,BSSID,%s", ssid, bssid);
+ send_resp(dut, conn, SIGMA_COMPLETE, resp);
+ hs2_set_policy(dut);
+ return 0;
+}
+
+
+static int sta_add_credential_uname_pwd(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *ifname,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ int id;
+
+ id = add_cred(ifname);
+ if (id < 0)
+ return -2;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Adding credential %d", id);
+
+ val = get_param(cmd, "prefer");
+ if (val && atoi(val) > 0)
+ set_cred(ifname, id, "priority", "1");
+
+ val = get_param(cmd, "REALM");
+ if (val && set_cred_quoted(ifname, id, "realm", val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not set "
+ "realm");
+ return 0;
+ }
+
+ val = get_param(cmd, "HOME_FQDN");
+ if (val && set_cred_quoted(ifname, id, "domain", val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not set "
+ "home_fqdn");
+ return 0;
+ }
+
+ val = get_param(cmd, "Username");
+ if (val && set_cred_quoted(ifname, id, "username", val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not set "
+ "username");
+ return 0;
+ }
+
+ val = get_param(cmd, "Password");
+ if (val && set_cred_quoted(ifname, id, "password", val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not set "
+ "password");
+ return 0;
+ }
+
+ val = get_param(cmd, "ROOT_CA");
+ if (val) {
+ char fname[200];
+ snprintf(fname, sizeof(fname), "%s/%s", sigma_cert_path, val);
+#ifdef __linux__
+ if (!file_exists(fname)) {
+ char msg[300];
+ snprintf(msg, sizeof(msg), "ErrorCode,ROOT_CA "
+ "file (%s) not found", fname);
+ send_resp(dut, conn, SIGMA_ERROR, msg);
+ return 0;
+ }
+#endif /* __linux__ */
+ if (set_cred_quoted(ifname, id, "ca_cert", fname) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could "
+ "not set root CA");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+static int update_devdetail_imsi(struct sigma_dut *dut, const char *imsi)
+{
+ FILE *in, *out;
+ char buf[500];
+ int found = 0;
+
+ in = fopen("devdetail.xml", "r");
+ if (in == NULL)
+ return -1;
+ out = fopen("devdetail.xml.tmp", "w");
+ if (out == NULL) {
+ fclose(in);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), in)) {
+ char *pos = strstr(buf, "<IMSI>");
+ if (pos) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Updated DevDetail IMSI to %s",
+ imsi);
+ pos += 6;
+ *pos = '\0';
+ fprintf(out, "%s%s</IMSI>\n", buf, imsi);
+ found++;
+ } else {
+ fprintf(out, "%s", buf);
+ }
+ }
+
+ fclose(out);
+ fclose(in);
+ if (found)
+ rename("devdetail.xml.tmp", "devdetail.xml");
+ else
+ unlink("devdetail.xml.tmp");
+
+ return 0;
+}
+
+
+static int sta_add_credential_sim(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *ifname, struct sigma_cmd *cmd)
+{
+ const char *val, *imsi = NULL;
+ int id;
+ char buf[200];
+ int res;
+ const char *pos;
+ size_t mnc_len;
+ char plmn_mcc[4];
+ char plmn_mnc[4];
+
+ id = add_cred(ifname);
+ if (id < 0)
+ return -2;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Adding credential %d", id);
+
+ val = get_param(cmd, "prefer");
+ if (val && atoi(val) > 0)
+ set_cred(ifname, id, "priority", "1");
+
+ val = get_param(cmd, "PLMN_MCC");
+ if (val == NULL) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Missing PLMN_MCC");
+ return 0;
+ }
+ if (strlen(val) != 3) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Invalid MCC");
+ return 0;
+ }
+ snprintf(plmn_mcc, sizeof(plmn_mcc), "%s", val);
+
+ val = get_param(cmd, "PLMN_MNC");
+ if (val == NULL) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Missing PLMN_MNC");
+ return 0;
+ }
+ if (strlen(val) != 2 && strlen(val) != 3) {
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Invalid MNC");
+ return 0;
+ }
+ snprintf(plmn_mnc, sizeof(plmn_mnc), "%s", val);
+
+ val = get_param(cmd, "IMSI");
+ if (val == NULL) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Missing SIM "
+ "IMSI");
+ return 0;
+ }
+
+ imsi = pos = val;
+
+ if (strncmp(plmn_mcc, pos, 3) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,MCC mismatch");
+ return 0;
+ }
+ pos += 3;
+
+ mnc_len = strlen(plmn_mnc);
+ if (mnc_len < 2) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,MNC not set");
+ return 0;
+ }
+
+ if (strncmp(plmn_mnc, pos, mnc_len) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,MNC mismatch");
+ return 0;
+ }
+ pos += mnc_len;
+
+ res = snprintf(buf, sizeof(buf), "%s%s-%s",plmn_mcc, plmn_mnc, pos);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ if (set_cred_quoted(ifname, id, "imsi", buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could "
+ "not set IMSI");
+ return 0;
+ }
+
+ val = get_param(cmd, "Password");
+ if (val && set_cred_quoted(ifname, id, "milenage", val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could "
+ "not set password");
+ return 0;
+ }
+
+ if (dut->program == PROGRAM_HS2_R2) {
+ /*
+ * Set provisioning_sp for the test cases where SIM/USIM
+ * provisioning is used.
+ */
+ if (val && set_cred_quoted(ifname, id, "provisioning_sp",
+ "wi-fi.org") < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could "
+ "not set provisioning_sp");
+ return 0;
+ }
+
+ update_devdetail_imsi(dut, imsi);
+ }
+
+ return 1;
+}
+
+
+static int sta_add_credential_cert(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *ifname,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ int id;
+
+ id = add_cred(ifname);
+ if (id < 0)
+ return -2;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Adding credential %d", id);
+
+ val = get_param(cmd, "prefer");
+ if (val && atoi(val) > 0)
+ set_cred(ifname, id, "priority", "1");
+
+ val = get_param(cmd, "REALM");
+ if (val && set_cred_quoted(ifname, id, "realm", val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not set "
+ "realm");
+ return 0;
+ }
+
+ val = get_param(cmd, "HOME_FQDN");
+ if (val && set_cred_quoted(ifname, id, "domain", val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not set "
+ "home_fqdn");
+ return 0;
+ }
+
+ val = get_param(cmd, "Username");
+ if (val && set_cred_quoted(ifname, id, "username", val) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not set "
+ "username");
+ return 0;
+ }
+
+ val = get_param(cmd, "clientCertificate");
+ if (val) {
+ char fname[200];
+ snprintf(fname, sizeof(fname), "%s/%s", sigma_cert_path, val);
+#ifdef __linux__
+ if (!file_exists(fname)) {
+ char msg[300];
+ snprintf(msg, sizeof(msg),
+ "ErrorCode,clientCertificate "
+ "file (%s) not found", fname);
+ send_resp(dut, conn, SIGMA_ERROR, msg);
+ return 0;
+ }
+#endif /* __linux__ */
+ if (set_cred_quoted(ifname, id, "client_cert", fname) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could "
+ "not set client_cert");
+ return 0;
+ }
+ if (set_cred_quoted(ifname, id, "private_key", fname) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could "
+ "not set private_key");
+ return 0;
+ }
+ }
+
+ val = get_param(cmd, "ROOT_CA");
+ if (val) {
+ char fname[200];
+ snprintf(fname, sizeof(fname), "%s/%s", sigma_cert_path, val);
+#ifdef __linux__
+ if (!file_exists(fname)) {
+ char msg[300];
+ snprintf(msg, sizeof(msg), "ErrorCode,ROOT_CA "
+ "file (%s) not found", fname);
+ send_resp(dut, conn, SIGMA_ERROR, msg);
+ return 0;
+ }
+#endif /* __linux__ */
+ if (set_cred_quoted(ifname, id, "ca_cert", fname) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could "
+ "not set root CA");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_add_credential(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *type;
+
+ start_sta_mode(dut);
+
+ type = get_param(cmd, "Type");
+ if (!type)
+ return -1;
+
+ if (strcasecmp(type, "uname_pwd") == 0)
+ return sta_add_credential_uname_pwd(dut, conn, intf, cmd);
+
+ if (strcasecmp(type, "sim") == 0)
+ return sta_add_credential_sim(dut, conn, intf, cmd);
+
+ if (strcasecmp(type, "cert") == 0)
+ return sta_add_credential_cert(dut, conn, intf, cmd);
+
+ send_resp(dut, conn, SIGMA_ERROR, "ErrorCode,Unsupported credential "
+ "type");
+ return 0;
+}
+
+
+static int cmd_sta_scan(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *val;
+ char buf[100];
+ int res;
+
+ val = get_param(cmd, "HESSID");
+ if (val) {
+ res = snprintf(buf, sizeof(buf), "SET hessid %s", val);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ wpa_command(intf, buf);
+ }
+
+ val = get_param(cmd, "ACCS_NET_TYPE");
+ if (val) {
+ res = snprintf(buf, sizeof(buf), "SET access_network_type %s",
+ val);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ wpa_command(intf, buf);
+ }
+
+ if (wpa_command(intf, "SCAN")) {
+ send_resp(dut, conn, SIGMA_ERROR, "errorCode,Could not start "
+ "scan");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int cmd_sta_set_systime(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+#ifdef __linux__
+ struct timeval tv;
+ struct tm tm;
+ time_t t;
+ const char *val;
+
+ wpa_command(get_station_ifname(), "PMKSA_FLUSH");
+
+ memset(&tm, 0, sizeof(tm));
+ val = get_param(cmd, "seconds");
+ if (val)
+ tm.tm_sec = atoi(val);
+ val = get_param(cmd, "minutes");
+ if (val)
+ tm.tm_min = atoi(val);
+ val = get_param(cmd, "hours");
+ if (val)
+ tm.tm_hour = atoi(val);
+ val = get_param(cmd, "date");
+ if (val)
+ tm.tm_mday = atoi(val);
+ val = get_param(cmd, "month");
+ if (val)
+ tm.tm_mon = atoi(val) - 1;
+ val = get_param(cmd, "year");
+ if (val) {
+ int year = atoi(val);
+#ifdef ANDROID
+ if (year > 2035)
+ year = 2035; /* years beyond 2035 not supported */
+#endif /* ANDROID */
+ tm.tm_year = year - 1900;
+ }
+ t = mktime(&tm);
+ if (t == (time_t) -1) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Invalid date or time");
+ return 0;
+ }
+
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = t;
+
+ if (settimeofday(&tv, NULL) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "settimeofday failed: %s",
+ strerror(errno));
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set time");
+ return 0;
+ }
+
+ return 1;
+#endif /* __linux__ */
+
+ return -1;
+}
+
+
+static int cmd_sta_osu(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *intf = get_param(cmd, "Interface");
+ const char *name, *val;
+ int prod_ess_assoc = 1;
+ char buf[200], bssid[100], ssid[100];
+ int res;
+ struct wpa_ctrl *ctrl;
+
+ name = get_param(cmd, "osuFriendlyName");
+
+ val = get_param(cmd, "ProdESSAssoc");
+ if (val)
+ prod_ess_assoc = atoi(val);
+
+ kill_dhcp_client(dut, intf);
+ if (start_dhcp_client(dut, intf) < 0)
+ return -2;
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Trigger OSU");
+ mkdir("Logs", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ res = snprintf(buf, sizeof(buf),
+ "%s %s%s%s signup osu-ca.pem",
+ prod_ess_assoc ? "" : "-N",
+ name ? "-O'" : "", name ? name : "",
+ name ? "'" : "");
+
+ if (run_hs20_osu(dut, buf) < 0) {
+ FILE *f;
+
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to complete OSU");
+
+ f = fopen("hs20-osu-client.res", "r");
+ if (f) {
+ char resp[400], res[300], *pos;
+ if (!fgets(res, sizeof(res), f))
+ res[0] = '\0';
+ pos = strchr(res, '\n');
+ if (pos)
+ *pos = '\0';
+ fclose(f);
+ sigma_dut_summary(dut, "hs20-osu-client provisioning failed: %s",
+ res);
+ snprintf(resp, sizeof(resp), "notify-send '%s'", res);
+ if (system(resp) != 0) {
+ }
+ snprintf(resp, sizeof(resp),
+ "SSID,,BSSID,,failureReason,%s", res);
+ send_resp(dut, conn, SIGMA_COMPLETE, resp);
+ return 0;
+ }
+
+ send_resp(dut, conn, SIGMA_COMPLETE, "SSID,,BSSID,");
+ return 0;
+ }
+
+ if (!prod_ess_assoc)
+ goto report;
+
+ ctrl = open_wpa_mon(intf);
+ if (ctrl == NULL) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to open "
+ "wpa_supplicant monitor connection");
+ return -1;
+ }
+
+ res = get_wpa_cli_event(dut, ctrl, "CTRL-EVENT-CONNECTED",
+ buf, sizeof(buf));
+
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+
+ if (res < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to connect to "
+ "network after OSU");
+ send_resp(dut, conn, SIGMA_COMPLETE, "SSID,,BSSID,");
+ return 0;
+ }
+
+report:
+ if (get_wpa_status(intf, "bssid", bssid, sizeof(bssid)) < 0 ||
+ get_wpa_status(intf, "ssid", ssid, sizeof(ssid)) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to get BSSID/SSID");
+ send_resp(dut, conn, SIGMA_COMPLETE, "SSID,,BSSID,");
+ return 0;
+ }
+
+ snprintf(buf, sizeof(buf), "SSID,%s,BSSID,%s", ssid, bssid);
+ send_resp(dut, conn, SIGMA_COMPLETE, buf);
+ hs2_set_policy(dut);
+ return 0;
+}
+
+
+static int cmd_sta_policy_update(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ int timeout = 120;
+
+ val = get_param(cmd, "PolicyUpdate");
+ if (val == NULL || atoi(val) == 0)
+ return 1; /* No operation requested */
+
+ val = get_param(cmd, "Timeout");
+ if (val)
+ timeout = atoi(val);
+
+ if (timeout) {
+ /* TODO: time out the command and return
+ * PolicyUpdateStatus,TIMEOUT if needed. */
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Trigger policy update");
+ mkdir("Logs", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ if (run_hs20_osu(dut, "pol_upd fqdn=wi-fi.org") < 0) {
+ send_resp(dut, conn, SIGMA_COMPLETE, "PolicyUpdateStatus,FAIL");
+ return 0;
+ }
+
+ send_resp(dut, conn, SIGMA_COMPLETE, "PolicyUpdateStatus,SUCCESS");
+ return 0;
+}
+
+
+static int cmd_sta_er_config(struct sigma_dut *dut, struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ struct wpa_ctrl *ctrl;
+ const char *intf = get_param(cmd, "Interface");
+ const char *bssid = get_param(cmd, "Bssid");
+ const char *ssid = get_param(cmd, "SSID");
+ const char *security = get_param(cmd, "Security");
+ const char *passphrase = get_param(cmd, "Passphrase");
+ const char *pin = get_param(cmd, "PIN");
+ char buf[1000];
+ char ssid_hex[200], passphrase_hex[200];
+ const char *keymgmt, *cipher;
+
+ if (intf == NULL)
+ intf = get_main_ifname();
+
+ if (!bssid) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing Bssid argument");
+ return 0;
+ }
+
+ if (!ssid) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing SSID argument");
+ return 0;
+ }
+
+ if (!security) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing Security argument");
+ return 0;
+ }
+
+ if (!passphrase) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing Passphrase argument");
+ return 0;
+ }
+
+ if (!pin) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing PIN argument");
+ return 0;
+ }
+
+ if (strlen(ssid) >= 2 * sizeof(ssid_hex) ||
+ strlen(passphrase) >= 2 * sizeof(passphrase_hex)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Too long SSID/passphrase");
+ return 0;
+ }
+
+ ctrl = open_wpa_mon(intf);
+ if (ctrl == NULL) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to open "
+ "wpa_supplicant monitor connection");
+ return -2;
+ }
+
+ if (strcasecmp(security, "wpa2-psk") == 0) {
+ keymgmt = "WPA2PSK";
+ cipher = "CCMP";
+ } else {
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported Security value");
+ return 0;
+ }
+
+ ascii2hexstr(ssid, ssid_hex);
+ ascii2hexstr(passphrase, passphrase_hex);
+ snprintf(buf, sizeof(buf), "WPS_REG %s %s %s %s %s %s",
+ bssid, pin, ssid_hex, keymgmt, cipher, passphrase_hex);
+
+ if (wpa_command(intf, buf) < 0) {
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to start registrar");
+ return 0;
+ }
+
+ snprintf(dut->er_oper_bssid, sizeof(dut->er_oper_bssid), "%s", bssid);
+ dut->er_oper_performed = 1;
+
+ return wps_connection_event(dut, conn, ctrl, intf, 0);
+}
+
+
+static int cmd_sta_wps_connect_pw_token(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ struct wpa_ctrl *ctrl;
+ const char *intf = get_param(cmd, "Interface");
+ const char *bssid = get_param(cmd, "Bssid");
+ char buf[100];
+
+ if (!bssid) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Missing Bssid argument");
+ return 0;
+ }
+
+ ctrl = open_wpa_mon(intf);
+ if (ctrl == NULL) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to open "
+ "wpa_supplicant monitor connection");
+ return -2;
+ }
+
+ snprintf(buf, sizeof(buf), "WPS_NFC %s", bssid);
+
+ if (wpa_command(intf, buf) < 0) {
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to start registrar");
+ return 0;
+ }
+
+ return wps_connection_event(dut, conn, ctrl, intf, 0);
+}
+
+
+static int req_intf(struct sigma_cmd *cmd)
+{
+ return get_param(cmd, "interface") == NULL ? -1 : 0;
+}
+
+
+void sta_register_cmds(void)
+{
+ sigma_dut_reg_cmd("sta_get_ip_config", req_intf,
+ cmd_sta_get_ip_config);
+ sigma_dut_reg_cmd("sta_set_ip_config", req_intf,
+ cmd_sta_set_ip_config);
+ sigma_dut_reg_cmd("sta_get_info", req_intf, cmd_sta_get_info);
+ sigma_dut_reg_cmd("sta_get_mac_address", req_intf,
+ cmd_sta_get_mac_address);
+ sigma_dut_reg_cmd("sta_is_connected", req_intf, cmd_sta_is_connected);
+ sigma_dut_reg_cmd("sta_verify_ip_connection", req_intf,
+ cmd_sta_verify_ip_connection);
+ sigma_dut_reg_cmd("sta_get_bssid", req_intf, cmd_sta_get_bssid);
+ sigma_dut_reg_cmd("sta_set_encryption", req_intf,
+ cmd_sta_set_encryption);
+ sigma_dut_reg_cmd("sta_set_psk", req_intf, cmd_sta_set_psk);
+ sigma_dut_reg_cmd("sta_set_eaptls", req_intf, cmd_sta_set_eaptls);
+ sigma_dut_reg_cmd("sta_set_eapttls", req_intf, cmd_sta_set_eapttls);
+ sigma_dut_reg_cmd("sta_set_eapsim", req_intf, cmd_sta_set_eapsim);
+ sigma_dut_reg_cmd("sta_set_peap", req_intf, cmd_sta_set_peap);
+ sigma_dut_reg_cmd("sta_set_eapfast", req_intf, cmd_sta_set_eapfast);
+ sigma_dut_reg_cmd("sta_set_eapaka", req_intf, cmd_sta_set_eapaka);
+ sigma_dut_reg_cmd("sta_set_eapakaprime", req_intf,
+ cmd_sta_set_eapakaprime);
+ sigma_dut_reg_cmd("sta_set_security", req_intf, cmd_sta_set_security);
+ sigma_dut_reg_cmd("sta_set_uapsd", req_intf, cmd_sta_set_uapsd);
+ /* TODO: sta_set_ibss */
+ /* TODO: sta_set_mode */
+ sigma_dut_reg_cmd("sta_set_wmm", req_intf, cmd_sta_set_wmm);
+ sigma_dut_reg_cmd("sta_associate", req_intf, cmd_sta_associate);
+ /* TODO: sta_up_load */
+ sigma_dut_reg_cmd("sta_preset_testparameters", req_intf,
+ cmd_sta_preset_testparameters);
+ /* TODO: sta_set_system */
+ sigma_dut_reg_cmd("sta_set_11n", req_intf, cmd_sta_set_11n);
+ /* TODO: sta_set_rifs_test */
+ sigma_dut_reg_cmd("sta_set_wireless", req_intf, cmd_sta_set_wireless);
+ sigma_dut_reg_cmd("sta_send_addba", req_intf, cmd_sta_send_addba);
+ /* TODO: sta_send_coexist_mgmt */
+ sigma_dut_reg_cmd("sta_disconnect", req_intf, cmd_sta_disconnect);
+ sigma_dut_reg_cmd("sta_reassoc", req_intf, cmd_sta_reassoc);
+ sigma_dut_reg_cmd("sta_reassociate", req_intf, cmd_sta_reassoc);
+ sigma_dut_reg_cmd("sta_reset_default", req_intf,
+ cmd_sta_reset_default);
+ sigma_dut_reg_cmd("sta_send_frame", req_intf, cmd_sta_send_frame);
+ sigma_dut_reg_cmd("sta_set_macaddr", req_intf, cmd_sta_set_macaddr);
+ sigma_dut_reg_cmd("sta_set_rfeature", req_intf, cmd_sta_set_rfeature);
+ sigma_dut_reg_cmd("sta_set_radio", req_intf, cmd_sta_set_radio);
+ sigma_dut_reg_cmd("sta_set_pwrsave", req_intf, cmd_sta_set_pwrsave);
+ sigma_dut_reg_cmd("sta_bssid_pool", req_intf, cmd_sta_bssid_pool);
+ sigma_dut_reg_cmd("sta_reset_parm", req_intf, cmd_sta_reset_parm);
+ sigma_dut_reg_cmd("sta_get_key", req_intf, cmd_sta_get_key);
+ sigma_dut_reg_cmd("sta_hs2_associate", req_intf,
+ cmd_sta_hs2_associate);
+ sigma_dut_reg_cmd("sta_add_credential", req_intf,
+ cmd_sta_add_credential);
+ sigma_dut_reg_cmd("sta_scan", req_intf, cmd_sta_scan);
+ sigma_dut_reg_cmd("sta_set_systime", NULL, cmd_sta_set_systime);
+ sigma_dut_reg_cmd("sta_osu", req_intf, cmd_sta_osu);
+ sigma_dut_reg_cmd("sta_policy_update", req_intf, cmd_sta_policy_update);
+ sigma_dut_reg_cmd("sta_er_config", NULL, cmd_sta_er_config);
+ sigma_dut_reg_cmd("sta_wps_connect_pw_token", req_intf,
+ cmd_sta_wps_connect_pw_token);
+ sigma_dut_reg_cmd("sta_exec_action", req_intf, cmd_sta_exec_action);
+ sigma_dut_reg_cmd("sta_get_events", req_intf, cmd_sta_get_events);
+ sigma_dut_reg_cmd("sta_get_parameter", req_intf, cmd_sta_get_parameter);
+}