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