blob: c6ea6c5c5b9c429ab12df0b44cad1e85b30e338a [file] [log] [blame]
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001/*
2 * Sigma Control API DUT (station/AP)
3 * Copyright (c) 2010-2011, Atheros Communications, Inc.
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -07004 * Copyright (c) 2011-2017, Qualcomm Atheros, Inc.
Jouni Malinenc12ea4a2018-01-05 21:07:10 +02005 * Copyright (c) 2018, The Linux Foundation
Jouni Malinencd4e3c32015-10-29 12:39:56 +02006 * 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__ */
Danny Segalf2af39b2016-04-10 16:23:11 +030015#include "wpa_ctrl.h"
Jouni Malinencd4e3c32015-10-29 12:39:56 +020016#include "wpa_helpers.h"
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -070017#include "miracast.h"
Jouni Malinencd4e3c32015-10-29 12:39:56 +020018
19#define SIGMA_DUT_PORT 9000
20#define MAX_CONNECTIONS 4
21
22extern enum driver_type wifi_chip_type;
23
24static struct sigma_dut sigma_dut;
25
26char *sigma_main_ifname = NULL;
27char *sigma_radio_ifname[MAX_RADIO] = {};
28char *sigma_station_ifname = NULL;
Danny Segalf2af39b2016-04-10 16:23:11 +030029char *sigma_p2p_ifname = NULL;
30static char *sigma_p2p_ifname_buf = NULL;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020031char *sigma_wpas_ctrl = "/var/run/wpa_supplicant/";
32char *sigma_hapd_ctrl = NULL;
Rajiv Ranjan525dbfd2018-04-20 17:42:48 +053033char *client_socket_path = NULL;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020034char *ap_inet_addr = "192.168.43.1";
35char *ap_inet_mask = "255.255.255.0";
36char *sigma_cert_path = "/etc/wpa_supplicant";
37
38/* For WMM-AC testing this set to 1 through argument,
39 * otherwise default WMM-PS 0 */
40int sigma_wmm_ac = 0;
41
42
43#ifdef ANDROID
44#include <android/log.h>
45
46static enum android_LogPriority level_to_android_priority(int level)
47{
48 switch (level) {
49 case DUT_MSG_ERROR:
50 return ANDROID_LOG_ERROR;
51 case DUT_MSG_INFO:
52 return ANDROID_LOG_INFO;
53 case DUT_MSG_DEBUG:
54 return ANDROID_LOG_DEBUG;
55 default:
56 return ANDROID_LOG_VERBOSE;
57 }
58}
59#endif /* ANDROID */
60
61
62void sigma_dut_print(struct sigma_dut *dut, int level, const char *fmt, ...)
63{
64 va_list ap;
65 struct timeval tv;
66
67 if (level < dut->debug_level)
68 return;
69
70#ifdef ANDROID
71 va_start(ap, fmt);
72 __android_log_vprint(level_to_android_priority(level),
73 "sigma_dut", fmt, ap);
74 va_end(ap);
75 if (!dut->stdout_debug)
76 return;
77#endif /* ANDROID */
78
79 va_start(ap, fmt);
80 gettimeofday(&tv, NULL);
81 printf("%ld.%06u: ", (long) tv.tv_sec,
82 (unsigned int) tv.tv_usec);
83 vprintf(fmt, ap);
84 printf("\n");
85 va_end(ap);
86}
87
88
89void sigma_dut_summary(struct sigma_dut *dut, const char *fmt, ...)
90{
91 va_list ap;
92 FILE *f;
93
94 if (!dut->summary_log)
95 return;
96
97 f = fopen(dut->summary_log, "a");
98 if (f == NULL)
99 return;
100
101 va_start(ap, fmt);
102 vfprintf(f, fmt, ap);
103 fprintf(f, "\n");
104 va_end(ap);
105 fclose(f);
106}
107
108
109int sigma_dut_reg_cmd(const char *cmd,
110 int (*validate)(struct sigma_cmd *cmd),
111 int (*process)(struct sigma_dut *dut,
112 struct sigma_conn *conn,
113 struct sigma_cmd *cmd))
114{
115 struct sigma_cmd_handler *h;
116 size_t clen, len;
117
118 clen = strlen(cmd);
119 len = sizeof(*h) + clen + 1;
120 h = malloc(len);
121 if (h == NULL)
122 return -1;
123 memset(h, 0, len);
124 h->cmd = (char *) (h + 1); /* include in same allocation */
125 memcpy(h->cmd, cmd, clen);
126 h->validate = validate;
127 h->process= process;
128
129 h->next = sigma_dut.cmds;
130 sigma_dut.cmds = h;
131
132 return 0;
133}
134
135
136static void sigma_dut_unreg_cmds(struct sigma_dut *dut)
137{
138 struct sigma_cmd_handler *cmd, *prev;
139 cmd = dut->cmds;
140 dut->cmds = NULL;
141 while (cmd) {
142 prev = cmd;
143 cmd = cmd->next;
144 free(prev);
145 }
146}
147
148
149static int open_socket(struct sigma_dut *dut, int port)
150{
151 struct sockaddr_in addr;
152#ifndef __QNXNTO__
153 int val;
154#endif /* !__QNXNTO__ */
155
156#ifdef __QNXNTO__
157 dut->s = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
158#else /* __QNXNTO__ */
159 dut->s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
160#endif /* __QNXNTO__ */
161 if (dut->s < 0) {
162 sigma_dut_print(dut, DUT_MSG_ERROR, "socket: %s",
163 strerror(errno));
164 return -1;
165 }
166
167#ifndef __QNXNTO__
168 val = 1;
169 if (setsockopt(dut->s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) <
170 0)
171 sigma_dut_print(dut, DUT_MSG_INFO, "setsockopt SO_REUSEADDR: "
172 "%s", strerror(errno));
173#endif /* !__QNXNTO__ */
174
175#ifdef __linux__
176 val = 1;
177 if (setsockopt(dut->s, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) <
178 0)
179 sigma_dut_print(dut, DUT_MSG_INFO, "setsockopt TCP_NODELAY: "
180 "%s", strerror(errno));
181#endif /* __linux__ */
182
183 memset(&addr, 0, sizeof(addr));
184 addr.sin_family = AF_INET;
185 addr.sin_port = htons(port);
186
187 if (bind(dut->s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
188 sigma_dut_print(dut, DUT_MSG_ERROR, "bind: %s",
189 strerror(errno));
190 goto fail;
191 }
192
193 if (listen(dut->s, 5) < 0) {
194 sigma_dut_print(dut, DUT_MSG_ERROR, "listen: %s",
195 strerror(errno));
196 goto fail;
197 }
198
199 return 0;
200
201fail:
202 shutdown(dut->s, SHUT_RDWR);
203 close(dut->s);
204 dut->s = -1;
205 return -1;
206}
207
208
209static void close_socket(struct sigma_dut *dut)
210{
211 shutdown(dut->s, SHUT_RDWR);
212 close(dut->s);
213 dut->s = -1;
214}
215
216
217void send_resp(struct sigma_dut *dut, struct sigma_conn *conn,
Jouni Malinen76401f52017-03-18 01:04:55 +0200218 enum sigma_status status, const char *buf)
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200219{
220 struct msghdr msg;
221 struct iovec iov[4];
222 size_t elems;
223
Jouni Malinena326d7b2017-09-04 13:46:02 +0300224 if (!conn)
225 return;
226
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200227 sigma_dut_print(dut, DUT_MSG_INFO, "resp: status=%d buf=%s",
228 status, buf ? buf : "N/A");
229
230 iov[0].iov_base = "status,";
231 iov[0].iov_len = 7;
232 switch (status) {
233 case SIGMA_RUNNING:
234 iov[1].iov_base = "RUNNING,";
235 iov[1].iov_len = 8;
236 break;
237 case SIGMA_INVALID:
238 iov[1].iov_base = "INVALID,";
239 iov[1].iov_len = 8;
240 break;
241 case SIGMA_ERROR:
242 iov[1].iov_base = "ERROR,";
243 iov[1].iov_len = 6;
244 break;
245 case SIGMA_COMPLETE:
246 iov[1].iov_base = "COMPLETE,";
247 iov[1].iov_len = 9;
248 break;
249 }
250 if (status != SIGMA_RUNNING) {
251 sigma_dut_summary(dut, "CAPI resp: status,%s%s",
252 (char *) iov[1].iov_base, buf ? buf : "");
253 }
254 if (buf) {
Jouni Malinen76401f52017-03-18 01:04:55 +0200255 iov[2].iov_base = (void *) buf;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200256 iov[2].iov_len = strlen(buf);
257 iov[3].iov_base = "\r\n";
258 iov[3].iov_len = 2;
259 elems = 4;
260 } else {
261 iov[1].iov_len--;
262 iov[2].iov_base = "\r\n";
263 iov[2].iov_len = 2;
264 elems = 3;
265 }
266
267 memset(&msg, 0, sizeof(msg));
268 msg.msg_iov = iov;
269 msg.msg_iovlen = elems;
270 if (sendmsg(conn->s, &msg, 0) < 0)
271 sigma_dut_print(dut, DUT_MSG_INFO, "sendmsg: %s",
272 strerror(errno));
273}
274
275
276const char * get_param(struct sigma_cmd *cmd, const char *name)
277{
278 int i;
279 for (i = 0; i < cmd->count; i++) {
280 if (strcasecmp(name, cmd->params[i]) == 0)
281 return cmd->values[i];
282 }
283 return NULL;
284}
285
286
287static void process_cmd(struct sigma_dut *dut, struct sigma_conn *conn,
288 char *buf)
289{
290 struct sigma_cmd_handler *h;
291 struct sigma_cmd c;
292 char *cmd, *pos, *pos2;
293 int len;
294 char txt[200];
295 int res;
296
297 while (*buf == '\r' || *buf == '\n' || *buf == '\t' || *buf == ' ')
298 buf++;
299 len = strlen(buf);
300 while (len > 0 && buf[len - 1] == ' ') {
301 buf[len - 1] = '\0';
302 len--;
303 }
304
305 if (dut->debug_level < DUT_MSG_INFO) {
306 pos = strchr(buf, ',');
307 if (pos == NULL)
308 pos = buf + len;
309 if (pos - buf > 50)
310 pos = buf + 50;
311 memcpy(txt, "/====[ ", 7);
312 pos2 = txt + 7;
313 memcpy(pos2, buf, pos - buf);
314 pos2 += pos - buf;
315 *pos2++ = ' ';
316 *pos2++ = ']';
317 while (pos2 - txt < 70)
318 *pos2++ = '=';
319 *pos2++ = '\\';
320 *pos2 = '\0';
321 printf("\n%s\n\n", txt);
322 }
323
324 sigma_dut_print(dut, DUT_MSG_INFO, "cmd: %s", buf);
325 sigma_dut_summary(dut, "CAPI cmd: %s", buf);
326 snprintf(txt, sizeof(txt), "NOTE CAPI:%s", buf);
327 txt[sizeof(txt) - 1] = '\0';
328 wpa_command(get_main_ifname(), txt);
329
330 memset(&c, 0, sizeof(c));
331 cmd = buf;
332 pos = strchr(cmd, ',');
333 if (pos) {
334 *pos++ = '\0';
335 if (strcasecmp(cmd, "AccessPoint") == 0 ||
336 strcasecmp(cmd, "PowerSwitch") == 0) {
337 pos2 = strchr(pos, ',');
338 if (pos2 == NULL)
339 goto invalid_params;
340 c.params[c.count] = pos;
341 c.values[c.count] = pos2;
342 c.count++;
343 pos = strchr(pos2, ',');
344 if (pos)
345 *pos++ = '\0';
346 }
347 while (pos) {
348 pos2 = strchr(pos, ',');
349 if (pos2 == NULL)
350 goto invalid_params;
351 *pos2++ = '\0';
352 if (c.count == MAX_PARAMS) {
353 sigma_dut_print(dut, DUT_MSG_INFO, "Too many "
354 "parameters");
355 goto invalid_params;
356 }
357 c.params[c.count] = pos;
358 c.values[c.count] = pos2;
359 c.count++;
360 pos = strchr(pos2, ',');
361 if (pos)
362 *pos++ = '\0';
363 }
364 }
365 h = dut->cmds;
366 while (h) {
367 if (strcasecmp(cmd, h->cmd) == 0)
368 break;
369 h = h->next;
370 }
371
372 if (h == NULL) {
373 sigma_dut_print(dut, DUT_MSG_INFO, "Unknown command: '%s'",
374 cmd);
375 send_resp(dut, conn, SIGMA_INVALID,
376 "errorCode,Unknown command");
377 goto out;
378 }
379
380 if (h->validate && h->validate(&c) < 0) {
381 invalid_params:
382 sigma_dut_print(dut, DUT_MSG_INFO, "Invalid parameters");
383 send_resp(dut, conn, SIGMA_INVALID, "errorCode,Invalid "
384 "parameters");
385 goto out;
386 }
387
388 send_resp(dut, conn, SIGMA_RUNNING, NULL);
389 sigma_dut_print(dut, DUT_MSG_INFO, "Run command: %s", cmd);
390 res = h->process(dut, conn, &c);
391 if (res == -2)
392 send_resp(dut, conn, SIGMA_ERROR, NULL);
393 else if (res == -1)
394 send_resp(dut, conn, SIGMA_INVALID, NULL);
395 else if (res == 1)
396 send_resp(dut, conn, SIGMA_COMPLETE, NULL);
397
398out:
399 if (dut->debug_level < DUT_MSG_INFO) {
400 pos2 = txt;
401 *pos2++ = '\\';
402 memset(pos2, '-', 69);
403 pos2 += 69;
404 *pos2++ = '/';
405 *pos2 = '\0';
406 printf("\n%s\n\n", txt);
407 }
408}
409
410
411static void process_conn(struct sigma_dut *dut, struct sigma_conn *conn)
412{
413 ssize_t res;
414 int i;
415
416 sigma_dut_print(dut, DUT_MSG_DEBUG, "Read from %s:%d",
417 inet_ntoa(conn->addr.sin_addr),
418 ntohs(conn->addr.sin_port));
419
420 res = recv(conn->s, conn->buf + conn->pos, MAX_CMD_LEN + 5 - conn->pos,
421 0);
422 if (res < 0) {
423 sigma_dut_print(dut, DUT_MSG_INFO, "recv: %s",
424 strerror(errno));
425 }
426 if (res <= 0) {
427 sigma_dut_print(dut, DUT_MSG_DEBUG, "Close connection from "
428 "%s:%d",
429 inet_ntoa(conn->addr.sin_addr),
430 ntohs(conn->addr.sin_port));
431 shutdown(conn->s, SHUT_RDWR);
432 close(conn->s);
433 conn->s = -1;
434 return;
435 }
436
437 sigma_dut_print(dut, DUT_MSG_DEBUG, "Received %d bytes",
438 (int) res);
439
440 for (;;) {
441 for (i = conn->pos; i < conn->pos + res; i++) {
442 if (conn->buf[i] == '\r' || conn->buf[i] == '\n')
443 break;
444 }
445
446 if (i == conn->pos + res) {
447 /* Full command not yet received */
448 conn->pos += res;
449 if (conn->pos >= MAX_CMD_LEN + 5) {
450 sigma_dut_print(dut, DUT_MSG_INFO, "Too long "
451 "command dropped");
452 conn->pos = 0;
453 }
454 break;
455 }
456
457 /* Full command received */
458 conn->buf[i++] = '\0';
459 process_cmd(dut, conn, conn->buf);
460 while (i < conn->pos + res &&
461 (conn->buf[i] == '\r' || conn->buf[i] == '\n'))
462 i++;
463 memmove(conn->buf, &conn->buf[i], conn->pos + res - i);
464 res = conn->pos + res - i;
465 conn->pos = 0;
466 }
467}
468
469
470static int stop_loop = 0;
471
472#ifdef __linux__
473static void handle_term(int sig)
474{
475 stop_loop = 1;
Purushottam Kushwaha091e2532016-08-23 11:52:21 +0530476 stop_event_thread();
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200477 printf("sigma_dut terminating\n");
478}
479#endif /* __linux__ */
480
481static void run_loop(struct sigma_dut *dut)
482{
483 struct sigma_conn conn[MAX_CONNECTIONS];
484 int i, res, maxfd, can_accept;
485 fd_set rfds;
486
487 memset(&conn, 0, sizeof(conn));
488 for (i = 0; i < MAX_CONNECTIONS; i++)
489 conn[i].s = -1;
490
491#ifdef __linux__
492 signal(SIGINT, handle_term);
493 signal(SIGTERM, handle_term);
494 signal(SIGPIPE, SIG_IGN);
495#endif /* __linux__ */
496
497 while (!stop_loop) {
498 FD_ZERO(&rfds);
499 maxfd = -1;
500 can_accept = 0;
501 for (i = 0; i < MAX_CONNECTIONS; i++) {
502 if (conn[i].s >= 0) {
503 FD_SET(conn[i].s, &rfds);
504 if (conn[i].s > maxfd)
505 maxfd = conn[i].s;
506 } else if (!conn[i].waiting_completion)
507 can_accept = 1;
508 }
509
510 if (can_accept) {
511 FD_SET(dut->s, &rfds);
512 if (dut->s > maxfd)
513 maxfd = dut->s;
514 }
515
516
517 sigma_dut_print(dut, DUT_MSG_DEBUG, "Waiting for next "
518 "command (can_accept=%d)", can_accept);
519 res = select(maxfd + 1, &rfds, NULL, NULL, NULL);
520 if (res < 0) {
521 perror("select");
522 if (!stop_loop)
523 sleep(1);
524 continue;
525 }
526
527 if (!res) {
528 sigma_dut_print(dut, DUT_MSG_DEBUG, "Nothing ready");
529 sleep(1);
530 continue;
531 }
532
533 if (FD_ISSET(dut->s, &rfds)) {
534 for (i = 0; i < MAX_CONNECTIONS; i++) {
535 if (conn[i].s < 0 &&
536 !conn[i].waiting_completion)
537 break;
538 }
539 if (i == MAX_CONNECTIONS) {
540 /*
541 * This cannot really happen since can_accept
542 * would not be set to one.
543 */
544 sigma_dut_print(dut, DUT_MSG_DEBUG,
545 "No room for new connection");
546 continue;
547 }
548 conn[i].addrlen = sizeof(conn[i].addr);
549 conn[i].s = accept(dut->s,
550 (struct sockaddr *) &conn[i].addr,
551 &conn[i].addrlen);
552 if (conn[i].s < 0) {
553 sigma_dut_print(dut, DUT_MSG_INFO,
554 "accept: %s",
555 strerror(errno));
556 continue;
557 }
558
559 sigma_dut_print(dut, DUT_MSG_DEBUG,
560 "Connection %d from %s:%d", i,
561 inet_ntoa(conn[i].addr.sin_addr),
562 ntohs(conn[i].addr.sin_port));
563 conn[i].pos = 0;
564 }
565
566 for (i = 0; i < MAX_CONNECTIONS; i++) {
567 if (conn[i].s < 0)
568 continue;
569 if (FD_ISSET(conn[i].s, &rfds))
570 process_conn(dut, &conn[i]);
571 }
572 }
573}
574
575
576static int run_local_cmd(int port, char *lcmd)
577{
578 int s, len;
579 struct sockaddr_in addr;
580 char cmd[MAX_CMD_LEN];
581 ssize_t res;
582 int count;
583 char resp[MAX_CMD_LEN];
584 int pos;
585
586
587 if (strlen(lcmd) > sizeof(cmd) - 4) {
588 printf("Too long command\n");
589 return -1;
590 }
591 len = snprintf(cmd, sizeof(cmd), "%s \r\n", lcmd);
592
593 memset(&addr, 0, sizeof(addr));
594 addr.sin_family = AF_INET;
595 inet_aton("127.0.0.1", &addr.sin_addr);
596 addr.sin_port = htons(port);
597
598 /* Make sure we do not get stuck indefinitely */
599 alarm(150);
600
601 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
602 if (s < 0) {
603 perror("socket");
604 return -1;
605 }
606
607 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
608 perror("connect");
609 close(s);
610 return -1;
611 }
612
613 res = send(s, cmd, len, 0);
614 if (res < 0) {
615 perror("send");
616 close(s);
617 return -1;
618 }
619 if (res != len) {
620 printf("Unexpected send result: %d (expected %d)\n",
621 (int) res, len);
622 close(s);
623 return -1;
624 }
625
626 count = 0;
627 pos = 0;
628 len = 0;
629 for (;;) {
630 char *e;
631 res = recv(s, resp + len, sizeof(resp) - len, 0);
632 if (res < 0) {
633 perror("recv");
634 close(s);
635 return -1;
636 }
637 if (res == 0) {
638 printf("Could not read response\n");
639 close(s);
640 return -1;
641 }
642 len += res;
643 next_line:
644 e = memchr(resp + pos, '\r', len - pos);
645 if (e == NULL)
646 continue;
647 *e++ = '\0';
648 if (e - resp < len && *e == '\n')
649 *e++ = '\n';
650 printf("%s\n", resp + pos);
651 if (strncasecmp(resp + pos, "status,RUNNING", 14) != 0)
652 break;
653 count++;
654 if (count == 2)
655 break;
656 pos = e - resp;
657 goto next_line;
658 }
659
660 close(s);
661
662 return 0;
663}
664
665
Purushottam Kushwaha091e2532016-08-23 11:52:21 +0530666static char * determine_sigma_p2p_ifname(void)
Danny Segalf2af39b2016-04-10 16:23:11 +0300667{
668 char buf[256];
669 struct wpa_ctrl *ctrl;
670
671 if (sigma_p2p_ifname)
Purushottam Kushwaha091e2532016-08-23 11:52:21 +0530672 return sigma_p2p_ifname;
Danny Segalf2af39b2016-04-10 16:23:11 +0300673
674 snprintf(buf, sizeof(buf), "p2p-dev-%s", get_station_ifname());
675 ctrl = open_wpa_mon(buf);
676 if (ctrl) {
677 wpa_ctrl_detach(ctrl);
678 wpa_ctrl_close(ctrl);
679 sigma_p2p_ifname_buf = strdup(buf);
680 sigma_p2p_ifname = sigma_p2p_ifname_buf;
681 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
682 "Using interface %s for P2P operations instead of interface %s",
683 sigma_p2p_ifname ? sigma_p2p_ifname : "NULL",
684 get_station_ifname());
685 } else {
686 sigma_p2p_ifname = get_station_ifname();
687 }
Purushottam Kushwaha091e2532016-08-23 11:52:21 +0530688
689 return sigma_p2p_ifname;
Danny Segalf2af39b2016-04-10 16:23:11 +0300690}
691
692
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200693static void set_defaults(struct sigma_dut *dut)
694{
695 dut->ap_p2p_cross_connect = -1;
696 dut->ap_chwidth = AP_AUTO;
Pradeep Reddy Pottetibf8af292017-02-15 15:28:39 +0530697 dut->default_11na_ap_chwidth = AP_AUTO;
698 dut->default_11ng_ap_chwidth = AP_AUTO;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200699 /* by default, enable writing of traffic stream stats */
700 dut->write_stats = 1;
701}
702
703
704static const char * const license1 =
705"sigma_dut - WFA Sigma DUT/CA\n"
706"----------------------------\n"
707"\n"
708"Copyright (c) 2010-2011, Atheros Communications, Inc.\n"
Jouni Malinen9d7e31d2017-12-22 18:55:04 +0200709"Copyright (c) 2011-2017, Qualcomm Atheros, Inc.\n"
Jouni Malinenc12ea4a2018-01-05 21:07:10 +0200710"Copyright (c) 2018, The Linux Foundation\n"
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200711"All Rights Reserved.\n"
712"Licensed under the Clear BSD license.\n"
713"\n";
714static const char * const license2 =
715"Redistribution and use in source and binary forms, with or without\n"
716"modification, are permitted (subject to the limitations in the\n"
717"disclaimer below) provided that the following conditions are met:\n"
718"\n";
719static const char * const license3 =
720"* Redistributions of source code must retain the above copyright notice,\n"
721" this list of conditions and the following disclaimer.\n"
722"\n"
723"* Redistributions in binary form must reproduce the above copyright\n"
724" notice, this list of conditions and the following disclaimer in the\n"
725" documentation and/or other materials provided with the distribution.\n"
726"\n"
727"* Neither the name of Qualcomm Atheros, Inc. nor the names of its\n"
728" contributors may be used to endorse or promote products derived from\n"
729" this software without specific prior written permission.\n"
730"\n";
731static const char * const license4 =
732"NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED\n"
733"BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n"
734"CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n"
735"BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\n"
736"FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n"
737"COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n"
738"INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"
739"NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n"
740"USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n"
741"ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
742"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n"
743"THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n";
744
745
746static void print_license(void)
747{
748 printf("%s%s%s%s\n",
749 license1, license2, license3, license4);
750}
751
752
753int main(int argc, char *argv[])
754{
755 int c;
756 int daemonize = 0;
757 int port = SIGMA_DUT_PORT;
758 char *local_cmd = NULL;
Purushottam Kushwaha091e2532016-08-23 11:52:21 +0530759 int internal_dhcp_enabled = 0;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200760#ifdef __QNXNTO__
761 char *env_str = NULL;
762 char buf[20];
763 char *sigma_ctrl_sock = NULL; /* env used for QNX */
764#endif /* __QNXNTO__ */
765
766 memset(&sigma_dut, 0, sizeof(sigma_dut));
767 sigma_dut.debug_level = DUT_MSG_INFO;
768 sigma_dut.default_timeout = 120;
769 sigma_dut.dialog_token = 0;
Jouni Malinend86e5822017-08-29 03:55:32 +0300770 sigma_dut.dpp_conf_id = -1;
Jouni Malinen63d50412017-11-24 11:55:38 +0200771 sigma_dut.dpp_local_bootstrap = -1;
Arif Hussainac6c5112018-05-25 17:34:00 -0700772 sigma_dut.sta_nss = 2; /* Make default nss 2 */
Peng Xu8863ec72018-08-06 11:50:37 -0700773 sigma_dut.trans_proto = NAN_TRANSPORT_PROTOCOL_DEFAULT;
774 sigma_dut.trans_port = NAN_TRANSPORT_PORT_DEFAULT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200775 set_defaults(&sigma_dut);
776
777 for (;;) {
778 c = getopt(argc, argv,
Rajiv Ranjan525dbfd2018-04-20 17:42:48 +0530779 "aAb:Bc:C:dDE:e:fF:gGhH:j:i:Ik:l:L:m:M:nN:o:O:p:P:qr:R:s:S:tT:uv:VWw:x:y:z:");
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200780 if (c < 0)
781 break;
782 switch (c) {
783 case 'a':
784 sigma_dut.ap_anqpserver = 1;
785 break;
786 case 'b':
787 sigma_dut.bridge = optarg;
788 break;
789 case 'B':
790 daemonize++;
791 break;
792 case 'C':
793 sigma_cert_path = optarg;
794 break;
795 case 'd':
796 if (sigma_dut.debug_level > 0)
797 sigma_dut.debug_level--;
798 break;
799#ifdef __QNXNTO__
800 case 'E':
801 sigma_ctrl_sock = optarg;
802 break;
803#endif /* __QNXNTO__ */
804 case 'D':
805 sigma_dut.stdout_debug = 1;
806 break;
807 case 'e':
808 sigma_dut.hostapd_entropy_log = optarg;
809 break;
810 case 'f':
811 /* Disable writing stats */
812 sigma_dut.write_stats = 0;
813 break;
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300814 case 'F':
815 sigma_dut.hostapd_bin = optarg;
816 break;
Purushottam Kushwaha091e2532016-08-23 11:52:21 +0530817 case 'g':
818 /* Enable internal processing of P2P group formation
819 * events to start/stop DHCP server/client. */
820 internal_dhcp_enabled = 1;
821 break;
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300822 case 'G':
823 sigma_dut.use_hostapd_pid_file = 1;
824 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200825 case 'H':
826 sigma_dut.hostapd_debug_log = optarg;
827 break;
828 case 'I':
829 print_license();
830 exit(0);
831 break;
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300832 case 'j':
833 sigma_dut.hostapd_ifname = optarg;
834 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200835 case 'l':
836 local_cmd = optarg;
837 break;
838 case 'L':
839 sigma_dut.summary_log = optarg;
840 break;
841 case 'p':
842 port = atoi(optarg);
843 break;
Danny Segalf2af39b2016-04-10 16:23:11 +0300844 case 'P':
845 sigma_p2p_ifname = optarg;
846 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200847 case 'q':
848 sigma_dut.debug_level++;
849 break;
850 case 'r':
851 if (strcmp(optarg, "HT40") == 0) {
Pradeep Reddy Pottetibf8af292017-02-15 15:28:39 +0530852 sigma_dut.default_11na_ap_chwidth = AP_40;
853 } else if (strcmp(optarg, "2.4_HT40") == 0) {
854 sigma_dut.default_11ng_ap_chwidth = AP_40;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200855 } else {
856 printf("Unsupported -r value\n");
857 exit(1);
858 }
859 break;
860 case 'R': {
861 static int num_radio = 0;
862 static char **radio_ptr = sigma_radio_ifname;
863
864 num_radio++;
865 if (num_radio > MAX_RADIO) {
866 printf("Multiple radio support limit (%d) exceeded\n",
867 MAX_RADIO);
868 exit(1);
869 }
870 *radio_ptr++ = optarg;
871 break;
872 }
873 case 's':
874 sigma_dut.sniffer_ifname = optarg;
875 break;
876 case 't':
877 sigma_dut.no_timestamps = 1;
878 break;
879 case 'T':
880 sigma_dut.throughput_pktsize = atoi(optarg);
Jouni Malinenc2493f82016-06-05 18:01:33 +0300881 if (sigma_dut.throughput_pktsize == 0) {
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200882 printf("Invalid -T value\n");
883 exit(0);
884 }
885 break;
886 case 'm':
887 sigma_dut.set_macaddr = optarg;
888 break;
889 case 'M':
890 sigma_main_ifname = optarg;
891 break;
892 case 'n':
893 sigma_dut.no_ip_addr_set = 1;
894 break;
Jouni Malinen5db3b102016-08-04 12:27:18 +0300895 case 'N':
896 sigma_dut.vendor_name = optarg;
897 break;
898 case 'o':
899 sigma_dut.model_name = optarg;
900 break;
901 case 'O':
902 sigma_dut.version_name = optarg;
903 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200904 case 'S':
905 sigma_station_ifname = optarg;
906 break;
907 case 'w':
908 sigma_hapd_ctrl = optarg;
909 sigma_wpas_ctrl = optarg;
910 break;
911 case 'i':
912 ap_inet_addr = optarg;
913 break;
914 case 'k':
915 ap_inet_mask = optarg;
916 break;
917 case 'c':
918 printf("%s", optarg);
919 if (set_wifi_chip(optarg) < 0)
920 sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
921 "WRONG CHIP TYPE: SAP will "
922 "not load");
923 break;
924 case 'v':
925 sigma_dut.version = optarg;
926 break;
927 case 'V':
928 printf("sigma_dut " SIGMA_DUT_VER "\n");
929 exit(0);
930 break;
931 case 'W':
932 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
933 "Running WMM-AC test suite");
934 sigma_wmm_ac = 1;
935 break;
936 case 'u':
937 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
938 "Use iface down/up in reset cmd");
939 sigma_dut.iface_down_on_reset = 1;
940 break;
Bala Krishna Bhamidipati73d7af02016-03-24 12:27:56 +0530941 case 'A':
942 sigma_dut.sim_no_username = 1;
943 break;
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -0700944#ifdef MIRACAST
945 case 'x':
946 if (strcmp(optarg, "sink") == 0) {
947 sigma_dut.wfd_device_type = 1;
948 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
949 "Device Type is SINK");
950 } else if (strcmp(optarg, "source") == 0) {
951 sigma_dut.wfd_device_type = 0;
952 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
953 "Device Type is SOURCE");
954 }
955 break;
956 case 'y':
957 sigma_dut.miracast_lib_path = optarg;
958 break;
959#endif /* MIRACAST */
Rajiv Ranjan525dbfd2018-04-20 17:42:48 +0530960 case 'z':
961 client_socket_path = optarg;
962 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200963 case 'h':
964 default:
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300965 printf("usage: sigma_dut [-aABdfGqDIntuVW] [-p<port>] "
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200966 "[-s<sniffer>] [-m<set_maccaddr.sh>] \\\n"
967 " [-M<main ifname>] [-R<radio ifname>] "
Danny Segalf2af39b2016-04-10 16:23:11 +0300968 "[-S<station ifname>] [-P<p2p_ifname>]\\\n"
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200969 " [-T<throughput pktsize>] \\\n"
970 " [-w<wpa_supplicant/hostapd ctrl_iface "
971 "dir>] \\\n"
972 " [-H <hostapd log file>] \\\n"
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300973 " [-F <hostapd binary path>] \\\n"
974 " [-j <hostapd ifname>] \\\n"
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200975 " [-C <certificate path>] \\\n"
976 " [-v <version string>] \\\n"
977 " [-L <summary log>] \\\n"
978 " [-c <wifi chip type: WCN or ATHEROS or "
Sreelakshmi Konamkib692f102016-04-26 19:47:00 +0530979 "AR6003 or MAC80211 or QNXNTO or OPENWRT or "
980 "LINUX-WCN>] "
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200981 "\\\n"
982 " [-i <IP address of the AP>] \\\n"
983 " [-k <subnet mask for the AP>] \\\n"
984 " [-e <hostapd entropy file>] \\\n"
Jouni Malinen5db3b102016-08-04 12:27:18 +0300985 " [-N <device_get_info vendor>] \\\n"
986 " [-o <device_get_info model>] \\\n"
987 " [-O <device_get_info version>] \\\n"
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -0700988#ifdef MIRACAST
989 " [-x <sink|source>] \\\n"
990 " [-y <Miracast library path>] \\\n"
991#endif /* MIRACAST */
Rajiv Ranjan525dbfd2018-04-20 17:42:48 +0530992 " [-z <client socket directory path \\\n"
993 " Ex: </data/vendor/wifi/sockets>] \\\n"
Pradeep Reddy Pottetibf8af292017-02-15 15:28:39 +0530994 " [-r <HT40 or 2.4_HT40>]\n");
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200995 printf("local command: sigma_dut [-p<port>] "
996 "<-l<cmd>>\n");
997 exit(0);
998 break;
999 }
1000 }
1001
Purushottam Kushwaha091e2532016-08-23 11:52:21 +05301002 sigma_dut.p2p_ifname = determine_sigma_p2p_ifname();
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -07001003#ifdef MIRACAST
1004 miracast_init(&sigma_dut);
1005#endif /* MIRACAST */
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001006 if (local_cmd)
1007 return run_local_cmd(port, local_cmd);
1008
Pradeep Reddy Potteti08eaeba2017-06-14 12:43:19 +05301009 if ((wifi_chip_type == DRIVER_QNXNTO ||
1010 wifi_chip_type == DRIVER_LINUX_WCN) &&
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001011 (sigma_main_ifname == NULL || sigma_station_ifname == NULL)) {
1012 sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
Pradeep Reddy Potteti08eaeba2017-06-14 12:43:19 +05301013 "Interface should be provided for QNX/LINUX-WCN driver - check option M and S");
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001014 }
1015
Peng Xu291d97d2018-01-31 16:34:03 -08001016#ifdef NL80211_SUPPORT
1017 sigma_dut.nl_ctx = nl80211_init(&sigma_dut);
1018#endif /* NL80211_SUPPORT */
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001019 sigma_dut_register_cmds();
1020
1021#ifdef __QNXNTO__
1022 /* Try to open socket in other env dev */
1023 if (sigma_ctrl_sock) {
1024 env_str = getenv("SOCK");
1025 if (env_str) {
1026 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
1027 "SOCK=%s", env_str);
1028 }
1029 snprintf(buf, sizeof(buf), "SOCK=%s", sigma_ctrl_sock);
1030 if (putenv(buf) != 0) {
1031 sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
1032 "putenv() failed setting SOCK");
1033 return EXIT_FAILURE;
1034 }
1035 }
1036#endif /* __QNXNTO__ */
1037
1038 if (open_socket(&sigma_dut, port) < 0)
1039 return -1;
1040
1041#ifdef __QNXNTO__
1042 /* restore back the SOCK */
1043 if (sigma_ctrl_sock) {
1044 if (env_str) {
1045 snprintf(buf, sizeof(buf), "SOCK=%s", env_str);
1046 if (putenv(buf) != 0) {
1047 sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
1048 "putenv() failed setting SOCK");
1049 return EXIT_FAILURE;
1050 }
1051 } else {
1052 /* unset the env for sock */
1053 unsetenv("SOCK");
1054 }
1055 }
1056#endif /* __QNXNTO__ */
1057
1058 if (daemonize) {
1059 if (daemon(0, 0) < 0) {
1060 perror("daemon");
1061 exit(-1);
1062 }
1063 } else {
1064#ifdef __linux__
1065 setlinebuf(stdout);
1066#endif /* __linux__ */
1067 }
1068
Purushottam Kushwaha091e2532016-08-23 11:52:21 +05301069 if (internal_dhcp_enabled)
1070 p2p_create_event_thread(&sigma_dut);
1071
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001072 run_loop(&sigma_dut);
1073
1074#ifdef CONFIG_SNIFFER
1075 sniffer_close(&sigma_dut);
1076#endif /* CONFIG_SNIFFER */
1077
Danny Segalf2af39b2016-04-10 16:23:11 +03001078 free(sigma_p2p_ifname_buf);
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001079 close_socket(&sigma_dut);
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -07001080#ifdef MIRACAST
1081 miracast_deinit(&sigma_dut);
1082#endif /* MIRACAST */
Ashwini Patil00402582017-04-13 12:29:39 +05301083 free(sigma_dut.non_pref_ch_list);
1084 sigma_dut.non_pref_ch_list = NULL;
Ashwini Patil5acd7382017-04-13 15:55:04 +05301085 free(sigma_dut.btm_query_cand_list);
1086 sigma_dut.btm_query_cand_list = NULL;
Jouni Malinen3c367e82017-06-23 17:01:47 +03001087 free(sigma_dut.rsne_override);
Jouni Malinened670f42017-08-31 01:39:28 +03001088 free(sigma_dut.ap_sae_groups);
Jouni Malinenb1dd21f2017-11-13 19:14:29 +02001089 free(sigma_dut.dpp_peer_uri);
Peng Xu291d97d2018-01-31 16:34:03 -08001090#ifdef NL80211_SUPPORT
1091 nl80211_deinit(&sigma_dut, sigma_dut.nl_ctx);
1092#endif /* NL80211_SUPPORT */
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001093 sigma_dut_unreg_cmds(&sigma_dut);
Ankita Bajaj1bde7942018-01-09 19:15:01 +05301094#ifdef ANDROID
1095 hlp_thread_cleanup(&sigma_dut);
1096#endif /* ANDROID */
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001097
1098 return 0;
1099}