1 /* 2 * Sigma Control API DUT (station/AP) 3 * Copyright (c) 2014-2017, Qualcomm Atheros, Inc. 4 * Copyright (c) 2018, The Linux Foundation 5 * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> 6 * All Rights Reserved. 7 * Licensed under the Clear BSD license. See README for more details. 8 */ 9 10 #include "sigma_dut.h" 11 #include <sys/stat.h> 12 #include "wpa_helpers.h" 13 14 enum driver_type wifi_chip_type = DRIVER_NOT_SET; 15 enum openwrt_driver_type openwrt_chip_type = OPENWRT_DRIVER_NOT_SET; 16 17 18 int file_exists(const char *fname) 19 { 20 struct stat s; 21 return stat(fname, &s) == 0; 22 } 23 24 25 int set_wifi_chip(const char *chip_type) 26 { 27 if (!strncmp(chip_type, "WCN", strlen("WCN"))) 28 wifi_chip_type = DRIVER_WCN; 29 else if (!strncmp(chip_type, "ATHEROS", strlen("ATHEROS"))) 30 wifi_chip_type = DRIVER_ATHEROS; 31 else if (!strncmp(chip_type, "AR6003", strlen("AR6003"))) 32 wifi_chip_type = DRIVER_AR6003; 33 else if (strcmp(chip_type, "MAC80211") == 0) 34 wifi_chip_type = DRIVER_MAC80211; 35 else if (strcmp(chip_type, "QNXNTO") == 0) 36 wifi_chip_type = DRIVER_QNXNTO; 37 else if (strcmp(chip_type, "OPENWRT") == 0) 38 wifi_chip_type = DRIVER_OPENWRT; 39 else if (!strncmp(chip_type, "LINUX-WCN", strlen("LINUX-WCN"))) 40 wifi_chip_type = DRIVER_LINUX_WCN; 41 else 42 return -1; 43 44 return 0; 45 } 46 47 48 enum driver_type get_driver_type(struct sigma_dut *dut) 49 { 50 struct stat s; 51 if (wifi_chip_type == DRIVER_NOT_SET) { 52 /* Check for 60G driver */ 53 ssize_t len; 54 char link[256]; 55 char buf[256]; 56 const char *ifname = get_station_ifname(dut); 57 58 snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver", 59 ifname); 60 len = readlink(buf, link, sizeof(link) - 1); 61 if (len >= 0) { 62 link[len] = '\0'; 63 if (strstr(link, DRIVER_NAME_60G)) 64 return DRIVER_WIL6210; 65 } 66 67 if (stat("/sys/module/mac80211", &s) == 0) 68 return DRIVER_MAC80211; 69 return DRIVER_ATHEROS; 70 } 71 return wifi_chip_type; 72 } 73 74 75 enum openwrt_driver_type get_openwrt_driver_type(void) 76 { 77 struct stat s; 78 79 if (openwrt_chip_type == OPENWRT_DRIVER_NOT_SET) { 80 if (stat("/sys/module/umac", &s) == 0 || 81 stat("/sys/module/atd", &s) == 0) 82 openwrt_chip_type = OPENWRT_DRIVER_ATHEROS; 83 } 84 85 return openwrt_chip_type; 86 } 87 88 89 enum sigma_program sigma_program_to_enum(const char *prog) 90 { 91 if (prog == NULL) 92 return PROGRAM_UNKNOWN; 93 94 if (strcasecmp(prog, "TDLS") == 0) 95 return PROGRAM_TDLS; 96 if (strcasecmp(prog, "HS2") == 0) 97 return PROGRAM_HS2; 98 if (strcasecmp(prog, "HS2_R2") == 0 || 99 strcasecmp(prog, "HS2-R2") == 0) 100 return PROGRAM_HS2_R2; 101 if (strcasecmp(prog, "HS2-R3") == 0) 102 return PROGRAM_HS2_R3; 103 if (strcasecmp(prog, "WFD") == 0) 104 return PROGRAM_WFD; 105 if (strcasecmp(prog, "DisplayR2") == 0) 106 return PROGRAM_DISPLAYR2; 107 if (strcasecmp(prog, "PMF") == 0) 108 return PROGRAM_PMF; 109 if (strcasecmp(prog, "WPS") == 0) 110 return PROGRAM_WPS; 111 if (strcasecmp(prog, "11n") == 0) 112 return PROGRAM_HT; 113 if (strcasecmp(prog, "VHT") == 0) 114 return PROGRAM_VHT; 115 if (strcasecmp(prog, "60GHZ") == 0) 116 return PROGRAM_60GHZ; 117 if (strcasecmp(prog, "NAN") == 0) 118 return PROGRAM_NAN; 119 if (strcasecmp(prog, "LOC") == 0) 120 return PROGRAM_LOC; 121 if (strcasecmp(prog, "MBO") == 0) 122 return PROGRAM_MBO; 123 if (strcasecmp(prog, "IoTLP") == 0) 124 return PROGRAM_IOTLP; 125 if (strcasecmp(prog, "DPP") == 0) 126 return PROGRAM_DPP; 127 if (strcasecmp(prog, "OCE") == 0) 128 return PROGRAM_OCE; 129 if (strcasecmp(prog, "WPA3") == 0) 130 return PROGRAM_WPA3; 131 if (strcasecmp(prog, "HE") == 0) 132 return PROGRAM_HE; 133 134 return PROGRAM_UNKNOWN; 135 } 136 137 138 static int parse_hex(char c) 139 { 140 if (c >= '0' && c <= '9') 141 return c - '0'; 142 if (c >= 'a' && c <= 'f') 143 return c - 'a' + 10; 144 if (c >= 'A' && c <= 'F') 145 return c - 'A' + 10; 146 return -1; 147 } 148 149 150 int hex_byte(const char *str) 151 { 152 int res1, res2; 153 154 res1 = parse_hex(str[0]); 155 if (res1 < 0) 156 return -1; 157 res2 = parse_hex(str[1]); 158 if (res2 < 0) 159 return -1; 160 return (res1 << 4) | res2; 161 } 162 163 164 int parse_hexstr(const char *hex, unsigned char *buf, size_t buflen) 165 { 166 size_t i; 167 const char *pos = hex; 168 169 for (i = 0; i < buflen; i++) { 170 int val; 171 172 if (*pos == '\0') 173 break; 174 val = hex_byte(pos); 175 if (val < 0) 176 return -1; 177 buf[i] = val; 178 pos += 2; 179 } 180 181 return i; 182 } 183 184 185 int parse_mac_address(struct sigma_dut *dut, const char *arg, 186 unsigned char *addr) 187 { 188 int i; 189 const char *pos = arg; 190 191 if (strlen(arg) != 17) 192 goto fail; 193 194 for (i = 0; i < ETH_ALEN; i++) { 195 int val; 196 197 val = hex_byte(pos); 198 if (val < 0) 199 goto fail; 200 addr[i] = val; 201 if (i + 1 < ETH_ALEN) { 202 pos += 2; 203 if (*pos != ':') 204 goto fail; 205 pos++; 206 } 207 } 208 209 return 0; 210 211 fail: 212 sigma_dut_print(dut, DUT_MSG_ERROR, 213 "Invalid MAC address %s (expected format xx:xx:xx:xx:xx:xx)", 214 arg); 215 return -1; 216 } 217 218 219 int is_60g_sigma_dut(struct sigma_dut *dut) 220 { 221 return dut->program == PROGRAM_60GHZ || 222 (dut->program == PROGRAM_WPS && 223 (get_driver_type(dut) == DRIVER_WIL6210)); 224 } 225 226 227 unsigned int channel_to_freq(struct sigma_dut *dut, unsigned int channel) 228 { 229 if (is_60g_sigma_dut(dut)) { 230 if (channel >= 1 && channel <= 4) 231 return 58320 + 2160 * channel; 232 233 return 0; 234 } 235 236 if (channel >= 1 && channel <= 13) 237 return 2407 + 5 * channel; 238 if (channel == 14) 239 return 2484; 240 if (channel >= 36 && channel <= 165) 241 return 5000 + 5 * channel; 242 243 return 0; 244 } 245 246 247 unsigned int freq_to_channel(unsigned int freq) 248 { 249 if (freq >= 2412 && freq <= 2472) 250 return (freq - 2407) / 5; 251 if (freq == 2484) 252 return 14; 253 if (freq >= 5180 && freq <= 5825) 254 return (freq - 5000) / 5; 255 if (freq >= 58320 && freq <= 64800) 256 return (freq - 58320) / 2160; 257 return 0; 258 } 259 260 261 int is_ipv6_addr(const char *str) 262 { 263 struct sockaddr_in6 addr; 264 265 return inet_pton(AF_INET6, str, &(addr.sin6_addr)); 266 } 267 268 269 void convert_mac_addr_to_ipv6_lladdr(u8 *mac_addr, char *ipv6_buf, 270 size_t buf_len) 271 { 272 u8 temp = mac_addr[0] ^ 0x02; 273 274 snprintf(ipv6_buf, buf_len, "fe80::%02x%02x:%02xff:fe%02x:%02x%02x", 275 temp, mac_addr[1], mac_addr[2], 276 mac_addr[3], mac_addr[4], mac_addr[5]); 277 } 278 279 280 size_t convert_mac_addr_to_ipv6_linklocal(const u8 *mac_addr, u8 *ipv6) 281 { 282 int i; 283 284 ipv6[0] = 0xfe; 285 ipv6[1] = 0x80; 286 for (i = 2; i < 8; i++) 287 ipv6[i] = 0; 288 ipv6[8] = mac_addr[0] ^ 0x02; 289 ipv6[9] = mac_addr[1]; 290 ipv6[10] = mac_addr[2]; 291 ipv6[11] = 0xff; 292 ipv6[12] = 0xfe; 293 ipv6[13] = mac_addr[3]; 294 ipv6[14] = mac_addr[4]; 295 ipv6[15] = mac_addr[5]; 296 297 return 16; 298 } 299 300 301 #ifndef ANDROID 302 303 size_t strlcpy(char *dest, const char *src, size_t siz) 304 { 305 const char *s = src; 306 size_t left = siz; 307 308 if (left) { 309 /* Copy string up to the maximum size of the dest buffer */ 310 while (--left != 0) { 311 if ((*dest++ = *s++) == '\0') 312 break; 313 } 314 } 315 316 if (left == 0) { 317 /* Not enough room for the string; force NUL-termination */ 318 if (siz != 0) 319 *dest = '\0'; 320 while (*s++) 321 ; /* determine total src string length */ 322 } 323 324 return s - src - 1; 325 } 326 327 328 size_t strlcat(char *dst, const char *str, size_t size) 329 { 330 char *pos; 331 size_t dstlen, srclen, copy; 332 333 srclen = strlen(str); 334 for (pos = dst; pos - dst < size && *dst; pos++) 335 ; 336 dstlen = pos - dst; 337 if (*dst) 338 return dstlen + srclen; 339 if (dstlen + srclen + 1 > size) 340 copy = size - dstlen - 1; 341 else 342 copy = srclen; 343 memcpy(pos, str, copy); 344 pos[copy] = '\0'; 345 return dstlen + srclen; 346 } 347 348 #endif /* ANDROID */ 349 350 351 void hex_dump(struct sigma_dut *dut, u8 *data, size_t len) 352 { 353 char buf[1024]; 354 size_t index; 355 u8 *ptr; 356 int pos; 357 358 memset(buf, 0, sizeof(buf)); 359 ptr = data; 360 pos = 0; 361 for (index = 0; index < len; index++) { 362 pos += snprintf(&(buf[pos]), sizeof(buf) - pos, 363 "%02x ", *ptr++); 364 if (pos > 1020) 365 break; 366 } 367 sigma_dut_print(dut, DUT_MSG_INFO, "HEXDUMP len=[%d]", (int) len); 368 sigma_dut_print(dut, DUT_MSG_INFO, "buf:%s", buf); 369 } 370 371 372 #ifdef NL80211_SUPPORT 373 374 void * nl80211_cmd(struct sigma_dut *dut, struct nl80211_ctx *ctx, 375 struct nl_msg *msg, int flags, uint8_t cmd) 376 { 377 return genlmsg_put(msg, 0, 0, ctx->netlink_familyid, 378 0, flags, cmd, 0); 379 } 380 381 382 static struct nl_msg * 383 nl80211_ifindex_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, int ifindex, 384 int flags, uint8_t cmd) 385 { 386 struct nl_msg *msg; 387 388 msg = nlmsg_alloc(); 389 if (!msg) { 390 sigma_dut_print(dut, DUT_MSG_ERROR, 391 "Failed to allocate NL message"); 392 return NULL; 393 } 394 395 if (!nl80211_cmd(dut, ctx, msg, flags, cmd) || 396 nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) { 397 nlmsg_free(msg); 398 return NULL; 399 } 400 401 return msg; 402 } 403 404 405 struct nl_msg * nl80211_drv_msg(struct sigma_dut *dut, struct nl80211_ctx *ctx, 406 int ifindex, int flags, uint8_t cmd) 407 { 408 return nl80211_ifindex_msg(dut, ctx, ifindex, flags, cmd); 409 } 410 411 412 static int ack_handler(struct nl_msg *msg, void *arg) 413 { 414 int *err = arg; 415 *err = 0; 416 return NL_STOP; 417 } 418 419 420 static int finish_handler(struct nl_msg *msg, void *arg) 421 { 422 int *ret = arg; 423 *ret = 0; 424 return NL_SKIP; 425 } 426 427 428 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, 429 void *arg) 430 { 431 int *ret = arg; 432 *ret = err->error; 433 return NL_SKIP; 434 } 435 436 437 int send_and_recv_msgs(struct sigma_dut *dut, struct nl80211_ctx *ctx, 438 struct nl_msg *nlmsg, 439 int (*valid_handler)(struct nl_msg *, void *), 440 void *valid_data) 441 { 442 struct nl_cb *cb; 443 int err = -ENOMEM; 444 445 if (!nlmsg) 446 return -ENOMEM; 447 448 cb = nl_cb_alloc(NL_CB_DEFAULT); 449 if (!cb) 450 goto out; 451 452 err = nl_send_auto_complete(ctx->sock, nlmsg); 453 if (err < 0) { 454 sigma_dut_print(dut, DUT_MSG_ERROR, 455 "nl80211: failed to send err=%d", err); 456 goto out; 457 } 458 459 err = 1; 460 461 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); 462 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); 463 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); 464 465 if (valid_handler) 466 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, 467 valid_handler, valid_data); 468 469 while (err > 0) { 470 int res = nl_recvmsgs(ctx->sock, cb); 471 472 if (res < 0) { 473 sigma_dut_print(dut, DUT_MSG_ERROR, 474 "nl80211: %s->nl_recvmsgs failed: res=%d, err=%d", 475 __func__, res, err); 476 } 477 } 478 out: 479 nl_cb_put(cb); 480 if (!valid_handler && valid_data == (void *) -1) { 481 if (nlmsg) { 482 struct nlmsghdr *hdr = nlmsg_hdr(nlmsg); 483 void *data = nlmsg_data(hdr); 484 int len = hdr->nlmsg_len - NLMSG_HDRLEN; 485 486 memset(data, 0, len); 487 } 488 } 489 490 nlmsg_free(nlmsg); 491 return err; 492 } 493 494 495 struct nl80211_ctx * nl80211_init(struct sigma_dut *dut) 496 { 497 struct nl80211_ctx *ctx; 498 499 ctx = calloc(1, sizeof(struct nl80211_ctx)); 500 if (!ctx) { 501 sigma_dut_print(dut, DUT_MSG_ERROR, 502 "Failed to alloc nl80211_ctx"); 503 return NULL; 504 } 505 506 ctx->sock = nl_socket_alloc(); 507 if (!ctx->sock) { 508 sigma_dut_print(dut, DUT_MSG_ERROR, 509 "Failed to create NL socket, err: %s", 510 strerror(errno)); 511 goto cleanup; 512 } 513 514 if (nl_connect(ctx->sock, NETLINK_GENERIC)) { 515 sigma_dut_print(dut, DUT_MSG_ERROR, 516 "Could not connect socket, err: %s", 517 strerror(errno)); 518 goto cleanup; 519 } 520 521 if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE, 0) < 0) { 522 sigma_dut_print(dut, DUT_MSG_INFO, 523 "Could not set nl_socket RX buffer size for sock: %s", 524 strerror(errno)); 525 } 526 527 ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "nl80211"); 528 if (ctx->netlink_familyid < 0) { 529 sigma_dut_print(dut, DUT_MSG_ERROR, 530 "Could not resolve nl80211 family id"); 531 goto cleanup; 532 } 533 534 ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl"); 535 if (ctx->nlctrl_familyid < 0) { 536 sigma_dut_print(dut, DUT_MSG_ERROR, 537 "net link family nlctrl is not present: %d err:%s", 538 ctx->nlctrl_familyid, strerror(errno)); 539 goto cleanup; 540 } 541 542 return ctx; 543 544 cleanup: 545 if (ctx->sock) 546 nl_socket_free(ctx->sock); 547 548 free(ctx); 549 return NULL; 550 } 551 552 553 void nl80211_deinit(struct sigma_dut *dut, struct nl80211_ctx *ctx) 554 { 555 if (!ctx || !ctx->sock) { 556 sigma_dut_print(dut, DUT_MSG_ERROR, "%s: ctx/sock is NULL", 557 __func__); 558 return; 559 } 560 nl_socket_free(ctx->sock); 561 free(ctx); 562 } 563 564 #endif /* NL80211_SUPPORT */ 565 566 567 static int get_wps_pin_checksum(int pin) 568 { 569 int a = 0; 570 571 while (pin > 0) { 572 a += 3 * (pin % 10); 573 pin = pin / 10; 574 a += (pin % 10); 575 pin = pin / 10; 576 } 577 578 return (10 - (a % 10)) % 10; 579 } 580 581 582 int get_wps_pin_from_mac(struct sigma_dut *dut, const char *macaddr, 583 char *pin, size_t len) 584 { 585 unsigned char mac[ETH_ALEN]; 586 int tmp, checksum; 587 588 if (len < 9) 589 return -1; 590 if (parse_mac_address(dut, macaddr, mac)) 591 return -1; 592 593 /* 594 * get 7 digit PIN from the last 24 bits of MAC 595 * range 1000000 - 9999999 596 */ 597 tmp = (mac[5] & 0xFF) | ((mac[4] & 0xFF) << 8) | 598 ((mac[3] & 0xFF) << 16); 599 tmp = (tmp % 9000000) + 1000000; 600 checksum = get_wps_pin_checksum(tmp); 601 snprintf(pin, len, "%07d%01d", tmp, checksum); 602 return 0; 603 } 604 605 606 int get_wps_forced_version(struct sigma_dut *dut, const char *str) 607 { 608 int major, minor, result = 0; 609 int count = sscanf(str, "%d.%d", &major, &minor); 610 611 if (count == 2) { 612 result = major * 16 + minor; 613 sigma_dut_print(dut, DUT_MSG_DEBUG, 614 "Force WPS version to 0x%02x (%s)", 615 result, str); 616 } else { 617 sigma_dut_print(dut, DUT_MSG_ERROR, 618 "Invalid WPS version %s", str); 619 } 620 621 return result; 622 } 623 624 625 void str_remove_chars(char *str, char ch) 626 { 627 char *pr = str, *pw = str; 628 629 while (*pr) { 630 *pw = *pr++; 631 if (*pw != ch) 632 pw++; 633 } 634 *pw = '\0'; 635 } 636 637 638 static const char base64_table[65] = 639 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 640 641 642 int base64_encode(const char *src, size_t len, char *out, size_t out_len) 643 { 644 unsigned char *pos; 645 const unsigned char *end, *in; 646 size_t olen; 647 648 olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ 649 olen++; /* nul termination */ 650 if (olen < len || olen > out_len) 651 return -1; 652 653 end = (unsigned char *)(src + len); 654 in = (unsigned char *)src; 655 pos = (unsigned char *)out; 656 while (end - in >= 3) { 657 *pos++ = base64_table[(in[0] >> 2) & 0x3f]; 658 *pos++ = base64_table[(((in[0] & 0x03) << 4) | 659 (in[1] >> 4)) & 0x3f]; 660 *pos++ = base64_table[(((in[1] & 0x0f) << 2) | 661 (in[2] >> 6)) & 0x3f]; 662 *pos++ = base64_table[in[2] & 0x3f]; 663 in += 3; 664 } 665 666 if (end - in) { 667 *pos++ = base64_table[(in[0] >> 2) & 0x3f]; 668 if (end - in == 1) { 669 *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f]; 670 *pos++ = '='; 671 } else { 672 *pos++ = base64_table[(((in[0] & 0x03) << 4) | 673 (in[1] >> 4)) & 0x3f]; 674 *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f]; 675 } 676 *pos++ = '='; 677 } 678 679 *pos = '\0'; 680 return 0; 681 } 682 683 684 int random_get_bytes(char *buf, size_t len) 685 { 686 FILE *f; 687 size_t rc; 688 689 f = fopen("/dev/urandom", "rb"); 690 if (!f) 691 return -1; 692 693 rc = fread(buf, 1, len, f); 694 fclose(f); 695 696 return rc != len ? -1 : 0; 697 } 698 699 700 int get_enable_disable(const char *val) 701 { 702 if (strcasecmp(val, "enable") == 0 || 703 strcasecmp(val, "enabled") == 0 || 704 strcasecmp(val, "on") == 0 || 705 strcasecmp(val, "yes") == 0) 706 return 1; 707 return atoi(val); 708 } 709