xref: /wlan-dirver/utils/sigma-dut/dev.c (revision 314b9c65f32c7b1de9faa8bf8dd2bf696922ccc4)
1 /*
2  * Sigma Control API DUT (station/AP/sniffer)
3  * Copyright (c) 2011-2013, 2017, Qualcomm Atheros, Inc.
4  * Copyright (c) 2018-2019, 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 <ctype.h>
11 #include "miracast.h"
12 #include <sys/wait.h>
13 #include "wpa_ctrl.h"
14 #include "wpa_helpers.h"
15 
16 
17 extern char *sigma_cert_path;
18 
19 
cmd_dev_send_frame(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)20 static enum sigma_cmd_result cmd_dev_send_frame(struct sigma_dut *dut,
21 						struct sigma_conn *conn,
22 						struct sigma_cmd *cmd)
23 {
24 #ifdef MIRACAST
25 	const char *program = get_param(cmd, "Program");
26 
27 	if (program && (strcasecmp(program, "WFD") == 0 ||
28 			strcasecmp(program, "DisplayR2") == 0))
29 		return miracast_dev_send_frame(dut, conn, cmd);
30 #endif /* MIRACAST */
31 
32 	if (dut->mode == SIGMA_MODE_STATION ||
33 	    dut->mode == SIGMA_MODE_UNKNOWN) {
34 		sigma_dut_print(dut, DUT_MSG_DEBUG, "Convert "
35 				"dev_send_frame to sta_send_frame");
36 		return cmd_sta_send_frame(dut, conn, cmd);
37 	}
38 
39 	if (dut->mode == SIGMA_MODE_AP) {
40 		sigma_dut_print(dut, DUT_MSG_DEBUG, "Convert "
41 				"dev_send_frame to ap_send_frame");
42 		return cmd_ap_send_frame(dut, conn, cmd);
43 	}
44 
45 #ifdef CONFIG_WLANTEST
46 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Convert dev_send_frame to "
47 			"wlantest_send_frame");
48 	return cmd_wlantest_send_frame(dut, conn, cmd);
49 #else /* CONFIG_WLANTEST */
50 	send_resp(dut, conn, SIGMA_ERROR,
51 		  "errorCode,Unsupported dev_send_frame");
52 	return STATUS_SENT;
53 #endif /* CONFIG_WLANTEST */
54 }
55 
56 
cmd_dev_set_parameter(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)57 static enum sigma_cmd_result cmd_dev_set_parameter(struct sigma_dut *dut,
58 						   struct sigma_conn *conn,
59 						   struct sigma_cmd *cmd)
60 {
61 	const char *device = get_param(cmd, "Device");
62 
63 	if (device && strcasecmp(device, "STA") == 0) {
64 		sigma_dut_print(dut, DUT_MSG_DEBUG, "Convert "
65 				"dev_set_parameter to sta_set_parameter");
66 		return cmd_sta_set_parameter(dut, conn, cmd);
67 	}
68 
69 	return INVALID_SEND_STATUS;
70 }
71 
72 
sta_server_cert_trust(struct sigma_dut * dut,struct sigma_conn * conn,const char * val)73 static enum sigma_cmd_result sta_server_cert_trust(struct sigma_dut *dut,
74 						   struct sigma_conn *conn,
75 						   const char *val)
76 {
77 	char buf[200];
78 	struct wpa_ctrl *ctrl = NULL;
79 	int e;
80 	char resp[200];
81 	int num_disconnected = 0;
82 	int tod = -1;
83 
84 	strlcpy(resp, "ServerCertTrustResult,Accepted", sizeof(resp));
85 
86 	if (strcasecmp(val, "Accept") != 0 && strcasecmp(val, "Reject") != 0) {
87 		sigma_dut_print(dut, DUT_MSG_INFO,
88 				"Unknown ServerCertTrust value '%s'", val);
89 		return INVALID_SEND_STATUS;
90 	}
91 
92 	snprintf(buf, sizeof(buf), "%s/uosc-disabled", sigma_cert_path);
93 	if (file_exists(buf)) {
94 		strlcpy(resp,
95 			"ServerCertTrustResult,OverrideNotAllowed,Reason,UOSC disabled on device",
96 			sizeof(resp));
97 		goto done;
98 	}
99 
100 	if (!dut->server_cert_hash[0]) {
101 		strlcpy(resp,
102 			"ServerCertTrustResult,OverrideNotAllowed,Reason,No server certificate stored",
103 			sizeof(resp));
104 		goto done;
105 	}
106 
107 	if (dut->sta_tod_policy) {
108 		strlcpy(resp,
109 			"ServerCertTrustResult,OverrideNotAllowed,Reason,TOD policy",
110 			sizeof(resp));
111 		goto done;
112 	}
113 
114 	if (dut->server_cert_tod == 1) {
115 		strlcpy(resp,
116 			"ServerCertTrustResult,OverrideNotAllowed,Reason,TOD-STRICT policy in received server certificate",
117 			sizeof(resp));
118 		goto done;
119 	}
120 
121 	if (strcasecmp(val, "Accept") != 0) {
122 		strlcpy(resp, "ServerCertTrustResult,Rejected", sizeof(resp));
123 		goto done;
124 	}
125 
126 	snprintf(buf, sizeof(buf), "hash://server/sha256/%s",
127 		 dut->server_cert_hash);
128 	if (set_network_quoted(get_station_ifname(dut), dut->infra_network_id,
129 			       "ca_cert", buf) < 0) {
130 		strlcpy(resp,
131 			"ServerCertTrustResult,OverrideNotAllowed,Reason,Could not configure server certificate hash for the network profile",
132 			sizeof(resp));
133 		goto done;
134 	}
135 
136 	if (set_network(get_station_ifname(dut), dut->infra_network_id,
137 			"domain_match", "NULL") < 0 ||
138 	    set_network(get_station_ifname(dut), dut->infra_network_id,
139 			"domain_suffix_match", "NULL") < 0) {
140 		strlcpy(resp,
141 			"ServerCertTrustResult,OverrideNotAllowed,Reason,Could not clear domain matching rules",
142 			sizeof(resp));
143 		goto done;
144 	}
145 
146 	wpa_command(get_station_ifname(dut), "DISCONNECT");
147 	snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", dut->infra_network_id);
148 	if (wpa_command(get_station_ifname(dut), buf) < 0) {
149 		sigma_dut_print(dut, DUT_MSG_INFO, "Failed to select "
150 				"network id %d on %s",
151 				dut->infra_network_id,
152 				get_station_ifname(dut));
153 		strlcpy(resp,
154 			"ServerCertTrustResult,Accepted,Result,Could not request reconnection",
155 			sizeof(resp));
156 		goto done;
157 	}
158 
159 	ctrl = open_wpa_mon(get_station_ifname(dut));
160 	if (!ctrl)
161 		goto done;
162 
163 	for (e = 0; e < 20; e++) {
164 		const char *events[] = {
165 			"CTRL-EVENT-EAP-PEER-CERT",
166 			"CTRL-EVENT-EAP-TLS-CERT-ERROR",
167 			"CTRL-EVENT-DISCONNECTED",
168 			"CTRL-EVENT-CONNECTED",
169 			NULL
170 		};
171 		char buf[1024];
172 		int res;
173 
174 		res = get_wpa_cli_events(dut, ctrl, events, buf, sizeof(buf));
175 		if (res < 0) {
176 			strlcpy(resp,
177 				"ServerCertTrustResult,Accepted,Result,Association did not complete",
178 				sizeof(resp));
179 			goto done;
180 		}
181 		sigma_dut_print(dut, DUT_MSG_DEBUG, "Connection event: %s",
182 				buf);
183 
184 
185 		if (strstr(buf, "CTRL-EVENT-EAP-PEER-CERT") &&
186 		    strstr(buf, " depth=0")) {
187 			char *pos = strstr(buf, " hash=");
188 
189 			if (pos) {
190 				if (strstr(buf, " tod=1"))
191 					tod = 1;
192 				else if (strstr(buf, " tod=2"))
193 					tod = 2;
194 				else
195 					tod = 0;
196 				sigma_dut_print(dut, DUT_MSG_DEBUG,
197 						"Server certificate TOD policy: %d",
198 						tod);
199 				dut->server_cert_tod = tod;
200 			}
201 		}
202 
203 		if (strstr(buf, "CTRL-EVENT-EAP-TLS-CERT-ERROR")) {
204 			strlcpy(resp,
205 				"ServerCertTrustResult,Accepted,Result,TLS server certificate validation failed with updated profile",
206 				sizeof(resp));
207 			goto done;
208 		}
209 
210 		if (strstr(buf, "CTRL-EVENT-DISCONNECTED")) {
211 			num_disconnected++;
212 
213 			if (num_disconnected > 2) {
214 				strlcpy(resp,
215 					"ServerCertTrustResult,Accepted,Result,Connection failed",
216 					sizeof(resp));
217 				goto done;
218 			}
219 		}
220 
221 		if (strstr(buf, "CTRL-EVENT-CONNECTED")) {
222 			if (tod >= 0) {
223 				sigma_dut_print(dut, DUT_MSG_DEBUG,
224 						"Network profile TOD policy update: %d -> %d",
225 						dut->sta_tod_policy, tod);
226 				dut->sta_tod_policy = tod;
227 			}
228 			strlcpy(resp,
229 				"ServerCertTrustResult,Accepted,Result,Connected",
230 				sizeof(resp));
231 			break;
232 		}
233 	}
234 
235 done:
236 	if (ctrl) {
237 		wpa_ctrl_detach(ctrl);
238 		wpa_ctrl_close(ctrl);
239 	}
240 
241 	send_resp(dut, conn, SIGMA_COMPLETE, resp);
242 	return STATUS_SENT;
243 }
244 
245 
dev_exec_key_rotation(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)246 static enum sigma_cmd_result dev_exec_key_rotation(struct sigma_dut *dut,
247 						   struct sigma_conn *conn,
248 						   struct sigma_cmd *cmd)
249 {
250 	if (dut->mode == SIGMA_MODE_AP ||
251 	    dut->mode == SIGMA_MODE_UNKNOWN) {
252 		const char *ifname;
253 
254 		ifname = get_hostapd_ifname(dut);
255 		if (hapd_command(ifname, "REKEY_GTK") < 0) {
256 			send_resp(dut, conn, SIGMA_ERROR,
257 				  "errorCode,Failed to request hostapd to rekey GTK");
258 			return STATUS_SENT_ERROR;
259 		}
260 		return SUCCESS_SEND_STATUS;
261 	} else if (dut->mode == SIGMA_MODE_STATION) {
262 		const char *intf = get_param(cmd, "Interface");
263 
264 		if (!intf)
265 			intf = get_main_ifname(dut);
266 		if (wpa_command(intf, "KEY_REQUEST 0 0") != 0) {
267 			send_resp(dut, conn, SIGMA_ERROR,
268 				  "errorCode,Failed to request wpa_supplicant to request AP to rekey GTK");
269 			return STATUS_SENT_ERROR;
270 		}
271 		return SUCCESS_SEND_STATUS;
272 	} else {
273 		send_resp(dut, conn, SIGMA_ERROR,
274 			  "errorCode,Unsupported mode for KeyRotation,1");
275 		return STATUS_SENT_ERROR;
276 	}
277 }
278 
279 
wpa3_dev_exec_action(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)280 static enum sigma_cmd_result wpa3_dev_exec_action(struct sigma_dut *dut,
281 						  struct sigma_conn *conn,
282 						  struct sigma_cmd *cmd)
283 {
284 	const char *val;
285 	char buf[4000], buf2[100], *pos, *end;
286 
287 	val = get_param(cmd, "Rejected_DH_Groups");
288 	if (val) {
289 		val = get_param(cmd, "Dest_MAC");
290 		if (!val)
291 			return ERROR_SEND_STATUS;
292 		snprintf(buf2, sizeof(buf2), "STA %s", val);
293 		if (wpa_command_resp(dut->hostapd_ifname, buf2,
294 				     buf, sizeof(buf)) < 0)
295 			return ERROR_SEND_STATUS;
296 		pos = buf;
297 		while (pos) {
298 			if (strncmp(pos, "sae_rejected_groups=", 20) == 0)
299 				break;
300 			pos = strchr(pos, '\n');
301 			if (pos)
302 				pos++;
303 		}
304 		if (pos) {
305 			pos += 20;
306 			end = strchr(pos, '\n');
307 			if (end)
308 				*end = '\0';
309 		}
310 		snprintf(buf2, sizeof(buf2), "DHGroupVerResult,%s",
311 			 pos ? pos : "");
312 		send_resp(dut, conn, SIGMA_COMPLETE, buf2);
313 		return STATUS_SENT;
314 	}
315 
316 	val = get_param(cmd, "KeyRotation");
317 	if (val && atoi(val) == 1)
318 		return dev_exec_key_rotation(dut, conn, cmd);
319 
320 	return ERROR_SEND_STATUS;
321 }
322 
323 
cmd_dev_exec_action(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)324 static enum sigma_cmd_result cmd_dev_exec_action(struct sigma_dut *dut,
325 						 struct sigma_conn *conn,
326 						 struct sigma_cmd *cmd)
327 {
328 	const char *program = get_param(cmd, "Program");
329 	const char *val;
330 
331 #ifdef MIRACAST
332 	if (program && (strcasecmp(program, "WFD") == 0 ||
333 			strcasecmp(program, "DisplayR2") == 0)) {
334 		if (get_param(cmd, "interface") == NULL)
335 			return INVALID_SEND_STATUS;
336 		return miracast_dev_exec_action(dut, conn, cmd);
337 	}
338 #endif /* MIRACAST */
339 
340 	if (program && strcasecmp(program, "DPP") == 0)
341 		return dpp_dev_exec_action(dut, conn, cmd);
342 
343 	val = get_param(cmd, "ServerCertTrust");
344 	if (val)
345 		return sta_server_cert_trust(dut, conn, val);
346 
347 	if (program && strcasecmp(program, "WPA3") == 0)
348 		return wpa3_dev_exec_action(dut, conn, cmd);
349 
350 	return ERROR_SEND_STATUS;
351 }
352 
353 
cmd_dev_configure_ie(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)354 static enum sigma_cmd_result cmd_dev_configure_ie(struct sigma_dut *dut,
355 						  struct sigma_conn *conn,
356 						  struct sigma_cmd *cmd)
357 {
358 	const char *ie_name = get_param(cmd, "IE_Name");
359 	const char *contents = get_param(cmd, "Contents");
360 
361 	if (!ie_name || !contents)
362 		return INVALID_SEND_STATUS;
363 
364 	if (strcasecmp(ie_name, "RSNE") != 0) {
365 		send_resp(dut, conn, SIGMA_ERROR,
366 			  "errorCode,Unsupported IE_Name value");
367 		return STATUS_SENT;
368 	}
369 
370 	free(dut->rsne_override);
371 	dut->rsne_override = strdup(contents);
372 
373 	return dut->rsne_override ? SUCCESS_SEND_STATUS : ERROR_SEND_STATUS;
374 }
375 
376 
cmd_dev_ble_action(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)377 static enum sigma_cmd_result cmd_dev_ble_action(struct sigma_dut *dut,
378 						struct sigma_conn *conn,
379 						struct sigma_cmd *cmd)
380 {
381 #ifdef ANDROID
382 	const char *ble_op = get_param(cmd, "BLEOp");
383 	const char *prog = get_param(cmd, "Prog");
384 	const char *service_name = get_param(cmd, "ServiceName");
385 	const char *ble_role = get_param(cmd, "BLERole");
386 	const char *discovery_type = get_param(cmd, "DiscoveryType");
387 	const char *msg_type = get_param(cmd, "messagetype");
388 	const char *action = get_param(cmd, "action");
389 	const char *M2Transmit = get_param(cmd, "M2Transmit");
390 	char *argv[17];
391 	pid_t pid;
392 
393 	if (prog && ble_role && action && msg_type) {
394 		send_resp(dut, conn, SIGMA_COMPLETE,
395 			  "OrgID,0x00,TransDataHeader,0x00,BloomFilterElement,NULL");
396 		return STATUS_SENT;
397 	}
398 	if (!ble_op || !prog || !service_name || !ble_role || !discovery_type) {
399 		sigma_dut_print(dut, DUT_MSG_ERROR, "Invalid arguments");
400 		return INVALID_SEND_STATUS;
401 	}
402 
403 	if ((strcasecmp(prog, "NAN") != 0)) {
404 		sigma_dut_print(dut, DUT_MSG_ERROR, "Program %s not supported",
405 				prog);
406 		return INVALID_SEND_STATUS;
407 	}
408 
409 	if (strcasecmp(ble_role, "seeker") != 0 &&
410 	    strcasecmp(ble_role, "provider") != 0 &&
411 	    strcasecmp(ble_role, "browser") != 0) {
412 		sigma_dut_print(dut, DUT_MSG_ERROR, "Invalid BLERole: %s",
413 				ble_role);
414 		return INVALID_SEND_STATUS;
415 	}
416 
417 	if (strcasecmp(discovery_type, "active") != 0 &&
418 	    strcasecmp(discovery_type, "passive") != 0) {
419 		sigma_dut_print(dut, DUT_MSG_ERROR, "Invalid DiscoveryType: %s",
420 				discovery_type);
421 		return INVALID_SEND_STATUS;
422 	}
423 
424 	if (!M2Transmit)
425 		M2Transmit = "disable";
426 
427 	argv[0] = "am";
428 	argv[1] = "start";
429 	argv[2] = "-n";
430 	argv[3] = "org.codeaurora.nanservicediscovery/org.codeaurora.nanservicediscovery.MainActivity";
431 	argv[4] = "--es";
432 	argv[5] = "service";
433 	argv[6] = (char *) service_name;
434 	argv[7] = "--es";
435 	argv[8] = "role";
436 	argv[9] = (char *) ble_role;
437 	argv[10] = "--es";
438 	argv[11] = "scantype";
439 	argv[12] = (char *) discovery_type;
440 	argv[13] = "--es";
441 	argv[14] = "M2Transmit";
442 	argv[15] = (char *) M2Transmit;
443 	argv[16] = NULL;
444 
445 	pid = fork();
446 	if (pid == -1) {
447 		sigma_dut_print(dut, DUT_MSG_ERROR, "fork: %s",
448 				strerror(errno));
449 		return ERROR_SEND_STATUS;
450 	}
451 
452 	if (pid == 0) {
453 		execv("/system/bin/am", argv);
454 		sigma_dut_print(dut, DUT_MSG_ERROR, "execv: %s",
455 				strerror(errno));
456 		exit(0);
457 		return ERROR_SEND_STATUS;
458 	}
459 
460 	dut->nanservicediscoveryinprogress = 1;
461 #endif /* ANDROID */
462 
463 	return SUCCESS_SEND_STATUS;
464 }
465 
466 
467 /* Runtime ID must contain only numbers */
is_runtime_id_valid(struct sigma_dut * dut,const char * val)468 static int is_runtime_id_valid(struct sigma_dut *dut, const char *val)
469 {
470 	int i;
471 
472 	for (i = 0; val[i] != '\0'; i++) {
473 		if (!isdigit(val[i])) {
474 			sigma_dut_print(dut, DUT_MSG_DEBUG,
475 					"Invalid Runtime_ID %s", val);
476 			return 0;
477 		}
478 	}
479 
480 	return 1;
481 }
482 
483 
build_log_dir(struct sigma_dut * dut,char * dir,size_t dir_size)484 static int build_log_dir(struct sigma_dut *dut, char *dir, size_t dir_size)
485 {
486 	int res;
487 	const char *vendor = dut->vendor_name;
488 	int i;
489 
490 	if (!vendor)
491 		return -1;
492 
493 	if (dut->log_file_dir) {
494 		res = snprintf(dir, dir_size, "%s/%s", dut->log_file_dir,
495 			       vendor);
496 	} else {
497 #ifdef ANDROID
498 		res = snprintf(dir, dir_size, "/data/vendor/wifi/%s",
499 			       vendor);
500 #else /* ANDROID */
501 		res = snprintf(dir, dir_size, "/var/log/%s", vendor);
502 #endif /* ANDROID */
503 	}
504 
505 	if (res < 0 || res >= dir_size)
506 		return -1;
507 
508 	/* Check for valid vendor name in log dir path since the log dir
509 	 * (/var/log/vendor) is deleted in dev_stop routine. This check is to
510 	 * avoid any unintended file deletion.
511 	 */
512 	for (i = 0; vendor[i] != '\0'; i++) {
513 		if (!isalpha(vendor[i])) {
514 			sigma_dut_print(dut, DUT_MSG_DEBUG,
515 					"Invalid char %c in vendor name %s",
516 					vendor[i], vendor);
517 			return -1;
518 		}
519 	}
520 
521 	return 0;
522 }
523 
524 
525 /* User has to redirect wpa_supplicant logs to the following file. */
526 #ifndef WPA_SUPPLICANT_LOG_FILE
527 #define WPA_SUPPLICANT_LOG_FILE "/var/log/supplicant_log/wpa_log.txt"
528 #endif /* WPA_SUPPLICANT_LOG_FILE */
529 
cmd_dev_start_test(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)530 static enum sigma_cmd_result cmd_dev_start_test(struct sigma_dut *dut,
531 						struct sigma_conn *conn,
532 						struct sigma_cmd *cmd)
533 {
534 	const char *val;
535 	char buf[250];
536 	char dir[200];
537 	FILE *supp_log;
538 	int res;
539 
540 	val = get_param(cmd, "Runtime_ID");
541 	if (!(val && is_runtime_id_valid(dut, val)))
542 		return INVALID_SEND_STATUS;
543 
544 	if (!dut->vendor_name) {
545 		sigma_dut_print(dut, DUT_MSG_INFO,
546 				"Log collection not supported without vendor name specified on the command line (-N)");
547 		return SUCCESS_SEND_STATUS;
548 	}
549 
550 	if (build_log_dir(dut, dir, sizeof(dir)) < 0)
551 		return ERROR_SEND_STATUS;
552 
553 	supp_log = fopen(WPA_SUPPLICANT_LOG_FILE, "r");
554 	if (!supp_log) {
555 		sigma_dut_print(dut, DUT_MSG_ERROR,
556 				"Failed to open wpa_log file %s",
557 				WPA_SUPPLICANT_LOG_FILE);
558 	} else {
559 		/* Get the wpa_supplicant log file size */
560 		if (fseek(supp_log, 0, SEEK_END))
561 			sigma_dut_print(dut, DUT_MSG_ERROR,
562 					"Failed to get file size for read");
563 		else
564 			dut->wpa_log_size = ftell(supp_log);
565 
566 		fclose(supp_log);
567 	}
568 
569 	strlcpy(dut->dev_start_test_runtime_id, val,
570 		sizeof(dut->dev_start_test_runtime_id));
571 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Runtime_ID %s",
572 			dut->dev_start_test_runtime_id);
573 
574 	run_system_wrapper(dut, "rm -rf %s", dir);
575 	run_system_wrapper(dut, "mkdir -p %s", dir);
576 
577 #ifdef ANDROID
578 	run_system_wrapper(dut, "logcat -v time > %s/logcat_%s.txt &",
579 			   dir, dut->dev_start_test_runtime_id);
580 #else /* ANDROID */
581 	/* Open log file for sigma_dut logs. This is not needed for Android, as
582 	 * we are already collecting logcat. */
583 	res = snprintf(buf, sizeof(buf), "%s/sigma_%s.txt", dir,
584 		       dut->dev_start_test_runtime_id);
585 	if (res >= 0 && res < sizeof(buf)) {
586 		if (dut->log_file_fd)
587 			fclose(dut->log_file_fd);
588 
589 		dut->log_file_fd = fopen(buf, "a");
590 		if (!dut->log_file_fd)
591 			sigma_dut_print(dut, DUT_MSG_ERROR,
592 					"Failed to create sigma_dut log %s",
593 					buf);
594 	}
595 
596 	run_system_wrapper(dut, "killall -9 cnss_diag_lite");
597 	run_system_wrapper(dut,
598 			   "cnss_diag_lite -c -x 31 > %s/cnss_diag_id_%s.txt &",
599 			   dir, dut->dev_start_test_runtime_id);
600 #endif /* ANDROID */
601 
602 	return SUCCESS_SEND_STATUS;
603 }
604 
605 
is_allowed_char(char ch)606 static int is_allowed_char(char ch)
607 {
608 	return strchr("./-_", ch) != NULL;
609 }
610 
611 
is_destpath_valid(struct sigma_dut * dut,const char * val)612 static int is_destpath_valid(struct sigma_dut *dut, const char *val)
613 {
614 	int i;
615 
616 	for (i = 0; val[i] != '\0'; i++) {
617 		if (!(isalnum(val[i]) || is_allowed_char(val[i]))) {
618 			sigma_dut_print(dut, DUT_MSG_DEBUG,
619 					"Invalid char %c in destpath %s",
620 					val[i], val);
621 			return 0;
622 		}
623 	}
624 
625 	return 1;
626 }
627 
628 
629 #ifndef ANDROID
630 #define SUPP_LOG_BUFF_SIZE 4 * 1024
631 
save_supplicant_log(struct sigma_dut * dut)632 static int save_supplicant_log(struct sigma_dut *dut)
633 {
634 	char dir[200];
635 	char buf[300];
636 	FILE *wpa_log = NULL;
637 	FILE *supp_log;
638 	char *buff_ptr = NULL;
639 	unsigned int file_size;
640 	unsigned int file_size_orig;
641 	int status = -1, res;
642 
643 	if (build_log_dir(dut, dir, sizeof(dir)) < 0)
644 		return -1;
645 
646 	res = snprintf(buf, sizeof(buf), "%s/wpa_supplicant_log_%s.txt", dir,
647 		       dut->dev_start_test_runtime_id);
648 	if (res < 0 || res >= sizeof(buf))
649 		return -1;
650 
651 	supp_log = fopen(WPA_SUPPLICANT_LOG_FILE, "r");
652 	if (!supp_log) {
653 		sigma_dut_print(dut, DUT_MSG_ERROR,
654 				"Failed to open wpa_log file %s",
655 				WPA_SUPPLICANT_LOG_FILE);
656 		return -1;
657 	}
658 
659 	/* Get the wpa_supplicant log file size */
660 	if (fseek(supp_log, 0, SEEK_END)) {
661 		sigma_dut_print(dut, DUT_MSG_ERROR,
662 				"Failed to get file size for read");
663 		goto exit;
664 	}
665 	file_size_orig = ftell(supp_log);
666 
667 	if (file_size_orig < dut->wpa_log_size) {
668 		sigma_dut_print(dut, DUT_MSG_ERROR,
669 				"file size err, new size %u, old size %u",
670 				file_size_orig, dut->wpa_log_size);
671 		goto exit;
672 	}
673 
674 	/* Get the wpa_supplicant file size for current test */
675 	file_size = file_size_orig - dut->wpa_log_size;
676 
677 	wpa_log = fopen(buf, "w");
678 	if (!wpa_log) {
679 		sigma_dut_print(dut, DUT_MSG_ERROR,
680 				"Failed to create tmp wpa_log file %s", buf);
681 		goto exit;
682 	}
683 
684 	if (fseek(supp_log, dut->wpa_log_size, SEEK_SET)) {
685 		sigma_dut_print(dut, DUT_MSG_ERROR,
686 				"Failed to set wpa_log file ptr for read");
687 		goto exit;
688 	}
689 
690 	buff_ptr = malloc(SUPP_LOG_BUFF_SIZE);
691 	if (!buff_ptr) {
692 		sigma_dut_print(dut, DUT_MSG_ERROR,
693 				"Failed to alloc buffer of size %d",
694 				SUPP_LOG_BUFF_SIZE);
695 		goto exit;
696 	}
697 
698 	/* Read wpa_supplicant log file in 4K byte chunks */
699 	do {
700 		unsigned int num_bytes_to_read;
701 		unsigned int bytes_read;
702 
703 		num_bytes_to_read = (file_size > SUPP_LOG_BUFF_SIZE) ?
704 			SUPP_LOG_BUFF_SIZE : file_size;
705 		bytes_read = fread(buff_ptr, 1, num_bytes_to_read, supp_log);
706 		if (!bytes_read) {
707 			sigma_dut_print(dut, DUT_MSG_ERROR,
708 					"Failed to read wpa_supplicant log");
709 			goto exit;
710 		}
711 		if (bytes_read != num_bytes_to_read) {
712 			sigma_dut_print(dut, DUT_MSG_DEBUG,
713 					"wpa_supplicant log read err, read %d, num_bytes_to_read %d",
714 					bytes_read, num_bytes_to_read);
715 			goto exit;
716 		}
717 		fwrite(buff_ptr, 1, bytes_read, wpa_log);
718 		file_size -= bytes_read;
719 	} while (file_size > 0);
720 	status = 0;
721 
722 exit:
723 	if (wpa_log)
724 		fclose(wpa_log);
725 	fclose(supp_log);
726 	free(buff_ptr);
727 
728 	return status;
729 }
730 #endif /* !ANDROID */
731 
732 
cmd_dev_stop_test(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)733 static enum sigma_cmd_result cmd_dev_stop_test(struct sigma_dut *dut,
734 					       struct sigma_conn *conn,
735 					       struct sigma_cmd *cmd)
736 {
737 	const char *val;
738 	char buf[300];
739 	char out_file[100];
740 	char dir[200];
741 	int res;
742 
743 	if (!dut->vendor_name) {
744 		sigma_dut_print(dut, DUT_MSG_INFO,
745 				"Log collection not supported without vendor name specified on the command line (-N)");
746 		return SUCCESS_SEND_STATUS;
747 	}
748 
749 	val = get_param(cmd, "Runtime_ID");
750 	if (!val || strcmp(val, dut->dev_start_test_runtime_id) != 0) {
751 		sigma_dut_print(dut, DUT_MSG_ERROR, "Invalid runtime id");
752 		return ERROR_SEND_STATUS;
753 	}
754 
755 	if (build_log_dir(dut, dir, sizeof(dir)) < 0)
756 		return ERROR_SEND_STATUS;
757 
758 #ifdef ANDROID
759 	/* Copy all cnss_diag logs to dir */
760 	run_system_wrapper(dut, "cp -a /data/vendor/wifi/wlan_logs/* %s", dir);
761 #else /* ANDROID */
762 	if (dut->log_file_fd) {
763 		fclose(dut->log_file_fd);
764 		dut->log_file_fd = NULL;
765 	}
766 	if (save_supplicant_log(dut))
767 		sigma_dut_print(dut, DUT_MSG_ERROR,
768 				"Failed to save wpa_supplicant log");
769 #endif /* ANDROID */
770 
771 	res = snprintf(out_file, sizeof(out_file), "%s_%s_%s.tar.gz",
772 		       dut->vendor_name,
773 		       dut->model_name ? dut->model_name : "Unknown",
774 		       dut->dev_start_test_runtime_id);
775 	if (res < 0 || res >= sizeof(out_file))
776 	    return ERROR_SEND_STATUS;
777 
778 	if (run_system_wrapper(dut, "tar -czvf %s/../%s %s", dir, out_file,
779 			       dir) < 0) {
780 		sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to create tar: %s",
781 				buf);
782 		return ERROR_SEND_STATUS;
783 	}
784 
785 	val = get_param(cmd, "destpath");
786 	if (!(val && is_destpath_valid(dut, val))) {
787 		sigma_dut_print(dut, DUT_MSG_DEBUG, "Invalid path for TFTP %s",
788 				val);
789 		return ERROR_SEND_STATUS;
790 	}
791 
792 	res = snprintf(buf, sizeof(buf), "tftp %s -c put %s/%s %s/%s",
793 		       inet_ntoa(conn->addr.sin_addr), dir, out_file, val,
794 		       out_file);
795 	if (res < 0 || res >= sizeof(buf))
796 		return ERROR_SEND_STATUS;
797 	if (run_system_wrapper(dut, buf) < 0) {
798 		sigma_dut_print(dut, DUT_MSG_ERROR,
799 				"TFTP file transfer failed: %s", buf);
800 		return ERROR_SEND_STATUS;
801 	}
802 	sigma_dut_print(dut, DUT_MSG_DEBUG, "TFTP file transfer: %s", buf);
803 	snprintf(buf, sizeof(buf), "filename,%s", out_file);
804 	send_resp(dut, conn, SIGMA_COMPLETE, buf);
805 	run_system_wrapper(dut, "rm -f %s/../%s", dir, out_file);
806 	run_system_wrapper(dut, "rm -rf %s", dir);
807 
808 	return SUCCESS_SEND_STATUS;
809 }
810 
811 
cmd_dev_get_log(struct sigma_dut * dut,struct sigma_conn * conn,struct sigma_cmd * cmd)812 static enum sigma_cmd_result cmd_dev_get_log(struct sigma_dut *dut,
813 					     struct sigma_conn *conn,
814 					     struct sigma_cmd *cmd)
815 {
816 	return SUCCESS_SEND_STATUS;
817 }
818 
819 
req_intf(struct sigma_cmd * cmd)820 static int req_intf(struct sigma_cmd *cmd)
821 {
822 	return get_param(cmd, "interface") == NULL ? -1 : 0;
823 }
824 
825 
req_role_svcname(struct sigma_cmd * cmd)826 static int req_role_svcname(struct sigma_cmd *cmd)
827 {
828 	if (!get_param(cmd, "BLERole"))
829 		 return -1;
830 	if (get_param(cmd, "BLEOp") && !get_param(cmd, "ServiceName"))
831 		return -1;
832 	return 0;
833 }
834 
835 
req_intf_prog(struct sigma_cmd * cmd)836 static int req_intf_prog(struct sigma_cmd *cmd)
837 {
838 	if (get_param(cmd, "interface") == NULL)
839 		return -1;
840 	if (get_param(cmd, "program") == NULL)
841 		return -1;
842 	return 0;
843 }
844 
845 
req_prog(struct sigma_cmd * cmd)846 static int req_prog(struct sigma_cmd *cmd)
847 {
848 	if (get_param(cmd, "program") == NULL)
849 		return -1;
850 	return 0;
851 }
852 
853 
dev_register_cmds(void)854 void dev_register_cmds(void)
855 {
856 	sigma_dut_reg_cmd("dev_send_frame", req_prog, cmd_dev_send_frame);
857 	sigma_dut_reg_cmd("dev_set_parameter", req_intf_prog,
858 			  cmd_dev_set_parameter);
859 	sigma_dut_reg_cmd("dev_exec_action", req_prog,
860 			  cmd_dev_exec_action);
861 	sigma_dut_reg_cmd("dev_configure_ie", req_intf, cmd_dev_configure_ie);
862 	sigma_dut_reg_cmd("dev_start_test", NULL, cmd_dev_start_test);
863 	sigma_dut_reg_cmd("dev_stop_test", NULL, cmd_dev_stop_test);
864 	sigma_dut_reg_cmd("dev_get_log", NULL, cmd_dev_get_log);
865 	sigma_dut_reg_cmd("dev_ble_action", req_role_svcname,
866 			  cmd_dev_ble_action);
867 }
868