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