blob: 709296b7615f072af4733bca6b219573758ab0b3 [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;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200772 set_defaults(&sigma_dut);
773
774 for (;;) {
775 c = getopt(argc, argv,
Rajiv Ranjan525dbfd2018-04-20 17:42:48 +0530776 "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 +0200777 if (c < 0)
778 break;
779 switch (c) {
780 case 'a':
781 sigma_dut.ap_anqpserver = 1;
782 break;
783 case 'b':
784 sigma_dut.bridge = optarg;
785 break;
786 case 'B':
787 daemonize++;
788 break;
789 case 'C':
790 sigma_cert_path = optarg;
791 break;
792 case 'd':
793 if (sigma_dut.debug_level > 0)
794 sigma_dut.debug_level--;
795 break;
796#ifdef __QNXNTO__
797 case 'E':
798 sigma_ctrl_sock = optarg;
799 break;
800#endif /* __QNXNTO__ */
801 case 'D':
802 sigma_dut.stdout_debug = 1;
803 break;
804 case 'e':
805 sigma_dut.hostapd_entropy_log = optarg;
806 break;
807 case 'f':
808 /* Disable writing stats */
809 sigma_dut.write_stats = 0;
810 break;
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300811 case 'F':
812 sigma_dut.hostapd_bin = optarg;
813 break;
Purushottam Kushwaha091e2532016-08-23 11:52:21 +0530814 case 'g':
815 /* Enable internal processing of P2P group formation
816 * events to start/stop DHCP server/client. */
817 internal_dhcp_enabled = 1;
818 break;
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300819 case 'G':
820 sigma_dut.use_hostapd_pid_file = 1;
821 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200822 case 'H':
823 sigma_dut.hostapd_debug_log = optarg;
824 break;
825 case 'I':
826 print_license();
827 exit(0);
828 break;
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300829 case 'j':
830 sigma_dut.hostapd_ifname = optarg;
831 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200832 case 'l':
833 local_cmd = optarg;
834 break;
835 case 'L':
836 sigma_dut.summary_log = optarg;
837 break;
838 case 'p':
839 port = atoi(optarg);
840 break;
Danny Segalf2af39b2016-04-10 16:23:11 +0300841 case 'P':
842 sigma_p2p_ifname = optarg;
843 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200844 case 'q':
845 sigma_dut.debug_level++;
846 break;
847 case 'r':
848 if (strcmp(optarg, "HT40") == 0) {
Pradeep Reddy Pottetibf8af292017-02-15 15:28:39 +0530849 sigma_dut.default_11na_ap_chwidth = AP_40;
850 } else if (strcmp(optarg, "2.4_HT40") == 0) {
851 sigma_dut.default_11ng_ap_chwidth = AP_40;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200852 } else {
853 printf("Unsupported -r value\n");
854 exit(1);
855 }
856 break;
857 case 'R': {
858 static int num_radio = 0;
859 static char **radio_ptr = sigma_radio_ifname;
860
861 num_radio++;
862 if (num_radio > MAX_RADIO) {
863 printf("Multiple radio support limit (%d) exceeded\n",
864 MAX_RADIO);
865 exit(1);
866 }
867 *radio_ptr++ = optarg;
868 break;
869 }
870 case 's':
871 sigma_dut.sniffer_ifname = optarg;
872 break;
873 case 't':
874 sigma_dut.no_timestamps = 1;
875 break;
876 case 'T':
877 sigma_dut.throughput_pktsize = atoi(optarg);
Jouni Malinenc2493f82016-06-05 18:01:33 +0300878 if (sigma_dut.throughput_pktsize == 0) {
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200879 printf("Invalid -T value\n");
880 exit(0);
881 }
882 break;
883 case 'm':
884 sigma_dut.set_macaddr = optarg;
885 break;
886 case 'M':
887 sigma_main_ifname = optarg;
888 break;
889 case 'n':
890 sigma_dut.no_ip_addr_set = 1;
891 break;
Jouni Malinen5db3b102016-08-04 12:27:18 +0300892 case 'N':
893 sigma_dut.vendor_name = optarg;
894 break;
895 case 'o':
896 sigma_dut.model_name = optarg;
897 break;
898 case 'O':
899 sigma_dut.version_name = optarg;
900 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200901 case 'S':
902 sigma_station_ifname = optarg;
903 break;
904 case 'w':
905 sigma_hapd_ctrl = optarg;
906 sigma_wpas_ctrl = optarg;
907 break;
908 case 'i':
909 ap_inet_addr = optarg;
910 break;
911 case 'k':
912 ap_inet_mask = optarg;
913 break;
914 case 'c':
915 printf("%s", optarg);
916 if (set_wifi_chip(optarg) < 0)
917 sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
918 "WRONG CHIP TYPE: SAP will "
919 "not load");
920 break;
921 case 'v':
922 sigma_dut.version = optarg;
923 break;
924 case 'V':
925 printf("sigma_dut " SIGMA_DUT_VER "\n");
926 exit(0);
927 break;
928 case 'W':
929 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
930 "Running WMM-AC test suite");
931 sigma_wmm_ac = 1;
932 break;
933 case 'u':
934 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
935 "Use iface down/up in reset cmd");
936 sigma_dut.iface_down_on_reset = 1;
937 break;
Bala Krishna Bhamidipati73d7af02016-03-24 12:27:56 +0530938 case 'A':
939 sigma_dut.sim_no_username = 1;
940 break;
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -0700941#ifdef MIRACAST
942 case 'x':
943 if (strcmp(optarg, "sink") == 0) {
944 sigma_dut.wfd_device_type = 1;
945 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
946 "Device Type is SINK");
947 } else if (strcmp(optarg, "source") == 0) {
948 sigma_dut.wfd_device_type = 0;
949 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
950 "Device Type is SOURCE");
951 }
952 break;
953 case 'y':
954 sigma_dut.miracast_lib_path = optarg;
955 break;
956#endif /* MIRACAST */
Rajiv Ranjan525dbfd2018-04-20 17:42:48 +0530957 case 'z':
958 client_socket_path = optarg;
959 break;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200960 case 'h':
961 default:
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300962 printf("usage: sigma_dut [-aABdfGqDIntuVW] [-p<port>] "
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200963 "[-s<sniffer>] [-m<set_maccaddr.sh>] \\\n"
964 " [-M<main ifname>] [-R<radio ifname>] "
Danny Segalf2af39b2016-04-10 16:23:11 +0300965 "[-S<station ifname>] [-P<p2p_ifname>]\\\n"
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200966 " [-T<throughput pktsize>] \\\n"
967 " [-w<wpa_supplicant/hostapd ctrl_iface "
968 "dir>] \\\n"
969 " [-H <hostapd log file>] \\\n"
Jouni Malinend6bf1b42017-06-23 17:51:01 +0300970 " [-F <hostapd binary path>] \\\n"
971 " [-j <hostapd ifname>] \\\n"
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200972 " [-C <certificate path>] \\\n"
973 " [-v <version string>] \\\n"
974 " [-L <summary log>] \\\n"
975 " [-c <wifi chip type: WCN or ATHEROS or "
Sreelakshmi Konamkib692f102016-04-26 19:47:00 +0530976 "AR6003 or MAC80211 or QNXNTO or OPENWRT or "
977 "LINUX-WCN>] "
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200978 "\\\n"
979 " [-i <IP address of the AP>] \\\n"
980 " [-k <subnet mask for the AP>] \\\n"
981 " [-e <hostapd entropy file>] \\\n"
Jouni Malinen5db3b102016-08-04 12:27:18 +0300982 " [-N <device_get_info vendor>] \\\n"
983 " [-o <device_get_info model>] \\\n"
984 " [-O <device_get_info version>] \\\n"
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -0700985#ifdef MIRACAST
986 " [-x <sink|source>] \\\n"
987 " [-y <Miracast library path>] \\\n"
988#endif /* MIRACAST */
Rajiv Ranjan525dbfd2018-04-20 17:42:48 +0530989 " [-z <client socket directory path \\\n"
990 " Ex: </data/vendor/wifi/sockets>] \\\n"
Pradeep Reddy Pottetibf8af292017-02-15 15:28:39 +0530991 " [-r <HT40 or 2.4_HT40>]\n");
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200992 printf("local command: sigma_dut [-p<port>] "
993 "<-l<cmd>>\n");
994 exit(0);
995 break;
996 }
997 }
998
Purushottam Kushwaha091e2532016-08-23 11:52:21 +0530999 sigma_dut.p2p_ifname = determine_sigma_p2p_ifname();
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -07001000#ifdef MIRACAST
1001 miracast_init(&sigma_dut);
1002#endif /* MIRACAST */
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001003 if (local_cmd)
1004 return run_local_cmd(port, local_cmd);
1005
Pradeep Reddy Potteti08eaeba2017-06-14 12:43:19 +05301006 if ((wifi_chip_type == DRIVER_QNXNTO ||
1007 wifi_chip_type == DRIVER_LINUX_WCN) &&
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001008 (sigma_main_ifname == NULL || sigma_station_ifname == NULL)) {
1009 sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
Pradeep Reddy Potteti08eaeba2017-06-14 12:43:19 +05301010 "Interface should be provided for QNX/LINUX-WCN driver - check option M and S");
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001011 }
1012
Peng Xu291d97d2018-01-31 16:34:03 -08001013#ifdef NL80211_SUPPORT
1014 sigma_dut.nl_ctx = nl80211_init(&sigma_dut);
1015#endif /* NL80211_SUPPORT */
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001016 sigma_dut_register_cmds();
1017
1018#ifdef __QNXNTO__
1019 /* Try to open socket in other env dev */
1020 if (sigma_ctrl_sock) {
1021 env_str = getenv("SOCK");
1022 if (env_str) {
1023 sigma_dut_print(&sigma_dut, DUT_MSG_INFO,
1024 "SOCK=%s", env_str);
1025 }
1026 snprintf(buf, sizeof(buf), "SOCK=%s", sigma_ctrl_sock);
1027 if (putenv(buf) != 0) {
1028 sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
1029 "putenv() failed setting SOCK");
1030 return EXIT_FAILURE;
1031 }
1032 }
1033#endif /* __QNXNTO__ */
1034
1035 if (open_socket(&sigma_dut, port) < 0)
1036 return -1;
1037
1038#ifdef __QNXNTO__
1039 /* restore back the SOCK */
1040 if (sigma_ctrl_sock) {
1041 if (env_str) {
1042 snprintf(buf, sizeof(buf), "SOCK=%s", env_str);
1043 if (putenv(buf) != 0) {
1044 sigma_dut_print(&sigma_dut, DUT_MSG_ERROR,
1045 "putenv() failed setting SOCK");
1046 return EXIT_FAILURE;
1047 }
1048 } else {
1049 /* unset the env for sock */
1050 unsetenv("SOCK");
1051 }
1052 }
1053#endif /* __QNXNTO__ */
1054
1055 if (daemonize) {
1056 if (daemon(0, 0) < 0) {
1057 perror("daemon");
1058 exit(-1);
1059 }
1060 } else {
1061#ifdef __linux__
1062 setlinebuf(stdout);
1063#endif /* __linux__ */
1064 }
1065
Purushottam Kushwaha091e2532016-08-23 11:52:21 +05301066 if (internal_dhcp_enabled)
1067 p2p_create_event_thread(&sigma_dut);
1068
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001069 run_loop(&sigma_dut);
1070
1071#ifdef CONFIG_SNIFFER
1072 sniffer_close(&sigma_dut);
1073#endif /* CONFIG_SNIFFER */
1074
Danny Segalf2af39b2016-04-10 16:23:11 +03001075 free(sigma_p2p_ifname_buf);
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001076 close_socket(&sigma_dut);
Amarnath Hullur Subramanyam9c381f52017-03-17 00:04:41 -07001077#ifdef MIRACAST
1078 miracast_deinit(&sigma_dut);
1079#endif /* MIRACAST */
Ashwini Patil00402582017-04-13 12:29:39 +05301080 free(sigma_dut.non_pref_ch_list);
1081 sigma_dut.non_pref_ch_list = NULL;
Ashwini Patil5acd7382017-04-13 15:55:04 +05301082 free(sigma_dut.btm_query_cand_list);
1083 sigma_dut.btm_query_cand_list = NULL;
Jouni Malinen3c367e82017-06-23 17:01:47 +03001084 free(sigma_dut.rsne_override);
Jouni Malinened670f42017-08-31 01:39:28 +03001085 free(sigma_dut.ap_sae_groups);
Jouni Malinenb1dd21f2017-11-13 19:14:29 +02001086 free(sigma_dut.dpp_peer_uri);
Jouni Malinenac367142018-05-01 00:32:24 +03001087 free(sigma_dut.ap_tnc_url);
Peng Xu291d97d2018-01-31 16:34:03 -08001088#ifdef NL80211_SUPPORT
1089 nl80211_deinit(&sigma_dut, sigma_dut.nl_ctx);
1090#endif /* NL80211_SUPPORT */
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001091 sigma_dut_unreg_cmds(&sigma_dut);
Ankita Bajaj1bde7942018-01-09 19:15:01 +05301092#ifdef ANDROID
1093 hlp_thread_cleanup(&sigma_dut);
1094#endif /* ANDROID */
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001095
1096 return 0;
1097}