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