Merge tag 'LA.UM.9.12.r1-15200-SMxx50.QSSI13.0' into int/13/fp4
"LA.UM.9.12.r1-15200-SMxx50.QSSI13.0"
* tag 'LA.UM.9.12.r1-15200-SMxx50.QSSI13.0': (83 commits)
DPP: Support SAE AKM in AP configuration
Support HS2-2022 as a program name
Use helper functions for checking Passpoint release
ap_send_frame: Verify stationID parameter is present
DPP: Check valid parameter combination for DPPReconfigure error case
sta_set_security: Support imsiPrivacyCertID
sta_set_security: Fix the error message for imsiPrivacyCert
Do not add vht_capab for the 2.4 GHz interface in dual band AP
traffic: Include -b argument for ping only for 255.255.255.255
Use a new macro to include wifi-hal path for Android builds
DPP: Start unconfigured AP on channel 6 if PB is used
DPP: Support DPPBootstrapPOST,HTTP
DPP: Report POSTResult for SetPeerBootstrap DPPNetRole,BSConfigurator
DPP: Report ConfResult,FAILED on Configurator if rejecting the request
DPP: Report push button failures immediately
DPP: Fix MUDURL handling for hostapd-as-initiator
DPP: More options for discovering the Controller for a Relay
DPP: Fix PB determination of DPPProvisioningRole for STA Configurator
DPP: Map DPPURICurves values as needed
DPP: Fix REST API use
...
Change-Id: I810597906093b085a44957d178064082b0ff80d6
diff --git a/Android.mk b/Android.mk
index 3f30c1f..a2ec223 100644
--- a/Android.mk
+++ b/Android.mk
@@ -65,6 +65,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := sigma_dut
+QCOM_WLAN_ROOT ?= hardware/qcom/wlan
ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED), true)
LOCAL_VENDOR_MODULE := true
endif
@@ -73,7 +74,7 @@
LOCAL_C_INCLUDES += \
$(LOCAL_PATH) frameworks/base/cmds/keystore system/security/keystore \
$(LOCAL_PATH) frameworks/opt/net/wifi/libwifi_hal/include/ \
- $(LOCAL_PATH) hardware/qcom/wlan/qcwcn/wifi_hal \
+ $(LOCAL_PATH) $(QCOM_WLAN_ROOT)/qcwcn/wifi_hal \
$(LOCAL_PATH) system/core/include/cutils \
$(LOCAL_PATH) hardware/libhardware_legacy/include/hardware_legacy \
$(LOCAL_PATH) external/libpcap \
diff --git a/DPP/README b/DPP/README
new file mode 100644
index 0000000..cbf7691
--- /dev/null
+++ b/DPP/README
@@ -0,0 +1,10 @@
+DPP bootstrapping services
+
+On the device that provides bootstrapping services, the following
+processes needs to be started:
+
+# stunnel to handle HTTPS(TLS-PSK)
+stunnel stunnel-server.conf
+
+# local-only HTTP server to handle the core DPP REST API
+./dpp-rest-server.py
diff --git a/DPP/dpp-rest-server.py b/DPP/dpp-rest-server.py
new file mode 100755
index 0000000..d4b630a
--- /dev/null
+++ b/DPP/dpp-rest-server.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+#
+# Sigma Control API DUT (DPP REST API server)
+# Copyright (c) 2022, Qualcomm Innovation Center, Inc.
+# All Rights Reserved.
+# Licensed under the Clear BSD license. See README for more details.
+
+from http.server import HTTPServer, BaseHTTPRequestHandler
+import json
+import os
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+ifname = None
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError as error:
+ print("Could not find wpa_supplicant: %s", str(error))
+ return None
+
+ if len(ifaces) < 1:
+ print("No wpa_supplicant control interface found")
+ return None
+
+ for ctrl in ifaces:
+ if ifname and ifname not in ctrl:
+ continue
+ if os.path.basename(ctrl).startswith("p2p-dev-"):
+ # skip P2P management interface
+ continue
+ try:
+ print("Trying to use control interface " + ctrl)
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception as e:
+ pass
+ print("Could not connect to wpa_supplicant")
+ return None
+
+class DPP_REST_HTTPRequestHandler(BaseHTTPRequestHandler):
+ def do_POST(self):
+ if self.path != "/dpp/bskey":
+ self.send_response(404)
+ self.end_headers()
+ return
+
+ if 'Content-Length' not in self.headers:
+ self.send_response(411)
+ self.end_headers()
+ return
+
+ content_len = int(self.headers['Content-Length'])
+ body = self.rfile.read(content_len)
+
+ try:
+ data = json.loads(body)
+ except:
+ self.send_response(400)
+ self.end_headers()
+ self.wfile.write("Invalid JSON data".encode("ascii"))
+ return
+
+ if 'dppUri' not in data:
+ print("Missing dppUri")
+ self.send_response(400)
+ self.end_headers()
+ self.wfile.write("Missing dppUri".encode("ascii"))
+ return
+
+ wpas = wpas_connect()
+ if wpas is None:
+ self.send_response(503)
+ self.end_headers()
+ self.wfile.write("DPP Configurator not available".encode("ascii"))
+ return
+
+ res = wpas.request("DPP_QR_CODE " + data['dppUri'])
+
+ if "UNKNOWN COMMAND" in res:
+ self.send_response(503)
+ self.end_headers()
+ self.wfile.write("DPP Configurator not available".encode("ascii"))
+ return
+
+ if "FAIL" in res:
+ self.send_response(400)
+ self.end_headers()
+ self.wfile.write("Invalid DPP URI".encode("ascii"))
+ return
+
+ id = int(res)
+ with open("/tmp/dpp-rest-server.id", "w") as f:
+ f.write(str(id))
+ with open("/tmp/dpp-rest-server.uri", "w") as f:
+ f.write(data['dppUri'])
+
+ self.send_response(200)
+ self.end_headers()
+
+def main():
+ # Bind to localhost only and use an external stunnel proxy to handle
+ # TLS-PSK.
+ httpd = HTTPServer(('localhost', 44444), DPP_REST_HTTPRequestHandler)
+ httpd.serve_forever()
+
+if __name__ == "__main__":
+ main()
diff --git a/DPP/stunnel-server.conf b/DPP/stunnel-server.conf
new file mode 100644
index 0000000..ec6544c
--- /dev/null
+++ b/DPP/stunnel-server.conf
@@ -0,0 +1,9 @@
+debug=debug
+foreground=yes
+pid = /tmp/stunnel-dpp-rest-server.pid
+
+[PSK server]
+accept = 8908
+connect = 44444
+ciphers = PSK
+PSKsecrets = stunnel-server.psk
diff --git a/DPP/stunnel-server.psk b/DPP/stunnel-server.psk
new file mode 100644
index 0000000..af86525
--- /dev/null
+++ b/DPP/stunnel-server.psk
@@ -0,0 +1 @@
+dpp-rest:00112233445566778899aabbccddeeff
diff --git a/ap.c b/ap.c
index 0bfa56b..b2ffa66 100644
--- a/ap.c
+++ b/ap.c
@@ -26,6 +26,7 @@
#include <net/if.h>
#include "wpa_ctrl.h"
#include "wpa_helpers.h"
+#include "nl80211_copy.h"
#ifdef ANDROID
#include <hardware_legacy/wifi.h>
#include <grp.h>
@@ -5412,6 +5413,10 @@
"venue_url=10:https://bed-bath-and-beyond.r2m-testbed.wi-fi.org/floorplans/index.html\n"
);
break;
+ case 3:
+ fprintf(f,
+ "venue_url=1:http://the-great-mall.r2m-test bed.wi-fi.org/floorplans/index.html\n");
+ break;
}
switch (dut->ap_advice_of_charge) {
@@ -7999,6 +8004,7 @@
enum driver_type drv;
const char *key_mgmt;
int conf_counter = 0;
+ bool append_vht = false;
#ifdef ANDROID
struct group *gr;
#endif /* ANDROID */
@@ -8027,6 +8033,13 @@
dut->mode = SIGMA_MODE_AP;
+ if (dut->ap_dpp_conf_addr &&
+ strcasecmp(dut->ap_dpp_conf_addr, "mDNS") == 0 &&
+ dpp_mdns_discover_relay_params(dut) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to discover DPP Controller for AP Relay using mDNS");
+ }
+
if (drv == DRIVER_ATHEROS)
return cmd_ath_ap_config_commit(dut, conn, cmd);
if (drv == DRIVER_WCN)
@@ -8445,7 +8458,8 @@
dut->ap_radius_port);
fprintf(f, "auth_server_shared_secret=%s\n",
dut->ap_radius_password);
- if (dut->program == PROGRAM_HS2_R3) {
+ if (dut->program == PROGRAM_HS2_R3 ||
+ dut->program == PROGRAM_HS2_R4) {
fprintf(f, "radius_das_port=3799\n");
fprintf(f, "radius_das_client=0.0.0.0 %s\n",
dut->ap_radius_password);
@@ -8809,9 +8823,14 @@
fprintf(f, "fragment_size=128\n");
}
- if (dut->ap_dpp_conf_addr && dut->ap_dpp_conf_pkhash)
- fprintf(f, "dpp_controller=ipaddr=%s pkhash=%s\n",
- dut->ap_dpp_conf_addr, dut->ap_dpp_conf_pkhash);
+ if (dut->ap_dpp_conf_addr && dut->ap_dpp_conf_pkhash) {
+ if (strcasecmp(dut->ap_dpp_conf_addr, "mDNS") != 0) {
+ fprintf(f, "dpp_controller=ipaddr=%s pkhash=%s\n",
+ dut->ap_dpp_conf_addr, dut->ap_dpp_conf_pkhash);
+ fprintf(f, "dpp_configurator_connectivity=1\n");
+ }
+ fprintf(f, "dpp_relay_port=8908\n");
+ }
if (dut->ap_he_rtsthrshld == VALUE_ENABLED)
fprintf(f, "he_rts_threshold=512\n");
@@ -8873,13 +8892,32 @@
get_6g_ch_op_class(dut->ap_channel));
}
+ if (dut->use_5g) {
+ /* Do not try to enable VHT on the 2.4 GHz band when
+ * configuring a dual band AP that does have VHT enabled
+ * on the 5 GHz radio. */
+ if (dut->ap_is_dual) {
+ int chan;
+
+ if (conf_counter)
+ chan = dut->ap_tag_channel[0];
+ else
+ chan = dut->ap_channel;
+ append_vht = chan >= 36 && chan <= 171;
+ } else {
+ append_vht = true;
+ }
+ }
+
find_ap_ampdu_exp_and_max_mpdu_len(dut);
- if (dut->ap_sgi80 || dut->ap_txBF ||
- dut->ap_ldpc != VALUE_NOT_SET ||
- dut->ap_tx_stbc == VALUE_ENABLED || dut->ap_mu_txBF ||
- dut->ap_ampdu_exp || dut->ap_max_mpdu_len ||
- dut->ap_chwidth == AP_160 || dut->ap_chwidth == AP_80_80) {
+ if (append_vht &&
+ (dut->ap_sgi80 || dut->ap_txBF ||
+ dut->ap_ldpc != VALUE_NOT_SET ||
+ dut->ap_tx_stbc == VALUE_ENABLED || dut->ap_mu_txBF ||
+ dut->ap_ampdu_exp || dut->ap_max_mpdu_len ||
+ dut->ap_chwidth == AP_160 ||
+ dut->ap_chwidth == AP_80_80)) {
fprintf(f, "vht_capab=%s%s%s%s%s%s",
dut->ap_sgi80 ? "[SHORT-GI-80]" : "",
dut->ap_txBF ?
@@ -9885,8 +9923,7 @@
dut->ap_ocvc = dut->user_config_ap_ocvc;
- if (dut->program == PROGRAM_HS2 || dut->program == PROGRAM_HS2_R2 ||
- dut->program == PROGRAM_HS2_R3 ||
+ if (is_passpoint(dut->program) ||
dut->program == PROGRAM_IOTLP) {
int i;
@@ -9943,7 +9980,7 @@
dut->ap_add_sha256 = 0;
}
- if (dut->program == PROGRAM_HS2_R2 || dut->program == PROGRAM_HS2_R3 ||
+ if (is_passpoint_r2_or_newer(dut->program) ||
dut->program == PROGRAM_IOTLP) {
int i;
const char hessid[] = "50:6f:9a:00:11:22";
@@ -10193,7 +10230,11 @@
dut->ap_dpp_conf_addr = NULL;
free(dut->ap_dpp_conf_pkhash);
dut->ap_dpp_conf_pkhash = NULL;
+ dut->dpp_local_bootstrap = -1;
dut->ap_start_disabled = 0;
+ dpp_mdns_stop(dut);
+ unlink("/tmp/dpp-rest-server.uri");
+ unlink("/tmp/dpp-rest-server.id");
if (is_60g_sigma_dut(dut)) {
dut->ap_mode = AP_11ad;
@@ -10459,10 +10500,10 @@
#endif /* __linux__ */
enum send_frame_type {
- DISASSOC, DEAUTH, SAQUERY
+ DISASSOC, DEAUTH, SAQUERY, CHANNEL_SWITCH
};
enum send_frame_protection {
- CORRECT_KEY, INCORRECT_KEY, UNPROTECTED
+ PROTECTION_NOT_SET, CORRECT_KEY, INCORRECT_KEY, UNPROTECTED
};
@@ -10533,6 +10574,8 @@
case SAQUERY:
*pos++ = 0xd0;
break;
+ default:
+ return -1;
}
if (protected == INCORRECT_KEY)
@@ -10609,6 +10652,8 @@
*pos++ = 0x12;
*pos++ = 0x34;
break;
+ default:
+ return -1;
}
}
@@ -11222,8 +11267,10 @@
/* const char *ifname = get_param(cmd, "INTERFACE"); */
const char *val;
enum send_frame_type frame;
- enum send_frame_protection protected;
+ enum send_frame_protection protected = PROTECTION_NOT_SET;
char buf[100];
+ unsigned int freq;
+ unsigned int chan;
val = get_param(cmd, "Program");
if (val) {
@@ -11254,6 +11301,8 @@
frame = DEAUTH;
else if (strcasecmp(val, "saquery") == 0)
frame = SAQUERY;
+ else if (strcasecmp(val, "ChannelSwitchAnncment") == 0)
+ frame = CHANNEL_SWITCH;
else {
send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unsupported "
"PMFFrameType");
@@ -11263,29 +11312,32 @@
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 (val) {
+ 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 STATUS_SENT_ERROR;
+ }
}
val = get_param(cmd, "stationID");
- if (val == NULL)
- return -1;
- if (protected == INCORRECT_KEY ||
- (protected == UNPROTECTED && frame == SAQUERY))
+ if (val && (protected == INCORRECT_KEY ||
+ (protected == UNPROTECTED && frame == SAQUERY)))
return ap_inject_frame(dut, conn, frame, protected, val);
+ if (!val && frame != CHANNEL_SWITCH) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "stationID not specified");
+ return INVALID_SEND_STATUS;
+ }
+
switch (frame) {
case DISASSOC:
snprintf(buf, sizeof(buf), "disassoc %s test=%d",
@@ -11298,6 +11350,19 @@
case SAQUERY:
snprintf(buf, sizeof(buf), "sa_query %s", val);
break;
+ case CHANNEL_SWITCH:
+ val = get_param(cmd, "channel");
+ if (!val)
+ return -1;
+ chan = atoi(val);
+ freq = channel_to_freq(dut, chan);
+ if (!freq) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Invalid channel: %d", chan);
+ return INVALID_SEND_STATUS;
+ }
+ snprintf(buf, sizeof(buf), "chan_switch 5 %d", freq);
+ break;
}
if (run_hostapd_cli(dut, buf) != 0)
@@ -13586,22 +13651,34 @@
val = get_param(cmd, "GI");
if (val) {
int fix_rate_sgi;
+ u8 he_gi_val;
+ u8 auto_rate_gi;
if (strcmp(val, "0.8") == 0) {
- run_iwpriv(dut, ifname, "enable_short_gi 9");
fix_rate_sgi = 1;
+ auto_rate_gi = 9;
+ he_gi_val = NL80211_RATE_INFO_HE_GI_0_8;
} else if (strcmp(val, "1.6") == 0) {
- run_iwpriv(dut, ifname, "enable_short_gi 10");
fix_rate_sgi = 2;
+ auto_rate_gi = 10;
+ he_gi_val = NL80211_RATE_INFO_HE_GI_1_6;
} else if (strcmp(val, "3.2") == 0) {
- run_iwpriv(dut, ifname, "enable_short_gi 11");
fix_rate_sgi = 3;
+ auto_rate_gi = 11;
+ he_gi_val = NL80211_RATE_INFO_HE_GI_3_2;
} else {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,GI value not supported");
return STATUS_SENT_ERROR;
}
- run_iwpriv(dut, ifname, "enable_short_gi %d", fix_rate_sgi);
+ if (wcn_set_he_gi(dut, ifname, he_gi_val)) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "wcn_set_he_gi failed, using iwpriv");
+ run_iwpriv(dut, ifname, "enable_short_gi %d",
+ auto_rate_gi);
+ run_iwpriv(dut, ifname, "enable_short_gi %d",
+ fix_rate_sgi);
+ }
}
val = get_param(cmd, "LTF");
@@ -14085,6 +14162,10 @@
dut->ap_dpp_conf_pkhash = strdup(val);
}
+ if (dut->ap_dpp_conf_addr &&
+ strcasecmp(dut->ap_dpp_conf_addr, "mDNS") == 0)
+ dpp_mdns_discover_relay_params(dut);
+
return 1;
}
diff --git a/dpp.c b/dpp.c
index e4bf459..3ae2bbf 100644
--- a/dpp.c
+++ b/dpp.c
@@ -19,6 +19,218 @@
#endif /* ANDROID */
+static const char * dpp_mdns_role_txt(enum dpp_mdns_role role)
+{
+ switch (role) {
+ case DPP_MDNS_NOT_RUNNING:
+ break;
+ case DPP_MDNS_RELAY:
+ return "relay";
+ case DPP_MDNS_CONTROLLER:
+ return "controller";
+ case DPP_MDNS_BOOTSTRAPPING:
+ return "bootstrapping";
+ }
+ return "unknown";
+}
+
+
+static int dpp_mdns_discover(struct sigma_dut *dut, enum dpp_mdns_role role,
+ char *addr, size_t addr_size, unsigned int *port,
+ unsigned char *hash)
+{
+ char cmd[200], buf[10000], *pos, *pos2, *pos3;
+ char *ifname = NULL, *ipaddr = NULL, *bskeyhash = NULL;
+ size_t len;
+ FILE *f;
+
+ if (port)
+ *port = 0;
+
+ snprintf(cmd, sizeof(cmd), "avahi-browse _%s._sub._dpp._tcp -r -t -p",
+ dpp_mdns_role_txt(role));
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", cmd);
+ f = popen(cmd, "r");
+ if (!f) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Could not run avahi-browse: %s",
+ strerror(errno));
+ return -1;
+ }
+ len = fread(buf, 1, sizeof(buf) - 1, f);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "avahi-browse returned %zu octets",
+ len);
+ pclose(f);
+ if (!len)
+ return -1;
+ buf[len] = '\0';
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "mDNS results:\n%s", buf);
+
+ pos = buf;
+ while (pos) {
+ pos2 = strchr(pos, '\n');
+ if (pos2)
+ *pos2 = '\0';
+ if (pos[0] != '=')
+ goto next;
+
+ pos = strchr(pos, ';');
+ if (!pos)
+ goto next;
+ pos++;
+ /* ifname */
+ pos3 = strchr(pos, ';');
+ if (!pos3)
+ goto next;
+ *pos3 = '\0';
+ ifname = pos;
+
+ pos = pos3 + 1;
+ /* IP version */
+ if (strncmp(pos, "IPv4;", 5) != 0)
+ goto next;
+
+ pos = strchr(pos, ';');
+ if (!pos)
+ goto next;
+ pos++;
+ /* name */
+
+ pos = strchr(pos, ';');
+ if (!pos)
+ goto next;
+ pos++;
+ /* service */
+
+ pos = strchr(pos, ';');
+ if (!pos)
+ goto next;
+ pos++;
+ /* local? */
+
+ pos = strchr(pos, ';');
+ if (!pos)
+ goto next;
+ pos++;
+ /* fqdn */
+
+ pos = strchr(pos, ';');
+ if (!pos)
+ goto next;
+ pos++;
+ /* IP address */
+
+ pos3 = strchr(pos, ';');
+ if (!pos3)
+ goto next;
+ *pos3 = '\0';
+ ipaddr = pos;
+ pos = pos3 + 1;
+
+ if (port)
+ *port = atoi(pos);
+
+ pos = strstr(pos, "\"bskeyhash=");
+ if (pos) {
+ pos += 11;
+ pos3 = strchr(pos, '"');
+ if (pos3)
+ *pos3 = '\0';
+ bskeyhash = pos;
+ }
+
+ /* Could try to pick the most appropriate candidate if multiple
+ * entries are discovered */
+ break;
+
+ next:
+ if (!pos2)
+ break;
+ pos = pos2 + 1;
+ }
+
+ if (!ipaddr)
+ return -1;
+ sigma_dut_print(dut, DUT_MSG_INFO, "Discovered (mDNS) service at %s@%s",
+ ipaddr, ifname);
+ if (bskeyhash && hash) {
+ unsigned char *bin;
+ size_t bin_len;
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "bskeyhash: %s", bskeyhash);
+
+ bin = base64_decode(bskeyhash, strlen(bskeyhash), &bin_len);
+ if (!bin || bin_len != 32) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Invalid bskeyhash value in mDNS records");
+ free(bin);
+ return -1;
+ }
+
+ memcpy(hash, bin, bin_len);
+ free(bin);
+ }
+ strlcpy(addr, ipaddr, addr_size);
+
+ return 0;
+}
+
+
+int dpp_mdns_discover_relay_params(struct sigma_dut *dut)
+{
+ char tcp_addr[30];
+ unsigned char hash[32];
+
+ if (dpp_mdns_discover(dut, DPP_MDNS_CONTROLLER,
+ tcp_addr, sizeof(tcp_addr), NULL, hash) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Could not discover Controller IP address using mDNS");
+ return -1;
+ }
+
+ free(dut->ap_dpp_conf_addr);
+ dut->ap_dpp_conf_addr = strdup(tcp_addr);
+
+ free(dut->ap_dpp_conf_pkhash);
+ dut->ap_dpp_conf_pkhash = malloc(2 * 32 + 1);
+ if (dut->ap_dpp_conf_pkhash) {
+ int i;
+ char *pos = dut->ap_dpp_conf_pkhash;
+ char *end = pos + 2 * 32 + 1;
+
+ for (i = 0; i < 32; i++)
+ pos += snprintf(pos, end - pos, "%02x", hash[i]);
+ *pos = '\0';
+ }
+
+ if (dut->ap_dpp_conf_addr && dut->ap_dpp_conf_pkhash) {
+ const char *ifname = dut->hostapd_ifname;
+
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Controller discovered using mDNS: %s (pkhash %s)",
+ dut->ap_dpp_conf_addr,
+ dut->ap_dpp_conf_pkhash);
+ if (dut->hostapd_running && ifname) {
+ char cmd[500];
+
+ snprintf(cmd, sizeof(cmd),
+ "DPP_RELAY_ADD_CONTROLLER %s %s",
+ dut->ap_dpp_conf_addr,
+ dut->ap_dpp_conf_pkhash);
+ if (wpa_command(ifname, cmd) < 0)
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to add Controller connection into hostapd");
+ else
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Added Controller connection into hostapd");
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+
static int sigma_dut_is_ap(struct sigma_dut *dut)
{
return dut->device_type == AP_unknown ||
@@ -27,16 +239,24 @@
}
-static int dpp_hostapd_run(struct sigma_dut *dut)
+static int dpp_hostapd_run(struct sigma_dut *dut, bool chirp_chan)
{
if (dut->hostapd_running)
return 0;
+ if (dut->ap_dpp_conf_addr &&
+ strcasecmp(dut->ap_dpp_conf_addr, "mDNS") == 0 &&
+ dpp_mdns_discover_relay_params(dut) < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to discover Controller for AP Relay using mDNS - cannot start hostapd");
+ return -1;
+ }
+
sigma_dut_print(dut, DUT_MSG_INFO,
"Starting hostapd in unconfigured state for DPP");
snprintf(dut->ap_ssid, sizeof(dut->ap_ssid), "unconfigured");
if (!dut->ap_oper_chn)
- dut->ap_channel = 11;
+ dut->ap_channel = chirp_chan ? 6 : 11;
dut->ap_is_dual = 0;
dut->ap_mode = dut->ap_channel <= 14 ? AP_11ng : AP_11na;
dut->ap_key_mgmt = AP_OPEN;
@@ -66,23 +286,27 @@
}
-static const char * dpp_get_curve(struct sigma_cmd *cmd, const char *arg)
+static const char * dpp_map_curve(const char *val)
{
- const char *val = get_param(cmd, arg);
-
if (!val)
- val = "P-256";
- else if (strcasecmp(val, "BP-256R1") == 0)
- val = "BP-256";
- else if (strcasecmp(val, "BP-384R1") == 0)
- val = "BP-384";
- else if (strcasecmp(val, "BP-512R1") == 0)
- val = "BP-512";
+ return "P-256";
+ if (strcasecmp(val, "BP-256R1") == 0)
+ return "BP-256";
+ if (strcasecmp(val, "BP-384R1") == 0)
+ return "BP-384";
+ if (strcasecmp(val, "BP-512R1") == 0)
+ return "BP-512";
return val;
}
+static const char * dpp_get_curve(struct sigma_cmd *cmd, const char *arg)
+{
+ return dpp_map_curve(get_param(cmd, arg));
+}
+
+
static enum sigma_cmd_result
dpp_get_local_bootstrap(struct sigma_dut *dut, struct sigma_conn *conn,
struct sigma_cmd *cmd, int send_result, int *success)
@@ -91,12 +315,22 @@
const char *bs = get_param(cmd, "DPPBS");
const char *chan_list = get_param(cmd, "DPPChannelList");
const char *tcp = get_param(cmd, "DPPOverTCP");
+ const char *val;
char *pos, mac[50], buf[200], resp[1000], hex[2000];
const char *ifname = get_station_ifname(dut);
int res;
const char *type;
int include_mac;
+ char host[100];
+ bool uri_host;
+ char ip[30];
+ char uri_curves_buf[200];
+ const char *uri_curves = NULL;
+ host[0] = '\0';
+ ip[0] = '\0';
+ val = get_param(cmd, "DPPURIHost");
+ uri_host = val && strcasecmp(val, "Yes") == 0;
include_mac = !tcp || strcasecmp(tcp, "yes") != 0;
if (success)
@@ -111,6 +345,32 @@
return STATUS_SENT_ERROR;
}
+ val = get_param(cmd, "DPPURICurves");
+ if (val) {
+ char *saveptr, *r, *tmp, *end;
+
+ pos = uri_curves_buf;
+ end = pos + sizeof(uri_curves_buf);
+ *pos = '\0';
+ tmp = strdup(val);
+ if (!tmp)
+ return ERROR_SEND_STATUS;
+ r = strtok_r(tmp, ":", &saveptr);
+ while (r) {
+ int len;
+
+ len = snprintf(pos, end - pos, "%s%s",
+ pos > uri_curves_buf ? ":" : "",
+ dpp_map_curve(r));
+ if (len < 0)
+ break;
+ pos += len;
+ r = strtok_r(NULL, ":", &saveptr);
+ }
+ free(tmp);
+ uri_curves = uri_curves_buf;
+ }
+
if (sigma_dut_is_ap(dut)) {
u8 bssid[ETH_ALEN];
@@ -129,14 +389,44 @@
snprintf(mac, sizeof(mac), "%02x%02x%02x%02x%02x%02x",
bssid[0], bssid[1], bssid[2],
bssid[3], bssid[4], bssid[5]);
+
+ if (uri_host) {
+ const char *ifname;
+
+ ifname = dut->bridge ? dut->bridge :
+ dut->hostapd_ifname;
+ if (get_ip_addr(ifname, 0, ip, sizeof(ip)) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Could not get IP address for AP mode: bridge=%s hostapd_ifname=%s",
+ dut->bridge ? dut->bridge :
+ "N/A",
+ dut->hostapd_ifname);
+ ip[0] = '\0';
+ }
+ }
} else {
if (get_wpa_status(ifname, "address", mac, sizeof(mac)) < 0) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Failed to get own MAC address from wpa_supplicant");
return STATUS_SENT_ERROR;
}
+
+ if (uri_host &&
+ get_wpa_status(ifname, "ip_address", ip, sizeof(ip)) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Could not get IP address for station mode");
+ ip[0] = '\0';
+ }
}
+ if (uri_host && ip[0] == '\0') {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,IP address not available on wireless interface");
+ return STATUS_SENT_ERROR;
+ }
+ if (uri_host)
+ snprintf(host, sizeof(host), " host=%s", ip);
+
pos = mac;
while (*pos) {
if (*pos == ':')
@@ -145,7 +435,7 @@
pos++;
}
- if (sigma_dut_is_ap(dut) && dpp_hostapd_run(dut) < 0) {
+ if (sigma_dut_is_ap(dut) && dpp_hostapd_run(dut, false) < 0) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Failed to start hostapd");
return STATUS_SENT_ERROR;
@@ -155,10 +445,13 @@
(strcmp(chan_list, "0/0") == 0 || chan_list[0] == '\0')) {
/* No channel list */
res = snprintf(buf, sizeof(buf),
- "DPP_BOOTSTRAP_GEN type=%s curve=%s%s%s",
+ "DPP_BOOTSTRAP_GEN type=%s curve=%s%s%s%s%s%s",
type, curve,
include_mac ? " mac=" : "",
- include_mac ? mac : "");
+ include_mac ? mac : "",
+ uri_curves ? " supported_curves=" : "",
+ uri_curves ? uri_curves : "",
+ host);
} else if (chan_list) {
/* Channel list override (CTT case) - space separated tuple(s)
* of OperatingClass/Channel; convert to wpa_supplicant/hostapd
@@ -169,9 +462,12 @@
*pos = ',';
}
res = snprintf(buf, sizeof(buf),
- "DPP_BOOTSTRAP_GEN type=%s curve=%s chan=%s%s%s",
+ "DPP_BOOTSTRAP_GEN type=%s curve=%s chan=%s%s%s%s%s%s",
type, curve, resp, include_mac ? " mac=" : "",
- include_mac ? mac : "");
+ include_mac ? mac : "",
+ uri_curves ? " supported_curves=" : "",
+ uri_curves ? uri_curves : "",
+ host);
} else {
int channel = 11;
@@ -181,9 +477,12 @@
dut->ap_channel > 0 && dut->ap_channel <= 13)
channel = dut->ap_channel;
res = snprintf(buf, sizeof(buf),
- "DPP_BOOTSTRAP_GEN type=%s curve=%s chan=81/%d%s%s",
+ "DPP_BOOTSTRAP_GEN type=%s curve=%s chan=81/%d%s%s%s%s%s",
type, curve, channel, include_mac ? " mac=" : "",
- include_mac ? mac : "");
+ include_mac ? mac : "",
+ uri_curves ? " supported_curves=" : "",
+ uri_curves ? uri_curves : "",
+ host);
}
if (res < 0 || res >= sizeof(buf) ||
@@ -199,6 +498,12 @@
sigma_dut_print(dut, DUT_MSG_DEBUG, "URI: %s", resp);
+ if (dut->dpp_mdns == DPP_MDNS_CONTROLLER) {
+ /* Update mDNS advertisement since the local boostrapping key
+ * has changed. */
+ dpp_mdns_start(dut, DPP_MDNS_CONTROLLER);
+ }
+
if (send_result) {
ascii2hexstr(resp, hex);
res = snprintf(resp, sizeof(resp), "BootstrappingData,%s", hex);
@@ -212,6 +517,141 @@
}
+static void stop_stunnel(struct sigma_dut *dut)
+{
+ FILE *f;
+ int pid;
+
+ f = fopen("/tmp/stunnel-dpp-rest-client.pid", "r");
+ if (!f)
+ return;
+
+ if (fscanf(f, "%d", &pid) == 1 && pid > 1) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Terminate stunnel process %d",
+ pid);
+ kill(pid, SIGTERM);
+ }
+ fclose(f);
+}
+
+
+static enum sigma_cmd_result dpp_post_uri(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *uri)
+{
+ FILE *f;
+ char buf[1000], *pos;
+ size_t len;
+ int status;
+ char tcp_addr[30];
+ unsigned int port;
+ const char *val;
+ bool http;
+
+ f = fopen("/tmp/dppuri.json", "w");
+ if (!f) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not write dppuri.json");
+ return STATUS_SENT_ERROR;
+ }
+ fprintf(f, "{\"dppUri\":\"%s\"}", uri);
+ fclose(f);
+
+ if (dpp_mdns_discover(dut, DPP_MDNS_BOOTSTRAPPING,
+ tcp_addr, sizeof(tcp_addr), &port, NULL) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not discover (mDNS) bootstrapping service");
+ return STATUS_SENT_ERROR;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_INFO, "Bootstrapping service at %s:%u",
+ tcp_addr, port);
+
+ val = get_param(cmd, "DPPBootstrapPOST");
+ http = val && strcmp(val, "HTTP") == 0;
+ if (http)
+ goto skip_stunnel;
+
+ f = fopen("/tmp/stunnel-dpp-rest-client.conf", "w");
+ if (!f) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not write stunnel-dpp-rest-client.conf");
+ return STATUS_SENT_ERROR;
+ }
+ fprintf(f, "pid = /tmp/stunnel-dpp-rest-client.pid\n");
+ fprintf(f, "[PSK client]\n");
+ fprintf(f, "client = yes\n");
+ fprintf(f, "accept = 127.0.0.1:33333\n");
+ fprintf(f, "connect = %s:%u\n", tcp_addr, port);
+ fprintf(f, "PSKsecrets = /tmp/stunnel-dpp-rest-client.psk\n");
+ fclose(f);
+
+
+ f = fopen("/tmp/stunnel-dpp-rest-client.psk", "w");
+ if (!f) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not write stunnel-dpp-rest-client.psk");
+ return STATUS_SENT_ERROR;
+ }
+ fprintf(f, "dpp-rest:00112233445566778899aabbccddeeff\n");
+ fclose(f);
+
+ stop_stunnel(dut);
+
+ if (system("stunnel /tmp/stunnel-dpp-rest-client.conf") != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not start stunnel");
+ return STATUS_SENT_ERROR;
+ }
+
+skip_stunnel:
+ if (http)
+ snprintf(buf, sizeof(buf),
+ "curl -i --request POST --header \"Content-Type: application/json\" --data @/tmp/dppuri.json http://%s:%d/dpp/bskey",
+ tcp_addr, port);
+ else
+ snprintf(buf, sizeof(buf),
+ "curl -i --request POST --header \"Content-Type: application/json\" --data @/tmp/dppuri.json http://localhost:33333/dpp/bskey");
+ sigma_dut_print(dut, DUT_MSG_INFO, "Run: %s", buf);
+ f = popen(buf, "r");
+ if (!f) {
+ if (!http)
+ stop_stunnel(dut);
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not run curl");
+ return STATUS_SENT_ERROR;
+ }
+ len = fread(buf, 1, sizeof(buf) - 1, f);
+ pclose(f);
+ if (!http)
+ stop_stunnel(dut);
+ if (!len) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "curl failed to fetch response");
+ send_resp(dut, conn, SIGMA_COMPLETE, "POSTResult,Failed");
+ return STATUS_SENT_ERROR;
+ }
+ buf[len] = '\0';
+ pos = strchr(buf, ' ');
+ if (!pos || strncmp(buf, "HTTP/", 5) != 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Invalid HTTP responder header received");
+ send_resp(dut, conn, SIGMA_COMPLETE, "POSTResult,Failed");
+ return STATUS_SENT;
+ }
+ pos++;
+ status = atoi(pos);
+
+ sigma_dut_print(dut, DUT_MSG_INFO, "curl reported HTTP status code %d",
+ status);
+ snprintf(buf, sizeof(buf), "POSTResult,%d", status);
+ send_resp(dut, conn, SIGMA_COMPLETE, buf);
+ return STATUS_SENT;
+}
+
+
static enum sigma_cmd_result dpp_set_peer_bootstrap(struct sigma_dut *dut,
struct sigma_conn *conn,
struct sigma_cmd *cmd)
@@ -231,6 +671,11 @@
return ERROR_SEND_STATUS;
uri[res] = '\0';
sigma_dut_print(dut, DUT_MSG_DEBUG, "URI: %s", uri);
+
+ val = get_param(cmd, "DPPNetRole");
+ if (val && strcasecmp(val, "BSConfigurator") == 0)
+ return dpp_post_uri(dut, conn, cmd, uri);
+
free(dut->dpp_peer_uri);
dut->dpp_peer_uri = strdup(uri);
@@ -254,11 +699,13 @@
};
unsigned int old_timeout;
int legacy_akm, dpp_akm;
+ bool sae_akm, psk_akm;
char *connector = NULL, *psk = NULL, *csign = NULL,
*net_access_key = NULL;
char pass[64];
int pass_len = 0;
int ret = 0;
+ const char *cmd;
sigma_dut_print(dut, DUT_MSG_INFO,
"Update hostapd configuration based on DPP Config Object");
@@ -286,6 +733,8 @@
"DPP: Config Object AKM: %s", pos);
legacy_akm = strstr(pos, "psk") != NULL || strstr(pos, "sae") != NULL;
dpp_akm = strstr(pos, "dpp") != NULL;
+ psk_akm = strstr(pos, "psk") != NULL;
+ sae_akm = strstr(pos, "sae") != NULL;
res = get_wpa_cli_event(dut, ctrl, "DPP-CONFOBJ-SSID",
buf, sizeof(buf));
@@ -382,15 +831,22 @@
}
}
- if ((!connector || !dpp_akm) &&
- wpa_command(ifname, "SET wpa_key_mgmt WPA-PSK") < 0) {
- send_resp(dut, conn, SIGMA_ERROR,
- "errorCode,Failed to update AP security parameters");
- goto out;
- }
+ if ((!connector || !dpp_akm) && psk_akm && sae_akm)
+ cmd = "SET wpa_key_mgmt SAE WPA-PSK";
+ else if ((!connector || !dpp_akm) && sae_akm)
+ cmd = "SET wpa_key_mgmt SAE";
+ else if ((!connector || !dpp_akm) && psk_akm)
+ cmd = "SET wpa_key_mgmt WPA-PSK";
+ else if (connector && dpp_akm && legacy_akm && psk_akm && sae_akm)
+ cmd = "SET wpa_key_mgmt DPP SAE WPA-PSK";
+ else if (connector && dpp_akm && legacy_akm && sae_akm)
+ cmd = "SET wpa_key_mgmt DPP SAE";
+ else if (connector && dpp_akm && legacy_akm && psk_akm)
+ cmd = "SET wpa_key_mgmt DPP WPA-PSK";
+ else
+ cmd = "UNKNOWN";
- if (connector && dpp_akm && legacy_akm &&
- wpa_command(ifname, "SET wpa_key_mgmt DPP WPA-PSK") < 0) {
+ if (wpa_command(ifname, cmd) < 0) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Failed to update AP security parameters");
goto out;
@@ -603,6 +1059,15 @@
{ "Timeout", "AuthenticationResponse", NULL, 88 },
{ "Timeout", "AuthenticationConfirm", NULL, 89 },
{ "Timeout", "ConfigurationRequest", NULL, 90 },
+ { "MissingAttribute", "PeerDiscoveryRequest", "ProtocolVersion", 92 },
+ { "MissingAttribute", "PeerDiscoveryResponse", "ProtocolVersion", 93 },
+ { "InvalidValue", "PeerDiscoveryRequest", "ProtocolVersion", 94 },
+ { "InvalidValue", "PeerDiscoveryResponse", "ProtocolVersion", 95 },
+ { "InvalidValue", "ReconfigAuthRequest", "ProtocolVersion", 96 },
+ { "MissingAttribute", "ReconfigAuthRequest", "ProtocolVersion", 97 },
+ { "InvalidValue", "PBPresAnnc", "RespBSKeyHash", 98 },
+ { "InvalidValue", "PBPAResponse", "InitBSKeyHash", 99 },
+ { "InvalidValue", "PBPAResponse", "RespBSKeyHash", 100 },
{ NULL, NULL, NULL, 0 }
};
@@ -628,12 +1093,19 @@
{
char buf[200], tmp[20];
int res;
+ const char *events[] = { "DPP-TX", "DPP-FAIL", NULL };
snprintf(tmp, sizeof(tmp), "type=%d", frame_type);
for (;;) {
- res = get_wpa_cli_event(dut, ctrl, "DPP-TX", buf, sizeof(buf));
+ res = get_wpa_cli_events(dut, ctrl, events, buf, sizeof(buf));
if (res < 0)
return -1;
+ if (strstr(buf, "DPP-FAIL")) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "DPP-FAIL reported while waiting for DPP-TX: %s",
+ buf);
+ return -1;
+ }
if (strstr(buf, tmp) != NULL)
break;
}
@@ -655,6 +1127,9 @@
return -1;
if (strstr(buf, tmp) != NULL)
break;
+ /* Alias for PKEXv2 Exchange Request */
+ if (frame_type == 7 && strstr(buf, "type=18") != NULL)
+ break;
}
res = get_wpa_cli_event(dut, ctrl, "DPP-TX-STATUS",
@@ -933,6 +1408,13 @@
}
sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP auth result: %s", buf);
+ if (strstr(buf, "DPP-PB-RESULT") &&
+ strstr(buf, "DPP-PB-RESULT success") == NULL) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "DPP PB failed: %s", buf);
+ send_resp(dut, conn, SIGMA_COMPLETE, "BootstrapResult,Failed");
+ return -1;
+ }
+
if (strstr(buf, "DPP-RESPONSE-PENDING")) {
/* Display own QR code in manual mode */
if (action_type && strcasecmp(action_type, "ManualDPP") == 0 &&
@@ -1051,6 +1533,110 @@
}
+static bool is_pkex_bs(const char *bs)
+{
+ return strcasecmp(bs, "PKEX") == 0 || strcasecmp(bs, "PKEXv1") == 0 ||
+ strcasecmp(bs, "PKEXv2") == 0;
+}
+
+
+static int dpp_pick_uri_curve(struct sigma_dut *dut, const char *ifname,
+ const char *uri, char *buf, size_t buflen)
+{
+ char tmp[2000], *pos, *pos2;
+ int id;
+ char *curves = NULL;
+ char *saveptr, *res;
+
+ if (!uri || strlen(uri) > 1900)
+ return -1;
+ snprintf(tmp, sizeof(tmp), "DPP_QR_CODE %s", uri);
+ if (wpa_command_resp(ifname, tmp, tmp, sizeof(tmp)) < 0 ||
+ strncmp(tmp, "FAIL", 4) == 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to parse peer URI");
+ return -1;
+ }
+ id = atoi(tmp);
+
+ snprintf(tmp, sizeof(tmp), "DPP_BOOTSTRAP_INFO %d", id);
+ if (wpa_command_resp(ifname, tmp, tmp, sizeof(tmp)) < 0 ||
+ strncmp(tmp, "FAIL", 4) == 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to get bootstrap information");
+ return -1;
+ }
+
+ pos = tmp;
+ while (pos) {
+ pos2 = strchr(pos, '\n');
+ if (pos2)
+ *pos2 = '\0';
+ if (strncmp(pos, "supp_curves=", 12) == 0) {
+ pos += 12;
+ curves = pos;
+ break;
+ }
+
+ if (!pos2)
+ break;
+ pos = pos2 + 1;
+ }
+
+ if (!curves) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "No supported curves indication in peer URI");
+
+ return -1;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Pick alternative curve from URI: %s", curves);
+ res = strtok_r(curves, ":", &saveptr);
+ while (res) {
+ if (strcmp(res, "P-256") != 0) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Selected %s", res);
+ strlcpy(buf, res, buflen);
+ return 0;
+ }
+ res = strtok_r(NULL, ":", &saveptr);
+ }
+
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Peer URI did not include any alternative curve");
+ return -1;
+}
+
+
+static bool dpp_peer_uri_available(struct sigma_dut *dut)
+{
+ FILE *f;
+ char buf[1000];
+ size_t len;
+
+ if (dut->dpp_peer_uri)
+ return true;
+
+ f = fopen("/tmp/dpp-rest-server.uri", "r");
+ if (!f)
+ return false;
+
+ len = fread(buf, 1, sizeof(buf) - 1, f);
+ fclose(f);
+ if (!len)
+ return false;
+ buf[len] = '\0';
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Use the most recently received URI from REST API: %s",
+ buf);
+
+ free(dut->dpp_peer_uri);
+ dut->dpp_peer_uri = strdup(buf);
+
+ return dut->dpp_peer_uri != NULL;
+}
+
+
static enum sigma_cmd_result dpp_automatic_dpp(struct sigma_dut *dut,
struct sigma_conn *conn,
struct sigma_cmd *cmd)
@@ -1080,6 +1666,7 @@
char conf_pass[100];
char csrattrs[200];
char pkex_identifier[200];
+ const char *pkex_ver = "";
struct wpa_ctrl *ctrl;
int res;
unsigned int old_timeout;
@@ -1092,6 +1679,7 @@
"DPP-RESPONSE-PENDING",
"DPP-SCAN-PEER-QR-CODE",
"DPP-AUTH-DIRECTION",
+ "DPP-PB-RESULT",
NULL
};
const char *conf_events[] = {
@@ -1123,6 +1711,10 @@
FILE *f;
char *no_mud_url = "";
char *mud_url = no_mud_url;
+ char tcp_addr[30];
+ bool pb = strcasecmp(bs, "PBBS") == 0;
+ char conf_extra[1000];
+ bool dpp_3rd_party;
time(&start);
@@ -1131,12 +1723,47 @@
if (!self_conf)
self_conf = "no";
+ if (pb) {
+ if (!prov_role) {
+ if (sigma_dut_is_ap(dut))
+ prov_role = "Configurator";
+ else
+ prov_role = "Enrollee";
+ } else if (sigma_dut_is_ap(dut) &&
+ strcasecmp(prov_role, "Configurator") != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,PB AP can only be a Configurator");
+ return STATUS_SENT_ERROR;
+ }
+
+ if (!auth_role) {
+ if (sigma_dut_is_ap(dut) ||
+ strcasecmp(prov_role, "Configurator") == 0)
+ auth_role = "Initiator";
+ else
+ auth_role = "Responder";
+ } else if (sigma_dut_is_ap(dut) &&
+ strcasecmp(auth_role, "Initiator") != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,PB AP can only be an Initiator");
+ return STATUS_SENT_ERROR;
+ }
+ }
+
if (!prov_role) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Missing DPPProvisioningRole");
return STATUS_SENT_ERROR;
}
+ val = get_param(cmd, "DPPPrivNetIntro");
+ if (val && strcasecmp(val, "Yes") == 0 && !sigma_dut_is_ap(dut) &&
+ wpa_command(ifname, "SET dpp_connector_privacy_default 1") < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not enable Connector privacy");
+ return STATUS_SENT_ERROR;
+ }
+
val = get_param(cmd, "DPPConfEnrolleeRole");
if (val) {
enrollee_ap = strcasecmp(val, "AP") == 0;
@@ -1171,6 +1798,21 @@
return STATUS_SENT_ERROR;
}
+ if (sigma_dut_is_ap(dut)) {
+ if (!dut->hostapd_ifname) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "hostapd ifname not specified (-j)");
+ return ERROR_SEND_STATUS;
+ }
+ ifname = dut->hostapd_ifname;
+
+ if (dpp_hostapd_run(dut, pb) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to start hostapd");
+ return STATUS_SENT_ERROR;
+ }
+ }
+
val = get_param(cmd, "MUDURL");
if (val) {
snprintf(buf, sizeof(buf), "SET dpp_mud_url %s", val);
@@ -1181,27 +1823,39 @@
}
}
- if (sigma_dut_is_ap(dut)) {
- if (!dut->hostapd_ifname) {
- sigma_dut_print(dut, DUT_MSG_ERROR,
- "hostapd ifname not specified (-j)");
- return ERROR_SEND_STATUS;
- }
- ifname = dut->hostapd_ifname;
-
- if (dpp_hostapd_run(dut) < 0) {
- send_resp(dut, conn, SIGMA_ERROR,
- "errorCode,Failed to start hostapd");
- return STATUS_SENT_ERROR;
- }
- }
-
if (strcasecmp(prov_role, "Configurator") == 0 ||
strcasecmp(prov_role, "Both") == 0) {
+ bool nak_curve_set = get_param(cmd, "DPPNAKECC") != NULL;
+ const char *nak_curve, *sign_curve;
+ char sel[20];
+
+ nak_curve = dpp_get_curve(cmd, "DPPNAKECC");
+ sign_curve = dpp_get_curve(cmd, "DPPSigningKeyECC");
+ if (strcasecmp(nak_curve, "URI") == 0 ||
+ strcasecmp(sign_curve, "URI") == 0) {
+ if (dpp_pick_uri_curve(dut, ifname, dut->dpp_peer_uri,
+ sel, sizeof(sel)) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to select alternative curve from URI");
+ return STATUS_SENT_ERROR;
+ }
+
+ if (strcasecmp(nak_curve, "URI") == 0)
+ nak_curve = sel;
+ if (strcasecmp(sign_curve, "URI") == 0)
+ sign_curve = sel;
+ }
+
if (dut->dpp_conf_id < 0) {
- snprintf(buf, sizeof(buf),
- "DPP_CONFIGURATOR_ADD curve=%s",
- dpp_get_curve(cmd, "DPPSigningKeyECC"));
+ if (nak_curve_set) {
+ snprintf(buf, sizeof(buf),
+ "DPP_CONFIGURATOR_ADD curve=%s net_access_key_curve=%s",
+ sign_curve, nak_curve);
+ } else {
+ snprintf(buf, sizeof(buf),
+ "DPP_CONFIGURATOR_ADD curve=%s",
+ sign_curve);
+ }
if (wpa_command_resp(ifname, buf,
buf, sizeof(buf)) < 0) {
send_resp(dut, conn, SIGMA_ERROR,
@@ -1209,6 +1863,11 @@
return STATUS_SENT_ERROR;
}
dut->dpp_conf_id = atoi(buf);
+ } else if (nak_curve_set) {
+ snprintf(buf, sizeof(buf),
+ "DPP_CONFIGURATOR_SET %d net_access_key_curve=%s",
+ dut->dpp_conf_id, nak_curve);
+ wpa_command(ifname, buf);
}
if (strcasecmp(prov_role, "Configurator") == 0)
role = "configurator";
@@ -1222,8 +1881,35 @@
return STATUS_SENT_ERROR;
}
+ if (auth_role && strcasecmp(auth_role, "Initiator") == 0 &&
+ tcp && strcasecmp(tcp, "mDNS") == 0) {
+ enum dpp_mdns_role role;
+
+ /* Discover Controller/Relay IP address using mDNS */
+ if (strcasecmp(prov_role, "Configurator") == 0)
+ role = DPP_MDNS_RELAY;
+ else
+ role = DPP_MDNS_CONTROLLER;
+ if (dpp_mdns_discover(dut, role,
+ tcp_addr, sizeof(tcp_addr), NULL,
+ NULL) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not discover Controller/Relay IP address using mDNS");
+ return STATUS_SENT_ERROR;
+ }
+ tcp = tcp_addr;
+ }
+
+ if (auth_role && strcasecmp(auth_role, "Initiator") == 0 &&
+ tcp && strcasecmp(tcp, "URI") == 0) {
+ /* Use the address/port from the host entry in peer URI */
+ tcp = "from-uri";
+ }
+
+ wpa_command(ifname, "SET dpp_discard_public_action 0");
+
pkex_identifier[0] = '\0';
- if (strcasecmp(bs, "PKEX") == 0) {
+ if (is_pkex_bs(bs)) {
if (sigma_dut_is_ap(dut) && dut->ap_channel != 6) {
/* For now, have to make operating channel match DPP
* listen channel. This should be removed once hostapd
@@ -1268,6 +1954,9 @@
return STATUS_SENT_ERROR;
}
own_pkex_id = atoi(buf);
+
+ if (strcasecmp(bs, "PKEXv1") == 0)
+ pkex_ver = " ver=1";
}
ctrl = open_wpa_mon(ifname);
@@ -1293,6 +1982,7 @@
csrattrs[0] = '\0';
group_id[0] = '\0';
conf2[0] = '\0';
+ conf_extra[0] = '\0';
if (!enrollee_configurator) {
val = get_param(cmd, "DPPConfIndex");
if (val)
@@ -1485,6 +2175,23 @@
snprintf(group_id, sizeof(group_id), " group_id=%s",
group_id_str);
+ val = get_param(cmd, "DPP3rdParty");
+ dpp_3rd_party = val && strcasecmp(val, "Yes") == 0;
+ if (dpp_3rd_party) {
+ wpa_command(ifname, "SET dpp_extra_conf_req_name com.example");
+ wpa_command(ifname,
+ "SET dpp_extra_conf_req_value \"sample-info\"");
+ }
+
+ snprintf(conf_extra, sizeof(conf_extra),
+ "configurator=%d%s%s%s%s%s%s",
+ dut->dpp_conf_id, group_id,
+ akm_use_selector ? " akm_use_selector=1" : "",
+ conn_status ? " conn_status=1" : "",
+ csrattrs,
+ dpp_3rd_party ? " conf_extra_name=com.example conf_extra_value=2273616d706c652d696e666f22" : "",
+ conf2);
+
if (force_gas_fragm) {
char spaces[1500];
@@ -1565,24 +2272,15 @@
goto out;
}
snprintf(buf, sizeof(buf),
- "SET dpp_configurator_params conf=%s %s %s configurator=%d%s%s%s%s%s",
- conf_role, conf_ssid, conf_pass,
- dut->dpp_conf_id, group_id,
- akm_use_selector ? " akm_use_selector=1" : "",
- conn_status ? " conn_status=1" : "",
- csrattrs, conf2);
+ "SET dpp_configurator_params conf=%s %s %s %s",
+ conf_role, conf_ssid, conf_pass, conf_extra);
if (wpa_command(ifname, buf) < 0) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Failed to set configurator parameters");
goto out;
}
- snprintf(buf, sizeof(buf),
- "conf=%s %s %s configurator=%d%s%s%s%s%s",
- conf_role, conf_ssid, conf_pass,
- dut->dpp_conf_id, group_id,
- akm_use_selector ? " akm_use_selector=1" : "",
- conn_status ? " conn_status=1" : "", csrattrs,
- conf2);
+ snprintf(buf, sizeof(buf), "conf=%s %s %s %s",
+ conf_role, conf_ssid, conf_pass, conf_extra);
} else {
buf[0] = '\0';
enrollee = 1;
@@ -1768,7 +2466,7 @@
}
if (strcasecmp(bs, "QR") == 0) {
- if (!dut->dpp_peer_uri) {
+ if (!dpp_peer_uri_available(dut)) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Missing peer bootstrapping info");
goto out;
@@ -1784,6 +2482,8 @@
goto out;
}
dpp_peer_bootstrap = atoi(buf);
+ free(dut->dpp_peer_uri);
+ dut->dpp_peer_uri = NULL;
} else if (strcasecmp(bs, "NFC") == 0 && nfc_handover &&
strcasecmp(nfc_handover, "Static") == 0) {
if (!dut->dpp_peer_uri) {
@@ -1853,13 +2553,9 @@
goto out;
}
snprintf(buf, sizeof(buf),
- "SET dpp_configurator_params conf=%s %s %s configurator=%d%s%s%s%s%s",
+ "SET dpp_configurator_params conf=%s %s %s %s",
conf_role, conf_ssid, conf_pass,
- dut->dpp_conf_id, group_id,
- akm_use_selector ?
- " akm_use_selector=1" : "",
- conn_status ? " conn_status=1" : "",
- csrattrs, conf2);
+ conf_extra);
if (wpa_command(ifname, buf) < 0) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Failed to set configurator parameters");
@@ -1869,6 +2565,8 @@
if (tcp && strcasecmp(tcp, "yes") == 0) {
wpa_command(ifname, "DPP_STOP_LISTEN");
+ wpa_command(ifname,
+ "SET dpp_discard_public_action 1");
snprintf(buf, sizeof(buf),
"DPP_CONTROLLER_START");
} else {
@@ -1887,20 +2585,21 @@
"errorCode,Missing DPPConfIndex");
goto out;
}
+ if (tcp)
+ wpa_command(ifname,
+ "SET dpp_discard_public_action 1");
+
snprintf(buf, sizeof(buf),
- "DPP_AUTH_INIT peer=%d%s role=%s%s%s conf=%s %s %s configurator=%d%s%s%s%s%s%s%s%s",
+ "DPP_AUTH_INIT peer=%d%s role=%s%s%s conf=%s %s %s %s%s%s %s",
dpp_peer_bootstrap, own_txt, role,
netrole ? " netrole=" : "",
netrole ? netrole : "",
- conf_role, conf_ssid, conf_pass,
- dut->dpp_conf_id, neg_freq, group_id,
- akm_use_selector ? " akm_use_selector=1" : "",
- conn_status ? " conn_status=1" : "",
- tcp ? " tcp_addr=" : "",
- tcp ? tcp : "",
- csrattrs, conf2);
+ conf_role, conf_ssid, conf_pass, neg_freq,
+ tcp ? " tcp_addr=" : "", tcp ? tcp : "",
+ conf_extra);
} else if (tcp && (strcasecmp(bs, "QR") == 0 ||
strcasecmp(bs, "NFC") == 0)) {
+ wpa_command(ifname, "SET dpp_discard_public_action 1");
snprintf(buf, sizeof(buf),
"DPP_AUTH_INIT peer=%d%s role=%s%s%s tcp_addr=%s%s%s",
dpp_peer_bootstrap, own_txt, role,
@@ -1915,7 +2614,7 @@
netrole ? " netrole=" : "",
netrole ? netrole : "",
neg_freq, group_id);
- } else if (strcasecmp(bs, "PKEX") == 0 &&
+ } else if (is_pkex_bs(bs) &&
(strcasecmp(prov_role, "Configurator") == 0 ||
strcasecmp(prov_role, "Both") == 0)) {
if (!conf_role) {
@@ -1923,15 +2622,61 @@
"errorCode,Missing DPPConfIndex");
goto out;
}
+ if (tcp)
+ wpa_command(ifname, "SET dpp_discard_public_action 1");
snprintf(buf, sizeof(buf),
- "DPP_PKEX_ADD own=%d init=1 role=%s conf=%s %s %s configurator=%d%s %scode=%s",
- own_pkex_id, role, conf_role,
+ "DPP_PKEX_ADD own=%d init=1%s%s%s role=%s conf=%s %s %s configurator=%d%s %scode=%s",
+ own_pkex_id, pkex_ver,
+ tcp ? " tcp_addr=" : "",
+ tcp ? tcp : "",
+ role, conf_role,
conf_ssid, conf_pass, dut->dpp_conf_id,
csrattrs, pkex_identifier, pkex_code);
- } else if (strcasecmp(bs, "PKEX") == 0) {
+ } else if (is_pkex_bs(bs)) {
+ if (tcp)
+ wpa_command(ifname, "SET dpp_discard_public_action 1");
snprintf(buf, sizeof(buf),
- "DPP_PKEX_ADD own=%d init=1 role=%s %scode=%s",
- own_pkex_id, role, pkex_identifier, pkex_code);
+ "DPP_PKEX_ADD own=%d init=1%s%s%s role=%s %scode=%s",
+ own_pkex_id, pkex_ver,
+ tcp ? " tcp_addr=" : "",
+ tcp ? tcp : "",
+ role, pkex_identifier, pkex_code);
+ } else if (pb && conf_role && sigma_dut_is_ap(dut)) {
+ dpp_hostapd_beacon(dut);
+ snprintf(buf, sizeof(buf),
+ "DPP_PUSH_BUTTON role=%s%s%s conf=%s %s %s %s %s",
+ role,
+ netrole ? " netrole=" : "",
+ netrole ? netrole : "",
+ conf_role, conf_ssid, conf_pass,
+ neg_freq, conf_extra);
+ } else if (pb && sigma_dut_is_ap(dut)) {
+ dpp_hostapd_beacon(dut);
+ snprintf(buf, sizeof(buf),
+ "DPP_PUSH_BUTTON");
+ } else if (pb) {
+ int freq = 2437;
+
+ val = get_param(cmd, "DPPListenChannel");
+ if (val) {
+ freq = channel_to_freq(dut, atoi(val));
+ if (freq == 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unsupported DPPListenChannel value");
+ goto out;
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "DPP_LISTEN %d", freq);
+ wpa_command(ifname, buf);
+
+ snprintf(buf, sizeof(buf),
+ "DPP_PUSH_BUTTON role=%s%s%s conf=%s %s %s %s %s",
+ role,
+ netrole ? " netrole=" : "",
+ netrole ? netrole : "",
+ conf_role, conf_ssid, conf_pass,
+ neg_freq, conf_extra);
} else {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Unsupported DPPBS");
@@ -1955,7 +2700,7 @@
dut->ap_oper_chn)
freq = channel_to_freq(dut, dut->ap_channel);
- if (strcasecmp(bs, "PKEX") == 0) {
+ if (is_pkex_bs(bs)) {
/* default: channel 6 for PKEX */
freq = 2437;
}
@@ -2060,37 +2805,26 @@
goto out;
}
snprintf(buf, sizeof(buf),
- "SET dpp_configurator_params conf=%s %s %s configurator=%d%s%s%s%s%s",
- conf_role, conf_ssid, conf_pass,
- dut->dpp_conf_id, group_id,
- akm_use_selector ? " akm_use_selector=1" : "",
- conn_status ? " conn_status=1" : "", csrattrs,
- conf2);
+ "SET dpp_configurator_params conf=%s %s %s %s",
+ conf_role, conf_ssid, conf_pass, conf_extra);
if (wpa_command(ifname, buf) < 0) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Failed to set configurator parameters");
goto out;
}
}
- if (strcasecmp(bs, "PKEX") == 0) {
- snprintf(buf, sizeof(buf),
- "DPP_PKEX_ADD own=%d role=%s %scode=%s",
- own_pkex_id, role, pkex_identifier, pkex_code);
- if (wpa_command(ifname, buf) < 0) {
- send_resp(dut, conn, SIGMA_ERROR,
- "errorCode,Failed to configure DPP PKEX");
- goto out;
- }
- }
if (chirp) {
snprintf(buf, sizeof(buf),
"DPP_CHIRP own=%d iter=10 listen=%d",
dut->dpp_local_bootstrap, freq);
} else if (tcp && strcasecmp(tcp, "yes") == 0) {
+ wpa_command(ifname, "SET dpp_discard_public_action 1");
snprintf(buf, sizeof(buf), "DPP_CONTROLLER_START%s",
(strcasecmp(bs, "QR") == 0 && mutual) ?
" qr=mutual" : "");
+ } else if (pb) {
+ snprintf(buf, sizeof(buf), "DPP_PUSH_BUTTON");
} else {
snprintf(buf, sizeof(buf),
"DPP_LISTEN %d role=%s%s%s%s",
@@ -2106,6 +2840,18 @@
goto out;
}
+ if (is_pkex_bs(bs)) {
+ snprintf(buf, sizeof(buf),
+ "DPP_PKEX_ADD own=%d%s role=%s %scode=%s",
+ own_pkex_id, pkex_ver, role,
+ pkex_identifier, pkex_code);
+ if (wpa_command(ifname, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to configure DPP PKEX");
+ goto out;
+ }
+ }
+
if (!(tcp && strcasecmp(tcp, "yes") == 0) &&
get_driver_type(dut) == DRIVER_OPENWRT) {
snprintf(buf, sizeof(buf), "iwconfig %s channel %d",
@@ -2304,18 +3050,20 @@
goto out;
}
- if (!frametype && strcasecmp(bs, "PKEX") == 0 &&
+ if (!frametype && is_pkex_bs(bs) &&
auth_role && strcasecmp(auth_role, "Responder") == 0) {
- if (dpp_wait_tx_status(dut, ctrl, 10) < 0) {
+ /* TODO: PKEX timeout check for over-TCP case? */
+ if (!tcp && dpp_wait_tx_status(dut, ctrl, 10) < 0) {
send_resp(dut, conn, SIGMA_COMPLETE,
"BootstrapResult,Timeout");
goto out;
}
}
- if (!frametype && strcasecmp(bs, "PKEX") == 0 &&
+ if (!frametype && is_pkex_bs(bs) &&
auth_role && strcasecmp(auth_role, "Initiator") == 0) {
- if (dpp_wait_tx(dut, ctrl, 0) < 0) {
+ /* TODO: PKEX timeout check for over-TCP case? */
+ if (!tcp && dpp_wait_tx(dut, ctrl, 0) < 0) {
send_resp(dut, conn, SIGMA_COMPLETE,
"BootstrapResult,Timeout");
goto out;
@@ -2456,8 +3204,15 @@
memcpy(mud_url, ",MUDURL,", 8);
memcpy(mud_url + 8, pos, url_len + 1);
- res = get_wpa_cli_events(dut, ctrl, conf_events,
- buf, sizeof(buf));
+ /* DPP-MUD-URL can be returned multiple times when configuration
+ * exchange needs to perform multiple GAS queries, e.g., for
+ * CSR or key changes. */
+ for (;;) {
+ res = get_wpa_cli_events(dut, ctrl, conf_events,
+ buf, sizeof(buf));
+ if (res < 0 || !strstr(buf, "DPP-MUD-URL "))
+ break;
+ }
}
if (res < 0) {
send_resp(dut, conn, SIGMA_COMPLETE,
@@ -2473,6 +3228,22 @@
goto out;
}
+ pos = strstr(buf, " conf_status=");
+ if (pos && strstr(buf, "DPP-CONF-SENT")) {
+ int status;
+
+ pos += 13;
+ status = atoi(pos);
+ if (status) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Configurator rejected configuration with status %d",
+ status);
+ send_resp(dut, conn, SIGMA_COMPLETE,
+ "BootstrapResult,OK,AuthResult,OK,ConfResult,FAILED");
+ goto out;
+ }
+ }
+
if (conn_status && strstr(buf, "DPP-CONF-SENT") &&
strstr(buf, "wait_conn_status=1")) {
res = get_wpa_cli_event(dut, ctrl, "DPP-CONN-STATUS-RESULT",
@@ -2738,6 +3509,9 @@
struct sigma_cmd *cmd)
{
const char *val;
+ const char *step = get_param(cmd, "DPPStep");
+ const char *frametype = get_param(cmd, "DPPFrameType");
+ const char *attr = get_param(cmd, "DPPIEAttribute");
int freq;
struct wpa_ctrl *ctrl = NULL;
const char *ifname;
@@ -2763,6 +3537,8 @@
"DPP-CONF-FAILED",
NULL
};
+ unsigned int old_timeout = dut->default_timeout;
+ bool controller_started = false;
if (sigma_dut_is_ap(dut)) {
if (!dut->hostapd_ifname) {
@@ -2993,6 +3769,26 @@
}
}
+ if (step && frametype) {
+ int test;
+
+ test = dpp_get_test(step, frametype, attr);
+ if (test <= 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Unsupported DPPStep/DPPFrameType/DPPIEAttribute");
+ goto out;
+ }
+
+ snprintf(buf, sizeof(buf), "SET dpp_test %d", test);
+ if (wpa_command(ifname, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set dpp_test");
+ goto out;
+ }
+ } else {
+ wpa_command(ifname, "SET dpp_test 0");
+ }
+
snprintf(buf, sizeof(buf),
"SET dpp_configurator_params conf=%s %s %s configurator=%d%s%s%s%s%s",
conf_role, conf_ssid, conf_pass,
@@ -3013,6 +3809,13 @@
return ERROR_SEND_STATUS;
}
+ val = get_param(cmd, "DPPTimeout");
+ if (val && atoi(val) > 0) {
+ dut->default_timeout = atoi(val);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP timeout: %u",
+ dut->default_timeout);
+ }
+
val = get_param(cmd, "DPPListenChannel");
if (val) {
freq = channel_to_freq(dut, atoi(val));
@@ -3030,6 +3833,27 @@
}
}
+ val = get_param(cmd, "DPPOverTCP");
+ if (val && strcasecmp(val, "yes") == 0) {
+ wpa_command(ifname, "DPP_STOP_LISTEN");
+ wpa_command(ifname, "SET dpp_discard_public_action 1");
+ wpa_command(ifname, "DPP_CONTROLLER_START");
+ controller_started = true;
+ } else {
+ wpa_command(ifname, "SET dpp_discard_public_action 0");
+ }
+
+ if (frametype && strcasecmp(frametype, "ReconfigAuthRequest") == 0) {
+ const char *result;
+
+ if (dpp_wait_tx_status(dut, ctrl, 15) < 0)
+ result = "ReconfigAuthResult,Timeout";
+ else
+ result = "ReconfigAuthResult,Errorsent";
+ send_resp(dut, conn, SIGMA_COMPLETE, result);
+ goto out;
+ }
+
res = get_wpa_cli_event(dut, ctrl, "DPP-CONF-REQ-RX",
buf, sizeof(buf));
if (res < 0) {
@@ -3080,6 +3904,9 @@
wpa_ctrl_detach(ctrl);
wpa_ctrl_close(ctrl);
}
+ if (controller_started)
+ wpa_command(ifname, "DPP_CONTROLLER_STOP");
+ dut->default_timeout = old_timeout;
return STATUS_SENT;
err:
send_resp(dut, conn, SIGMA_ERROR, NULL);
@@ -3235,6 +4062,265 @@
}
+#define AVAHI_SERVICE "/etc/avahi/services/sigma_dut-dpp.service"
+
+int dpp_mdns_start(struct sigma_dut *dut, enum dpp_mdns_role role)
+{
+ FILE *f;
+ const char *org = "Qualcomm DPP testing";
+ const char *location = "Somewhere in the test network";
+ const char *bskeyhash = NULL;
+ const char *ifname = get_station_ifname(dut);
+ char buf[2000];
+
+ if (sigma_dut_is_ap(dut)) {
+ if (!dut->hostapd_ifname) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "hostapd ifname not specified (-j)");
+ return -1;
+ }
+ ifname = dut->hostapd_ifname;
+ }
+
+ if (role == DPP_MDNS_CONTROLLER && dut->dpp_local_bootstrap >= 0) {
+ char *pos, *pos2;
+ unsigned char pkhash[32];
+ int pkhash_len = -1;
+
+ snprintf(buf, sizeof(buf), "DPP_BOOTSTRAP_INFO %d",
+ dut->dpp_local_bootstrap);
+ if (wpa_command_resp(ifname, buf, buf, sizeof(buf)) < 0 ||
+ strncmp(buf, "FAIL", 4) == 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to get bootstrap information");
+ return -1;
+ }
+
+ pos = buf;
+ while (pos) {
+ pos2 = strchr(pos, '\n');
+ if (pos2)
+ *pos2 = '\0';
+ if (strncmp(pos, "pkhash=", 7) == 0) {
+ pkhash_len = parse_hexstr(pos + 7, pkhash,
+ sizeof(pkhash));
+ break;
+ }
+
+ if (!pos2)
+ break;
+ pos = pos2 + 1;
+ }
+
+ if (pkhash_len != 32 ||
+ base64_encode((char *) pkhash, pkhash_len,
+ buf, sizeof(buf)) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to get own bootstrapping public key hash");
+ return -1;
+ }
+
+ bskeyhash = buf;
+ }
+
+ f = fopen(AVAHI_SERVICE, "w");
+ if (!f) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Could not write Avahi service file (%s)",
+ AVAHI_SERVICE);
+ return -1;
+ }
+
+ fprintf(f, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
+ fprintf(f, "<!DOCTYPE service-group SYSTEM \"avahi-service.dtd\">\n");
+ fprintf(f, "<service-group>\n");
+ fprintf(f, " <name replace-wildcards=\"yes\">%%h</name>\n");
+ fprintf(f, " <service>\n");
+ fprintf(f, " <type>_dpp._tcp</type>\n");
+ fprintf(f, " <subtype>_%s._sub._dpp._tcp</subtype>\n",
+ dpp_mdns_role_txt(role));
+ fprintf(f, " <port>8908</port>\n");
+ fprintf(f, " <txt-record>txtversion=1</txt-record>\n");
+ fprintf(f, " <txt-record>organization=%s</txt-record>\n", org);
+ fprintf(f, " <txt-record>location=%s</txt-record>\n", location);
+ if (bskeyhash)
+ fprintf(f, " <txt-record>bskeyhash=%s</txt-record>\n",
+ bskeyhash);
+ if (role == DPP_MDNS_RELAY) {
+ int opclass, chan;
+
+ chan = dut->ap_channel;
+ if (!chan)
+ chan = 11;
+ if (chan >= 1 && chan <= 13)
+ opclass = 81;
+ else if (chan >= 36 && chan <= 48)
+ opclass = 115;
+ else if (chan >= 52 && chan <= 64)
+ opclass = 118;
+ else if (chan >= 100 && chan <= 144)
+ opclass = 121;
+ else if (chan >= 149 && chan <= 177)
+ opclass = 125;
+ else
+ opclass = 0;
+
+ fprintf(f, " <txt-record>channellist=%d/%d</txt-record>\n",
+ opclass, chan);
+ }
+ fprintf(f, " </service>\n");
+ fprintf(f, "</service-group>\n");
+
+ fclose(f);
+
+ sigma_dut_print(dut, DUT_MSG_INFO, "Started DPP mDNS advertisement");
+ dut->dpp_mdns = role;
+
+ return 0;
+}
+
+
+void dpp_mdns_stop(struct sigma_dut *dut)
+{
+ dut->dpp_mdns = DPP_MDNS_NOT_RUNNING;
+
+ if (file_exists(AVAHI_SERVICE)) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Stopping DPP mDNS service advertisement");
+ unlink(AVAHI_SERVICE);
+ }
+}
+
+
+static enum sigma_cmd_result dpp_set_mdns_advertise(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd,
+ const char *role)
+{
+ int ret = -1;
+
+ if (strcasecmp(role, "Relay") == 0) {
+ ret = dpp_mdns_start(dut, DPP_MDNS_RELAY);
+ } else if (strcasecmp(role, "Controller") == 0) {
+ const char *curve = dpp_get_curve(cmd, "DPPCryptoIdentifier");
+
+ if (sigma_dut_is_ap(dut) && dpp_hostapd_run(dut, false) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to start hostapd");
+ return STATUS_SENT_ERROR;
+ }
+
+ if (dut->dpp_local_bootstrap < 0) {
+ char buf[200], resp[200];
+ int res;
+ const char *ifname = get_station_ifname(dut);
+
+ if (sigma_dut_is_ap(dut)) {
+ if (!dut->hostapd_ifname) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "hostapd ifname not specified (-j)");
+ return ERROR_SEND_STATUS;
+ }
+ ifname = dut->hostapd_ifname;
+ }
+
+
+ res = snprintf(buf, sizeof(buf),
+ "DPP_BOOTSTRAP_GEN type=qrcode curve=%s",
+ curve);
+ if (res < 0 || res >= sizeof(buf) ||
+ wpa_command_resp(ifname, buf, resp,
+ sizeof(resp)) < 0 ||
+ strncmp(resp, "FAIL", 4) == 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Failed to generate own bootstrapping key");
+ return ERROR_SEND_STATUS;
+ }
+ dut->dpp_local_bootstrap = atoi(resp);
+ }
+ ret = dpp_mdns_start(dut, DPP_MDNS_CONTROLLER);
+ } else if (strcasecmp(role, "Bootstrapping") == 0) {
+ ret = dpp_mdns_start(dut, DPP_MDNS_BOOTSTRAPPING);
+ } else {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "Unsupported DPPmDNSAdvertise role: %s", role);
+ }
+
+ return ret < 0 ? ERROR_SEND_STATUS : SUCCESS_SEND_STATUS;
+}
+
+
+static int dpp_check_mdns_discovery_result(struct sigma_dut *dut)
+{
+ if (sigma_dut_is_ap(dut) && dut->ap_dpp_conf_addr &&
+ strcasecmp(dut->ap_dpp_conf_addr, "mDNS") == 0 &&
+ dpp_mdns_discover_relay_params(dut) < 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to discover Controller for AP Relay using mDNS");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static enum sigma_cmd_result dpp_set_parameter(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ const char *val;
+ enum sigma_cmd_result res = SUCCESS_SEND_STATUS;
+
+ val = get_param(cmd, "DPPmDNSAdvertise");
+ if (val &&
+ dpp_set_mdns_advertise(dut, conn, cmd, val) < 0)
+ res = ERROR_SEND_STATUS;
+
+ val = get_param(cmd, "DPPmDNSEnable");
+ if (val && strcasecmp(val, "Yes") == 0 &&
+ dpp_check_mdns_discovery_result(dut) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,mDNS discovery has not succeeded");
+ return STATUS_SENT_ERROR;
+ }
+
+ return res;
+}
+
+
+static enum sigma_cmd_result dpp_get_peer_bootstrap(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ struct sigma_cmd *cmd)
+{
+ char uri[1000], hex[2000], resp[2100];
+ FILE *f;
+ int res;
+ size_t len;
+
+ f = fopen("/tmp/dpp-rest-server.uri", "r");
+ if (!f) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,No DPP URI received through REST API");
+ return STATUS_SENT_ERROR;
+ }
+
+ len = fread(uri, 1, sizeof(uri), f);
+ fclose(f);
+ if (len == 0 || len == sizeof(uri)) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Could not read the received DPP URI");
+ return STATUS_SENT_ERROR;
+ }
+ uri[len] = '\0';
+
+ ascii2hexstr(uri, hex);
+ res = snprintf(resp, sizeof(resp), "BootstrappingData,%s", hex);
+ send_resp(dut, conn, SIGMA_COMPLETE,
+ res >= 0 && res < sizeof(resp) ? resp : NULL);
+ return STATUS_SENT;
+}
+
+
enum sigma_cmd_result dpp_dev_exec_action(struct sigma_dut *dut,
struct sigma_conn *conn,
struct sigma_cmd *cmd)
@@ -3250,6 +4336,10 @@
if (strcasecmp(type, "DPPReconfigure") == 0)
return dpp_reconfigure(dut, conn, cmd);
+ if (strcasecmp(type, "SetParameter") == 0)
+ return dpp_set_parameter(dut, conn, cmd);
+ if (strcasecmp(type, "GetPeerBootstrap") == 0)
+ return dpp_get_peer_bootstrap(dut, conn, cmd);
if (!bs) {
send_resp(dut, conn, SIGMA_ERROR,
diff --git a/server.c b/server.c
index bd07f22..0d2da05 100644
--- a/server.c
+++ b/server.c
@@ -245,8 +245,12 @@
SERVER_DB);
return -1;
}
- sql = sqlite3_mprintf("DELETE FROM cert_enroll WHERE mac_addr=%Q",
- addr);
+
+ if (strcasecmp(addr, "any") == 0)
+ sql = sqlite3_mprintf("DELETE FROM cert_enroll");
+ else
+ sql = sqlite3_mprintf("DELETE FROM cert_enroll WHERE mac_addr=%Q",
+ addr);
if (!sql) {
sqlite3_close(db);
return -1;
@@ -321,7 +325,7 @@
}
prog = sigma_program_to_enum(var);
- if (prog != PROGRAM_HS2_R2 && prog != PROGRAM_HS2_R3) {
+ if (!is_passpoint_r2_or_newer(prog)) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Unsupported program");
return STATUS_SENT;
@@ -485,8 +489,11 @@
{
char *sql, *last_serial = NULL;
- sql = sqlite3_mprintf("SELECT serialnum FROM cert_enroll WHERE mac_addr=%Q",
- addr);
+ if (!addr || strcasecmp(addr, "any") == 0)
+ sql = sqlite3_mprintf("SELECT serialnum FROM cert_enroll");
+ else
+ sql = sqlite3_mprintf("SELECT serialnum FROM cert_enroll WHERE mac_addr=%Q",
+ addr);
if (!sql)
return NULL;
sigma_dut_print(dut, DUT_MSG_DEBUG, "SQL: %s", sql);
@@ -877,7 +884,7 @@
}
prog = sigma_program_to_enum(var);
- if (prog != PROGRAM_HS2_R2 && prog != PROGRAM_HS2_R3) {
+ if (!is_passpoint_r2_or_newer(prog)) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Unsupported program");
return STATUS_SENT;
@@ -936,7 +943,7 @@
return aaa_auth_status(dut, conn, cmd, resp, timeout);
}
- if (osu && status && strcasecmp(status, "OSU") == 0 && addr)
+ if (osu && status && strcasecmp(status, "OSU") == 0)
return osu_cert_enroll_status(dut, conn, cmd, addr, timeout);
if (osu && status && strcasecmp(status, "PolicyProvisioning") == 0 &&
@@ -1005,7 +1012,7 @@
}
prog = sigma_program_to_enum(var);
- if (prog != PROGRAM_HS2_R2 && prog != PROGRAM_HS2_R3) {
+ if (!is_passpoint_r2_or_newer(prog)) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Unsupported program");
return STATUS_SENT;
diff --git a/sigma_dut.c b/sigma_dut.c
index c4d13aa..07bfc15 100644
--- a/sigma_dut.c
+++ b/sigma_dut.c
@@ -860,6 +860,7 @@
#ifdef ANDROID
dut->dscp_use_iptables = 1;
#endif /* ANDROID */
+ dut->autoconnect_default = 1;
}
@@ -999,7 +1000,7 @@
static void usage(void)
{
- printf("usage: sigma_dut [-aABdfGqDIntuVW234] [-p<port>] "
+ printf("usage: sigma_dut [-aABdfGqDIntuVW2347] [-p<port>] "
"[-s<sniffer>] [-m<set_maccaddr.sh>] \\\n"
" [-M<main ifname>] [-R<radio ifname>] "
"[-S<station ifname>] [-P<p2p_ifname>]\\\n"
@@ -1053,7 +1054,7 @@
for (;;) {
c = getopt(argc, argv,
- "aAb:Bc:C:dDE:e:fF:gGhH:j:J:i:Ik:K:l:L:m:M:nN:o:O:p:P:qQr:R:s:S:tT:uv:VWw:x:y:z:Z:2345:6:");
+ "aAb:Bc:C:dDE:e:fF:gGhH:j:J:i:Ik:K:l:L:m:M:nN:o:O:p:P:qQr:R:s:S:tT:uv:VWw:x:y:z:Z:2345:6:7");
if (c < 0)
break;
switch (c) {
@@ -1288,6 +1289,9 @@
exit(1);
}
break;
+ case '7':
+ sigma_dut.autoconnect_default = 0;
+ break;
case 'h':
default:
usage();
diff --git a/sigma_dut.h b/sigma_dut.h
index 60ce86c..73a234a 100644
--- a/sigma_dut.h
+++ b/sigma_dut.h
@@ -94,6 +94,7 @@
#define MAX_RADIO 3
#define NAN_AWARE_IFACE "wifi-aware0"
+#define BROADCAST_ADDR "255.255.255.255"
/* Set default operating channel width 80 MHz */
#define VHT_DEFAULT_OPER_CHWIDTH AP_80_VHT_OPER_CHWIDTH
@@ -397,6 +398,13 @@
struct dscp_policy_data *next;
};
+enum dpp_mdns_role {
+ DPP_MDNS_NOT_RUNNING,
+ DPP_MDNS_RELAY,
+ DPP_MDNS_CONTROLLER,
+ DPP_MDNS_BOOTSTRAPPING,
+};
+
struct sigma_dut {
const char *main_ifname;
char *main_ifname_2g;
@@ -893,6 +901,8 @@
PROGRAM_HE,
PROGRAM_HS2_R3,
PROGRAM_QM,
+ PROGRAM_HS2_R4,
+ PROGRAM_HS2_2022,
} program;
enum device_type {
@@ -988,6 +998,7 @@
int dpp_local_bootstrap;
int dpp_conf_id;
int dpp_network_id;
+ enum dpp_mdns_role dpp_mdns;
u8 fils_hlp;
pthread_t hlp_thread;
@@ -1041,6 +1052,8 @@
unsigned int prev_disable_scs_support;
unsigned int prev_disable_mscs_support;
int dscp_use_iptables;
+ int autoconnect_default;
+ int dhcp_client_running;
};
@@ -1182,6 +1195,7 @@
int wil6210_set_force_mcs(struct sigma_dut *dut, int force, int mcs);
int sta_set_addba_buf_size(struct sigma_dut *dut,
const char *intf, int bufsize);
+int wcn_set_he_gi(struct sigma_dut *dut, const char *intf, u8 gi_val);
#ifdef NL80211_SUPPORT
int wcn_set_he_ltf(struct sigma_dut *dut, const char *intf,
enum qca_wlan_he_ltf_cfg ltf);
@@ -1209,6 +1223,8 @@
/* utils.c */
enum sigma_program sigma_program_to_enum(const char *prog);
+bool is_passpoint_r2_or_newer(enum sigma_program prog);
+bool is_passpoint(enum sigma_program prog);
int hex_byte(const char *str);
int parse_hexstr(const char *hex, unsigned char *buf, size_t buflen);
int parse_mac_address(struct sigma_dut *dut, const char *arg,
@@ -1233,6 +1249,7 @@
int get_wps_forced_version(struct sigma_dut *dut, const char *str);
int base64_encode(const char *src, size_t len, char *out, size_t out_len);
+unsigned char * base64_decode(const char *src, size_t len, size_t *out_len);
int random_get_bytes(char *buf, size_t len);
int get_enable_disable(const char *val);
int wcn_driver_cmd(const char *ifname, char *buf);
@@ -1274,6 +1291,9 @@
enum sigma_cmd_result dpp_dev_exec_action(struct sigma_dut *dut,
struct sigma_conn *conn,
struct sigma_cmd *cmd);
+int dpp_mdns_discover_relay_params(struct sigma_dut *dut);
+int dpp_mdns_start(struct sigma_dut *dut, enum dpp_mdns_role role);
+void dpp_mdns_stop(struct sigma_dut *dut);
/* dhcp.c */
void process_fils_hlp(struct sigma_dut *dut);
@@ -1282,6 +1302,8 @@
#ifdef NL80211_SUPPORT
struct nl80211_ctx * nl80211_init(struct sigma_dut *dut);
void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx);
+int nl80211_open_event_sock(struct sigma_dut *dut);
+void nl80211_close_event_sock(struct sigma_dut *dut);
struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx,
int ifindex, int flags,
uint8_t cmd);
@@ -1307,5 +1329,7 @@
void miracast_register_cmds(void);
int set_ipv6_addr(struct sigma_dut *dut, const char *ip, const char *mask,
const char *ifname);
+void kill_pid(struct sigma_dut *dut, const char *pid_file);
+int get_ip_addr(const char *ifname, int ipv6, char *buf, size_t len);
#endif /* SIGMA_DUT_H */
diff --git a/sta.c b/sta.c
index 2940757..fd1a2c5 100644
--- a/sta.c
+++ b/sta.c
@@ -34,6 +34,7 @@
#include "wpa_helpers.h"
#include "miracast.h"
#include "qca-vendor_copy.h"
+#include "nl80211_copy.h"
/* Temporary files for sta_send_addba */
#define VI_QOS_TMP_FILE "/tmp/vi-qos.tmp"
@@ -1288,6 +1289,8 @@
sleep(1);
}
}
+
+ dut->dhcp_client_running = 0;
#endif /* __linux__ */
}
@@ -1328,6 +1331,8 @@
#endif /* ANDROID */
}
}
+
+ dut->dhcp_client_running = 1;
#endif /* __linux__ */
return 0;
@@ -1491,6 +1496,15 @@
sigma_dut_print(dut, DUT_MSG_INFO, "Using IPv6 "
"stateless address autoconfiguration");
#ifdef ANDROID
+ snprintf(buf, sizeof(buf),
+ "sysctl net.ipv6.conf.%s.disable_ipv6=0",
+ ifname);
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Run: %s", buf);
+ if (system(buf) != 0) {
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Failed to enable IPv6 address");
+ }
+
/*
* This sleep is required as the assignment in case of
* Android is taking time and is done by the kernel.
@@ -1584,9 +1598,24 @@
val = get_param(cmd, "primary-dns");
if (val) {
#ifdef ANDROID
- /* TODO */
- sigma_dut_print(dut, DUT_MSG_INFO, "Ignored primary-dns %s "
- "setting", val);
+ char dns_cmd[200];
+ int len;
+ char dnsmasq[100];
+
+ kill_pid(dut, concat_sigma_tmpdir(dut, "/sigma_dut-dnsmasq.pid",
+ dnsmasq, sizeof(dnsmasq)));
+
+ len = snprintf(dns_cmd, sizeof(dns_cmd),
+ "/system/bin/dnsmasq -uroot --no-resolv -S%s -x/%s", val,
+ dnsmasq);
+ if (len < 0 || len >= sizeof(dns_cmd))
+ return ERROR_SEND_STATUS;
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Running %s", dns_cmd);
+ if (system(dns_cmd) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to set primary-dns");
+ return STATUS_SENT_ERROR;
+ }
#else /* ANDROID */
char dns_cmd[200];
int len;
@@ -2586,6 +2615,30 @@
}
}
+ val = get_param(cmd, "imsiPrivacyCert");
+ if (val) {
+ snprintf(buf, sizeof(buf), "%s/%s", sigma_cert_path, val);
+#ifdef __linux__
+ if (!file_exists(buf)) {
+ char msg[300];
+
+ snprintf(msg, sizeof(msg),
+ "ErrorCode,imsiPrivacyCert file (%s) not found",
+ buf);
+ send_resp(dut, conn, SIGMA_ERROR, msg);
+ return STATUS_SENT_ERROR;
+ }
+#endif /* __linux__ */
+ if (set_network_quoted(ifname, id, "imsi_privacy_cert",
+ buf) < 0)
+ return ERROR_SEND_STATUS;
+ }
+
+ val = get_param(cmd, "imsiPrivacyCertID");
+ if (val && set_network_quoted(ifname, id, "imsi_privacy_attr",
+ val) < 0)
+ return ERROR_SEND_STATUS;
+
if (dut->akm_values &
((1 << AKM_FILS_SHA256) |
(1 << AKM_FILS_SHA384) |
@@ -2632,6 +2685,7 @@
struct sigma_conn *conn,
struct sigma_cmd *cmd)
{
+ const char *type = get_param(cmd, "Type");
const char *intf = get_param(cmd, "Interface");
const char *ifname, *val;
int id;
@@ -2751,6 +2805,16 @@
}
}
+ if (set_network(ifname, id, "ocsp", "1") < 0)
+ return ERROR_SEND_STATUS;
+
+ if (type && strcasecmp(type, "EAPTLS_1_3") == 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Enable only TLS v1.3");
+ if (set_network_quoted(ifname, id, "phase1",
+ "tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1 tls_disable_tlsv1_3=0") < 0)
+ return ERROR_SEND_STATUS;
+ }
+
return 1;
}
@@ -3089,7 +3153,8 @@
strcasecmp(type, "PSK-SAE") == 0 ||
strcasecmp(type, "SAE") == 0)
return cmd_sta_set_psk(dut, conn, cmd);
- if (strcasecmp(type, "EAPTLS") == 0)
+ if (strcasecmp(type, "EAPTLS") == 0 ||
+ strcasecmp(type, "EAPTLS_1_3") == 0)
return cmd_sta_set_eaptls(dut, conn, cmd);
if (strcasecmp(type, "EAPTTLS") == 0)
return cmd_sta_set_eapttls(dut, conn, cmd);
@@ -4605,7 +4670,8 @@
if ((dut->program == PROGRAM_WPA3 &&
dut->sta_associate_wait_connect) ||
- dut->program == PROGRAM_QM) {
+ dut->program == PROGRAM_QM ||
+ (dut->dhcp_client_running && dut->client_privacy)) {
ctrl = open_wpa_mon(get_station_ifname(dut));
if (!ctrl)
return ERROR_SEND_STATUS;
@@ -4716,6 +4782,22 @@
}
if (strstr(buf, "CTRL-EVENT-CONNECTED")) {
+ if (dut->dhcp_client_running && dut->client_privacy) {
+ /*
+ * Interface MAC address will be changed by
+ * wpa_supplicant before connection attempt when
+ * client privacy enabled. Restart DHCP client
+ * to make sure DHCP frames use the correct
+ * source MAC address.
+ * */
+ kill_dhcp_client(dut, ifname);
+ if (start_dhcp_client(dut, ifname) < 0) {
+ send_resp(dut, conn, SIGMA_COMPLETE,
+ "Result,DHCP client start failed");
+ ret = STATUS_SENT_ERROR;
+ break;
+ }
+ }
if (tod >= 0) {
sigma_dut_print(dut, DUT_MSG_DEBUG,
"Network profile TOD policy update: %d -> %d",
@@ -5941,27 +6023,34 @@
val = get_param(cmd, "FT_DS");
if (val) {
+ int sta_ft_ds;
+
if (strcasecmp(val, "Enable") == 0) {
- dut->sta_ft_ds = 1;
+ sta_ft_ds = 1;
} else if (strcasecmp(val, "Disable") == 0) {
- dut->sta_ft_ds = 0;
+ sta_ft_ds = 0;
} else {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Unsupported value for FT_DS");
return STATUS_SENT_ERROR;
}
- if (get_driver_type(dut) == DRIVER_WCN &&
+
+ if (dut->sta_ft_ds != sta_ft_ds &&
+ get_driver_type(dut) == DRIVER_WCN &&
sta_config_params(dut, intf, STA_SET_FT_DS,
- dut->sta_ft_ds) != 0) {
+ sta_ft_ds) != 0) {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,Failed to enable/disable FT_DS");
return STATUS_SENT_ERROR;
}
+
+ dut->sta_ft_ds = sta_ft_ds;
}
val = get_param(cmd, "Program");
if (val && (strcasecmp(val, "HS2-R2") == 0 ||
- strcasecmp(val, "HS2-R3") == 0))
+ strcasecmp(val, "HS2-R3") == 0 ||
+ strcasecmp(val, "HS2-R4") == 0))
return cmd_sta_preset_testparameters_hs2_r2(dut, conn, intf,
cmd);
@@ -6410,6 +6499,35 @@
if (val)
dut->dscp_reject_resp_code = atoi(val);
+ val = get_param(cmd, "Deauth_Reconnect_Policy");
+ if (val) {
+ char buf[35];
+ int len;
+
+ if (strcasecmp(val, "0") == 0) {
+ len = snprintf(buf, sizeof(buf),
+ "STA_AUTOCONNECT %d",
+ dut->autoconnect_default);
+ } else if (strcasecmp(val, "1") == 0) {
+ len = snprintf(buf, sizeof(buf),
+ "STA_AUTOCONNECT 0");
+ } else if (strcasecmp(val, "2") == 0) {
+ len = snprintf(buf, sizeof(buf),
+ "STA_AUTOCONNECT 1");
+ } else {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Invalid Deauth_Reconnect_Policy");
+ return INVALID_SEND_STATUS;
+ }
+
+ if (len < 0 || len >= sizeof(buf) ||
+ wpa_command(intf, buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Failed to update Deauth_Reconnect_Policy");
+ return STATUS_SENT_ERROR;
+ }
+ }
+
return 1;
}
@@ -8732,6 +8850,136 @@
}
+int wcn_set_he_gi(struct sigma_dut *dut, const char *intf, u8 gi_val)
+{
+ #ifdef NL80211_SUPPORT
+ struct nlattr *attr;
+ struct nlattr *attr1;
+ int ifindex, ret;
+ struct nl_msg *msg;
+
+ ifindex = if_nametoindex(intf);
+ if (ifindex == 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: Index for interface %s failed",
+ __func__, intf);
+ return -1;
+ }
+
+ if (!(msg = nl80211_drv_msg(dut, dut->nl_ctx, ifindex, 0,
+ NL80211_CMD_SET_TX_BITRATE_MASK)) ||
+ !(attr = nla_nest_start(msg, NL80211_ATTR_TX_RATES))) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: NL80211_CMD_SET_TX_BITRATE_MASK msg failed",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "%s: Setting HE GI %d",
+ __func__, gi_val);
+
+ attr1 = nla_nest_start(msg, NL80211_BAND_2GHZ);
+ if (!attr1) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: Netlink nest start failed for NL80211_BAND_2GHZ",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_put_u8(msg, NL80211_TXRATE_HE_GI, gi_val);
+ nla_nest_end(msg, attr1);
+
+ attr1 = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ if (!attr1) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: Netlink nest start failed for NL80211_BAND_5GHZ",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_put_u8(msg, NL80211_TXRATE_HE_GI, gi_val);
+ nla_nest_end(msg, attr1);
+
+ nla_nest_end(msg, attr);
+ ret = send_and_recv_msgs(dut, dut->nl_ctx, msg, NULL, NULL);
+ if (ret) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: send_and_recv_msgs failed, ret=%d",
+ __func__, ret);
+ }
+ return ret;
+#else /* NL80211_SUPPORT */
+ return -1;
+#endif /* NL80211_SUPPORT */
+}
+
+
+static int sta_set_vht_gi(struct sigma_dut *dut, const char *intf, u8 gi_val)
+{
+ #ifdef NL80211_SUPPORT
+ struct nlattr *attr;
+ struct nlattr *attr1;
+ int ifindex, ret;
+ struct nl_msg *msg;
+
+ ifindex = if_nametoindex(intf);
+ if (ifindex == 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: Index for interface %s failed",
+ __func__, intf);
+ return -1;
+ }
+
+ if (!(msg = nl80211_drv_msg(dut, dut->nl_ctx, ifindex, 0,
+ NL80211_CMD_SET_TX_BITRATE_MASK)) ||
+ !(attr = nla_nest_start(msg, NL80211_ATTR_TX_RATES))) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: NL80211_CMD_SET_TX_BITRATE_MASK msg failed",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "%s: Setting VHT GI %d",
+ __func__, gi_val);
+
+ attr1 = nla_nest_start(msg, NL80211_BAND_2GHZ);
+ if (!attr1) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: Netlink nest start failed for NL80211_BAND_2GHZ",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_put_u8(msg, NL80211_TXRATE_GI, gi_val);
+ nla_nest_end(msg, attr1);
+
+ attr1 = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ if (!attr1) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: Netlink nest start failed for NL80211_BAND_5GHZ",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_put_u8(msg, NL80211_TXRATE_GI, gi_val);
+ nla_nest_end(msg, attr1);
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(dut, dut->nl_ctx, msg, NULL, NULL);
+ if (ret) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "%s: send_and_recv_msgs failed, ret=%d",
+ __func__, ret);
+ }
+ return ret;
+#else /* NL80211_SUPPORT */
+ return -1;
+#endif /* NL80211_SUPPORT */
+}
+
+
static void sta_reset_default_wcn(struct sigma_dut *dut, const char *intf,
const char *type)
{
@@ -8772,6 +9020,8 @@
sta_set_scan_unicast_probe(dut, intf, 0);
#ifdef NL80211_SUPPORT
+ nl80211_close_event_sock(dut);
+
/* Reset the device HE capabilities to its default supported
* configuration. */
sta_set_he_testbed_def(dut, intf, 0);
@@ -9027,6 +9277,11 @@
char buf[100];
int ret;
+#ifdef ANDROID
+ kill_pid(dut, concat_sigma_tmpdir(dut, "/sigma_dut-dnsmasq.pid",
+ buf, sizeof(buf)));
+#endif /* ANDROID */
+
if (dut->station_ifname_2g &&
strcmp(dut->station_ifname_2g, intf) == 0)
dut->use_5g = 0;
@@ -9087,7 +9342,7 @@
lowi_cmd_sta_reset_default(dut, conn, cmd) < 0)
return ERROR_SEND_STATUS;
- if (dut->program == PROGRAM_HS2_R2 || dut->program == PROGRAM_HS2_R3) {
+ if (is_passpoint_r2_or_newer(dut->program)) {
unlink("SP/wi-fi.org/pps.xml");
if (system("rm -r SP/*") != 0) {
}
@@ -9189,14 +9444,12 @@
set_ps(intf, dut, 0);
- if (dut->program == PROGRAM_HS2 || dut->program == PROGRAM_HS2_R2 ||
- dut->program == PROGRAM_HS2_R3) {
+ if (is_passpoint(dut->program)) {
wpa_command(intf, "SET interworking 1");
wpa_command(intf, "SET hs20 1");
}
- if (dut->program == PROGRAM_HS2_R2 ||
- dut->program == PROGRAM_HS2_R3 ||
+ if (is_passpoint_r2_or_newer(dut->program) ||
dut->program == PROGRAM_OCE) {
wpa_command(intf, "SET pmf 1");
} else {
@@ -9250,6 +9503,12 @@
dut->dpp_local_bootstrap = -1;
wpa_command(intf, "SET dpp_config_processing 2");
wpa_command(intf, "SET dpp_mud_url ");
+ wpa_command(intf, "SET dpp_extra_conf_req_name ");
+ wpa_command(intf, "SET dpp_extra_conf_req_value ");
+ wpa_command(intf, "SET dpp_connector_privacy_default 0");
+ dpp_mdns_stop(dut);
+ unlink("/tmp/dpp-rest-server.uri");
+ unlink("/tmp/dpp-rest-server.id");
wpa_command(intf, "VENDOR_ELEM_REMOVE 13 *");
@@ -9328,6 +9587,11 @@
dut->prev_disable_scs_support = 0;
dut->prev_disable_mscs_support = 0;
+ if (dut->autoconnect_default)
+ wpa_command(intf, "STA_AUTOCONNECT 1");
+ else
+ wpa_command(intf, "STA_AUTOCONNECT 0");
+
if (dut->program != PROGRAM_VHT)
return cmd_sta_p2p_reset(dut, conn, cmd);
@@ -9672,11 +9936,12 @@
static int twt_async_event_wait(struct sigma_dut *dut, unsigned int twt_op)
{
- struct nl_cb *cb;
+ struct nl_cb *cb = NULL;
int err_code = 0, select_retval = 0;
struct wait_event wait_info;
- cb = nl_socket_get_cb(dut->nl_ctx->event_sock);
+ if (dut->nl_ctx->event_sock)
+ cb = nl_socket_get_cb(dut->nl_ctx->event_sock);
if (!cb) {
sigma_dut_print(dut, DUT_MSG_ERROR,
"event callback not found");
@@ -10289,9 +10554,18 @@
val = get_param(cmd, "SGI80");
if (val) {
int sgi80;
+ enum nl80211_txrate_gi gi_val;
sgi80 = strcmp(val, "1") == 0 || strcasecmp(val, "Enable") == 0;
- run_iwpriv(dut, intf, "shortgi %d", sgi80);
+ if (sgi80)
+ gi_val = NL80211_TXRATE_FORCE_LGI;
+ else
+ gi_val = NL80211_TXRATE_FORCE_SGI;
+ if (sta_set_vht_gi(dut, intf, (u8) gi_val)) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "sta_set_vht_gi failed, using iwpriv");
+ run_iwpriv(dut, intf, "shortgi %d", sgi80);
+ }
}
val = get_param(cmd, "TxBF");
@@ -11011,6 +11285,20 @@
return STATUS_SENT_ERROR;
}
+ val = get_param(cmd, "GKH_G2_Tx");
+ if (val) {
+ char buf[50];
+
+ snprintf(buf, sizeof(buf), "SET disable_eapol_g2_tx %d",
+ strcasecmp(val, "disable") == 0);
+
+ if (wpa_command(intf, buf) < 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to enable/disable G2 transmit");
+ return STATUS_SENT_ERROR;
+ }
+ }
+
return cmd_sta_set_wireless_common(intf, dut, conn, cmd);
}
@@ -11022,6 +11310,8 @@
const char *val;
val = get_param(cmd, "Program");
+ if (!val)
+ val = get_param(cmd, "Prog");
if (val) {
if (strcasecmp(val, "11n") == 0)
return cmd_sta_set_11n(dut, conn, cmd);
@@ -13784,7 +14074,8 @@
return cmd_sta_send_frame_tdls(dut, conn, cmd);
if (val && (strcasecmp(val, "HS2") == 0 ||
strcasecmp(val, "HS2-R2") == 0 ||
- strcasecmp(val, "HS2-R3") == 0))
+ strcasecmp(val, "HS2-R3") == 0 ||
+ strcasecmp(val, "HS2-R4") == 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);
@@ -13994,7 +14285,8 @@
val = get_param(cmd, "program");
if (val && (strcasecmp(val, "HS2") == 0 ||
strcasecmp(val, "HS2-R2") == 0 ||
- strcasecmp(val, "HS2-R3") == 0))
+ strcasecmp(val, "HS2-R3") == 0 ||
+ strcasecmp(val, "HS2-R4") == 0))
return cmd_sta_set_parameter_hs2(dut, conn, cmd, intf);
return -1;
@@ -14511,34 +14803,42 @@
val = get_param(cmd, "GI");
if (val) {
int fix_rate_sgi;
+ u8 he_gi_val = 0;
if (strcmp(val, "0.8") == 0) {
snprintf(buf, sizeof(buf), "iwpriv %s shortgi 9", intf);
fix_rate_sgi = 1;
+ he_gi_val = NL80211_RATE_INFO_HE_GI_0_8;
} else if (strcmp(val, "1.6") == 0) {
snprintf(buf, sizeof(buf), "iwpriv %s shortgi 10",
intf);
fix_rate_sgi = 2;
+ he_gi_val = NL80211_RATE_INFO_HE_GI_1_6;
} else if (strcmp(val, "3.2") == 0) {
snprintf(buf, sizeof(buf), "iwpriv %s shortgi 11",
intf);
fix_rate_sgi = 3;
+ he_gi_val = NL80211_RATE_INFO_HE_GI_3_2;
} else {
send_resp(dut, conn, SIGMA_ERROR,
"errorCode,GI value not supported");
return STATUS_SENT_ERROR;
}
- if (system(buf) != 0) {
- send_resp(dut, conn, SIGMA_ERROR,
- "errorCode,Failed to set shortgi");
- return STATUS_SENT_ERROR;
- }
- snprintf(buf, sizeof(buf), "iwpriv %s shortgi %d",
- intf, fix_rate_sgi);
- if (system(buf) != 0) {
- send_resp(dut, conn, SIGMA_ERROR,
- "errorCode,Failed to set fix rate shortgi");
- return STATUS_SENT_ERROR;
+ if (wcn_set_he_gi(dut, intf, he_gi_val)) {
+ sigma_dut_print(dut, DUT_MSG_INFO,
+ "wcn_set_he_gi failed, using iwpriv");
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set shortgi");
+ return STATUS_SENT_ERROR;
+ }
+ snprintf(buf, sizeof(buf), "iwpriv %s shortgi %d",
+ intf, fix_rate_sgi);
+ if (system(buf) != 0) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "errorCode,Failed to set fix rate shortgi");
+ return STATUS_SENT_ERROR;
+ }
}
}
@@ -14613,6 +14913,11 @@
val = get_param(cmd, "TWT_Setup");
if (val) {
+#ifdef NL80211_SUPPORT
+ if (dut->sta_async_twt_supp && nl80211_open_event_sock(dut))
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to open nl80211 event socket");
+#endif /* NL80211_SUPPORT */
if (strcasecmp(val, "Request") == 0) {
if (set_power_save_wcn(dut, intf, 1) < 0)
sigma_dut_print(dut, DUT_MSG_ERROR,
@@ -14633,6 +14938,11 @@
val = get_param(cmd, "TWT_Operation");
if (val) {
+#ifdef NL80211_SUPPORT
+ if (dut->sta_async_twt_supp && nl80211_open_event_sock(dut))
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "Failed to open nl80211 event socket");
+#endif /* NL80211_SUPPORT */
if (strcasecmp(val, "Suspend") == 0) {
if (sta_twt_suspend_or_nudge(dut, conn, cmd)) {
send_resp(dut, conn, SIGMA_ERROR,
@@ -15624,6 +15934,7 @@
int info_avail = 0;
unsigned int old_timeout;
int res;
+ const char *events[] = { "RX-VENUE-URL", "ANQP-QUERY-DONE", NULL };
if (get_wpa_status(intf, "bssid", bssid, sizeof(bssid)) < 0) {
send_resp(dut, conn, SIGMA_ERROR,
@@ -15649,18 +15960,32 @@
old_timeout = dut->default_timeout;
dut->default_timeout = 2;
- res = get_wpa_cli_event(dut, ctrl, "RX-VENUE-URL", buf, sizeof(buf));
+ for (;;) {
+ res = get_wpa_cli_events(dut, ctrl, events, buf, sizeof(buf));
+ if (res < 0)
+ break;
+ if (strstr(buf, "ANQP-QUERY-DONE") != NULL) {
+ res = -1;
+ break;
+ }
+ pos = strchr(buf, ' ');
+ if (!pos)
+ continue;
+ pos++;
+ pos = strchr(pos, ' ');
+ if (!pos)
+ continue;
+ pos++;
+
+ if (strncmp(pos, "https://", 8) == 0)
+ break;
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG,
+ "Ignore non-HTTPS venue URL: %s", pos);
+ }
dut->default_timeout = old_timeout;
if (res < 0)
goto done;
- pos = strchr(buf, ' ');
- if (!pos)
- goto done;
- pos++;
- pos = strchr(pos, ' ');
- if (!pos)
- goto done;
- pos++;
info_avail = 1;
snprintf(params, sizeof(params), "browser %s", pos);
@@ -15888,7 +16213,7 @@
return 0;
}
- if (dut->program == PROGRAM_HS2_R2 || dut->program == PROGRAM_HS2_R3) {
+ if (is_passpoint_r2_or_newer(dut->program)) {
/*
* Set provisioning_sp for the test cases where SIM/USIM
* provisioning is used.
diff --git a/traffic.c b/traffic.c
index ee2dbc0..c6c5968 100644
--- a/traffic.c
+++ b/traffic.c
@@ -41,6 +41,7 @@
int dscp = 0, use_dscp = 0;
char extra[100], int_arg[100], intf_arg[100], ip_dst[100], ping[100];
struct in6_addr ip6_addr;
+ bool broadcast = false;
val = get_param(cmd, "Type");
if (!val)
@@ -78,6 +79,14 @@
if (val == NULL)
return INVALID_SEND_STATUS;
size = atoi(val);
+ if (type != 2 && strcmp(dst, BROADCAST_ADDR) == 0) {
+ if (size > 1472) {
+ send_resp(dut, conn, SIGMA_ERROR,
+ "ErrorCode,Unsupported broadcast ping frame size");
+ return STATUS_SENT;
+ }
+ broadcast = true;
+ }
val = get_param(cmd, "frameRate");
if (val == NULL)
@@ -141,10 +150,11 @@
else
intf_arg[0] = '\0';
fprintf(f, "#!" SHELL "\n"
- "ping%s -c %d%s -s %d%s -q%s %s > %s"
+ "ping%s%s -c %d%s -s %d%s -q%s %s > %s"
"/sigma_dut-ping.%d &\n"
"echo $! > %s/sigma_dut-ping-pid.%d\n",
- type == 2 ? "6" : "", pkts, int_arg, size, extra,
+ type == 2 ? "6" : "", broadcast ? " -b" : "",
+ pkts, int_arg, size, extra,
intf_arg, dst, dut->sigma_tmpdir, id, dut->sigma_tmpdir, id);
fclose(f);
@@ -259,7 +269,7 @@
}
-static int get_ip_addr(const char *ifname, int ipv6, char *buf, size_t len)
+int get_ip_addr(const char *ifname, int ipv6, char *buf, size_t len)
{
struct ifaddrs *ifa, *ifa_tmp;
bool non_ll_addr_found = false;
diff --git a/utils.c b/utils.c
index cb69a99..21f5cc3 100644
--- a/utils.c
+++ b/utils.c
@@ -10,6 +10,7 @@
#include "sigma_dut.h"
#include <sys/ioctl.h>
#include <sys/stat.h>
+#include <signal.h>
#include "wpa_helpers.h"
enum driver_type wifi_chip_type = DRIVER_NOT_SET;
@@ -140,6 +141,10 @@
return PROGRAM_HS2_R2;
if (strcasecmp(prog, "HS2-R3") == 0)
return PROGRAM_HS2_R3;
+ if (strcasecmp(prog, "HS2-2022") == 0)
+ return PROGRAM_HS2_2022;
+ if (strcasecmp(prog, "HS2-R4") == 0)
+ return PROGRAM_HS2_R4;
if (strcasecmp(prog, "WFD") == 0)
return PROGRAM_WFD;
if (strcasecmp(prog, "DisplayR2") == 0)
@@ -177,6 +182,22 @@
}
+bool is_passpoint_r2_or_newer(enum sigma_program prog)
+{
+ return prog == PROGRAM_HS2_R2 ||
+ prog == PROGRAM_HS2_R3 ||
+ prog == PROGRAM_HS2_2022 ||
+ prog == PROGRAM_HS2_R4;
+}
+
+
+bool is_passpoint(enum sigma_program prog)
+{
+ return prog == PROGRAM_HS2 ||
+ is_passpoint_r2_or_newer(prog);
+}
+
+
static int parse_hex(char c)
{
if (c >= '0' && c <= '9')
@@ -616,8 +637,6 @@
struct nl80211_ctx * nl80211_init(struct sigma_dut *dut)
{
struct nl80211_ctx *ctx;
- struct nl_cb *cb = NULL;
- int ret;
ctx = calloc(1, sizeof(struct nl80211_ctx));
if (!ctx) {
@@ -662,19 +681,42 @@
goto cleanup;
}
+ return ctx;
+
+cleanup:
+ if (ctx->sock)
+ nl_socket_free(ctx->sock);
+
+ free(ctx);
+ return NULL;
+}
+
+
+int nl80211_open_event_sock(struct sigma_dut *dut)
+{
+ struct nl_cb *cb = NULL;
+ int ret;
+ struct nl80211_ctx *ctx = dut->nl_ctx;
+
+ if (!ctx) {
+ sigma_dut_print(dut, DUT_MSG_ERROR, "nl80211 context is NULL");
+ return -1;
+ }
+
+ nl80211_close_event_sock(dut);
ctx->event_sock = nl_socket_alloc();
if (!ctx->event_sock) {
sigma_dut_print(dut, DUT_MSG_ERROR,
"Failed to create NL event socket, err: %s",
strerror(errno));
- goto cleanup;
+ return -1;
}
if (nl_connect(ctx->event_sock, NETLINK_GENERIC)) {
sigma_dut_print(dut, DUT_MSG_ERROR,
"Could not connect event socket, err: %s",
strerror(errno));
- goto cleanup;
+ return -1;
}
if (nl_socket_set_buffer_size(ctx->event_sock, SOCK_BUF_SIZE, 0) < 0) {
@@ -687,7 +729,7 @@
if (!cb) {
sigma_dut_print(dut, DUT_MSG_INFO,
"Failed to get NL control block for event socket port");
- goto cleanup;
+ return -1;
}
ret = nl_get_multicast_id(dut, ctx, "nl80211", "vendor");
@@ -706,16 +748,7 @@
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
nl_cb_put(cb);
- return ctx;
-
-cleanup:
- if (ctx->sock)
- nl_socket_free(ctx->sock);
- if (ctx->event_sock)
- nl_socket_free(ctx->event_sock);
-
- free(ctx);
- return NULL;
+ return 0;
}
@@ -734,6 +767,17 @@
}
+void nl80211_close_event_sock(struct sigma_dut *dut)
+{
+ struct nl80211_ctx *ctx = dut->nl_ctx;
+
+ if (ctx && ctx->event_sock) {
+ nl_socket_free(ctx->event_sock);
+ ctx->event_sock = NULL;
+ }
+}
+
+
static struct nl_msg *
wcn_create_wifi_test_config_msg(struct sigma_dut *dut, const char *intf)
{
@@ -960,6 +1004,74 @@
}
+unsigned char * base64_decode(const char *src, size_t len, size_t *out_len)
+{
+ unsigned char dtable[256], *out, *pos, block[4], tmp;
+ size_t i, count, olen;
+ int pad = 0;
+ size_t extra_pad;
+
+ memset(dtable, 0x80, 256);
+ for (i = 0; i < sizeof(base64_table) - 1; i++)
+ dtable[(unsigned char) base64_table[i]] = (unsigned char) i;
+ dtable['='] = 0;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ if (dtable[(unsigned char) src[i]] != 0x80)
+ count++;
+ }
+
+ if (count == 0)
+ return NULL;
+ extra_pad = (4 - count % 4) % 4;
+
+ olen = (count + extra_pad) / 4 * 3;
+ pos = out = malloc(olen);
+ if (!out)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < len + extra_pad; i++) {
+ unsigned char val;
+
+ if (i >= len)
+ val = '=';
+ else
+ val = src[i];
+ tmp = dtable[val];
+ if (tmp == 0x80)
+ continue;
+
+ if (val == '=')
+ pad++;
+ block[count] = tmp;
+ count++;
+ if (count == 4) {
+ *pos++ = (block[0] << 2) | (block[1] >> 4);
+ *pos++ = (block[1] << 4) | (block[2] >> 2);
+ *pos++ = (block[2] << 6) | block[3];
+ count = 0;
+ if (pad) {
+ if (pad == 1)
+ pos--;
+ else if (pad == 2)
+ pos -= 2;
+ else {
+ /* Invalid padding */
+ free(out);
+ return NULL;
+ }
+ break;
+ }
+ }
+ }
+
+ *out_len = pos - out;
+ return out;
+}
+
+
int random_get_bytes(char *buf, size_t len)
{
FILE *f;
@@ -1043,3 +1155,32 @@
{
return res < 0 || (unsigned int) res >= size;
}
+
+
+void kill_pid(struct sigma_dut *dut, const char *pid_file)
+{
+ int pid;
+ FILE *f;
+
+ f = fopen(pid_file, "r");
+ if (!f)
+ return; /* process is not running */
+
+ if (fscanf(f, "%d", &pid) != 1 || pid <= 0) {
+ sigma_dut_print(dut, DUT_MSG_ERROR,
+ "No PID for process in %s", pid_file);
+ fclose(f);
+ unlink(pid_file);
+ return;
+ }
+ fclose(f);
+
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Process PID found in %s: %d",
+ pid_file, pid);
+ if (kill(pid, SIGINT) < 0 && errno != ESRCH)
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "kill failed: %s",
+ strerror(errno));
+
+ unlink(pid_file);
+ sleep(1);
+}