xref: /wlan-dirver/utils/sigma-dut/sigma_dut.c (revision affdb1b8c387503b72afa0d73af0f183236733ef)
1 /*
2  * Sigma Control API DUT (station/AP)
3  * Copyright (c) 2010-2011, Atheros Communications, Inc.
4  * Copyright (c) 2011-2017, Qualcomm Atheros, Inc.
5  * Copyright (c) 2018-2019, The Linux Foundation
6  * All Rights Reserved.
7  * Licensed under the Clear BSD license. See README for more details.
8  */
9 
10 #include "sigma_dut.h"
11 #ifdef __linux__
12 #include <signal.h>
13 #include <netinet/tcp.h>
14 #endif /* __linux__ */
15 #include "wpa_ctrl.h"
16 #include "wpa_helpers.h"
17 #include "miracast.h"
18 
19 #define SIGMA_DUT_PORT 9000
20 #define MAX_CONNECTIONS 4
21 
22 extern enum driver_type wifi_chip_type;
23 
24 static struct sigma_dut sigma_dut;
25 
26 char *sigma_main_ifname = NULL;
27 char *sigma_radio_ifname[MAX_RADIO] = {};
28 char *sigma_station_ifname = NULL;
29 char *sigma_p2p_ifname = NULL;
30 static char *sigma_p2p_ifname_buf = NULL;
31 char *sigma_wpas_ctrl = "/var/run/wpa_supplicant/";
32 char *sigma_hapd_ctrl = NULL;
33 char *client_socket_path = NULL;
34 char *ap_inet_addr = "192.168.43.1";
35 char *ap_inet_mask = "255.255.255.0";
36 char *sigma_cert_path = "/etc/wpa_supplicant";
37 
38 /* For WMM-AC testing this set to 1 through argument,
39  * otherwise default WMM-PS 0 */
40 int sigma_wmm_ac = 0;
41 
42 
43 #ifdef ANDROID
44 #include <android/log.h>
45 
46 #ifdef ANDROID_WIFI_HAL
47 
48 static void * wifi_hal_event_thread(void *ptr)
49 {
50 	struct sigma_dut *dut = ptr;
51 
52 	wifi_event_loop(dut->wifi_hal_handle);
53 	pthread_exit(0);
54 
55 	return NULL;
56 }
57 
58 
59 int wifi_hal_initialize(struct sigma_dut *dut)
60 {
61 	pthread_t thread1;
62 	wifi_error err;
63 
64 	if (dut->wifi_hal_initialized)
65 		return 0;
66 
67 	err = wifi_initialize(&dut->wifi_hal_handle);
68 	if (err) {
69 		sigma_dut_print(dut, DUT_MSG_ERROR,
70 				"wifi hal initialize failed");
71 		return -1;
72 	}
73 
74 	dut->wifi_hal_iface_handle = wifi_get_iface_handle(dut->wifi_hal_handle,
75 							   (char *) "wlan0");
76 	pthread_create(&thread1, NULL, &wifi_hal_event_thread, (void *) dut);
77 	dut->wifi_hal_initialized = true;
78 
79 	return 0;
80 }
81 
82 #endif /* ANDROID_WIFI_HAL */
83 
84 
85 static enum android_LogPriority level_to_android_priority(int level)
86 {
87 	switch (level) {
88 	case DUT_MSG_ERROR:
89 		return ANDROID_LOG_ERROR;
90 	case DUT_MSG_INFO:
91 		return ANDROID_LOG_INFO;
92 	case DUT_MSG_DEBUG:
93 		return ANDROID_LOG_DEBUG;
94 	default:
95 		return ANDROID_LOG_VERBOSE;
96 	}
97 }
98 
99 #endif /* ANDROID */
100 
101 
102 void sigma_dut_print(struct sigma_dut *dut, int level, const char *fmt, ...)
103 {
104 	va_list ap;
105 	struct timeval tv;
106 
107 	if (level < dut->debug_level)
108 		return;
109 
110 	gettimeofday(&tv, NULL);
111 #ifdef ANDROID
112 	va_start(ap, fmt);
113 	__android_log_vprint(level_to_android_priority(level),
114 			     "sigma_dut", fmt, ap);
115 	va_end(ap);
116 	if (!dut->stdout_debug)
117 		return;
118 #else /* ANDROID */
119 	if (dut->log_file_fd) {
120 		va_start(ap, fmt);
121 		fprintf(dut->log_file_fd, "%ld.%06u: ",
122 			(long) tv.tv_sec, (unsigned int) tv.tv_usec);
123 		vfprintf(dut->log_file_fd, fmt, ap);
124 		fprintf(dut->log_file_fd, "\n");
125 		va_end(ap);
126 	}
127 #endif /* ANDROID */
128 
129 	va_start(ap, fmt);
130 	printf("%ld.%06u: ", (long) tv.tv_sec,
131 	       (unsigned int) tv.tv_usec);
132 	vprintf(fmt, ap);
133 	printf("\n");
134 	va_end(ap);
135 }
136 
137 
138 void sigma_dut_summary(struct sigma_dut *dut, const char *fmt, ...)
139 {
140 	va_list ap;
141 	FILE *f;
142 
143 	if (!dut->summary_log)
144 		return;
145 
146 	f = fopen(dut->summary_log, "a");
147 	if (f == NULL)
148 		return;
149 
150 	va_start(ap, fmt);
151 	vfprintf(f, fmt, ap);
152 	fprintf(f, "\n");
153 	va_end(ap);
154 	fclose(f);
155 }
156 
157 
158 int sigma_dut_reg_cmd(const char *cmd,
159 		      int (*validate)(struct sigma_cmd *cmd),
160 		      enum sigma_cmd_result (*process)(struct sigma_dut *dut,
161 						       struct sigma_conn *conn,
162 						       struct sigma_cmd *cmd))
163 {
164 	struct sigma_cmd_handler *h;
165 	size_t clen, len;
166 
167 	for (h = sigma_dut.cmds; h; h = h->next) {
168 		if (strcmp(h->cmd, cmd) == 0) {
169 			printf("ERROR: Duplicate sigma_dut command registration for '%s'\n",
170 			       cmd);
171 			return -1;
172 		}
173 	}
174 
175 	clen = strlen(cmd);
176 	len = sizeof(*h) + clen + 1;
177 	h = malloc(len);
178 	if (h == NULL)
179 		return -1;
180 	memset(h, 0, len);
181 	h->cmd = (char *) (h + 1); /* include in same allocation */
182 	memcpy(h->cmd, cmd, clen);
183 	h->validate = validate;
184 	h->process= process;
185 
186 	h->next = sigma_dut.cmds;
187 	sigma_dut.cmds = h;
188 
189 	return 0;
190 }
191 
192 
193 static void sigma_dut_unreg_cmds(struct sigma_dut *dut)
194 {
195 	struct sigma_cmd_handler *cmd, *prev;
196 	cmd = dut->cmds;
197 	dut->cmds = NULL;
198 	while (cmd) {
199 		prev = cmd;
200 		cmd = cmd->next;
201 		free(prev);
202 	}
203 }
204 
205 
206 static int open_socket(struct sigma_dut *dut, int port)
207 {
208 	struct sockaddr_in addr;
209 #ifndef __QNXNTO__
210 	int val;
211 #endif /* !__QNXNTO__ */
212 
213 #ifdef __QNXNTO__
214 	dut->s = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
215 #else /* __QNXNTO__ */
216 	dut->s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
217 #endif /* __QNXNTO__ */
218 	if (dut->s < 0) {
219 		sigma_dut_print(dut, DUT_MSG_ERROR, "socket: %s",
220 				strerror(errno));
221 		return -1;
222 	}
223 
224 #ifndef __QNXNTO__
225 	val = 1;
226 	if (setsockopt(dut->s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) <
227 	    0)
228 		sigma_dut_print(dut, DUT_MSG_INFO, "setsockopt SO_REUSEADDR: "
229 				"%s", strerror(errno));
230 #endif /* !__QNXNTO__ */
231 
232 #ifdef __linux__
233 	val = 1;
234 	if (setsockopt(dut->s, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) <
235 	    0)
236 		sigma_dut_print(dut, DUT_MSG_INFO, "setsockopt TCP_NODELAY: "
237 				"%s", strerror(errno));
238 #endif /* __linux__ */
239 
240 	memset(&addr, 0, sizeof(addr));
241 	addr.sin_family = AF_INET;
242 	addr.sin_port = htons(port);
243 
244 	if (bind(dut->s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
245 		sigma_dut_print(dut, DUT_MSG_ERROR, "bind: %s",
246 				strerror(errno));
247 		goto fail;
248 	}
249 
250 	if (listen(dut->s, 5) < 0) {
251 		sigma_dut_print(dut, DUT_MSG_ERROR, "listen: %s",
252 				strerror(errno));
253 		goto fail;
254 	}
255 
256 	return 0;
257 
258 fail:
259 	shutdown(dut->s, SHUT_RDWR);
260 	close(dut->s);
261 	dut->s = -1;
262 	return -1;
263 }
264 
265 
266 static void close_socket(struct sigma_dut *dut)
267 {
268 	shutdown(dut->s, SHUT_RDWR);
269 	close(dut->s);
270 	dut->s = -1;
271 }
272 
273 
274 void send_resp(struct sigma_dut *dut, struct sigma_conn *conn,
275 	       enum sigma_status status, const char *buf)
276 {
277 	struct msghdr msg;
278 	struct iovec iov[4];
279 	size_t elems;
280 
281 	if (!conn)
282 		return;
283 
284 	sigma_dut_print(dut, DUT_MSG_INFO, "resp: status=%d buf=%s",
285 			status, buf ? buf : "N/A");
286 
287 	iov[0].iov_base = "status,";
288 	iov[0].iov_len = 7;
289 	switch (status) {
290 	case SIGMA_RUNNING:
291 		iov[1].iov_base = "RUNNING,";
292 		iov[1].iov_len = 8;
293 		break;
294 	case SIGMA_INVALID:
295 		iov[1].iov_base = "INVALID,";
296 		iov[1].iov_len = 8;
297 		break;
298 	case SIGMA_ERROR:
299 		iov[1].iov_base = "ERROR,";
300 		iov[1].iov_len = 6;
301 		break;
302 	case SIGMA_COMPLETE:
303 		iov[1].iov_base = "COMPLETE,";
304 		iov[1].iov_len = 9;
305 		break;
306 	}
307 	if (status != SIGMA_RUNNING) {
308 		sigma_dut_summary(dut, "CAPI resp: status,%s%s",
309 				  (char *) iov[1].iov_base, buf ? buf : "");
310 	}
311 	if (buf) {
312 		iov[2].iov_base = (void *) buf;
313 		iov[2].iov_len = strlen(buf);
314 		iov[3].iov_base = "\r\n";
315 		iov[3].iov_len = 2;
316 		elems = 4;
317 	} else {
318 		iov[1].iov_len--;
319 		iov[2].iov_base = "\r\n";
320 		iov[2].iov_len = 2;
321 		elems = 3;
322 	}
323 
324 	memset(&msg, 0, sizeof(msg));
325 	msg.msg_iov = iov;
326 	msg.msg_iovlen = elems;
327 	if (sendmsg(conn->s, &msg, 0) < 0)
328 		sigma_dut_print(dut, DUT_MSG_INFO, "sendmsg: %s",
329 				strerror(errno));
330 	dut->response_sent++;
331 }
332 
333 
334 const char * get_param(struct sigma_cmd *cmd, const char *name)
335 {
336 	int i;
337 	for (i = 0; i < cmd->count; i++) {
338 		if (strcasecmp(name, cmd->params[i]) == 0)
339 			return cmd->values[i];
340 	}
341 	return NULL;
342 }
343 
344 
345 const char * get_param_indexed(struct sigma_cmd *cmd, const char *name,
346 			       int index)
347 {
348 	int i, j;
349 
350 	for (i = 0, j = 0; i < cmd->count; i++) {
351 		if (strcasecmp(name, cmd->params[i]) == 0) {
352 			j++;
353 			if (j > index)
354 				return cmd->values[i];
355 		}
356 	}
357 
358 	return NULL;
359 }
360 
361 
362 static void process_cmd(struct sigma_dut *dut, struct sigma_conn *conn,
363 			char *buf)
364 {
365 	struct sigma_cmd_handler *h;
366 	struct sigma_cmd c;
367 	char *cmd, *pos, *pos2;
368 	int len;
369 	char txt[300];
370 	enum sigma_cmd_result res;
371 
372 	while (*buf == '\r' || *buf == '\n' || *buf == '\t' || *buf == ' ')
373 		buf++;
374 	len = strlen(buf);
375 	while (len > 0 && buf[len - 1] == ' ') {
376 		buf[len - 1] = '\0';
377 		len--;
378 	}
379 
380 	if (dut->debug_level < DUT_MSG_INFO) {
381 		pos = strchr(buf, ',');
382 		if (pos == NULL)
383 			pos = buf + len;
384 		if (pos - buf > 50)
385 			pos = buf + 50;
386 		memcpy(txt, "/====[ ", 7);
387 		pos2 = txt + 7;
388 		memcpy(pos2, buf, pos - buf);
389 		pos2 += pos - buf;
390 		*pos2++ = ' ';
391 		*pos2++ = ']';
392 		while (pos2 - txt < 70)
393 			*pos2++ = '=';
394 		*pos2++ = '\\';
395 		*pos2 = '\0';
396 		printf("\n%s\n\n", txt);
397 	}
398 
399 	sigma_dut_print(dut, DUT_MSG_INFO, "cmd: %s", buf);
400 	sigma_dut_summary(dut, "CAPI cmd: %s", buf);
401 	snprintf(txt, sizeof(txt), "NOTE CAPI:%s", buf);
402 	txt[sizeof(txt) - 1] = '\0';
403 	wpa_command(get_main_ifname(), txt);
404 
405 	memset(&c, 0, sizeof(c));
406 	cmd = buf;
407 	pos = strchr(cmd, ',');
408 	if (pos) {
409 		*pos++ = '\0';
410 		if (strcasecmp(cmd, "AccessPoint") == 0 ||
411 		    strcasecmp(cmd, "PowerSwitch") == 0) {
412 			pos2 = strchr(pos, ',');
413 			if (pos2 == NULL)
414 				goto invalid_params;
415 			c.params[c.count] = pos;
416 			c.values[c.count] = pos2;
417 			c.count++;
418 			pos = strchr(pos2, ',');
419 			if (pos)
420 				*pos++ = '\0';
421 		}
422 		while (pos) {
423 			pos2 = strchr(pos, ',');
424 			if (pos2 == NULL)
425 				goto invalid_params;
426 			*pos2++ = '\0';
427 			if (c.count == MAX_PARAMS) {
428 				sigma_dut_print(dut, DUT_MSG_INFO, "Too many "
429 						"parameters");
430 				goto invalid_params;
431 			}
432 			c.params[c.count] = pos;
433 			c.values[c.count] = pos2;
434 			c.count++;
435 			pos = strchr(pos2, ',');
436 			if (pos)
437 				*pos++ = '\0';
438 		}
439 	}
440 	h = dut->cmds;
441 	while (h) {
442 		if (strcasecmp(cmd, h->cmd) == 0)
443 			break;
444 		h = h->next;
445 	}
446 
447 	if (h == NULL) {
448 		sigma_dut_print(dut, DUT_MSG_INFO, "Unknown command: '%s'",
449 				cmd);
450 		send_resp(dut, conn, SIGMA_INVALID,
451 			  "errorCode,Unknown command");
452 		goto out;
453 	}
454 
455 	if (h->validate && h->validate(&c) < 0) {
456 	invalid_params:
457 		sigma_dut_print(dut, DUT_MSG_INFO, "Invalid parameters");
458 		send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid "
459 			  "parameters");
460 		goto out;
461 	}
462 
463 	dut->response_sent = 0;
464 	send_resp(dut, conn, SIGMA_RUNNING, NULL);
465 	sigma_dut_print(dut, DUT_MSG_INFO, "Run command: %s", cmd);
466 	res = h->process(dut, conn, &c);
467 	switch (res) {
468 	case ERROR_SEND_STATUS:
469 		send_resp(dut, conn, SIGMA_ERROR, NULL);
470 		break;
471 	case INVALID_SEND_STATUS:
472 		send_resp(dut, conn, SIGMA_INVALID, NULL);
473 		break;
474 	case STATUS_SENT:
475 	case STATUS_SENT_ERROR:
476 		break;
477 	case SUCCESS_SEND_STATUS:
478 		send_resp(dut, conn, SIGMA_COMPLETE, NULL);
479 		break;
480 	}
481 
482 	if (!conn->waiting_completion && dut->response_sent != 2) {
483 		sigma_dut_print(dut, DUT_MSG_ERROR,
484 				"ERROR: Unexpected number of status lines sent (%d) for command '%s'",
485 				dut->response_sent, cmd);
486 	}
487 
488 out:
489 	if (dut->debug_level < DUT_MSG_INFO) {
490 		pos2 = txt;
491 		*pos2++ = '\\';
492 		memset(pos2, '-', 69);
493 		pos2 += 69;
494 		*pos2++ = '/';
495 		*pos2 = '\0';
496 		printf("\n%s\n\n", txt);
497 	}
498 }
499 
500 
501 static void process_conn(struct sigma_dut *dut, struct sigma_conn *conn)
502 {
503 	ssize_t res;
504 	int i;
505 
506 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Read from %s:%d",
507 			inet_ntoa(conn->addr.sin_addr),
508 			ntohs(conn->addr.sin_port));
509 
510 	res = recv(conn->s, conn->buf + conn->pos, MAX_CMD_LEN + 5 - conn->pos,
511 		   0);
512 	if (res < 0) {
513 		sigma_dut_print(dut, DUT_MSG_INFO, "recv: %s",
514 				strerror(errno));
515 	}
516 	if (res <= 0) {
517 		sigma_dut_print(dut, DUT_MSG_DEBUG, "Close connection from "
518 				"%s:%d",
519 				inet_ntoa(conn->addr.sin_addr),
520 				ntohs(conn->addr.sin_port));
521 		shutdown(conn->s, SHUT_RDWR);
522 		close(conn->s);
523 		conn->s = -1;
524 		return;
525 	}
526 
527 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Received %d bytes",
528 			(int) res);
529 
530 	for (;;) {
531 		for (i = conn->pos; i < conn->pos + res; i++) {
532 			if (conn->buf[i] == '\r' || conn->buf[i] == '\n')
533 				break;
534 		}
535 
536 		if (i == conn->pos + res) {
537 			/* Full command not yet received */
538 			conn->pos += res;
539 			if (conn->pos >= MAX_CMD_LEN + 5) {
540 				sigma_dut_print(dut, DUT_MSG_INFO, "Too long "
541 						"command dropped");
542 				conn->pos = 0;
543 			}
544 			break;
545 		}
546 
547 		/* Full command received */
548 		conn->buf[i++] = '\0';
549 		process_cmd(dut, conn, conn->buf);
550 		while (i < conn->pos + res &&
551 		       (conn->buf[i] == '\r' || conn->buf[i] == '\n'))
552 			i++;
553 		memmove(conn->buf, &conn->buf[i], conn->pos + res - i);
554 		res = conn->pos + res - i;
555 		conn->pos = 0;
556 	}
557 }
558 
559 
560 static int stop_loop = 0;
561 
562 #ifdef __linux__
563 static void handle_term(int sig)
564 {
565 	stop_loop = 1;
566 	stop_event_thread();
567 	printf("sigma_dut terminating\n");
568 }
569 #endif /* __linux__ */
570 
571 static void run_loop(struct sigma_dut *dut)
572 {
573 	struct sigma_conn conn[MAX_CONNECTIONS];
574 	int i, res, maxfd, can_accept;
575 	fd_set rfds;
576 
577 	memset(&conn, 0, sizeof(conn));
578 	for (i = 0; i < MAX_CONNECTIONS; i++)
579 		conn[i].s = -1;
580 
581 #ifdef __linux__
582 	signal(SIGINT, handle_term);
583 	signal(SIGTERM, handle_term);
584 	signal(SIGPIPE, SIG_IGN);
585 #endif /* __linux__ */
586 
587 	while (!stop_loop) {
588 		FD_ZERO(&rfds);
589 		maxfd = -1;
590 		can_accept = 0;
591 		for (i = 0; i < MAX_CONNECTIONS; i++) {
592 			if (conn[i].s >= 0) {
593 				FD_SET(conn[i].s, &rfds);
594 				if (conn[i].s > maxfd)
595 					maxfd = conn[i].s;
596 			} else if (!conn[i].waiting_completion)
597 				can_accept = 1;
598 		}
599 
600 		if (can_accept) {
601 			FD_SET(dut->s, &rfds);
602 			if (dut->s > maxfd)
603 				maxfd = dut->s;
604 		}
605 
606 
607 		sigma_dut_print(dut, DUT_MSG_DEBUG, "Waiting for next "
608 				"command (can_accept=%d)", can_accept);
609 		res = select(maxfd + 1, &rfds, NULL, NULL, NULL);
610 		if (res < 0) {
611 			perror("select");
612 			if (!stop_loop)
613 				sleep(1);
614 			continue;
615 		}
616 
617 		if (!res) {
618 			sigma_dut_print(dut, DUT_MSG_DEBUG, "Nothing ready");
619 			sleep(1);
620 			continue;
621 		}
622 
623 		if (FD_ISSET(dut->s, &rfds)) {
624 			for (i = 0; i < MAX_CONNECTIONS; i++) {
625 				if (conn[i].s < 0 &&
626 				    !conn[i].waiting_completion)
627 					break;
628 			}
629 			if (i == MAX_CONNECTIONS) {
630 				/*
631 				 * This cannot really happen since can_accept
632 				 * would not be set to one.
633 				 */
634 				sigma_dut_print(dut, DUT_MSG_DEBUG,
635 						"No room for new connection");
636 				continue;
637 			}
638 			conn[i].addrlen = sizeof(conn[i].addr);
639 			conn[i].s = accept(dut->s,
640 					   (struct sockaddr *) &conn[i].addr,
641 					   &conn[i].addrlen);
642 			if (conn[i].s < 0) {
643 				sigma_dut_print(dut, DUT_MSG_INFO,
644 						"accept: %s",
645 						strerror(errno));
646 				continue;
647 			}
648 
649 			sigma_dut_print(dut, DUT_MSG_DEBUG,
650 					"Connection %d from %s:%d", i,
651 					inet_ntoa(conn[i].addr.sin_addr),
652 					ntohs(conn[i].addr.sin_port));
653 			conn[i].pos = 0;
654 		}
655 
656 		for (i = 0; i < MAX_CONNECTIONS; i++) {
657 			if (conn[i].s < 0)
658 				continue;
659 			if (FD_ISSET(conn[i].s, &rfds))
660 				process_conn(dut, &conn[i]);
661 		}
662 	}
663 }
664 
665 
666 static int run_local_cmd(int port, char *lcmd)
667 {
668 	int s, len;
669 	struct sockaddr_in addr;
670 	char cmd[MAX_CMD_LEN];
671 	ssize_t res;
672 	int count;
673 	char resp[MAX_CMD_LEN];
674 	int pos;
675 
676 
677 	if (strlen(lcmd) > sizeof(cmd) - 4) {
678 		printf("Too long command\n");
679 		return -1;
680 	}
681 	len = snprintf(cmd, sizeof(cmd), "%s \r\n", lcmd);
682 
683 	memset(&addr, 0, sizeof(addr));
684 	addr.sin_family = AF_INET;
685 	inet_aton("127.0.0.1", &addr.sin_addr);
686 	addr.sin_port = htons(port);
687 
688 	/* Make sure we do not get stuck indefinitely */
689 	alarm(150);
690 
691 	s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
692 	if (s < 0) {
693 		perror("socket");
694 		return -1;
695 	}
696 
697 	if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
698 		perror("connect");
699 		close(s);
700 		return -1;
701 	}
702 
703 	res = send(s, cmd, len, 0);
704 	if (res < 0) {
705 		perror("send");
706 		close(s);
707 		return -1;
708 	}
709 	if (res != len) {
710 		printf("Unexpected send result: %d (expected %d)\n",
711 		       (int) res, len);
712 		close(s);
713 		return -1;
714 	}
715 
716 	count = 0;
717 	pos = 0;
718 	len = 0;
719 	for (;;) {
720 		char *e;
721 		res = recv(s, resp + len, sizeof(resp) - len, 0);
722 		if (res < 0) {
723 			perror("recv");
724 			close(s);
725 			return -1;
726 		}
727 		if (res == 0) {
728 			printf("Could not read response\n");
729 			close(s);
730 			return -1;
731 		}
732 		len += res;
733 	next_line:
734 		e = memchr(resp + pos, '\r', len - pos);
735 		if (e == NULL)
736 			continue;
737 		*e++ = '\0';
738 		if (e - resp < len && *e == '\n')
739 			*e++ = '\n';
740 		printf("%s\n", resp + pos);
741 		if (strncasecmp(resp + pos, "status,RUNNING", 14) != 0)
742 			break;
743 		count++;
744 		if (count == 2)
745 			break;
746 		pos = e - resp;
747 		goto next_line;
748 	}
749 
750 	close(s);
751 
752 	return 0;
753 }
754 
755 
756 static char * determine_sigma_p2p_ifname(void)
757 {
758 	char buf[256];
759 	struct wpa_ctrl *ctrl;
760 
761 	if (sigma_p2p_ifname)
762 		return sigma_p2p_ifname;
763 
764 	snprintf(buf, sizeof(buf), "p2p-dev-%s", get_station_ifname());
765 	ctrl = open_wpa_mon(buf);
766 	if (ctrl) {
767 		wpa_ctrl_detach(ctrl);
768 		wpa_ctrl_close(ctrl);
769 		sigma_p2p_ifname_buf = strdup(buf);
770 		sigma_p2p_ifname = sigma_p2p_ifname_buf;
771 		sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
772 				"Using interface %s for P2P operations instead of interface %s",
773 				sigma_p2p_ifname ? sigma_p2p_ifname : "NULL",
774 				get_station_ifname());
775 	} else {
776 		sigma_p2p_ifname = get_station_ifname();
777 	}
778 
779 	return sigma_p2p_ifname;
780 }
781 
782 
783 static int get_nl80211_config_enable_option(struct sigma_dut *dut)
784 {
785 	char cmd[100], result[5];
786 	FILE *f;
787 	size_t len;
788 	int ap_nl80211_enable;
789 
790 	snprintf(cmd, sizeof(cmd), "uci get qcacfg80211.config.enable");
791 	f = popen(cmd, "r");
792 	if (!f)
793 		return -1;
794 
795 	len = fread(result, 1, sizeof(result) - 1, f);
796 	pclose(f);
797 
798 	if (len == 0)
799 		return -1;
800 
801 	result[len] = '\0';
802 	ap_nl80211_enable = atoi(result);
803 
804 	if (ap_nl80211_enable)
805 		dut->priv_cmd = "cfg80211tool";
806 
807 	return 0;
808 }
809 
810 
811 static void set_defaults(struct sigma_dut *dut)
812 {
813 	dut->ap_p2p_cross_connect = -1;
814 	dut->ap_chwidth = AP_AUTO;
815 	dut->default_11na_ap_chwidth = AP_AUTO;
816 	dut->default_11ng_ap_chwidth = AP_AUTO;
817 	/* by default, enable writing of traffic stream stats */
818 	dut->write_stats = 1;
819 	dut->priv_cmd = "iwpriv";
820 }
821 
822 
823 static const char * const license1 =
824 "sigma_dut - WFA Sigma DUT/CA\n"
825 "----------------------------\n"
826 "\n"
827 "Copyright (c) 2010-2011, Atheros Communications, Inc.\n"
828 "Copyright (c) 2011-2017, Qualcomm Atheros, Inc.\n"
829 "Copyright (c) 2018-2019, The Linux Foundation\n"
830 "All Rights Reserved.\n"
831 "Licensed under the Clear BSD license.\n"
832 "\n";
833 static const char * const license2 =
834 "Redistribution and use in source and binary forms, with or without\n"
835 "modification, are permitted (subject to the limitations in the\n"
836 "disclaimer below) provided that the following conditions are met:\n"
837 "\n";
838 static const char * const license3 =
839 "* Redistributions of source code must retain the above copyright notice,\n"
840 "  this list of conditions and the following disclaimer.\n"
841 "\n"
842 "* Redistributions in binary form must reproduce the above copyright\n"
843 "  notice, this list of conditions and the following disclaimer in the\n"
844 "  documentation and/or other materials provided with the distribution.\n"
845 "\n"
846 "* Neither the name of Qualcomm Atheros, Inc. nor the names of its\n"
847 "  contributors may be used to endorse or promote products derived from\n"
848 "  this software without specific prior written permission.\n"
849 "\n";
850 static const char * const license4 =
851 "NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED\n"
852 "BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n"
853 "CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n"
854 "BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\n"
855 "FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n"
856 "COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n"
857 "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"
858 "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n"
859 "USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n"
860 "ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
861 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n"
862 "THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n";
863 
864 
865 static void print_license(void)
866 {
867 	printf("%s%s%s%s\n",
868 	       license1, license2, license3, license4);
869 }
870 
871 
872 int main(int argc, char *argv[])
873 {
874 	int c;
875 	int daemonize = 0;
876 	int port = SIGMA_DUT_PORT;
877 	char *local_cmd = NULL;
878 	int internal_dhcp_enabled = 0;
879 #ifdef __QNXNTO__
880 	char *env_str = NULL;
881 	char buf[20];
882 	char *sigma_ctrl_sock = NULL; /* env used for QNX */
883 #endif /* __QNXNTO__ */
884 
885 	memset(&sigma_dut, 0, sizeof(sigma_dut));
886 	sigma_dut.debug_level = DUT_MSG_INFO;
887 	sigma_dut.default_timeout = 120;
888 	sigma_dut.dialog_token = 0;
889 	sigma_dut.dpp_conf_id = -1;
890 	sigma_dut.dpp_local_bootstrap = -1;
891 	sigma_dut.sta_nss = 2; /* Make default nss 2 */
892 	sigma_dut.trans_proto = NAN_TRANSPORT_PROTOCOL_DEFAULT;
893 	sigma_dut.trans_port = NAN_TRANSPORT_PORT_DEFAULT;
894 	sigma_dut.nan_ipv6_len = 0;
895 	set_defaults(&sigma_dut);
896 
897 	for (;;) {
898 		c = getopt(argc, argv,
899 			   "aAb:Bc:C:dDE:e:fF:gGhH:j:J:i:Ik:K:l:L:m:M:nN:o:O:p:P:qr:R:s:S:tT:uv:VWw:x:y:z:");
900 		if (c < 0)
901 			break;
902 		switch (c) {
903 		case 'a':
904 			sigma_dut.ap_anqpserver = 1;
905 			break;
906 		case 'b':
907 			sigma_dut.bridge = optarg;
908 			break;
909 		case 'B':
910 			daemonize++;
911 			break;
912 		case 'C':
913 			sigma_cert_path = optarg;
914 			break;
915 		case 'd':
916 			if (sigma_dut.debug_level > 0)
917 				sigma_dut.debug_level--;
918 			break;
919 #ifdef __QNXNTO__
920 		case 'E':
921 			sigma_ctrl_sock = optarg;
922 			break;
923 #endif /* __QNXNTO__ */
924 		case 'D':
925 			sigma_dut.stdout_debug = 1;
926 			break;
927 		case 'e':
928 			sigma_dut.hostapd_entropy_log = optarg;
929 			break;
930 		case 'f':
931 			/* Disable writing stats */
932 			sigma_dut.write_stats = 0;
933 			break;
934 		case 'F':
935 			sigma_dut.hostapd_bin = optarg;
936 			break;
937 		case 'g':
938 			/* Enable internal processing of P2P group formation
939 			 * events to start/stop DHCP server/client. */
940 			internal_dhcp_enabled = 1;
941 			break;
942 		case 'G':
943 			sigma_dut.use_hostapd_pid_file = 1;
944 			break;
945 		case 'H':
946 			sigma_dut.hostapd_debug_log = optarg;
947 			break;
948 		case 'I':
949 			print_license();
950 			exit(0);
951 			break;
952 		case 'j':
953 			sigma_dut.hostapd_ifname = optarg;
954 			break;
955 		case 'J':
956 			sigma_dut.wpa_supplicant_debug_log = optarg;
957 			break;
958 		case 'l':
959 			local_cmd = optarg;
960 			break;
961 		case 'L':
962 			sigma_dut.summary_log = optarg;
963 			break;
964 		case 'p':
965 			port = atoi(optarg);
966 			break;
967 		case 'P':
968 			sigma_p2p_ifname = optarg;
969 			break;
970 		case 'q':
971 			sigma_dut.debug_level++;
972 			break;
973 		case 'r':
974 			if (strcmp(optarg, "HT40") == 0) {
975 				sigma_dut.default_11na_ap_chwidth = AP_40;
976 			} else if (strcmp(optarg, "2.4_HT40") == 0) {
977 				sigma_dut.default_11ng_ap_chwidth = AP_40;
978 			} else {
979 				printf("Unsupported -r value\n");
980 				exit(1);
981 			}
982 			break;
983 		case 'R': {
984 			static int num_radio = 0;
985 			static char **radio_ptr = sigma_radio_ifname;
986 
987 			num_radio++;
988 			if (num_radio > MAX_RADIO) {
989 				printf("Multiple radio support limit (%d) exceeded\n",
990 				       MAX_RADIO);
991 				exit(1);
992 			}
993 			*radio_ptr++ = optarg;
994 			break;
995 		}
996 		case 's':
997 			sigma_dut.sniffer_ifname = optarg;
998 			break;
999 		case 't':
1000 			sigma_dut.no_timestamps = 1;
1001 			break;
1002 		case 'T':
1003 			sigma_dut.throughput_pktsize = atoi(optarg);
1004 			if (sigma_dut.throughput_pktsize == 0) {
1005 				printf("Invalid -T value\n");
1006 				exit(0);
1007 			}
1008 			break;
1009 		case 'm':
1010 			sigma_dut.set_macaddr = optarg;
1011 			break;
1012 		case 'M':
1013 			sigma_main_ifname = optarg;
1014 			break;
1015 		case 'n':
1016 			sigma_dut.no_ip_addr_set = 1;
1017 			break;
1018 		case 'N':
1019 			sigma_dut.vendor_name = optarg;
1020 			break;
1021 		case 'o':
1022 			sigma_dut.model_name = optarg;
1023 			break;
1024 		case 'O':
1025 			sigma_dut.version_name = optarg;
1026 			break;
1027 		case 'K':
1028 			sigma_dut.log_file_dir = optarg;
1029 			break;
1030 		case 'S':
1031 			sigma_station_ifname = optarg;
1032 			break;
1033 		case 'w':
1034 			sigma_hapd_ctrl = optarg;
1035 			sigma_wpas_ctrl = optarg;
1036 			break;
1037 		case 'i':
1038 			ap_inet_addr = optarg;
1039 			break;
1040 		case 'k':
1041 			ap_inet_mask = optarg;
1042 			break;
1043 		case 'c':
1044 			printf("%s", optarg);
1045 			if (set_wifi_chip(optarg) < 0)
1046 				sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
1047 						"WRONG CHIP TYPE: SAP will "
1048 						"not load");
1049 			break;
1050 		case 'v':
1051 			sigma_dut.version = optarg;
1052 			break;
1053 		case 'V':
1054 			printf("sigma_dut " SIGMA_DUT_VER "\n");
1055 			exit(0);
1056 			break;
1057 		case 'W':
1058 			sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
1059 					"Running WMM-AC test suite");
1060 			sigma_wmm_ac = 1;
1061 			break;
1062 		case 'u':
1063 		       sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
1064 				       "Use iface down/up in reset cmd");
1065 		       sigma_dut.iface_down_on_reset = 1;
1066 		       break;
1067 		case 'A':
1068 			sigma_dut.sim_no_username = 1;
1069 			break;
1070 #ifdef MIRACAST
1071 		case 'x':
1072 			if (strcmp(optarg, "sink") == 0) {
1073 				sigma_dut.wfd_device_type = 1;
1074 				sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
1075 						"Device Type is SINK");
1076 			} else if (strcmp(optarg, "source") == 0) {
1077 				sigma_dut.wfd_device_type = 0;
1078 				sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
1079 						"Device Type is SOURCE");
1080 			}
1081 			break;
1082 		case 'y':
1083 			sigma_dut.miracast_lib_path = optarg;
1084 			break;
1085 #endif /* MIRACAST */
1086 		case 'z':
1087 			client_socket_path = optarg;
1088 			break;
1089 		case 'h':
1090 		default:
1091 			printf("usage: sigma_dut [-aABdfGqDIntuVW] [-p<port>] "
1092 			       "[-s<sniffer>] [-m<set_maccaddr.sh>] \\\n"
1093 				"       [-M<main ifname>] [-R<radio ifname>] "
1094 			       "[-S<station ifname>] [-P<p2p_ifname>]\\\n"
1095 			       "       [-T<throughput pktsize>] \\\n"
1096 			       "       [-w<wpa_supplicant/hostapd ctrl_iface "
1097 			       "dir>] \\\n"
1098 			       "       [-H <hostapd log file>] \\\n"
1099 			       "       [-F <hostapd binary path>] \\\n"
1100 			       "       [-j <hostapd ifname>] \\\n"
1101 			       "       [-J <wpa_supplicant debug log>] \\\n"
1102 			       "       [-C <certificate path>] \\\n"
1103 			       "       [-v <version string>] \\\n"
1104 			       "       [-L <summary log>] \\\n"
1105 			       "       [-c <wifi chip type: WCN or ATHEROS or "
1106 			       "AR6003 or MAC80211 or QNXNTO or OPENWRT or "
1107 			       "LINUX-WCN>] "
1108 			       "\\\n"
1109 			       "       [-i <IP address of the AP>] \\\n"
1110 			       "       [-k <subnet mask for the AP>] \\\n"
1111 			       "       [-K <sigma_dut log file directory>] \\\n"
1112 			       "       [-e <hostapd entropy file>] \\\n"
1113 			       "       [-N <device_get_info vendor>] \\\n"
1114 			       "       [-o <device_get_info model>] \\\n"
1115 			       "       [-O <device_get_info version>] \\\n"
1116 #ifdef MIRACAST
1117 			       "       [-x <sink|source>] \\\n"
1118 			       "       [-y <Miracast library path>] \\\n"
1119 #endif /* MIRACAST */
1120 			       "       [-z <client socket directory path \\\n"
1121 			       "       Ex: </data/vendor/wifi/sockets>] \\\n"
1122 			       "       [-r <HT40 or 2.4_HT40>]\n");
1123 			printf("local command: sigma_dut [-p<port>] "
1124 			       "<-l<cmd>>\n");
1125 			exit(0);
1126 			break;
1127 		}
1128 	}
1129 
1130 	sigma_dut.p2p_ifname = determine_sigma_p2p_ifname();
1131 #ifdef MIRACAST
1132 	miracast_init(&sigma_dut);
1133 #endif /* MIRACAST */
1134 	if (local_cmd)
1135 		return run_local_cmd(port, local_cmd);
1136 
1137 	if ((wifi_chip_type == DRIVER_QNXNTO ||
1138 	     wifi_chip_type == DRIVER_LINUX_WCN) &&
1139 	    (sigma_main_ifname == NULL || sigma_station_ifname == NULL)) {
1140 		sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
1141 				"Interface should be provided for QNX/LINUX-WCN driver - check option M and S");
1142 	}
1143 
1144 	if (get_openwrt_driver_type() == OPENWRT_DRIVER_ATHEROS)
1145 		get_nl80211_config_enable_option(&sigma_dut);
1146 
1147 #ifdef NL80211_SUPPORT
1148 	sigma_dut.nl_ctx = nl80211_init(&sigma_dut);
1149 #endif /* NL80211_SUPPORT */
1150 	sigma_dut_register_cmds();
1151 
1152 #ifdef __QNXNTO__
1153 	/* Try to open socket in other env dev */
1154 	if (sigma_ctrl_sock) {
1155 		env_str = getenv("SOCK");
1156 		if (env_str) {
1157 			sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
1158 					"SOCK=%s", env_str);
1159 		}
1160 		snprintf(buf, sizeof(buf), "SOCK=%s", sigma_ctrl_sock);
1161 		if (putenv(buf) != 0) {
1162 			sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
1163 					"putenv() failed setting SOCK");
1164 			return EXIT_FAILURE;
1165 		}
1166 	}
1167 #endif /* __QNXNTO__ */
1168 
1169 	if (open_socket(&sigma_dut, port) < 0)
1170 		return -1;
1171 
1172 #ifdef __QNXNTO__
1173 	/* restore back the SOCK */
1174 	if (sigma_ctrl_sock) {
1175 		if (env_str) {
1176 			snprintf(buf, sizeof(buf), "SOCK=%s", env_str);
1177 			if (putenv(buf) != 0) {
1178 				sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
1179 						"putenv() failed setting SOCK");
1180 				return EXIT_FAILURE;
1181 			}
1182 		} else {
1183 			/* unset the env for sock */
1184 			unsetenv("SOCK");
1185 		}
1186 	}
1187 #endif /* __QNXNTO__ */
1188 
1189 	if (daemonize) {
1190 		if (daemon(0, 0) < 0) {
1191 			perror("daemon");
1192 			exit(-1);
1193 		}
1194 	} else {
1195 #ifdef __linux__
1196 		setlinebuf(stdout);
1197 #endif /* __linux__ */
1198 	}
1199 
1200 	if (internal_dhcp_enabled)
1201 		p2p_create_event_thread(&sigma_dut);
1202 
1203 	run_loop(&sigma_dut);
1204 
1205 #ifdef CONFIG_SNIFFER
1206 	sniffer_close(&sigma_dut);
1207 #endif /* CONFIG_SNIFFER */
1208 
1209 	free(sigma_p2p_ifname_buf);
1210 	close_socket(&sigma_dut);
1211 #ifdef MIRACAST
1212 	miracast_deinit(&sigma_dut);
1213 #endif /* MIRACAST */
1214 	free(sigma_dut.non_pref_ch_list);
1215 	sigma_dut.non_pref_ch_list = NULL;
1216 	free(sigma_dut.btm_query_cand_list);
1217 	sigma_dut.btm_query_cand_list = NULL;
1218 	free(sigma_dut.rsne_override);
1219 	free(sigma_dut.ap_sae_groups);
1220 	free(sigma_dut.dpp_peer_uri);
1221 	free(sigma_dut.ap_sae_passwords);
1222 	free(sigma_dut.ar_ltf);
1223 	sigma_dut.ar_ltf = NULL;
1224 	free(sigma_dut.ap_dpp_conf_addr);
1225 	free(sigma_dut.ap_dpp_conf_pkhash);
1226 	if (sigma_dut.log_file_fd)
1227 		fclose(sigma_dut.log_file_fd);
1228 #ifdef NL80211_SUPPORT
1229 	nl80211_deinit(&sigma_dut, sigma_dut.nl_ctx);
1230 #endif /* NL80211_SUPPORT */
1231 	sigma_dut_unreg_cmds(&sigma_dut);
1232 #ifdef ANDROID
1233 	hlp_thread_cleanup(&sigma_dut);
1234 #endif /* ANDROID */
1235 
1236 	return 0;
1237 }
1238