xref: /wlan-dirver/utils/sigma-dut/dpp.c (revision 9541ee876754c01f8bf1b2ec81d493e077d71c61)
1 /*
2  * Sigma Control API DUT (station/AP/sniffer)
3  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4  * Copyright (c) 2018-2020, The Linux Foundation
5  * All Rights Reserved.
6  * Licensed under the Clear BSD license. See README for more details.
7  */
8 
9 #include "sigma_dut.h"
10 #include <sys/wait.h>
11 #include "wpa_ctrl.h"
12 #include "wpa_helpers.h"
13 
14 extern char *sigma_wpas_ctrl;
15 extern char *sigma_cert_path;
16 
17 #ifdef ANDROID
18 char *dpp_qrcode_file = "/sdcard/wpadebug_qrdata.txt";
19 #endif /* ANDROID */
20 
21 
22 static int sigma_dut_is_ap(struct sigma_dut *dut)
23 {
24 	return dut->device_type == AP_unknown ||
25 		dut->device_type == AP_testbed ||
26 		dut->device_type == AP_dut;
27 }
28 
29 
30 static int dpp_hostapd_run(struct sigma_dut *dut)
31 {
32 	if (dut->hostapd_running)
33 		return 0;
34 
35 	sigma_dut_print(dut, DUT_MSG_INFO,
36 			"Starting hostapd in unconfigured state for DPP");
37 	snprintf(dut->ap_ssid, sizeof(dut->ap_ssid), "unconfigured");
38 	if (!dut->ap_oper_chn)
39 		dut->ap_channel = 11;
40 	dut->ap_is_dual = 0;
41 	dut->ap_mode = dut->ap_channel <= 14 ? AP_11ng : AP_11na;
42 	dut->ap_key_mgmt = AP_OPEN;
43 	dut->ap_cipher = AP_PLAIN;
44 	if (!dut->ap_dpp_conf_addr || !dut->ap_dpp_conf_pkhash)
45 		dut->ap_start_disabled = 1;
46 	return cmd_ap_config_commit(dut, NULL, NULL) == 1 ? 0 : -1;
47 }
48 
49 
50 static int dpp_hostapd_beacon(struct sigma_dut *dut)
51 {
52 	const char *ifname = dut->hostapd_ifname;
53 
54 	if (!dut->ap_start_disabled)
55 		return 0;
56 
57 	if (!ifname ||
58 	    wpa_command(ifname, "SET start_disabled 0") < 0 ||
59 	    wpa_command(ifname, "DISABLE") < 0 ||
60 	    wpa_command(ifname, "ENABLE") < 0)
61 		return -1;
62 
63 	dut->ap_start_disabled = 0;
64 	return 0;
65 }
66 
67 
68 static const char * dpp_get_curve(struct sigma_cmd *cmd, const char *arg)
69 {
70 	const char *val = get_param(cmd, arg);
71 
72 	if (!val)
73 		val = "P-256";
74 	else if (strcasecmp(val, "BP-256R1") == 0)
75 		val = "BP-256";
76 	else if (strcasecmp(val, "BP-384R1") == 0)
77 		val = "BP-384";
78 	else if (strcasecmp(val, "BP-512R1") == 0)
79 		val = "BP-512";
80 
81 	return val;
82 }
83 
84 
85 static enum sigma_cmd_result
86 dpp_get_local_bootstrap(struct sigma_dut *dut, struct sigma_conn *conn,
87 			struct sigma_cmd *cmd, int send_result, int *success)
88 {
89 	const char *curve = dpp_get_curve(cmd, "DPPCryptoIdentifier");
90 	const char *bs = get_param(cmd, "DPPBS");
91 	const char *chan_list = get_param(cmd, "DPPChannelList");
92 	char *pos, mac[50], buf[200], resp[1000], hex[2000];
93 	const char *ifname = get_station_ifname(dut);
94 	int res;
95 	const char *type;
96 
97 	if (success)
98 		*success = 0;
99 	if (strcasecmp(bs, "QR") == 0) {
100 		type = "qrcode";
101 	} else if (strcasecmp(bs, "NFC") == 0) {
102 		type ="nfc-uri";
103 	} else {
104 		send_resp(dut, conn, SIGMA_ERROR,
105 			  "errorCode,Unsupported DPPBS");
106 		return STATUS_SENT_ERROR;
107 	}
108 
109 	if (sigma_dut_is_ap(dut)) {
110 		u8 bssid[ETH_ALEN];
111 
112 		if (!dut->hostapd_ifname) {
113 			sigma_dut_print(dut, DUT_MSG_ERROR,
114 					"hostapd ifname not specified (-j)");
115 			return ERROR_SEND_STATUS;
116 		}
117 		ifname = dut->hostapd_ifname;
118 		if (get_hwaddr(dut->hostapd_ifname, bssid) < 0) {
119 			sigma_dut_print(dut, DUT_MSG_ERROR,
120 					"Could not get MAC address for %s",
121 					dut->hostapd_ifname);
122 			return ERROR_SEND_STATUS;
123 		}
124 		snprintf(mac, sizeof(mac), "%02x%02x%02x%02x%02x%02x",
125 			 bssid[0], bssid[1], bssid[2],
126 			 bssid[3], bssid[4], bssid[5]);
127 	} else {
128 		if (get_wpa_status(ifname, "address", mac, sizeof(mac)) < 0) {
129 			send_resp(dut, conn, SIGMA_ERROR,
130 				  "errorCode,Failed to get own MAC address from wpa_supplicant");
131 			return STATUS_SENT_ERROR;
132 		}
133 	}
134 
135 	pos = mac;
136 	while (*pos) {
137 		if (*pos == ':')
138 			memmove(pos, pos + 1, strlen(pos));
139 		else
140 			pos++;
141 	}
142 
143 	if (sigma_dut_is_ap(dut) && dpp_hostapd_run(dut) < 0) {
144 		send_resp(dut, conn, SIGMA_ERROR,
145 			  "errorCode,Failed to start hostapd");
146 		return STATUS_SENT_ERROR;
147 	}
148 
149 	if (chan_list &&
150 	    (strcmp(chan_list, "0/0") == 0 || chan_list[0] == '\0')) {
151 		/* No channel list */
152 		res = snprintf(buf, sizeof(buf),
153 			       "DPP_BOOTSTRAP_GEN type=%s curve=%s mac=%s",
154 			       type, curve, mac);
155 	} else if (chan_list) {
156 		/* Channel list override (CTT case) - space separated tuple(s)
157 		 * of OperatingClass/Channel; convert to wpa_supplicant/hostapd
158 		 * format: comma separated tuples */
159 		strlcpy(resp, chan_list, sizeof(resp));
160 		for (pos = resp; *pos; pos++) {
161 			if (*pos == ' ')
162 				*pos = ',';
163 		}
164 		res = snprintf(buf, sizeof(buf),
165 			       "DPP_BOOTSTRAP_GEN type=%s curve=%s chan=%s mac=%s",
166 			       type, curve, resp, mac);
167 	} else {
168 		int channel = 11;
169 
170 		/* Default channel list (normal DUT case) */
171 		if (sigma_dut_is_ap(dut) && dut->hostapd_running &&
172 		    dut->ap_oper_chn &&
173 		    dut->ap_channel > 0 && dut->ap_channel <= 13)
174 			channel = dut->ap_channel;
175 		res = snprintf(buf, sizeof(buf),
176 			       "DPP_BOOTSTRAP_GEN type=%s curve=%s chan=81/%d mac=%s",
177 			       type, curve, channel, mac);
178 	}
179 
180 	if (res < 0 || res >= sizeof(buf) ||
181 	    wpa_command_resp(ifname, buf, resp, sizeof(resp)) < 0 ||
182 	    strncmp(resp, "FAIL", 4) == 0)
183 		return ERROR_SEND_STATUS;
184 	dut->dpp_local_bootstrap = atoi(resp);
185 	snprintf(buf, sizeof(buf), "DPP_BOOTSTRAP_GET_URI %d",
186 		 atoi(resp));
187 	if (wpa_command_resp(ifname, buf, resp, sizeof(resp)) < 0 ||
188 	    strncmp(resp, "FAIL", 4) == 0)
189 		return ERROR_SEND_STATUS;
190 
191 	sigma_dut_print(dut, DUT_MSG_DEBUG, "URI: %s", resp);
192 
193 	if (send_result) {
194 		ascii2hexstr(resp, hex);
195 		res = snprintf(resp, sizeof(resp), "BootstrappingData,%s", hex);
196 		send_resp(dut, conn, SIGMA_COMPLETE,
197 			  res >= 0 && res < sizeof(resp) ? resp : NULL);
198 	}
199 
200 	if (success)
201 		*success = 1;
202 	return STATUS_SENT;
203 }
204 
205 
206 static enum sigma_cmd_result dpp_set_peer_bootstrap(struct sigma_dut *dut,
207 						    struct sigma_conn *conn,
208 						    struct sigma_cmd *cmd)
209 {
210 	const char *val = get_param(cmd, "DPPBootstrappingdata");
211 	char uri[1000];
212 	int res;
213 
214 	if (!val) {
215 		send_resp(dut, conn, SIGMA_ERROR,
216 			  "errorCode,Missing DPPBootstrappingdata");
217 		return STATUS_SENT_ERROR;
218 	}
219 
220 	res = parse_hexstr(val, (unsigned char *) uri, sizeof(uri));
221 	if (res < 0 || (size_t) res >= sizeof(uri))
222 		return ERROR_SEND_STATUS;
223 	uri[res] = '\0';
224 	sigma_dut_print(dut, DUT_MSG_DEBUG, "URI: %s", uri);
225 	free(dut->dpp_peer_uri);
226 	dut->dpp_peer_uri = strdup(uri);
227 
228 	return SUCCESS_SEND_STATUS;
229 }
230 
231 
232 static int dpp_hostapd_conf_update(struct sigma_dut *dut,
233 				   struct sigma_conn *conn, const char *ifname,
234 				   struct wpa_ctrl *ctrl)
235 {
236 	int res;
237 	char buf[2000], buf2[2500], *pos, *pos2;
238 	const char *conf_data_events[] = {
239 		"DPP-CONNECTOR",
240 		"DPP-CONFOBJ-PASS",
241 		"DPP-CONFOBJ-PSK",
242 		"DPP-C-SIGN-KEY",
243 		"DPP-NET-ACCESS-KEY",
244 		NULL
245 	};
246 	unsigned int old_timeout;
247 	int legacy_akm, dpp_akm;
248 	char *connector = NULL, *psk = NULL, *csign = NULL,
249 		*net_access_key = NULL;
250 	char pass[64];
251 	int pass_len = 0;
252 	int ret = 0;
253 
254 	sigma_dut_print(dut, DUT_MSG_INFO,
255 			"Update hostapd configuration based on DPP Config Object");
256 
257 	if (wpa_command(ifname, "SET wpa 2") < 0 ||
258 	    wpa_command(ifname, "SET wpa_key_mgmt DPP") < 0 ||
259 	    wpa_command(ifname, "SET ieee80211w 1") < 0 ||
260 	    wpa_command(ifname, "SET rsn_pairwise CCMP") < 0) {
261 		send_resp(dut, conn, SIGMA_ERROR,
262 			  "errorCode,Failed to update AP security parameters");
263 		goto out;
264 	}
265 
266 	res = get_wpa_cli_event(dut, ctrl, "DPP-CONFOBJ-AKM", buf, sizeof(buf));
267 	if (res < 0) {
268 		send_resp(dut, conn, SIGMA_ERROR,
269 			  "errorCode,No DPP-CONFOBJ-AKM");
270 		goto out;
271 	}
272 	pos = strchr(buf, ' ');
273 	if (!pos)
274 		return -2;
275 	pos++;
276 	sigma_dut_print(dut, DUT_MSG_INFO,
277 			"DPP: Config Object AKM: %s", pos);
278 	legacy_akm = strstr(pos, "psk") != NULL || strstr(pos, "sae") != NULL;
279 	dpp_akm = strstr(pos, "dpp") != NULL;
280 
281 	res = get_wpa_cli_event(dut, ctrl, "DPP-CONFOBJ-SSID",
282 				buf, sizeof(buf));
283 	if (res < 0) {
284 		send_resp(dut, conn, SIGMA_ERROR,
285 			  "errorCode,No DPP-CONFOBJ-SSID");
286 		goto out;
287 	}
288 	pos = strchr(buf, ' ');
289 	if (!pos)
290 		return -2;
291 	pos++;
292 	sigma_dut_print(dut, DUT_MSG_INFO,
293 			"DPP: Config Object SSID: %s", pos);
294 	snprintf(buf2, sizeof(buf2), "SET ssid %s", pos);
295 	if (wpa_command(ifname, buf2) < 0) {
296 		send_resp(dut, conn, SIGMA_ERROR,
297 			  "errorCode,Failed to update AP SSID");
298 		goto out;
299 	}
300 
301 	if (wpa_command(ifname, "SET utf8_ssid 1") < 0) {
302 		send_resp(dut, conn, SIGMA_ERROR,
303 			  "errorCode,Failed to update AP UTF-8 SSID capa");
304 		goto out;
305 	}
306 
307 	while ((dpp_akm && (!connector || !csign || !net_access_key)) ||
308 	       (legacy_akm && !pass_len && !psk)) {
309 		res = get_wpa_cli_events(dut, ctrl, conf_data_events,
310 					 buf, sizeof(buf));
311 		if (res < 0) {
312 			send_resp(dut, conn, SIGMA_ERROR,
313 				  "errorCode,Not all config object information received");
314 			goto out;
315 		}
316 
317 		if (strstr(buf, "DPP-CONNECTOR")) {
318 			pos = strchr(buf, ' ');
319 			if (!pos) {
320 				ret = -2;
321 				goto out;
322 			}
323 			pos++;
324 			sigma_dut_print(dut, DUT_MSG_INFO, "DPP: Connector: %s",
325 					pos);
326 			if (!connector)
327 				connector = strdup(pos);
328 		} else if (strstr(buf, "DPP-C-SIGN-KEY")) {
329 			pos = strchr(buf, ' ');
330 			if (!pos) {
331 				ret = -2;
332 				goto out;
333 			}
334 			pos++;
335 			sigma_dut_print(dut, DUT_MSG_INFO,
336 					"DPP: C-sign-key: %s", pos);
337 			if (!csign)
338 				csign = strdup(pos);
339 		} else if (strstr(buf, "DPP-NET-ACCESS-KEY")) {
340 			pos = strchr(buf, ' ');
341 			if (!pos) {
342 				ret = -2;
343 				goto out;
344 			}
345 			pos++;
346 			if (!net_access_key)
347 				net_access_key = strdup(pos);
348 		} else if (strstr(buf, "DPP-CONFOBJ-PASS")) {
349 			pos = strchr(buf, ' ');
350 			if (!pos) {
351 				ret = -2;
352 				goto out;
353 			}
354 			pos++;
355 			pass_len = parse_hexstr(pos, (u8 *) pass, sizeof(pass));
356 			if (pass_len < 0 || (size_t) pass_len >= sizeof(pass)) {
357 				ret = -2;
358 				goto out;
359 			}
360 			pass[pass_len] = '\0';
361 			sigma_dut_print(dut, DUT_MSG_INFO,
362 					"DPP: Passphrase: %s", pass);
363 		} else if (strstr(buf, "DPP-CONFOBJ-PSK")) {
364 			pos = strchr(buf, ' ');
365 			if (!pos) {
366 				ret = -2;
367 				goto out;
368 			}
369 			pos++;
370 			sigma_dut_print(dut, DUT_MSG_INFO, "DPP: PSK: %s", pos);
371 			if (!psk)
372 				psk = strdup(pos);
373 		}
374 	}
375 
376 	if ((!connector || !dpp_akm) &&
377 	    wpa_command(ifname, "SET wpa_key_mgmt WPA-PSK") < 0) {
378 		send_resp(dut, conn, SIGMA_ERROR,
379 			  "errorCode,Failed to update AP security parameters");
380 		goto out;
381 	}
382 
383 	if (connector && dpp_akm && legacy_akm &&
384 	    wpa_command(ifname, "SET wpa_key_mgmt DPP WPA-PSK") < 0) {
385 		send_resp(dut, conn, SIGMA_ERROR,
386 			  "errorCode,Failed to update AP security parameters");
387 		goto out;
388 	}
389 
390 	if (pass_len) {
391 		snprintf(buf2, sizeof(buf2), "SET wpa_passphrase %s",
392 			 pass);
393 		if (wpa_command(ifname, buf2) < 0) {
394 			send_resp(dut, conn, SIGMA_ERROR,
395 				  "errorCode,Failed to set passphrase");
396 			goto out;
397 		}
398 	} else if (psk) {
399 		snprintf(buf2, sizeof(buf2), "SET wpa_psk %s", psk);
400 		if (wpa_command(ifname, buf2) < 0) {
401 			send_resp(dut, conn, SIGMA_ERROR,
402 				  "errorCode,Failed to set PSK");
403 			goto out;
404 		}
405 	}
406 
407 	if (connector) {
408 		snprintf(buf2, sizeof(buf2), "SET dpp_connector %s", connector);
409 		if (wpa_command(ifname, buf2) < 0) {
410 			send_resp(dut, conn, SIGMA_ERROR,
411 				  "errorCode,Failed to update AP Connector");
412 			goto out;
413 		}
414 	}
415 
416 	if (csign) {
417 		snprintf(buf2, sizeof(buf2), "SET dpp_csign %s", csign);
418 		if (wpa_command(ifname, buf2) < 0) {
419 			send_resp(dut, conn, SIGMA_ERROR,
420 				  "errorCode,Failed to update AP C-sign-key");
421 			goto out;
422 		}
423 	}
424 
425 	if (net_access_key) {
426 		pos2 = strchr(net_access_key, ' ');
427 		if (pos2)
428 			*pos2++ = '\0';
429 		sigma_dut_print(dut, DUT_MSG_INFO, "DPP: netAccessKey: %s",
430 				net_access_key);
431 		snprintf(buf2, sizeof(buf2), "SET dpp_netaccesskey %s",
432 			 net_access_key);
433 		if (wpa_command(ifname, buf2) < 0) {
434 			send_resp(dut, conn, SIGMA_ERROR,
435 				  "errorCode,Failed to update AP netAccessKey");
436 			goto out;
437 		}
438 		if (pos2) {
439 			sigma_dut_print(dut, DUT_MSG_INFO,
440 					"DPP: netAccessKey expiry: %s", pos2);
441 			snprintf(buf2, sizeof(buf2),
442 				 "SET dpp_netaccesskey_expiry %s", pos2);
443 			if (wpa_command(ifname, buf2) < 0) {
444 				send_resp(dut, conn, SIGMA_ERROR,
445 					  "errorCode,Failed to update AP netAccessKey expiry");
446 				goto out;
447 			}
448 		}
449 	}
450 
451 	if (wpa_command(ifname, "SET start_disabled 0") < 0 &&
452 	    dut->ap_start_disabled) {
453 		send_resp(dut, conn, SIGMA_ERROR,
454 			  "errorCode,Failed to update AP security parameters");
455 		goto out;
456 	}
457 	dut->ap_start_disabled = 0;
458 
459 	/* Wait for a possible Configuration Result to be sent */
460 	old_timeout = dut->default_timeout;
461 	dut->default_timeout = 1;
462 	get_wpa_cli_event(dut, ctrl, "DPP-TX-STATUS", buf, sizeof(buf));
463 	dut->default_timeout = old_timeout;
464 	if (wpa_command(ifname, "DISABLE") < 0 ||
465 	    wpa_command(ifname, "ENABLE") < 0) {
466 		send_resp(dut, conn, SIGMA_ERROR,
467 			  "errorCode,Failed to update AP configuration");
468 		goto out;
469 	}
470 
471 	res = get_wpa_cli_event(dut, ctrl, "AP-ENABLED", buf, sizeof(buf));
472 	if (res < 0) {
473 		send_resp(dut, conn, SIGMA_ERROR, "errorCode,No AP-ENABLED");
474 		goto out;
475 	}
476 
477 	ret = 1;
478 out:
479 	free(connector);
480 	free(psk);
481 	free(csign);
482 	free(net_access_key);
483 	return ret;
484 }
485 
486 
487 struct dpp_test_info {
488 	const char *step;
489 	const char *frame;
490 	const char *attr;
491 	int value;
492 };
493 
494 static const struct dpp_test_info dpp_tests[] = {
495 	{ "InvalidValue", "AuthenticationRequest", "WrappedData", 1 },
496 	{ "InvalidValue", "AuthenticationResponse", "WrappedData", 2 },
497 	{ "InvalidValue", "AuthenticationResponse", "PrimaryWrappedData", 2 },
498 	{ "InvalidValue", "AuthenticationConfirm", "WrappedData", 3 },
499 	{ "InvalidValue", "PKEXCRRequest", "WrappedData", 4 },
500 	{ "InvalidValue", "PKEXCRResponse", "WrappedData", 5 },
501 	{ "InvalidValue", "ConfigurationRequest", "WrappedData", 6 },
502 	{ "InvalidValue", "ConfigurationResponse", "WrappedData", 7 },
503 	{ "InvalidValue", "AuthenticationRequest", "InitCapabilities", 8 },
504 	{ "MissingAttribute", "AuthenticationRequest", "RespBSKeyHash", 10 },
505 	{ "MissingAttribute", "AuthenticationRequest", "InitBSKeyHash", 11 },
506 	{ "MissingAttribute", "AuthenticationRequest", "InitProtocolKey", 12 },
507 	{ "MissingAttribute", "AuthenticationRequest", "InitNonce", 13 },
508 	{ "MissingAttribute", "AuthenticationRequest", "InitCapabilities", 14 },
509 	{ "MissingAttribute", "AuthenticationRequest", "WrappedData", 15 },
510 	{ "MissingAttribute", "AuthenticationResponse", "DPPStatus", 16 },
511 	{ "MissingAttribute", "AuthenticationResponse", "RespBSKeyHash", 17 },
512 	{ "MissingAttribute", "AuthenticationResponse", "InitBSKeyHash", 18 },
513 	{ "MissingAttribute", "AuthenticationResponse", "RespProtocolKey", 19 },
514 	{ "MissingAttribute", "AuthenticationResponse", "RespNonce", 20 },
515 	{ "MissingAttribute", "AuthenticationResponse", "InitNonce", 21 },
516 	{ "MissingAttribute", "AuthenticationResponse", "RespCapabilities",
517 	  22 },
518 	{ "MissingAttribute", "AuthenticationResponse", "RespAuthTag", 23 },
519 	{ "MissingAttribute", "AuthenticationResponse", "WrappedData", 24 },
520 	{ "MissingAttribute", "AuthenticationResponse", "PrimaryWrappedData",
521 	  24 },
522 	{ "MissingAttribute", "AuthenticationConfirm", "DPPStatus", 25 },
523 	{ "MissingAttribute", "AuthenticationConfirm", "RespBSKeyHash", 26 },
524 	{ "MissingAttribute", "AuthenticationConfirm", "InitBSKeyHash", 27 },
525 	{ "MissingAttribute", "AuthenticationConfirm", "InitAuthTag", 28 },
526 	{ "MissingAttribute", "AuthenticationConfirm", "WrappedData", 29 },
527 	{ "InvalidValue", "AuthenticationResponse", "InitNonce", 30 },
528 	{ "InvalidValue", "AuthenticationResponse", "RespCapabilities", 31 },
529 	{ "InvalidValue", "AuthenticationResponse", "RespAuthTag", 32 },
530 	{ "InvalidValue", "AuthenticationConfirm", "InitAuthTag", 33 },
531 	{ "MissingAttribute", "PKEXExchangeRequest", "FiniteCyclicGroup", 34 },
532 	{ "MissingAttribute", "PKEXExchangeRequest", "EncryptedKey", 35 },
533 	{ "MissingAttribute", "PKEXExchangeResponse", "DPPStatus", 36 },
534 	{ "MissingAttribute", "PKEXExchangeResponse", "EncryptedKey", 37 },
535 	{ "MissingAttribute", "PKEXCRRequest", "BSKey", 38 },
536 	{ "MissingAttribute", "PKEXCRRequest", "InitAuthTag", 39 },
537 	{ "MissingAttribute", "PKEXCRRequest", "WrappedData", 40 },
538 	{ "MissingAttribute", "PKEXCRResponse", "BSKey", 41 },
539 	{ "MissingAttribute", "PKEXCRResponse", "RespAuthTag", 42 },
540 	{ "MissingAttribute", "PKEXCRResponse", "WrappedData", 43 },
541 	{ "InvalidValue", "PKEXExchangeRequest", "EncryptedKey", 44 },
542 	{ "InvalidValue", "PKEXExchangeResponse", "EncryptedKey", 45 },
543 	{ "InvalidValue", "PKEXExchangeResponse", "DPPStatus", 46 },
544 	{ "InvalidValue", "PKEXCRRequest", "BSKey", 47 },
545 	{ "InvalidValue", "PKEXCRResponse", "BSKey", 48 },
546 	{ "InvalidValue", "PKEXCRRequest", "InitAuthTag", 49 },
547 	{ "InvalidValue", "PKEXCRResponse", "RespAuthTag", 50 },
548 	{ "MissingAttribute", "ConfigurationRequest", "EnrolleeNonce", 51 },
549 	{ "MissingAttribute", "ConfigurationRequest", "ConfigAttr", 52 },
550 	{ "MissingAttribute", "ConfigurationRequest", "WrappedData", 53 },
551 	{ "MissingAttribute", "ConfigurationResponse", "EnrolleeNonce", 54 },
552 	{ "MissingAttribute", "ConfigurationResponse", "ConfigObj", 55 },
553 	{ "MissingAttribute", "ConfigurationResponse", "DPPStatus", 56 },
554 	{ "MissingAttribute", "ConfigurationResponse", "WrappedData", 57 },
555 	{ "InvalidValue", "ConfigurationResponse", "DPPStatus", 58 },
556 	{ "InvalidValue", "ConfigurationResponse", "EnrolleeNonce", 59 },
557 	{ "MissingAttribute", "PeerDiscoveryRequest", "TransactionID", 60 },
558 	{ "MissingAttribute", "PeerDiscoveryRequest", "Connector", 61 },
559 	{ "MissingAttribute", "PeerDiscoveryResponse", "TransactionID", 62 },
560 	{ "MissingAttribute", "PeerDiscoveryResponse", "DPPStatus", 63 },
561 	{ "MissingAttribute", "PeerDiscoveryResponse", "Connector", 64 },
562 	{ "InvalidValue", "AuthenticationRequest", "InitProtocolKey", 66 },
563 	{ "InvalidValue", "AuthenticationResponse", "RespProtocolKey", 67 },
564 	{ "InvalidValue", "AuthenticationRequest", "RespBSKeyHash", 68 },
565 	{ "InvalidValue", "AuthenticationRequest", "InitBSKeyHash", 69 },
566 	{ "InvalidValue", "AuthenticationResponse", "RespBSKeyHash", 70 },
567 	{ "InvalidValue", "AuthenticationResponse", "InitBSKeyHash", 71 },
568 	{ "InvalidValue", "AuthenticationConfirm", "RespBSKeyHash", 72 },
569 	{ "InvalidValue", "AuthenticationConfirm", "InitBSKeyHash", 73 },
570 	{ "InvalidValue", "AuthenticationResponse", "DPPStatus", 74 },
571 	{ "InvalidValue", "AuthenticationConfirm", "DPPStatus", 75 },
572 	{ "InvalidValue", "ConfigurationRequest", "ConfigAttr", 76 },
573 	{ "InvalidValue", "PeerDiscoveryResponse", "TransactionID", 77 },
574 	{ "InvalidValue", "PeerDiscoveryResponse", "DPPStatus", 78 },
575 	{ "InvalidValue", "PeerDiscoveryResponse", "Connector", 79 },
576 	{ "InvalidValue", "PeerDiscoveryRequest", "Connector", 80 },
577 	{ "InvalidValue", "AuthenticationRequest", "InitNonce", 81 },
578 	{ "InvalidValue", "PeerDiscoveryRequest", "TransactionID", 82 },
579 	{ "InvalidValue", "ConfigurationRequest", "EnrolleeNonce", 83 },
580 	{ "Timeout", "PKEXExchangeResponse", NULL, 84 },
581 	{ "Timeout", "PKEXCRRequest", NULL, 85 },
582 	{ "Timeout", "PKEXCRResponse", NULL, 86 },
583 	{ "Timeout", "AuthenticationRequest", NULL, 87 },
584 	{ "Timeout", "AuthenticationResponse", NULL, 88 },
585 	{ "Timeout", "AuthenticationConfirm", NULL, 89 },
586 	{ "Timeout", "ConfigurationRequest", NULL, 90 },
587 	{ NULL, NULL, NULL, 0 }
588 };
589 
590 
591 static int dpp_get_test(const char *step, const char *frame, const char *attr)
592 {
593 	int i;
594 
595 	for (i = 0; dpp_tests[i].step; i++) {
596 		if (strcasecmp(step, dpp_tests[i].step) == 0 &&
597 		    strcasecmp(frame, dpp_tests[i].frame) == 0 &&
598 		    ((!attr && dpp_tests[i].attr == NULL) ||
599 		     (attr && strcasecmp(attr, dpp_tests[i].attr) == 0)))
600 			return dpp_tests[i].value;
601 	}
602 
603 	return -1;
604 }
605 
606 
607 static int dpp_wait_tx(struct sigma_dut *dut, struct wpa_ctrl *ctrl,
608 		       int frame_type)
609 {
610 	char buf[200], tmp[20];
611 	int res;
612 
613 	snprintf(tmp, sizeof(tmp), "type=%d", frame_type);
614 	for (;;) {
615 		res = get_wpa_cli_event(dut, ctrl, "DPP-TX", buf, sizeof(buf));
616 		if (res < 0)
617 			return -1;
618 		if (strstr(buf, tmp) != NULL)
619 			break;
620 	}
621 
622 	return 0;
623 }
624 
625 
626 static int dpp_wait_tx_status(struct sigma_dut *dut, struct wpa_ctrl *ctrl,
627 			      int frame_type)
628 {
629 	char buf[200], tmp[20];
630 	int res;
631 
632 	snprintf(tmp, sizeof(tmp), "type=%d", frame_type);
633 	for (;;) {
634 		res = get_wpa_cli_event(dut, ctrl, "DPP-TX", buf, sizeof(buf));
635 		if (res < 0)
636 			return -1;
637 		if (strstr(buf, tmp) != NULL)
638 			break;
639 	}
640 
641 	res = get_wpa_cli_event(dut, ctrl, "DPP-TX-STATUS",
642 				buf, sizeof(buf));
643 	if (res < 0 || strstr(buf, "result=FAILED") != NULL)
644 		return -1;
645 
646 	return 0;
647 }
648 
649 
650 static int dpp_wait_rx(struct sigma_dut *dut, struct wpa_ctrl *ctrl,
651 		       int frame_type, unsigned int max_wait)
652 {
653 	char buf[200], tmp[20];
654 	int res;
655 	unsigned int old_timeout;
656 
657 	old_timeout = dut->default_timeout;
658 	if (max_wait > 0 && dut->default_timeout > max_wait)
659 		dut->default_timeout = max_wait;
660 
661 	snprintf(tmp, sizeof(tmp), "type=%d", frame_type);
662 	for (;;) {
663 		res = get_wpa_cli_event(dut, ctrl, "DPP-RX", buf, sizeof(buf));
664 		if (res < 0) {
665 			dut->default_timeout = old_timeout;
666 			return -1;
667 		}
668 		if (strstr(buf, tmp) != NULL)
669 			break;
670 	}
671 
672 	dut->default_timeout = old_timeout;
673 	return 0;
674 }
675 
676 
677 static int dpp_wait_rx_conf_req(struct sigma_dut *dut, struct wpa_ctrl *ctrl,
678 				unsigned int max_wait)
679 {
680 	char buf[200];
681 	int res;
682 	unsigned int old_timeout;
683 
684 	old_timeout = dut->default_timeout;
685 	if (max_wait > 0 && dut->default_timeout > max_wait)
686 		dut->default_timeout = max_wait;
687 
688 	for (;;) {
689 		res = get_wpa_cli_event(dut, ctrl, "DPP-CONF-REQ-RX",
690 					buf, sizeof(buf));
691 		if (res < 0) {
692 			dut->default_timeout = old_timeout;
693 			return -1;
694 		}
695 
696 		break;
697 	}
698 
699 	dut->default_timeout = old_timeout;
700 	return 0;
701 }
702 
703 
704 static int dpp_scan_peer_qrcode(struct sigma_dut *dut)
705 {
706 #ifdef ANDROID
707 	char buf[100];
708 	char *buf2 = NULL;
709 	FILE *fp = NULL;
710 	uint32_t length;
711 	unsigned int count;
712 
713 	unlink(dpp_qrcode_file);
714 
715 	snprintf(buf, sizeof(buf),
716 		 "am start -n w1.fi.wpadebug/w1.fi.wpadebug.QrCodeReadActivity");
717 	if (system(buf) != 0) {
718 		sigma_dut_print(dut, DUT_MSG_ERROR,
719 				"Failed to launch QR Code scanner");
720 		return -1;
721 	}
722 
723 	count = 0;
724 	while (!(fp = fopen(dpp_qrcode_file, "r"))) {
725 		if (count > dut->default_timeout) {
726 			sigma_dut_print(dut, DUT_MSG_ERROR,
727 					"Failed to open dpp_qrcode_file - QR Code scanning timed out");
728 			return -1;
729 		}
730 
731 		sleep(1);
732 		count++;
733 	}
734 
735 	if (fseek(fp, 0, SEEK_END) < 0 || (length = ftell(fp)) <= 0 ||
736 	    fseek(fp, 0, SEEK_SET) < 0) {
737 		sigma_dut_print(dut, DUT_MSG_ERROR,
738 				"Failed to get QR Code result file length");
739 		fclose(fp);
740 		return -1;
741 	}
742 
743 	buf2 = malloc(length + 1);
744 	if (!buf2) {
745 		fclose(fp);
746 		return -1;
747 	}
748 
749 	if (fread(buf2, 1, length, fp) != length) {
750 		fclose(fp);
751 		free(buf2);
752 		return -1;
753 	}
754 
755 	fclose(fp);
756 	buf2[length] = '\0';
757 
758 	free(dut->dpp_peer_uri);
759 	dut->dpp_peer_uri = strdup(buf2);
760 	free(buf2);
761 	return 0;
762 #else /* ANDROID */
763 	pid_t pid;
764 	int pid_status;
765 	int pipe_out[2];
766 	char buf[4000], *pos;
767 	ssize_t len;
768 	int res = -1, ret;
769 	struct timeval tv;
770 	fd_set rfd;
771 
772 	if (pipe(pipe_out) != 0) {
773 		perror("pipe");
774 		return -1;
775 	}
776 
777 	pid = fork();
778 	if (pid < 0) {
779 		perror("fork");
780 		close(pipe_out[0]);
781 		close(pipe_out[1]);
782 		return -1;
783 	}
784 
785 	if (pid == 0) {
786 		char *argv[4] = { "zbarcam", "--raw", "--prescale=320x240",
787 				  NULL };
788 
789 		dup2(pipe_out[1], STDOUT_FILENO);
790 		close(pipe_out[0]);
791 		close(pipe_out[1]);
792 		execv("/usr/bin/zbarcam", argv);
793 		perror("execv");
794 		exit(0);
795 		return -1;
796 	}
797 
798 	close(pipe_out[1]);
799 
800 	FD_ZERO(&rfd);
801 	FD_SET(pipe_out[0], &rfd);
802 	tv.tv_sec = dut->default_timeout;
803 	tv.tv_usec = 0;
804 
805 	ret = select(pipe_out[0] + 1, &rfd, NULL, NULL, &tv);
806 	if (ret < 0) {
807 		perror("select");
808 		goto out;
809 	}
810 	if (ret == 0) {
811 		sigma_dut_print(dut, DUT_MSG_DEBUG,
812 				"QR Code scanning timed out");
813 		goto out;
814 	}
815 
816 	len = read(pipe_out[0], buf, sizeof(buf));
817 	if (len <= 0)
818 		goto out;
819 	if (len == sizeof(buf))
820 		len--;
821 	buf[len] = '\0';
822 	pos = strchr(buf, '\n');
823 	if (pos)
824 		*pos = '\0';
825 	sigma_dut_print(dut, DUT_MSG_DEBUG, "URI from QR scanner: %s", buf);
826 
827 	free(dut->dpp_peer_uri);
828 	dut->dpp_peer_uri = strdup(buf);
829 	res = 0;
830 out:
831 	close(pipe_out[0]);
832 	kill(pid, SIGTERM);
833 	waitpid(pid, &pid_status, 0);
834 
835 	return res;
836 #endif /* ANDROID */
837 }
838 
839 
840 static int dpp_display_own_qrcode(struct sigma_dut *dut)
841 {
842 	char buf[200], resp[2000];
843 	const char *ifname = get_station_ifname(dut);
844 #ifdef ANDROID
845 	FILE *fp;
846 #else /* ANDROID */
847 	pid_t pid;
848 	int pid_status;
849 #endif /* ANDROID */
850 
851 	snprintf(buf, sizeof(buf), "DPP_BOOTSTRAP_GET_URI %d",
852 		 dut->dpp_local_bootstrap);
853 	if (wpa_command_resp(ifname, buf, resp, sizeof(resp)) < 0 ||
854 	    strncmp(resp, "FAIL", 4) == 0)
855 		return -2;
856 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Own bootstrap URI: %s", resp);
857 
858 #ifdef ANDROID
859 	unlink(dpp_qrcode_file);
860 
861 	fp = fopen(dpp_qrcode_file, "w");
862 	if (!fp) {
863 		sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to open file %s",
864 				dpp_qrcode_file);
865 		return -2;
866 	}
867 
868 	fwrite(resp, 1, strlen(resp), fp);
869 	fclose(fp);
870 
871 	snprintf(buf, sizeof(buf),
872 		 "am start -n w1.fi.wpadebug/w1.fi.wpadebug.QrCodeDisplayActivity");
873 	if (system(buf) != 0) {
874 		sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to display QR Code");
875 		return -1;
876 	}
877 #else /* ANDROID */
878 	pid = fork();
879 	if (pid < 0) {
880 		perror("fork");
881 		return -1;
882 	}
883 
884 	if (pid == 0) {
885 		char *argv[3] = { "qr", resp, NULL };
886 
887 		execv("/usr/bin/qr", argv);
888 		perror("execv");
889 		exit(0);
890 		return -1;
891 	}
892 
893 	waitpid(pid, &pid_status, 0);
894 #endif /* ANDROID */
895 
896 	return 0;
897 }
898 
899 
900 static int dpp_process_auth_response(struct sigma_dut *dut,
901 				     struct sigma_conn *conn,
902 				     struct wpa_ctrl *ctrl,
903 				     const char **auth_events,
904 				     const char *action_type,
905 				     int check_mutual, char *buf, size_t buflen)
906 {
907 	int res;
908 
909 	res = get_wpa_cli_events(dut, ctrl, auth_events, buf, buflen);
910 	if (res < 0) {
911 		send_resp(dut, conn, SIGMA_COMPLETE,
912 			  "BootstrapResult,OK,AuthResult,Timeout");
913 		return res;
914 	}
915 	sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP auth result: %s", buf);
916 
917 	if (strstr(buf, "DPP-RESPONSE-PENDING")) {
918 		/* Display own QR code in manual mode */
919 		if (action_type && strcasecmp(action_type, "ManualDPP") == 0 &&
920 		    dpp_display_own_qrcode(dut) < 0) {
921 			send_resp(dut, conn, SIGMA_ERROR,
922 				  "errorCode,Failed to display own QR code");
923 			return -1;
924 		}
925 
926 		/* Wait for the actual result after the peer has scanned the
927 		 * QR Code. */
928 		res = get_wpa_cli_events(dut, ctrl, auth_events,
929 					 buf, buflen);
930 		if (res < 0) {
931 			send_resp(dut, conn, SIGMA_COMPLETE,
932 				  "BootstrapResult,OK,AuthResult,Timeout");
933 			return res;
934 		}
935 
936 		sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP auth result: %s", buf);
937 	} else if (strstr(buf, "DPP-AUTH-INIT-FAILED")) {
938 		send_resp(dut, conn, SIGMA_ERROR,
939 			  "errorCode,Peer did not reply to DPP Authentication Request");
940 		return -1;
941 	}
942 
943 	if (check_mutual) {
944 		if (strstr(buf, "DPP-NOT-COMPATIBLE")) {
945 			send_resp(dut, conn, SIGMA_COMPLETE,
946 				  "BootstrapResult,OK,AuthResult,ROLES_NOT_COMPATIBLE");
947 			return -1;
948 		}
949 
950 		if (!strstr(buf, "DPP-AUTH-DIRECTION")) {
951 			send_resp(dut, conn, SIGMA_ERROR,
952 				  "errorCode,No event for auth direction seen");
953 			return -1;
954 		}
955 
956 		sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP auth direction: %s",
957 				buf);
958 		if (strstr(buf, "mutual=1") == NULL) {
959 			send_resp(dut, conn, SIGMA_ERROR,
960 				  "errorCode,Peer did not use mutual authentication");
961 			return -1;
962 		}
963 	}
964 
965 	return 0;
966 }
967 
968 
969 static int dpp_process_csr(struct sigma_dut *dut, const char *ifname,
970 			   char *csr_event)
971 {
972 	FILE *f;
973 	char buf[2000], cmd[2500], tmp[300];
974 	char *pos;
975 	int peer;
976 	size_t len;
977 
978 	pos = strstr(csr_event, " peer=");
979 	if (!pos) {
980 		sigma_dut_print(dut, DUT_MSG_INFO, "No peer id known for CSR");
981 		return -1;
982 	}
983 	pos += 6;
984 	peer = atoi(pos);
985 
986 	pos = strstr(csr_event, " csr=");
987 	if (!pos) {
988 		sigma_dut_print(dut, DUT_MSG_INFO, "No CSR found");
989 		return -1;
990 	}
991 	pos += 5;
992 
993 	snprintf(tmp, sizeof(tmp), "%s/dpp-ca-certbag", sigma_cert_path);
994 	unlink(tmp);
995 
996 	snprintf(tmp, sizeof(tmp), "%s/dpp-ca-csr", sigma_cert_path);
997 	f = fopen(tmp, "w");
998 	if (!f) {
999 		sigma_dut_print(dut, DUT_MSG_INFO, "Failed to write CSR file");
1000 		return -1;
1001 	}
1002 	fprintf(f, "%s", pos);
1003 	fclose(f);
1004 
1005 	if (run_system_wrapper(dut, "./dpp-ca.py %s", sigma_cert_path) < 0) {
1006 		sigma_dut_print(dut, DUT_MSG_INFO, "Failed to run dpp-ca.py");
1007 		return -1;
1008 	}
1009 
1010 	snprintf(tmp, sizeof(tmp), "%s/dpp-ca-certbag", sigma_cert_path);
1011 	f = fopen(tmp, "r");
1012 	if (!f) {
1013 		sigma_dut_print(dut, DUT_MSG_INFO, "No certBag available");
1014 		return -1;
1015 	}
1016 	len = fread(buf, 1, sizeof(buf), f);
1017 	fclose(f);
1018 	if (len >= sizeof(buf)) {
1019 		sigma_dut_print(dut, DUT_MSG_INFO, "No bufferroom for certBag");
1020 		return -1;
1021 	}
1022 	buf[len] = '\0';
1023 
1024 	snprintf(cmd, sizeof(cmd), "DPP_CA_SET peer=%d name=certBag value=%s",
1025 		 peer, buf);
1026 	if (wpa_command(ifname, cmd) < 0) {
1027 		sigma_dut_print(dut, DUT_MSG_INFO, "DPP_CA_SET failed");
1028 		return -1;
1029 	}
1030 
1031 	return 0;
1032 }
1033 
1034 
1035 static enum sigma_cmd_result dpp_automatic_dpp(struct sigma_dut *dut,
1036 					       struct sigma_conn *conn,
1037 					       struct sigma_cmd *cmd)
1038 {
1039 	const char *bs = get_param(cmd, "DPPBS");
1040 	const char *type = get_param(cmd, "DPPActionType");
1041 	const char *auth_role = get_param(cmd, "DPPAuthRole");
1042 	const char *prov_role = get_param(cmd, "DPPProvisioningRole");
1043 	const char *pkex_code = get_param(cmd, "DPPPKEXCode");
1044 	const char *pkex_code_id = get_param(cmd, "DPPPKEXCodeIdentifier");
1045 	const char *wait_conn = get_param(cmd, "DPPWaitForConnect");
1046 	const char *self_conf = get_param(cmd, "DPPSelfConfigure");
1047 	const char *step = get_param(cmd, "DPPStep");
1048 	const char *frametype = get_param(cmd, "DPPFrameType");
1049 	const char *attr = get_param(cmd, "DPPIEAttribute");
1050 	const char *action_type = get_param(cmd, "DPPActionType");
1051 	const char *tcp = get_param(cmd, "DPPOverTCP");
1052 	const char *nfc_handover = get_param(cmd, "DPPNFCHandover");
1053 	const char *role;
1054 	const char *netrole = NULL;
1055 	const char *val;
1056 	const char *conf_role;
1057 	int conf_index = -1;
1058 	char buf[2000], *pos, *pos2;
1059 	char buf2[200];
1060 	char conf_ssid[100];
1061 	char conf_pass[100];
1062 	char csrattrs[200];
1063 	char pkex_identifier[200];
1064 	struct wpa_ctrl *ctrl;
1065 	int res;
1066 	unsigned int old_timeout;
1067 	int own_pkex_id = -1;
1068 	const char *ifname = get_station_ifname(dut);
1069 	const char *auth_events[] = {
1070 		"DPP-AUTH-SUCCESS",
1071 		"DPP-AUTH-INIT-FAILED",
1072 		"DPP-NOT-COMPATIBLE",
1073 		"DPP-RESPONSE-PENDING",
1074 		"DPP-SCAN-PEER-QR-CODE",
1075 		"DPP-AUTH-DIRECTION",
1076 		NULL
1077 	};
1078 	const char *conf_events[] = {
1079 		"DPP-CONF-RECEIVED",
1080 		"DPP-CONF-SENT",
1081 		"DPP-CONF-FAILED",
1082 		NULL
1083 	};
1084 	const char *conn_events[] = {
1085 		"PMKSA-CACHE-ADDED",
1086 		"CTRL-EVENT-CONNECTED",
1087 		NULL
1088 	};
1089 	const char *group_id_str = NULL;
1090 	char group_id[100];
1091 	char conf2[300];
1092 	const char *result;
1093 	int check_mutual = 0;
1094 	int enrollee_ap;
1095 	int enrollee_configurator;
1096 	int force_gas_fragm = 0;
1097 	int not_dpp_akm = 0;
1098 	int akm_use_selector = 0;
1099 	int conn_status;
1100 	int chirp = 0;
1101 	int manual = strcasecmp(type, "ManualDPP") == 0;
1102 	time_t start, now;
1103 	FILE *f;
1104 
1105 	time(&start);
1106 
1107 	if (!wait_conn)
1108 		wait_conn = "no";
1109 	if (!self_conf)
1110 		self_conf = "no";
1111 
1112 	if (!prov_role) {
1113 		send_resp(dut, conn, SIGMA_ERROR,
1114 			  "errorCode,Missing DPPProvisioningRole");
1115 		return STATUS_SENT_ERROR;
1116 	}
1117 
1118 	val = get_param(cmd, "DPPConfEnrolleeRole");
1119 	if (val) {
1120 		enrollee_ap = strcasecmp(val, "AP") == 0;
1121 		enrollee_configurator = strcasecmp(val, "Configurator") == 0;
1122 	} else {
1123 		enrollee_ap = sigma_dut_is_ap(dut);
1124 		enrollee_configurator = 0;
1125 	}
1126 
1127 	val = get_param(cmd, "DPPNetworkRole");
1128 	if (val) {
1129 		if (strcasecmp(val, "AP") == 0) {
1130 			netrole = "ap";
1131 		} else if (strcasecmp(val, "STA") == 0) {
1132 			netrole = "sta";
1133 		} else if (strcasecmp(val, "Configurator") == 0) {
1134 			netrole = "configurator";
1135 		} else {
1136 			send_resp(dut, conn, SIGMA_ERROR,
1137 				  "errorCode,Unsupported DPPNetworkRole value");
1138 			return STATUS_SENT_ERROR;
1139 		}
1140 	}
1141 
1142 	val = get_param(cmd, "DPPChirp");
1143 	if (val)
1144 		chirp = get_enable_disable(val);
1145 
1146 	if ((step || frametype) && (!step || !frametype)) {
1147 		send_resp(dut, conn, SIGMA_ERROR,
1148 			  "errorCode,Invalid DPPStep,DPPFrameType,DPPIEAttribute combination");
1149 		return STATUS_SENT_ERROR;
1150 	}
1151 
1152 	val = get_param(cmd, "MUDURL");
1153 	if (val) {
1154 		snprintf(buf, sizeof(buf), "SET dpp_mud_url %s", val);
1155 		if (wpa_command(ifname, buf) < 0) {
1156 			send_resp(dut, conn, SIGMA_ERROR,
1157 				  "errorCode,Failed to set MUD URL");
1158 			return STATUS_SENT_ERROR;
1159 		}
1160 	}
1161 
1162 	if (sigma_dut_is_ap(dut)) {
1163 		if (!dut->hostapd_ifname) {
1164 			sigma_dut_print(dut, DUT_MSG_ERROR,
1165 					"hostapd ifname not specified (-j)");
1166 			return ERROR_SEND_STATUS;
1167 		}
1168 		ifname = dut->hostapd_ifname;
1169 
1170 		if (dpp_hostapd_run(dut) < 0) {
1171 			send_resp(dut, conn, SIGMA_ERROR,
1172 				  "errorCode,Failed to start hostapd");
1173 			return STATUS_SENT_ERROR;
1174 		}
1175 	}
1176 
1177 	if (strcasecmp(prov_role, "Configurator") == 0 ||
1178 	    strcasecmp(prov_role, "Both") == 0) {
1179 		if (dut->dpp_conf_id < 0) {
1180 			snprintf(buf, sizeof(buf),
1181 				 "DPP_CONFIGURATOR_ADD curve=%s",
1182 				 dpp_get_curve(cmd, "DPPSigningKeyECC"));
1183 			if (wpa_command_resp(ifname, buf,
1184 					     buf, sizeof(buf)) < 0) {
1185 				send_resp(dut, conn, SIGMA_ERROR,
1186 					  "errorCode,Failed to set up configurator");
1187 				return STATUS_SENT_ERROR;
1188 			}
1189 			dut->dpp_conf_id = atoi(buf);
1190 		}
1191 		if (strcasecmp(prov_role, "Configurator") == 0)
1192 			role = "configurator";
1193 		else
1194 			role = "either";
1195 	} else if (strcasecmp(prov_role, "Enrollee") == 0) {
1196 		role = "enrollee";
1197 	} else {
1198 		send_resp(dut, conn, SIGMA_ERROR,
1199 			  "errorCode,Unknown DPPProvisioningRole");
1200 		return STATUS_SENT_ERROR;
1201 	}
1202 
1203 	pkex_identifier[0] = '\0';
1204 	if (strcasecmp(bs, "PKEX") == 0) {
1205 		if (sigma_dut_is_ap(dut) && dut->ap_channel != 6) {
1206 			/* For now, have to make operating channel match DPP
1207 			 * listen channel. This should be removed once hostapd
1208 			 * has support for DPP listen on non-operating channel.
1209 			 */
1210 			sigma_dut_print(dut, DUT_MSG_INFO,
1211 					"Update hostapd operating channel to match listen needs");
1212 			dut->ap_channel = 6;
1213 
1214 			if (get_driver_type(dut) == DRIVER_OPENWRT) {
1215 				snprintf(buf, sizeof(buf),
1216 					 "iwconfig %s channel %d",
1217 					 dut->hostapd_ifname, dut->ap_channel);
1218 				run_system(dut, buf);
1219 			}
1220 
1221 			if (wpa_command(ifname, "SET channel 6") < 0 ||
1222 			    wpa_command(ifname, "DISABLE") < 0 ||
1223 			    wpa_command(ifname, "ENABLE") < 0) {
1224 				send_resp(dut, conn, SIGMA_ERROR,
1225 					  "errorCode,Failed to update channel");
1226 				return STATUS_SENT_ERROR;
1227 			}
1228 		}
1229 
1230 		if (!pkex_code) {
1231 			send_resp(dut, conn, SIGMA_ERROR,
1232 				  "errorCode,Missing DPPPKEXCode");
1233 			return STATUS_SENT_ERROR;
1234 		}
1235 
1236 		if (pkex_code_id)
1237 			snprintf(pkex_identifier, sizeof(pkex_identifier),
1238 				 "identifier=%s ", pkex_code_id);
1239 
1240 		snprintf(buf, sizeof(buf),
1241 			 "DPP_BOOTSTRAP_GEN type=pkex curve=%s",
1242 			 dpp_get_curve(cmd, "DPPCryptoIdentifier"));
1243 		if (wpa_command_resp(ifname, buf, buf, sizeof(buf)) < 0) {
1244 			send_resp(dut, conn, SIGMA_ERROR,
1245 				  "errorCode,Failed to set up PKEX");
1246 			return STATUS_SENT_ERROR;
1247 		}
1248 		own_pkex_id = atoi(buf);
1249 	}
1250 
1251 	ctrl = open_wpa_mon(ifname);
1252 	if (!ctrl) {
1253 		sigma_dut_print(dut, DUT_MSG_ERROR,
1254 				"Failed to open wpa_supplicant monitor connection");
1255 		return ERROR_SEND_STATUS;
1256 	}
1257 
1258 	old_timeout = dut->default_timeout;
1259 	val = get_param(cmd, "DPPTimeout");
1260 	if (val && atoi(val) > 0) {
1261 		dut->default_timeout = atoi(val);
1262 		sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP timeout: %u",
1263 				dut->default_timeout);
1264 	}
1265 
1266 	val = get_param(cmd, "DPPStatusQuery");
1267 	conn_status = val && strcasecmp(val, "Yes") == 0;
1268 
1269 	conf_ssid[0] = '\0';
1270 	conf_pass[0] = '\0';
1271 	csrattrs[0] = '\0';
1272 	group_id[0] = '\0';
1273 	conf2[0] = '\0';
1274 	if (!enrollee_configurator) {
1275 		val = get_param(cmd, "DPPConfIndex");
1276 		if (val)
1277 			conf_index = atoi(val);
1278 	}
1279 	switch (conf_index) {
1280 	case -1:
1281 		if (enrollee_configurator)
1282 			conf_role = "configurator";
1283 		else
1284 			conf_role = NULL;
1285 		break;
1286 	case 1:
1287 		ascii2hexstr("DPPNET01", buf);
1288 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1289 		if (res < 0 || res >= sizeof(conf_ssid))
1290 			goto err;
1291 		if (enrollee_ap) {
1292 			conf_role = "ap-dpp";
1293 		} else {
1294 			conf_role = "sta-dpp";
1295 		}
1296 		group_id_str = "DPPGROUP_DPP_INFRA";
1297 		break;
1298 	case 2:
1299 		ascii2hexstr("DPPNET01", buf);
1300 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1301 		if (res < 0 || res >= sizeof(conf_ssid))
1302 			goto err;
1303 		snprintf(conf_pass, sizeof(conf_pass),
1304 			 "psk=10506e102ad1e7f95112f6b127675bb8344dacacea60403f3fa4055aec85b0fc");
1305 		if (enrollee_ap)
1306 			conf_role = "ap-psk";
1307 		else
1308 			conf_role = "sta-psk";
1309 		break;
1310 	case 3:
1311 		ascii2hexstr("DPPNET01", buf);
1312 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1313 		if (res < 0 || res >= sizeof(conf_ssid))
1314 			goto err;
1315 		ascii2hexstr("ThisIsDppPassphrase", buf);
1316 		res = snprintf(conf_pass, sizeof(conf_pass), "pass=%s", buf);
1317 		if (res < 0 || res >= sizeof(conf_pass))
1318 			goto err;
1319 		if (enrollee_ap)
1320 			conf_role = "ap-psk";
1321 		else
1322 			conf_role = "sta-psk";
1323 		break;
1324 	case 4:
1325 		ascii2hexstr("DPPNET01", buf);
1326 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1327 		if (res < 0 || res >= sizeof(conf_ssid))
1328 			goto err;
1329 		if (enrollee_ap) {
1330 			conf_role = "ap-dpp";
1331 		} else {
1332 			conf_role = "sta-dpp";
1333 		}
1334 		group_id_str = "DPPGROUP_DPP_INFRA2";
1335 		break;
1336 	case 5:
1337 		ascii2hexstr("DPPNET01", buf);
1338 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1339 		if (res < 0 || res >= sizeof(conf_ssid))
1340 			goto err;
1341 		ascii2hexstr("ThisIsDppPassphrase", buf);
1342 		res = snprintf(conf_pass, sizeof(conf_pass), "pass=%s", buf);
1343 		if (res < 0 || res >= sizeof(conf_pass))
1344 			goto err;
1345 		if (enrollee_ap)
1346 			conf_role = "ap-sae";
1347 		else
1348 			conf_role = "sta-sae";
1349 		break;
1350 	case 6:
1351 		ascii2hexstr("DPPNET01", buf);
1352 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1353 		if (res < 0 || res >= sizeof(conf_ssid))
1354 			goto err;
1355 		ascii2hexstr("ThisIsDppPassphrase", buf);
1356 		res = snprintf(conf_pass, sizeof(conf_pass), "pass=%s", buf);
1357 		if (res < 0 || res >= sizeof(conf_pass))
1358 			goto err;
1359 		if (enrollee_ap)
1360 			conf_role = "ap-psk-sae";
1361 		else
1362 			conf_role = "sta-psk-sae";
1363 		break;
1364 	case 7:
1365 		ascii2hexstr("DPPNET01", buf);
1366 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1367 		if (res < 0 || res >= sizeof(conf_ssid))
1368 			goto err;
1369 		if (enrollee_ap) {
1370 			conf_role = "ap-dpp";
1371 		} else {
1372 			conf_role = "sta-dpp";
1373 		}
1374 		group_id_str = "DPPGROUP_DPP_INFRA";
1375 		force_gas_fragm = 1;
1376 		break;
1377 	case 8:
1378 	case 9:
1379 		ascii2hexstr("DPPNET01", buf);
1380 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1381 		if (res < 0 || res >= sizeof(conf_ssid))
1382 			goto err;
1383 		ascii2hexstr("This_is_legacy_password", buf);
1384 		res = snprintf(conf_pass, sizeof(conf_pass), "pass=%s", buf);
1385 		if (res < 0 || res >= sizeof(conf_pass))
1386 			goto err;
1387 		if (enrollee_ap) {
1388 			conf_role = "ap-dpp+psk+sae";
1389 		} else {
1390 			conf_role = "sta-dpp+psk+sae";
1391 		}
1392 		group_id_str = "DPPGROUP_DPP_INFRA1";
1393 		if (conf_index == 9)
1394 			akm_use_selector = 1;
1395 		break;
1396 	case 10:
1397 		ascii2hexstr("DPPNET01", buf);
1398 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1399 		if (res < 0 || res >= sizeof(conf_ssid))
1400 			goto err;
1401 		if (enrollee_ap)
1402 			conf_role = "ap-dpp";
1403 		else
1404 			conf_role = "sta-dpp";
1405 		group_id_str = "DPPGROUP_DPP_INFRA1";
1406 		ascii2hexstr("DPPNET02", buf);
1407 		ascii2hexstr("This_is_legacy_password", buf2);
1408 		res = snprintf(conf2, sizeof(conf2),
1409 			       " @CONF-OBJ-SEP@ conf=%s-dpp+psk+sae ssid=%s pass=%s group_id=DPPGROUP_DPP_INFRA2",
1410 			       enrollee_ap ? "ap" : "sta", buf, buf2);
1411 		if (res < 0 || res >= sizeof(conf2))
1412 			goto err;
1413 		break;
1414 	case 11:
1415 		ascii2hexstr("DPPNET01", buf);
1416 		res = snprintf(conf_ssid, sizeof(conf_ssid), "ssid=%s", buf);
1417 		if (res < 0 || res >= sizeof(conf_ssid))
1418 			goto err;
1419 		if (enrollee_ap) {
1420 			send_resp(dut, conn, SIGMA_ERROR,
1421 				  "errorCode,dot1x AKM provisioning not supported for AP");
1422 			goto out;
1423 		}
1424 		conf_role = "sta-dot1x";
1425 		snprintf(buf, sizeof(buf), "%s/dpp-ca-csrattrs",
1426 			 sigma_cert_path);
1427 		f = fopen(buf, "r");
1428 		if (f) {
1429 			size_t len;
1430 			int r;
1431 
1432 			len = fread(buf, 1, sizeof(buf), f);
1433 			fclose(f);
1434 			if (len >= sizeof(buf)) {
1435 				send_resp(dut, conn, SIGMA_ERROR,
1436 					  "errorCode,No room for csrAttrs");
1437 				goto out;
1438 			}
1439 			buf[len] = '\0';
1440 			sigma_dut_print(dut, DUT_MSG_INFO,
1441 					"Use csrAttrs from file");
1442 			r = snprintf(csrattrs, sizeof(csrattrs),
1443 				     " csrattrs=%s", buf);
1444 			if (r <= 0 || r >= sizeof(csrattrs)) {
1445 				send_resp(dut, conn, SIGMA_ERROR,
1446 					  "errorCode,No room for csrAttrs");
1447 				goto out;
1448 			}
1449 		} else {
1450 			sigma_dut_print(dut, DUT_MSG_INFO,
1451 					"Use default csrAttrs");
1452 			snprintf(csrattrs, sizeof(csrattrs), "%s",
1453 				 " csrattrs=MAsGCSqGSIb3DQEJBw==");
1454 		}
1455 		break;
1456 	default:
1457 		send_resp(dut, conn, SIGMA_ERROR,
1458 			  "errorCode,Unsupported DPPConfIndex");
1459 		goto out;
1460 	}
1461 
1462 	if (group_id_str)
1463 		snprintf(group_id, sizeof(group_id), " group_id=%s",
1464 			 group_id_str);
1465 
1466 	if (force_gas_fragm) {
1467 		char spaces[1500];
1468 
1469 		memset(spaces, ' ', sizeof(spaces));
1470 		spaces[sizeof(spaces) - 1] = '\0';
1471 
1472 		snprintf(buf, sizeof(buf),
1473 			 "SET dpp_discovery_override {\"ssid\":\"DPPNET01\"}%s",
1474 			 spaces);
1475 		if (wpa_command(ifname, buf) < 0) {
1476 			send_resp(dut, conn, SIGMA_ERROR,
1477 				  "errorCode,Failed to set discovery override");
1478 			goto out;
1479 		}
1480 	}
1481 
1482 	if (step) {
1483 		int test;
1484 
1485 		test = dpp_get_test(step, frametype, attr);
1486 		if (test <= 0) {
1487 			send_resp(dut, conn, SIGMA_ERROR,
1488 				  "errorCode,Unsupported DPPStep/DPPFrameType/DPPIEAttribute");
1489 			goto out;
1490 		}
1491 
1492 		snprintf(buf, sizeof(buf), "SET dpp_test %d", test);
1493 		if (wpa_command(ifname, buf) < 0) {
1494 			send_resp(dut, conn, SIGMA_ERROR,
1495 				  "errorCode,Failed to set dpp_test");
1496 			goto out;
1497 		}
1498 	} else {
1499 		wpa_command(ifname, "SET dpp_test 0");
1500 	}
1501 
1502 	if (strcasecmp(self_conf, "Yes") == 0) {
1503 		if (strcasecmp(prov_role, "Configurator") != 0) {
1504 			send_resp(dut, conn, SIGMA_ERROR,
1505 				  "errorCode,Invalid DPPSelfConfigure use - only allowed for Configurator role");
1506 			goto out;
1507 		}
1508 		if (!conf_role) {
1509 			send_resp(dut, conn, SIGMA_ERROR,
1510 				  "errorCode,Missing DPPConfIndex");
1511 			goto out;
1512 		}
1513 
1514 		snprintf(buf, sizeof(buf),
1515 			 "DPP_CONFIGURATOR_SIGN  conf=%s %s %s configurator=%d",
1516 			 conf_role, conf_ssid, conf_pass, dut->dpp_conf_id);
1517 		if (wpa_command(ifname, buf) < 0) {
1518 			send_resp(dut, conn, SIGMA_ERROR,
1519 				  "errorCode,Failed to initiate DPP self-configuration");
1520 			goto out;
1521 		}
1522 		if (sigma_dut_is_ap(dut))
1523 			goto update_ap;
1524 		goto wait_connect;
1525 	} else if (manual && strcasecmp(bs, "NFC") == 0) {
1526 		const char *val = get_param(cmd, "DPPNFCInit");
1527 		int init = val && atoi(val) > 0;
1528 		pid_t pid;
1529 		int pid_status;
1530 		int enrollee = 0;
1531 		const char *tx_rx_events[] = { "DPP-TX", "DPP-RX", NULL };
1532 
1533 		if (strcasecmp(prov_role, "Configurator") == 0 ||
1534 		    strcasecmp(prov_role, "Both") == 0) {
1535 			if (!conf_role) {
1536 				send_resp(dut, conn, SIGMA_ERROR,
1537 					  "errorCode,Missing DPPConfIndex");
1538 				goto out;
1539 			}
1540 			snprintf(buf, sizeof(buf),
1541 				 "SET dpp_configurator_params  conf=%s %s %s configurator=%d%s%s%s%s%s",
1542 				 conf_role, conf_ssid, conf_pass,
1543 				 dut->dpp_conf_id, group_id,
1544 				 akm_use_selector ? " akm_use_selector=1" : "",
1545 				 conn_status ? " conn_status=1" : "",
1546 				 csrattrs, conf2);
1547 			if (wpa_command(ifname, buf) < 0) {
1548 				send_resp(dut, conn, SIGMA_ERROR,
1549 					  "errorCode,Failed to set configurator parameters");
1550 				goto out;
1551 			}
1552 			snprintf(buf, sizeof(buf),
1553 				 "conf=%s %s %s configurator=%d%s%s%s%s%s",
1554 				 conf_role, conf_ssid, conf_pass,
1555 				 dut->dpp_conf_id, group_id,
1556 				 akm_use_selector ? " akm_use_selector=1" : "",
1557 				 conn_status ? " conn_status=1" : "", csrattrs,
1558 				 conf2);
1559 		} else {
1560 			buf[0] = '\0';
1561 			enrollee = 1;
1562 		}
1563 
1564 		run_system(dut, "killall dpp-nfc.py");
1565 		sigma_dut_print(dut, DUT_MSG_INFO, "Manual NFC operation");
1566 		if (!file_exists("dpp-nfc.py")) {
1567 			send_resp(dut, conn, SIGMA_ERROR,
1568 				  "errorCode,dpp-nfc.py not found");
1569 			goto out;
1570 		}
1571 
1572 		pid = fork();
1573 		if (pid < 0) {
1574 			perror("fork");
1575 			send_resp(dut, conn, SIGMA_ERROR,
1576 				  "errorCode,fork() failed");
1577 			goto out;
1578 		}
1579 
1580 		if (pid == 0) {
1581 			char * argv[] = { "dpp-nfc.py",
1582 					  "--only-one", "--no-input",
1583 					  "-i", (char *) ifname,
1584 					  "--ctrl", sigma_wpas_ctrl,
1585 					  enrollee ? "--enrollee" :
1586 					  "--configurator",
1587 					  "--config-params", buf,
1588 					  init ? "-I" : NULL,
1589 					  NULL };
1590 
1591 			execv("./dpp-nfc.py", argv);
1592 			perror("execv");
1593 			exit(0);
1594 			return -1;
1595 		}
1596 
1597 		usleep(300000);
1598 		for (;;) {
1599 			if (waitpid(pid, &pid_status, WNOHANG) > 0) {
1600 				sigma_dut_print(dut, DUT_MSG_DEBUG,
1601 						"dpp-nfc.py exited");
1602 				break;
1603 			}
1604 
1605 			time(&now);
1606 			if ((unsigned int) (now - start) >=
1607 			    dut->default_timeout) {
1608 				sigma_dut_print(dut, DUT_MSG_DEBUG,
1609 						"dpp-nfc.py did not exit within timeout - stop it");
1610 				kill(pid, SIGTERM);
1611 				waitpid(pid, &pid_status, 0);
1612 				send_resp(dut, conn, SIGMA_ERROR,
1613 					  "errorCode,dpp-nfc.py did not complete within timeout");
1614 				goto out;
1615 			}
1616 
1617 			old_timeout = dut->default_timeout;
1618 			dut->default_timeout = 2;
1619 
1620 			res = get_wpa_cli_events(dut, ctrl, tx_rx_events,
1621 						buf, sizeof(buf));
1622 			dut->default_timeout = old_timeout;
1623 			if (res >= 0) {
1624 				sigma_dut_print(dut, DUT_MSG_DEBUG,
1625 						"DPP exchange started");
1626 				usleep(500000);
1627 				kill(pid, SIGTERM);
1628 				waitpid(pid, &pid_status, 0);
1629 				break;
1630 			}
1631 		}
1632 	} else if ((nfc_handover &&
1633 		    strcasecmp(nfc_handover, "Negotiated_Requestor") == 0) ||
1634 		   ((!nfc_handover ||
1635 		     strcasecmp(nfc_handover, "Static") == 0) &&
1636 		    auth_role && strcasecmp(auth_role, "Initiator") == 0)) {
1637 		char own_txt[20];
1638 		int dpp_peer_bootstrap = -1;
1639 		char neg_freq[30];
1640 
1641 		val = get_param(cmd, "DPPAuthDirection");
1642 		check_mutual = val && strcasecmp(val, "Mutual") == 0;
1643 
1644 		neg_freq[0] = '\0';
1645 		val = get_param(cmd, "DPPSubsequentChannel");
1646 		if (val) {
1647 			int opclass, channel, freq;
1648 
1649 			opclass = atoi(val);
1650 			val = strchr(val, '/');
1651 			if (opclass == 0 || !val) {
1652 				send_resp(dut, conn, SIGMA_ERROR,
1653 					  "errorCode,Invalid DPPSubsequentChannel");
1654 				goto out;
1655 			}
1656 			val++;
1657 			channel = atoi(val);
1658 
1659 			/* Ignoring opclass for now; could use it here for more
1660 			 * robust frequency determination. */
1661 			freq = channel_to_freq(dut, channel);
1662 			if (!freq) {
1663 				send_resp(dut, conn, SIGMA_ERROR,
1664 					  "errorCode,Unsupported DPPSubsequentChannel channel");
1665 				goto out;
1666 			}
1667 			snprintf(neg_freq, sizeof(neg_freq), " neg_freq=%d",
1668 				 freq);
1669 		}
1670 
1671 		if (strcasecmp(bs, "QR") == 0) {
1672 			if (!dut->dpp_peer_uri) {
1673 				send_resp(dut, conn, SIGMA_ERROR,
1674 					  "errorCode,Missing peer bootstrapping info");
1675 				goto out;
1676 			}
1677 
1678 			snprintf(buf, sizeof(buf), "DPP_QR_CODE %s",
1679 				 dut->dpp_peer_uri);
1680 			if (wpa_command_resp(ifname, buf, buf,
1681 					     sizeof(buf)) < 0 ||
1682 			    strncmp(buf, "FAIL", 4) == 0) {
1683 				send_resp(dut, conn, SIGMA_ERROR,
1684 					  "errorCode,Failed to parse URI");
1685 				goto out;
1686 			}
1687 			dpp_peer_bootstrap = atoi(buf);
1688 		} else if (strcasecmp(bs, "NFC") == 0 && nfc_handover &&
1689 			   strcasecmp(nfc_handover, "Static") == 0) {
1690 			if (!dut->dpp_peer_uri) {
1691 				send_resp(dut, conn, SIGMA_ERROR,
1692 					  "errorCode,Missing peer bootstrapping info");
1693 				goto out;
1694 			}
1695 
1696 			snprintf(buf, sizeof(buf), "DPP_NFC_URI %s",
1697 				 dut->dpp_peer_uri);
1698 			if (wpa_command_resp(ifname, buf,
1699 					     buf, sizeof(buf)) < 0 ||
1700 			    strncmp(buf, "FAIL", 4) == 0) {
1701 				send_resp(dut, conn, SIGMA_ERROR,
1702 					  "errorCode,Failed to process URI from NFC Tag");
1703 				goto out;
1704 			}
1705 			dpp_peer_bootstrap = atoi(buf);
1706 		} else if (strcasecmp(bs, "NFC") == 0) {
1707 			if (!dut->dpp_peer_uri) {
1708 				send_resp(dut, conn, SIGMA_ERROR,
1709 					  "errorCode,Missing peer bootstrapping info");
1710 				goto out;
1711 			}
1712 			if (dut->dpp_local_bootstrap < 0) {
1713 				send_resp(dut, conn, SIGMA_ERROR,
1714 					  "errorCode,Missing own bootstrapping info");
1715 				goto out;
1716 			}
1717 
1718 			snprintf(buf, sizeof(buf),
1719 				 "DPP_NFC_HANDOVER_SEL own=%d uri=%s",
1720 				 dut->dpp_local_bootstrap, dut->dpp_peer_uri);
1721 			if (wpa_command_resp(ifname, buf,
1722 					     buf, sizeof(buf)) < 0 ||
1723 			    strncmp(buf, "FAIL", 4) == 0) {
1724 				send_resp(dut, conn, SIGMA_ERROR,
1725 					  "errorCode,Failed to process NFC Handover Select");
1726 				goto out;
1727 			}
1728 			dpp_peer_bootstrap = atoi(buf);
1729 		}
1730 
1731 		if (dut->dpp_local_bootstrap >= 0)
1732 			snprintf(own_txt, sizeof(own_txt), " own=%d",
1733 				 dut->dpp_local_bootstrap);
1734 		else
1735 			own_txt[0] = '\0';
1736 		if (chirp) {
1737 			int freq = 2437; /* default: channel 6 */
1738 
1739 			val = get_param(cmd, "DPPChirpChannel");
1740 			if (val) {
1741 				freq = channel_to_freq(dut, atoi(val));
1742 				if (!freq) {
1743 					send_resp(dut, conn, SIGMA_ERROR,
1744 						  "errorCode,Unsupported DPPChirpChannel channel");
1745 					goto out;
1746 				}
1747 			}
1748 
1749 			if (strcasecmp(prov_role, "Configurator") == 0 ||
1750 			    strcasecmp(prov_role, "Both") == 0) {
1751 				if (!conf_role) {
1752 					send_resp(dut, conn, SIGMA_ERROR,
1753 						  "errorCode,Missing DPPConfIndex");
1754 					goto out;
1755 				}
1756 				snprintf(buf, sizeof(buf),
1757 					 "SET dpp_configurator_params  conf=%s %s %s configurator=%d%s%s%s%s%s",
1758 					 conf_role, conf_ssid, conf_pass,
1759 					 dut->dpp_conf_id, group_id,
1760 					 akm_use_selector ?
1761 					 " akm_use_selector=1" : "",
1762 					 conn_status ? " conn_status=1" : "",
1763 					 csrattrs, conf2);
1764 				if (wpa_command(ifname, buf) < 0) {
1765 					send_resp(dut, conn, SIGMA_ERROR,
1766 						  "errorCode,Failed to set configurator parameters");
1767 					goto out;
1768 				}
1769 			}
1770 
1771 			if (tcp && strcasecmp(tcp, "yes") == 0) {
1772 				snprintf(buf, sizeof(buf),
1773 					 "DPP_CONTROLLER_START");
1774 			} else {
1775 				snprintf(buf, sizeof(buf),
1776 					 "DPP_LISTEN %d role=%s%s%s",
1777 					 freq, role,
1778 					 netrole ? " netrole=" : "",
1779 					 netrole ? netrole : "");
1780 			}
1781 		} else if ((strcasecmp(bs, "QR") == 0 ||
1782 			    strcasecmp(bs, "NFC") == 0) &&
1783 			   (strcasecmp(prov_role, "Configurator") == 0 ||
1784 			    strcasecmp(prov_role, "Both") == 0)) {
1785 			if (!conf_role) {
1786 				send_resp(dut, conn, SIGMA_ERROR,
1787 					  "errorCode,Missing DPPConfIndex");
1788 				goto out;
1789 			}
1790 			snprintf(buf, sizeof(buf),
1791 				 "DPP_AUTH_INIT peer=%d%s role=%s%s%s conf=%s %s %s configurator=%d%s%s%s%s%s%s%s%s",
1792 				 dpp_peer_bootstrap, own_txt, role,
1793 				 netrole ? " netrole=" : "",
1794 				 netrole ? netrole : "",
1795 				 conf_role, conf_ssid, conf_pass,
1796 				 dut->dpp_conf_id, neg_freq, group_id,
1797 				 akm_use_selector ? " akm_use_selector=1" : "",
1798 				 conn_status ? " conn_status=1" : "",
1799 				 tcp ? " tcp_addr=" : "",
1800 				 tcp ? tcp : "",
1801 				 csrattrs, conf2);
1802 		} else if (tcp && (strcasecmp(bs, "QR") == 0 ||
1803 				   strcasecmp(bs, "NFC") == 0)) {
1804 			snprintf(buf, sizeof(buf),
1805 				 "DPP_AUTH_INIT peer=%d%s role=%s%s%s tcp_addr=%s%s%s",
1806 				 dpp_peer_bootstrap, own_txt, role,
1807 				 netrole ? " netrole=" : "",
1808 				 netrole ? netrole : "",
1809 				 tcp, neg_freq, group_id);
1810 		} else if (strcasecmp(bs, "QR") == 0 ||
1811 			   strcasecmp(bs, "NFC") == 0) {
1812 			snprintf(buf, sizeof(buf),
1813 				 "DPP_AUTH_INIT peer=%d%s role=%s%s%s%s%s",
1814 				 dpp_peer_bootstrap, own_txt, role,
1815 				 netrole ? " netrole=" : "",
1816 				 netrole ? netrole : "",
1817 				 neg_freq, group_id);
1818 		} else if (strcasecmp(bs, "PKEX") == 0 &&
1819 			   (strcasecmp(prov_role, "Configurator") == 0 ||
1820 			    strcasecmp(prov_role, "Both") == 0)) {
1821 			if (!conf_role) {
1822 				send_resp(dut, conn, SIGMA_ERROR,
1823 					  "errorCode,Missing DPPConfIndex");
1824 				goto out;
1825 			}
1826 			snprintf(buf, sizeof(buf),
1827 				 "DPP_PKEX_ADD own=%d init=1 role=%s conf=%s %s %s configurator=%d%s %scode=%s",
1828 				 own_pkex_id, role, conf_role,
1829 				 conf_ssid, conf_pass, dut->dpp_conf_id,
1830 				 csrattrs, pkex_identifier, pkex_code);
1831 		} else if (strcasecmp(bs, "PKEX") == 0) {
1832 			snprintf(buf, sizeof(buf),
1833 				 "DPP_PKEX_ADD own=%d init=1 role=%s %scode=%s",
1834 				 own_pkex_id, role, pkex_identifier, pkex_code);
1835 		} else {
1836 			send_resp(dut, conn, SIGMA_ERROR,
1837 				  "errorCode,Unsupported DPPBS");
1838 			goto out;
1839 		}
1840 		if (wpa_command(ifname, buf) < 0) {
1841 			send_resp(dut, conn, SIGMA_ERROR,
1842 				  "errorCode,Failed to initiate DPP authentication");
1843 			goto out;
1844 		}
1845 	} else if ((nfc_handover &&
1846 		    strcasecmp(nfc_handover, "Negotiated_Selector") == 0) ||
1847 		   ((!nfc_handover ||
1848 		     strcasecmp(nfc_handover, "Static") == 0) &&
1849 		    auth_role && strcasecmp(auth_role, "Responder") == 0)) {
1850 		const char *delay_qr_resp;
1851 		int mutual;
1852 		int freq = 2462; /* default: channel 11 */
1853 
1854 		if (sigma_dut_is_ap(dut) && dut->hostapd_running &&
1855 		    dut->ap_oper_chn)
1856 			freq = channel_to_freq(dut, dut->ap_channel);
1857 
1858 		if (sigma_dut_is_ap(dut) && dpp_hostapd_beacon(dut) < 0) {
1859 			send_resp(dut, conn, SIGMA_ERROR,
1860 				  "errorCode,Failed to start AP mode listen");
1861 			goto out;
1862 		}
1863 
1864 		if (strcasecmp(bs, "PKEX") == 0) {
1865 			/* default: channel 6 for PKEX */
1866 			freq = 2437;
1867 		}
1868 
1869 		delay_qr_resp = get_param(cmd, "DPPDelayQRResponse");
1870 
1871 		val = get_param(cmd, "DPPAuthDirection");
1872 		mutual = val && strcasecmp(val, "Mutual") == 0;
1873 
1874 		val = get_param(cmd, "DPPListenChannel");
1875 		if (val) {
1876 			freq = channel_to_freq(dut, atoi(val));
1877 			if (freq == 0) {
1878 				send_resp(dut, conn, SIGMA_ERROR,
1879 					  "errorCode,Unsupported DPPListenChannel value");
1880 				goto out;
1881 			}
1882 		}
1883 
1884 		if (strcasecmp(bs, "NFC") == 0 && nfc_handover &&
1885 		    strcasecmp(nfc_handover, "Static") == 0) {
1886 			/* No steps needed here - waiting for peer to initiate
1887 			 * once it reads the URI from the NFC Tag */
1888 		} else if (strcasecmp(bs, "NFC") == 0) {
1889 			if (!dut->dpp_peer_uri) {
1890 				send_resp(dut, conn, SIGMA_ERROR,
1891 					  "errorCode,Missing peer bootstrapping info");
1892 				goto out;
1893 			}
1894 			if (dut->dpp_local_bootstrap < 0) {
1895 				send_resp(dut, conn, SIGMA_ERROR,
1896 					  "errorCode,Missing own bootstrapping info");
1897 				goto out;
1898 			}
1899 
1900 			snprintf(buf, sizeof(buf),
1901 				 "DPP_NFC_HANDOVER_REQ own=%d uri=%s",
1902 				 dut->dpp_local_bootstrap, dut->dpp_peer_uri);
1903 			if (wpa_command(ifname, buf) < 0) {
1904 				send_resp(dut, conn, SIGMA_ERROR,
1905 					  "errorCode,Failed to process NFC Handover Request");
1906 				goto out;
1907 			}
1908 
1909 			snprintf(buf, sizeof(buf), "DPP_BOOTSTRAP_INFO %d",
1910 				 dut->dpp_local_bootstrap);
1911 			if (wpa_command_resp(ifname, buf,
1912 					     buf, sizeof(buf)) < 0 ||
1913 			    strncmp(buf, "FAIL", 4) == 0) {
1914 				send_resp(dut, conn, SIGMA_ERROR,
1915 					  "errorCode,Failed to get bootstrap information");
1916 				goto out;
1917 			}
1918 			pos = buf;
1919 			while (pos) {
1920 				pos2 = strchr(pos, '\n');
1921 				if (pos2)
1922 					*pos2 = '\0';
1923 				if (strncmp(pos, "use_freq=", 9) == 0) {
1924 					freq = atoi(pos + 9);
1925 					sigma_dut_print(dut, DUT_MSG_DEBUG,
1926 							"DPP negotiation frequency from NFC handover: %d MHz",
1927 							freq);
1928 					break;
1929 				}
1930 
1931 				if (!pos2)
1932 					break;
1933 				pos = pos2 + 1;
1934 			}
1935 		} else if (!delay_qr_resp && dut->dpp_peer_uri) {
1936 			snprintf(buf, sizeof(buf), "DPP_QR_CODE %s",
1937 				 dut->dpp_peer_uri);
1938 			if (wpa_command_resp(ifname, buf, buf,
1939 					     sizeof(buf)) < 0) {
1940 				send_resp(dut, conn, SIGMA_ERROR,
1941 					  "errorCode,Failed to parse URI");
1942 				goto out;
1943 			}
1944 		}
1945 
1946 		if (strcasecmp(prov_role, "Configurator") == 0) {
1947 			if (!conf_role) {
1948 				send_resp(dut, conn, SIGMA_ERROR,
1949 					  "errorCode,Missing DPPConfIndex");
1950 				goto out;
1951 			}
1952 			snprintf(buf, sizeof(buf),
1953 				 "SET dpp_configurator_params  conf=%s %s %s configurator=%d%s%s%s%s%s",
1954 				 conf_role, conf_ssid, conf_pass,
1955 				 dut->dpp_conf_id, group_id,
1956 				 akm_use_selector ? " akm_use_selector=1" : "",
1957 				 conn_status ? " conn_status=1" : "", csrattrs,
1958 				 conf2);
1959 			if (wpa_command(ifname, buf) < 0) {
1960 				send_resp(dut, conn, SIGMA_ERROR,
1961 					  "errorCode,Failed to set configurator parameters");
1962 				goto out;
1963 			}
1964 		}
1965 		if (strcasecmp(bs, "PKEX") == 0) {
1966 			snprintf(buf, sizeof(buf),
1967 				 "DPP_PKEX_ADD own=%d role=%s %scode=%s",
1968 				 own_pkex_id, role, pkex_identifier, pkex_code);
1969 			if (wpa_command(ifname, buf) < 0) {
1970 				send_resp(dut, conn, SIGMA_ERROR,
1971 					  "errorCode,Failed to configure DPP PKEX");
1972 				goto out;
1973 			}
1974 		}
1975 
1976 		if (chirp) {
1977 			snprintf(buf, sizeof(buf),
1978 				 "DPP_CHIRP own=%d iter=10 listen=%d",
1979 				 dut->dpp_local_bootstrap, freq);
1980 		} else if (tcp && strcasecmp(tcp, "yes") == 0) {
1981 			snprintf(buf, sizeof(buf), "DPP_CONTROLLER_START");
1982 		} else {
1983 			snprintf(buf, sizeof(buf),
1984 				 "DPP_LISTEN %d role=%s%s%s%s",
1985 				 freq, role,
1986 				 (strcasecmp(bs, "QR") == 0 && mutual) ?
1987 				 " qr=mutual" : "",
1988 				 netrole ? " netrole=" : "",
1989 				 netrole ? netrole : "");
1990 		}
1991 		if (wpa_command(ifname, buf) < 0) {
1992 			send_resp(dut, conn, SIGMA_ERROR,
1993 				  "errorCode,Failed to start DPP listen/chirp");
1994 			goto out;
1995 		}
1996 
1997 		if (!(tcp && strcasecmp(tcp, "yes") == 0) &&
1998 		    get_driver_type(dut) == DRIVER_OPENWRT) {
1999 			snprintf(buf, sizeof(buf), "iwconfig %s channel %d",
2000 				 dut->hostapd_ifname, freq_to_channel(freq));
2001 			run_system(dut, buf);
2002 		}
2003 
2004 		if (delay_qr_resp && mutual && dut->dpp_peer_uri) {
2005 			int wait_time = atoi(delay_qr_resp);
2006 
2007 			res = get_wpa_cli_events(dut, ctrl, auth_events,
2008 						 buf, sizeof(buf));
2009 			if (res < 0) {
2010 				send_resp(dut, conn, SIGMA_COMPLETE,
2011 					  "BootstrapResult,OK,AuthResult,Timeout");
2012 				goto out;
2013 			}
2014 			sigma_dut_print(dut, DUT_MSG_DEBUG,
2015 					"DPP auth result: %s", buf);
2016 			if (strstr(buf, "DPP-SCAN-PEER-QR-CODE") == NULL) {
2017 				send_resp(dut, conn, SIGMA_ERROR,
2018 					  "errorCode,No scan request for peer QR Code seen");
2019 				goto out;
2020 			}
2021 			sigma_dut_print(dut, DUT_MSG_INFO,
2022 					"Waiting %d second(s) before processing peer URI",
2023 					wait_time);
2024 			sleep(wait_time);
2025 
2026 			snprintf(buf, sizeof(buf), "DPP_QR_CODE %s",
2027 				 dut->dpp_peer_uri);
2028 			if (wpa_command_resp(ifname, buf, buf,
2029 					     sizeof(buf)) < 0) {
2030 				send_resp(dut, conn, SIGMA_ERROR,
2031 					  "errorCode,Failed to parse URI");
2032 				goto out;
2033 			}
2034 		} else if (mutual && action_type &&
2035 			   strcasecmp(action_type, "ManualDPP") == 0) {
2036 			res = get_wpa_cli_events(dut, ctrl, auth_events,
2037 						 buf, sizeof(buf));
2038 			if (res < 0) {
2039 				send_resp(dut, conn, SIGMA_COMPLETE,
2040 					  "BootstrapResult,OK,AuthResult,Timeout");
2041 				goto out;
2042 			}
2043 			sigma_dut_print(dut, DUT_MSG_DEBUG,
2044 					"DPP auth result: %s", buf);
2045 			if (strstr(buf, "DPP-NOT-COMPATIBLE")) {
2046 			    send_resp(dut, conn, SIGMA_COMPLETE,
2047 				      "BootstrapResult,OK,AuthResult,ROLES_NOT_COMPATIBLE");
2048 			    goto out;
2049 			}
2050 
2051 			if (strstr(buf, "DPP-SCAN-PEER-QR-CODE") == NULL) {
2052 				send_resp(dut, conn, SIGMA_ERROR,
2053 					  "errorCode,No scan request for peer QR Code seen");
2054 				goto out;
2055 			}
2056 
2057 			if (dpp_scan_peer_qrcode(dut) < 0) {
2058 				send_resp(dut, conn, SIGMA_ERROR,
2059 					  "errorCode,Failed to scan peer QR Code");
2060 				goto out;
2061 			}
2062 
2063 			snprintf(buf, sizeof(buf), "DPP_QR_CODE %s",
2064 				 dut->dpp_peer_uri);
2065 			if (wpa_command_resp(ifname, buf, buf,
2066 					     sizeof(buf)) < 0) {
2067 				send_resp(dut, conn, SIGMA_ERROR,
2068 					  "errorCode,Failed to parse URI");
2069 				goto out;
2070 			}
2071 		}
2072 	} else {
2073 		send_resp(dut, conn, SIGMA_ERROR,
2074 			  "errorCode,Unknown DPPAuthRole");
2075 		goto out;
2076 	}
2077 
2078 	if (step && strcasecmp(step, "Timeout") == 0) {
2079 		result = "errorCode,Unexpected state";
2080 
2081 		if (strcasecmp(frametype, "PKEXExchangeResponse") == 0) {
2082 			if (dpp_wait_rx(dut, ctrl, 8, -1) < 0)
2083 				result = "BootstrapResult,Timeout";
2084 			else
2085 				result = "BootstrapResult,Errorsent";
2086 		}
2087 
2088 		if (strcasecmp(frametype, "PKEXCRRequest") == 0) {
2089 			if (dpp_wait_rx(dut, ctrl, 9, -1) < 0)
2090 				result = "BootstrapResult,Timeout";
2091 			else
2092 				result = "BootstrapResult,Errorsent";
2093 		}
2094 
2095 		if (strcasecmp(frametype, "PKEXCRResponse") == 0) {
2096 			if (dpp_wait_rx(dut, ctrl, 10, -1) < 0)
2097 				result = "BootstrapResult,Timeout";
2098 			else
2099 				result = "BootstrapResult,Errorsent";
2100 		}
2101 
2102 		if (strcasecmp(frametype, "AuthenticationRequest") == 0) {
2103 			if (dpp_wait_rx(dut, ctrl, 0, -1) < 0)
2104 				result = "BootstrapResult,OK,AuthResult,Timeout";
2105 			else
2106 				result = "BootstrapResult,OK,AuthResult,Errorsent";
2107 		}
2108 
2109 		if (strcasecmp(frametype, "AuthenticationResponse") == 0) {
2110 			if (dpp_wait_rx(dut, ctrl, 1, -1) < 0)
2111 				result = "BootstrapResult,OK,AuthResult,Timeout";
2112 			else
2113 				result = "BootstrapResult,OK,AuthResult,Errorsent";
2114 		}
2115 
2116 		if (strcasecmp(frametype, "AuthenticationConfirm") == 0) {
2117 			if (auth_role &&
2118 			    strcasecmp(auth_role, "Initiator") == 0) {
2119 				/* This special case of DPPStep,Timeout with
2120 				 * DPPFrameType,AuthenticationConfirm on an
2121 				 * Initiator is used to cover need for stopping
2122 				 * the Initiator/Enrollee from sending out
2123 				 * Configuration Request message. */
2124 				if (strcasecmp(prov_role, "Enrollee") != 0) {
2125 					send_resp(dut, conn, SIGMA_ERROR,
2126 						  "errorCode,Unexpected use of timeout after AuthenticationConfirm TX in Configurator role");
2127 					goto out;
2128 				}
2129 				if (check_mutual &&
2130 				    dpp_process_auth_response(
2131 					    dut, conn, ctrl, auth_events,
2132 					    action_type, check_mutual,
2133 					    buf, sizeof(buf)) < 0)
2134 					goto out;
2135 				if (dpp_wait_tx_status(dut, ctrl, 2) < 0)
2136 					result = "BootstrapResult,OK,AuthResult,Timeout";
2137 				else
2138 					result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,AuthenticationResponse";
2139 			} else {
2140 				if (dpp_wait_rx(dut, ctrl, 2, -1) < 0)
2141 					result = "BootstrapResult,OK,AuthResult,Timeout";
2142 				else
2143 					result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,AuthenticationConfirm";
2144 			}
2145 		}
2146 
2147 		if (strcasecmp(frametype, "ConfigurationRequest") == 0) {
2148 			if (get_wpa_cli_event(dut, ctrl, "DPP-CONF-FAILED",
2149 					      buf, sizeof(buf)) < 0)
2150 				result = "BootstrapResult,OK,AuthResult,OK,ConfResult,Timeout";
2151 			else
2152 				result = "BootstrapResult,OK,AuthResult,OK,ConfResult,Errorsent";
2153 		}
2154 
2155 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2156 		goto out;
2157 	}
2158 
2159 	if (frametype && strcasecmp(frametype, "PKEXExchangeRequest") == 0) {
2160 		if (dpp_wait_tx_status(dut, ctrl, 7) < 0)
2161 			result = "BootstrapResult,Timeout";
2162 		else
2163 			result = "BootstrapResult,Errorsent";
2164 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2165 		goto out;
2166 	}
2167 
2168 	if (frametype && strcasecmp(frametype, "PKEXExchangeResponse") == 0) {
2169 		if (dpp_wait_tx_status(dut, ctrl, 8) < 0)
2170 			result = "BootstrapResult,Timeout";
2171 		else
2172 			result = "BootstrapResult,Errorsent";
2173 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2174 		goto out;
2175 	}
2176 
2177 	if (frametype && strcasecmp(frametype, "PKEXCRRequest") == 0) {
2178 		if (dpp_wait_tx_status(dut, ctrl, 9) < 0)
2179 			result = "BootstrapResult,Timeout";
2180 		else
2181 			result = "BootstrapResult,Errorsent";
2182 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2183 		goto out;
2184 	}
2185 
2186 	if (frametype && strcasecmp(frametype, "PKEXCRResponse") == 0) {
2187 		if (dpp_wait_tx_status(dut, ctrl, 10) < 0)
2188 			result = "BootstrapResult,Timeout";
2189 		else
2190 			result = "BootstrapResult,Errorsent";
2191 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2192 		goto out;
2193 	}
2194 
2195 	if (!frametype && strcasecmp(bs, "PKEX") == 0 &&
2196 	    auth_role && strcasecmp(auth_role, "Responder") == 0) {
2197 		if (dpp_wait_tx_status(dut, ctrl, 10) < 0) {
2198 			send_resp(dut, conn, SIGMA_COMPLETE,
2199 				  "BootstrapResult,Timeout");
2200 			goto out;
2201 		}
2202 	}
2203 
2204 	if (!frametype && strcasecmp(bs, "PKEX") == 0 &&
2205 	    auth_role && strcasecmp(auth_role, "Initiator") == 0) {
2206 		if (dpp_wait_tx(dut, ctrl, 0) < 0) {
2207 			send_resp(dut, conn, SIGMA_COMPLETE,
2208 				  "BootstrapResult,Timeout");
2209 			goto out;
2210 		}
2211 	}
2212 
2213 	if (frametype && strcasecmp(frametype, "AuthenticationRequest") == 0) {
2214 		if (dpp_wait_tx_status(dut, ctrl, 0) < 0) {
2215 			send_resp(dut, conn, SIGMA_COMPLETE,
2216 				  "BootstrapResult,OK,AuthResult,Timeout");
2217 			goto out;
2218 		}
2219 
2220 		if (dpp_wait_rx(dut, ctrl, 1, 5) < 0)
2221 			result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,None";
2222 		else if	(get_wpa_cli_events(dut, ctrl, auth_events,
2223 					    buf, sizeof(buf)) >= 0 &&
2224 			 strstr(buf, "DPP-RESPONSE-PENDING") != NULL)
2225 			result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,AuthenticationResponseWithStatusPending";
2226 		else
2227 			result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,AuthenticationResponse";
2228 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2229 		goto out;
2230 	}
2231 
2232 	if (frametype && strcasecmp(frametype, "AuthenticationResponse") == 0) {
2233 		if (dpp_wait_tx_status(dut, ctrl, 1) < 0) {
2234 			send_resp(dut, conn, SIGMA_COMPLETE,
2235 				  "BootstrapResult,OK,AuthResult,Timeout");
2236 			goto out;
2237 		}
2238 
2239 		if (dpp_wait_rx(dut, ctrl, 2, 5) < 0)
2240 			result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,AuthenticationRequest";
2241 		else
2242 			result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,AuthenticationConfirm";
2243 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2244 		goto out;
2245 	}
2246 
2247 	if (dpp_process_auth_response(dut, conn, ctrl, auth_events, action_type,
2248 				      check_mutual, buf, sizeof(buf)) < 0)
2249 		goto out;
2250 
2251 	if (frametype && strcasecmp(frametype, "AuthenticationConfirm") == 0) {
2252 		if (dpp_wait_tx_status(dut, ctrl, 2) < 0) {
2253 			send_resp(dut, conn, SIGMA_COMPLETE,
2254 				  "BootstrapResult,OK,AuthResult,Timeout");
2255 			goto out;
2256 		}
2257 
2258 		if (dpp_wait_rx_conf_req(dut, ctrl, 5) < 0)
2259 			result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,AuthenticationResponse";
2260 		else
2261 			result = "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,ConfigurationRequest";
2262 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2263 		goto out;
2264 	}
2265 
2266 	if (strstr(buf, "DPP-AUTH-DIRECTION")) {
2267 		res = get_wpa_cli_events(dut, ctrl, auth_events,
2268 					 buf, sizeof(buf));
2269 		if (res < 0) {
2270 			send_resp(dut, conn, SIGMA_COMPLETE,
2271 				  "BootstrapResult,OK,AuthResult,Timeout");
2272 			goto out;
2273 		}
2274 
2275 		sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP auth result: %s", buf);
2276 	}
2277 
2278 	if (strstr(buf, "DPP-NOT-COMPATIBLE")) {
2279 		send_resp(dut, conn, SIGMA_COMPLETE,
2280 			  "BootstrapResult,OK,AuthResult,ROLES_NOT_COMPATIBLE");
2281 		goto out;
2282 	}
2283 
2284 	if (!strstr(buf, "DPP-AUTH-SUCCESS")) {
2285 		send_resp(dut, conn, SIGMA_COMPLETE,
2286 			  "BootstrapResult,OK,AuthResult,FAILED");
2287 		goto out;
2288 	}
2289 
2290 	if (frametype && strcasecmp(frametype, "ConfigurationRequest") == 0) {
2291 		res = get_wpa_cli_event(dut, ctrl, "GAS-QUERY-DONE",
2292 					buf, sizeof(buf));
2293 		if (res < 0)
2294 			result = "BootstrapResult,OK,AuthResult,OK,ConfResult,Timeout";
2295 		else
2296 			result = "BootstrapResult,OK,AuthResult,OK,ConfResult,Errorsent";
2297 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2298 		goto out;
2299 	}
2300 
2301 	if (frametype && strcasecmp(frametype, "ConfigurationResponse") == 0) {
2302 		res = get_wpa_cli_events(dut, ctrl, conf_events,
2303 					 buf, sizeof(buf));
2304 		if (res < 0)
2305 			result = "BootstrapResult,OK,AuthResult,OK,ConfResult,Timeout";
2306 		else
2307 			result = "BootstrapResult,OK,AuthResult,OK,ConfResult,Errorsent,LastFrameReceived,ConfigurationRequest";
2308 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2309 		goto out;
2310 	}
2311 
2312 	if (strcasecmp(prov_role, "Configurator") == 0 && csrattrs[0]) {
2313 		res = get_wpa_cli_event(dut, ctrl, "DPP-CSR", buf, sizeof(buf));
2314 		if (res < 0) {
2315 			send_resp(dut, conn, SIGMA_ERROR,
2316 				  "errorCode,No CSR received from Enrollee");
2317 			res = STATUS_SENT_ERROR;
2318 			goto out;
2319 		}
2320 
2321 		if (dpp_process_csr(dut, ifname, buf) < 0) {
2322 			send_resp(dut, conn, SIGMA_ERROR,
2323 				  "errorCode,Failed to process CSR");
2324 			res = STATUS_SENT_ERROR;
2325 			goto out;
2326 		}
2327 	}
2328 
2329 	res = get_wpa_cli_events(dut, ctrl, conf_events, buf, sizeof(buf));
2330 	if (res < 0) {
2331 		send_resp(dut, conn, SIGMA_COMPLETE,
2332 			  "BootstrapResult,OK,AuthResult,OK,ConfResult,Timeout");
2333 		goto out;
2334 	}
2335 	sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP conf result: %s", buf);
2336 
2337 	if (!strstr(buf, "DPP-CONF-SENT") &&
2338 	    !strstr(buf, "DPP-CONF-RECEIVED")) {
2339 		send_resp(dut, conn, SIGMA_COMPLETE,
2340 			  "BootstrapResult,OK,AuthResult,OK,ConfResult,FAILED");
2341 		goto out;
2342 	}
2343 
2344 	if (conn_status && strstr(buf, "DPP-CONF-SENT") &&
2345 	    strstr(buf, "wait_conn_status=1")) {
2346 		res = get_wpa_cli_event(dut, ctrl, "DPP-CONN-STATUS-RESULT",
2347 					buf, sizeof(buf));
2348 		if (res < 0) {
2349 			send_resp(dut, conn, SIGMA_COMPLETE,
2350 				  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,StatusResult,Timeout");
2351 		} else {
2352 			pos = strstr(buf, "result=");
2353 			if (!pos) {
2354 				send_resp(dut, conn, SIGMA_ERROR,
2355 					  "errorCode,Status result value not reported");
2356 			} else {
2357 				pos += 7;
2358 				snprintf(buf, sizeof(buf),
2359 					 "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,StatusResult,%d",
2360 					 atoi(pos));
2361 				send_resp(dut, conn, SIGMA_COMPLETE, buf);
2362 			}
2363 		}
2364 		goto out;
2365 	}
2366 
2367 	if (strcasecmp(prov_role, "Enrollee") == 0 && netrole &&
2368 	    strcmp(netrole, "configurator") == 0) {
2369 		res = get_wpa_cli_event(dut, ctrl, "DPP-CONFIGURATOR-ID",
2370 					buf, sizeof(buf));
2371 		if (res < 0) {
2372 			send_resp(dut, conn, SIGMA_ERROR,
2373 				  "errorCode,No DPP-CONFIGURATOR-ID");
2374 			goto out;
2375 		}
2376 		pos = strchr(buf, ' ');
2377 		if (!pos) {
2378 			send_resp(dut, conn, SIGMA_ERROR,
2379 				  "errorCode,Invalid DPP-CONFIGURATOR-ID");
2380 			goto out;
2381 		}
2382 		pos++;
2383 		dut->dpp_conf_id = atoi(pos);
2384 	} else if (sigma_dut_is_ap(dut) &&
2385 		   strcasecmp(prov_role, "Enrollee") == 0) {
2386 	update_ap:
2387 		res = dpp_hostapd_conf_update(dut, conn, ifname, ctrl);
2388 		if (res == 0)
2389 			goto out;
2390 		if (res < 0) {
2391 			send_resp(dut, conn, SIGMA_ERROR, NULL);
2392 			goto out;
2393 		}
2394 	}
2395 
2396 	if (strcasecmp(wait_conn, "Yes") == 0 &&
2397 	    !sigma_dut_is_ap(dut) &&
2398 	    strcasecmp(prov_role, "Enrollee") == 0) {
2399 		int netw_id;
2400 		char *pos;
2401 
2402 		res = get_wpa_cli_event(dut, ctrl, "DPP-NETWORK-ID",
2403 					buf, sizeof(buf));
2404 		if (res < 0) {
2405 			send_resp(dut, conn, SIGMA_ERROR,
2406 				  "errorCode,No DPP-NETWORK-ID");
2407 			goto out;
2408 		}
2409 		pos = strchr(buf, ' ');
2410 		if (!pos) {
2411 			send_resp(dut, conn, SIGMA_ERROR,
2412 				  "errorCode,Invalid DPP-NETWORK-ID");
2413 			goto out;
2414 		}
2415 		pos++;
2416 		netw_id = atoi(pos);
2417 		snprintf(buf, sizeof(buf), "GET_NETWORK %d key_mgmt", netw_id);
2418 		if (wpa_command_resp(ifname, buf, buf, sizeof(buf)) < 0) {
2419 			send_resp(dut, conn, SIGMA_ERROR,
2420 				  "errorCode,Could not fetch provisioned key_mgmt");
2421 			goto out;
2422 		}
2423 		if (strncmp(buf, "SAE", 3) == 0) {
2424 			/* SAE generates PMKSA-CACHE-ADDED event */
2425 			not_dpp_akm = 1;
2426 		}
2427 	wait_connect:
2428 		if (frametype && strcasecmp(frametype,
2429 					    "PeerDiscoveryRequest") == 0) {
2430 			if (dpp_wait_tx_status(dut, ctrl, 5) < 0)
2431 				result = "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,Timeout";
2432 			else
2433 				result = "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,Errorsent";
2434 			send_resp(dut, conn, SIGMA_COMPLETE, result);
2435 			goto out;
2436 		}
2437 
2438 		res = get_wpa_cli_events(dut, ctrl, conn_events,
2439 					 buf, sizeof(buf));
2440 		if (res < 0) {
2441 			send_resp(dut, conn, SIGMA_COMPLETE,
2442 				  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,Timeout,NetworkConnectResult,Timeout");
2443 			goto out;
2444 		}
2445 		sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP connect result: %s",
2446 				buf);
2447 
2448 		if (strstr(buf, "PMKSA-CACHE-ADDED")) {
2449 			res = get_wpa_cli_events(dut, ctrl, conn_events,
2450 						 buf, sizeof(buf));
2451 			if (res < 0) {
2452 				send_resp(dut, conn, SIGMA_COMPLETE,
2453 					  not_dpp_akm ?
2454 					  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkConnectResult,Timeout" :
2455 					  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,OK,NetworkConnectResult,Timeout");
2456 				goto out;
2457 			}
2458 			sigma_dut_print(dut, DUT_MSG_DEBUG,
2459 					"DPP connect result: %s", buf);
2460 			if (strstr(buf, "CTRL-EVENT-CONNECTED"))
2461 				send_resp(dut, conn, SIGMA_COMPLETE,
2462 					  not_dpp_akm ?
2463 					  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkConnectResult,OK" :
2464 					  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,OK,NetworkConnectResult,OK");
2465 			else
2466 				send_resp(dut, conn, SIGMA_COMPLETE,
2467 					  not_dpp_akm ?
2468 					  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkConnectResult,Timeout" :
2469 					  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,OK,NetworkConnectResult,Timeout");
2470 			goto out;
2471 		}
2472 
2473 		send_resp(dut, conn, SIGMA_COMPLETE,
2474 			  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkConnectResult,OK");
2475 		goto out;
2476 	}
2477 
2478 	if (strcasecmp(wait_conn, "Yes") == 0 &&
2479 	    frametype && strcasecmp(frametype, "PeerDiscoveryResponse") == 0) {
2480 		if (dpp_wait_tx_status(dut, ctrl, 6) < 0)
2481 			result = "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,Timeout";
2482 		else
2483 			result = "BootstrapResult,OK,AuthResult,OK,ConfResult,OK,NetworkIntroResult,Errorsent";
2484 		send_resp(dut, conn, SIGMA_COMPLETE, result);
2485 		goto out;
2486 	}
2487 
2488 	send_resp(dut, conn, SIGMA_COMPLETE,
2489 		  "BootstrapResult,OK,AuthResult,OK,ConfResult,OK");
2490 out:
2491 	wpa_ctrl_detach(ctrl);
2492 	wpa_ctrl_close(ctrl);
2493 	if (tcp && strcasecmp(tcp, "yes") == 0 &&
2494 	    auth_role && strcasecmp(auth_role, "Responder") == 0)
2495 		wpa_command(ifname, "DPP_CONTROLLER_STOP");
2496 	dut->default_timeout = old_timeout;
2497 	return STATUS_SENT;
2498 err:
2499 	send_resp(dut, conn, SIGMA_ERROR, NULL);
2500 	goto out;
2501 }
2502 
2503 
2504 static enum sigma_cmd_result dpp_manual_dpp(struct sigma_dut *dut,
2505 					    struct sigma_conn *conn,
2506 					    struct sigma_cmd *cmd)
2507 {
2508 	const char *auth_role = get_param(cmd, "DPPAuthRole");
2509 	const char *self_conf = get_param(cmd, "DPPSelfConfigure");
2510 	enum sigma_cmd_result res = INVALID_SEND_STATUS;
2511 	int success;
2512 	const char *val;
2513 	unsigned int old_timeout;
2514 	const char *bs = get_param(cmd, "DPPBS");
2515 
2516 	if (!auth_role) {
2517 		send_resp(dut, conn, SIGMA_ERROR,
2518 			  "errorCode,Missing DPPAuthRole");
2519 		return STATUS_SENT_ERROR;
2520 	}
2521 
2522 	if (!self_conf)
2523 		self_conf = "no";
2524 
2525 	old_timeout = dut->default_timeout;
2526 	val = get_param(cmd, "DPPTimeout");
2527 	if (val && atoi(val) > 0) {
2528 		dut->default_timeout = atoi(val);
2529 		sigma_dut_print(dut, DUT_MSG_DEBUG, "DPP timeout: %u",
2530 				dut->default_timeout);
2531 	}
2532 
2533 	if (strcasecmp(bs, "NFC") == 0) {
2534 		res = dpp_automatic_dpp(dut, conn, cmd);
2535 		goto out;
2536 	}
2537 
2538 	res = dpp_get_local_bootstrap(dut, conn, cmd, 0, &success);
2539 	if (res != STATUS_SENT || !success)
2540 		goto out;
2541 
2542 	if (strcasecmp(auth_role, "Responder") == 0) {
2543 		if (dpp_display_own_qrcode(dut) < 0) {
2544 			send_resp(dut, conn, SIGMA_ERROR,
2545 				  "errorCode,Failed to display own QR code");
2546 			res = STATUS_SENT_ERROR;
2547 			goto out;
2548 		}
2549 
2550 		res = dpp_automatic_dpp(dut, conn, cmd);
2551 		goto out;
2552 	}
2553 
2554 	if (strcasecmp(auth_role, "Initiator") == 0) {
2555 		if (strcasecmp(self_conf, "Yes") != 0) {
2556 			if (dpp_scan_peer_qrcode(dut) < 0) {
2557 				send_resp(dut, conn, SIGMA_ERROR,
2558 					  "errorCode,Failed to scan peer QR Code");
2559 				res = STATUS_SENT_ERROR;
2560 				goto out;
2561 			}
2562 		}
2563 
2564 		res = dpp_automatic_dpp(dut, conn, cmd);
2565 		goto out;
2566 	}
2567 
2568 	send_resp(dut, conn, SIGMA_ERROR, "errorCode,Unknown DPPAuthRole");
2569 	res = STATUS_SENT_ERROR;
2570 out:
2571 	dut->default_timeout = old_timeout;
2572 	return res;
2573 }
2574 
2575 
2576 enum sigma_cmd_result dpp_dev_exec_action(struct sigma_dut *dut,
2577 					  struct sigma_conn *conn,
2578 					  struct sigma_cmd *cmd)
2579 {
2580 	const char *type = get_param(cmd, "DPPActionType");
2581 	const char *bs = get_param(cmd, "DPPBS");
2582 
2583 	if (!bs) {
2584 		send_resp(dut, conn, SIGMA_ERROR,
2585 			  "errorCode,Missing DPPBS");
2586 		return STATUS_SENT_ERROR;
2587 	}
2588 
2589 	if (!type) {
2590 		send_resp(dut, conn, SIGMA_ERROR,
2591 			  "errorCode,Missing DPPActionType");
2592 		return STATUS_SENT_ERROR;
2593 	}
2594 
2595 	if (strcasecmp(type, "GetLocalBootstrap") == 0)
2596 		return dpp_get_local_bootstrap(dut, conn, cmd, 1, NULL);
2597 	if (strcasecmp(type, "SetPeerBootstrap") == 0)
2598 		return dpp_set_peer_bootstrap(dut, conn, cmd);
2599 	if (strcasecmp(type, "ManualDPP") == 0)
2600 		return dpp_manual_dpp(dut, conn, cmd);
2601 	if (strcasecmp(type, "AutomaticDPP") == 0)
2602 		return dpp_automatic_dpp(dut, conn, cmd);
2603 
2604 	send_resp(dut, conn, SIGMA_ERROR,
2605 		  "errorCode,Unsupported DPPActionType");
2606 	return STATUS_SENT_ERROR;
2607 }
2608