1 /* 2 * iwinfo - Wireless Information Library - Shared utility routines 3 * 4 * Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org> 5 * 6 * The iwinfo library is free software: you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License version 2 8 * as published by the Free Software Foundation. 9 * 10 * The iwinfo library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 * See the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 * 18 * The signal handling code is derived from the official madwifi tools, 19 * wlanconfig.c in particular. The encryption property handling was 20 * inspired by the hostapd madwifi driver. 21 */ 22 23 #include "iwinfo/utils.h" 24 25 26 static int ioctl_socket = -1; 27 struct uci_context *uci_ctx = NULL; 28 29 static int iwinfo_ioctl_socket(void) 30 { 31 /* Prepare socket */ 32 if (ioctl_socket == -1) 33 { 34 ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0); 35 fcntl(ioctl_socket, F_SETFD, fcntl(ioctl_socket, F_GETFD) | FD_CLOEXEC); 36 } 37 38 return ioctl_socket; 39 } 40 41 int iwinfo_ioctl(int cmd, void *ifr) 42 { 43 int s = iwinfo_ioctl_socket(); 44 return ioctl(s, cmd, ifr); 45 } 46 47 int iwinfo_dbm2mw(int in) 48 { 49 double res = 1.0; 50 int ip = in / 10; 51 int fp = in % 10; 52 int k; 53 54 for(k = 0; k < ip; k++) res *= 10; 55 for(k = 0; k < fp; k++) res *= LOG10_MAGIC; 56 57 return (int)res; 58 } 59 60 int iwinfo_mw2dbm(int in) 61 { 62 double fin = (double) in; 63 int res = 0; 64 65 while(fin > 10.0) 66 { 67 res += 10; 68 fin /= 10.0; 69 } 70 71 while(fin > 1.000001) 72 { 73 res += 1; 74 fin /= LOG10_MAGIC; 75 } 76 77 return (int)res; 78 } 79 80 static int iwinfo_bit(int value, int max) 81 { 82 int i; 83 84 if (max > 31 || !(value & ((1 << max) - 1))) 85 return -1; 86 87 for (i = 0; i < max; i++) 88 { 89 if (value & 1) 90 break; 91 92 value >>= 1; 93 } 94 95 return i; 96 } 97 98 static const char * const iwinfo_name(int mask, int max, const char * const names[]) 99 { 100 int index = iwinfo_bit(mask, max); 101 102 if (index < 0) 103 return NULL; 104 105 return names[index]; 106 } 107 108 const char * const iwinfo_band_name(int mask) 109 { 110 return iwinfo_name(mask, IWINFO_BAND_COUNT, IWINFO_BAND_NAMES); 111 } 112 113 const char * const iwinfo_htmode_name(int mask) 114 { 115 return iwinfo_name(mask, IWINFO_HTMODE_COUNT, IWINFO_HTMODE_NAMES); 116 } 117 118 uint32_t iwinfo_band2ghz(uint8_t band) 119 { 120 switch (band) 121 { 122 case IWINFO_BAND_24: 123 return 2; 124 case IWINFO_BAND_5: 125 return 5; 126 case IWINFO_BAND_6: 127 return 6; 128 case IWINFO_BAND_60: 129 return 60; 130 } 131 132 return 0; 133 } 134 135 uint8_t iwinfo_ghz2band(uint32_t ghz) 136 { 137 switch (ghz) 138 { 139 case 2: 140 return IWINFO_BAND_24; 141 case 5: 142 return IWINFO_BAND_5; 143 case 6: 144 return IWINFO_BAND_6; 145 case 60: 146 return IWINFO_BAND_60; 147 } 148 149 return 0; 150 } 151 152 size_t iwinfo_format_hwmodes(int modes, char *buf, size_t len) 153 { 154 // bit numbers as per IWINFO_80211_*: ad ac ax a b g n 155 const int order[IWINFO_80211_COUNT] = { 5, 4, 6, 0, 1, 2, 3 }; 156 size_t res = 0; 157 int i; 158 159 *buf = 0; 160 161 if (!(modes & ((1 << IWINFO_80211_COUNT) - 1))) 162 return 0; 163 164 for (i = 0; i < IWINFO_80211_COUNT; i++) 165 if (modes & 1 << order[i]) 166 res += snprintf(buf + res, len - res, "%s/", IWINFO_80211_NAMES[order[i]]); 167 168 if (res > 0) 169 { 170 res--; 171 buf[res] = 0; 172 } 173 174 return res; 175 } 176 177 int iwinfo_htmode_is_ht(int htmode) 178 { 179 switch (htmode) 180 { 181 case IWINFO_HTMODE_HT20: 182 case IWINFO_HTMODE_HT40: 183 return 1; 184 } 185 186 return 0; 187 } 188 189 int iwinfo_htmode_is_vht(int htmode) 190 { 191 switch (htmode) 192 { 193 case IWINFO_HTMODE_VHT20: 194 case IWINFO_HTMODE_VHT40: 195 case IWINFO_HTMODE_VHT80: 196 case IWINFO_HTMODE_VHT80_80: 197 case IWINFO_HTMODE_VHT160: 198 return 1; 199 } 200 201 return 0; 202 } 203 204 int iwinfo_htmode_is_he(int htmode) 205 { 206 switch (htmode) 207 { 208 case IWINFO_HTMODE_HE20: 209 case IWINFO_HTMODE_HE40: 210 case IWINFO_HTMODE_HE80: 211 case IWINFO_HTMODE_HE80_80: 212 case IWINFO_HTMODE_HE160: 213 return 1; 214 } 215 216 return 0; 217 } 218 219 int iwinfo_ifup(const char *ifname) 220 { 221 struct ifreq ifr; 222 223 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 224 225 if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr)) 226 return 0; 227 228 ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); 229 230 return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr); 231 } 232 233 int iwinfo_ifdown(const char *ifname) 234 { 235 struct ifreq ifr; 236 237 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 238 239 if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr)) 240 return 0; 241 242 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING); 243 244 return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr); 245 } 246 247 int iwinfo_ifmac(const char *ifname) 248 { 249 struct ifreq ifr; 250 251 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 252 253 if (iwinfo_ioctl(SIOCGIFHWADDR, &ifr)) 254 return 0; 255 256 ifr.ifr_hwaddr.sa_data[0] |= 0x02; 257 ifr.ifr_hwaddr.sa_data[1]++; 258 ifr.ifr_hwaddr.sa_data[2]++; 259 260 return !iwinfo_ioctl(SIOCSIFHWADDR, &ifr); 261 } 262 263 void iwinfo_close(void) 264 { 265 if (ioctl_socket > -1) 266 close(ioctl_socket); 267 268 ioctl_socket = -1; 269 } 270 271 struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id) 272 { 273 FILE *db; 274 char buf[256] = { 0 }; 275 static struct iwinfo_hardware_entry e; 276 struct iwinfo_hardware_entry *rv = NULL; 277 278 if (!(db = fopen(IWINFO_HARDWARE_FILE, "r"))) 279 return NULL; 280 281 while (fgets(buf, sizeof(buf) - 1, db) != NULL) 282 { 283 if (buf[0] == '#') 284 continue; 285 286 memset(&e, 0, sizeof(e)); 287 288 if (sscanf(buf, "%hx %hx %hx %hx %hd %hd \"%63[^\"]\" \"%63[^\"]\"", 289 &e.vendor_id, &e.device_id, 290 &e.subsystem_vendor_id, &e.subsystem_device_id, 291 &e.txpower_offset, &e.frequency_offset, 292 e.vendor_name, e.device_name) != 8 && 293 sscanf(buf, "\"%127[^\"]\" %hd %hd \"%63[^\"]\" \"%63[^\"]\"", 294 e.compatible, &e.txpower_offset, &e.frequency_offset, 295 e.vendor_name, e.device_name) != 5) 296 continue; 297 298 if ((e.vendor_id != 0xffff) && (e.vendor_id != id->vendor_id)) 299 continue; 300 301 if ((e.device_id != 0xffff) && (e.device_id != id->device_id)) 302 continue; 303 304 if ((e.subsystem_vendor_id != 0xffff) && 305 (e.subsystem_vendor_id != id->subsystem_vendor_id)) 306 continue; 307 308 if ((e.subsystem_device_id != 0xffff) && 309 (e.subsystem_device_id != id->subsystem_device_id)) 310 continue; 311 312 if (strcmp(e.compatible, id->compatible)) 313 continue; 314 315 rv = &e; 316 break; 317 } 318 319 fclose(db); 320 return rv; 321 } 322 323 int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id) 324 { 325 FILE *mtd; 326 uint16_t *bc; 327 328 int fd, off; 329 unsigned int len; 330 char buf[128]; 331 332 if (!(mtd = fopen("/proc/mtd", "r"))) 333 return -1; 334 335 while (fgets(buf, sizeof(buf), mtd) != NULL) 336 { 337 if (fscanf(mtd, "mtd%d: %x %*x %127s", &off, &len, buf) < 3 || 338 (strcmp(buf, "\"boardconfig\"") && strcmp(buf, "\"EEPROM\"") && 339 strcmp(buf, "\"factory\""))) 340 { 341 off = -1; 342 continue; 343 } 344 345 break; 346 } 347 348 fclose(mtd); 349 350 if (off < 0) 351 return -1; 352 353 snprintf(buf, sizeof(buf), "/dev/mtdblock%d", off); 354 355 if ((fd = open(buf, O_RDONLY)) < 0) 356 return -1; 357 358 bc = mmap(NULL, len, PROT_READ, MAP_PRIVATE|MAP_LOCKED, fd, 0); 359 360 if ((void *)bc != MAP_FAILED) 361 { 362 id->vendor_id = 0; 363 id->device_id = 0; 364 365 for (off = len / 2 - 0x800; off >= 0; off -= 0x800) 366 { 367 /* AR531X board data magic */ 368 if ((bc[off] == 0x3533) && (bc[off + 1] == 0x3131)) 369 { 370 id->vendor_id = bc[off + 0x7d]; 371 id->device_id = bc[off + 0x7c]; 372 id->subsystem_vendor_id = bc[off + 0x84]; 373 id->subsystem_device_id = bc[off + 0x83]; 374 break; 375 } 376 377 /* AR5416 EEPROM magic */ 378 else if ((bc[off] == 0xA55A) || (bc[off] == 0x5AA5)) 379 { 380 id->vendor_id = bc[off + 0x0D]; 381 id->device_id = bc[off + 0x0E]; 382 id->subsystem_vendor_id = bc[off + 0x13]; 383 id->subsystem_device_id = bc[off + 0x14]; 384 break; 385 } 386 387 /* Rt3xxx SoC */ 388 else if ((bc[off] == 0x3050) || (bc[off] == 0x5030) || 389 (bc[off] == 0x3051) || (bc[off] == 0x5130) || 390 (bc[off] == 0x3052) || (bc[off] == 0x5230) || 391 (bc[off] == 0x3350) || (bc[off] == 0x5033) || 392 (bc[off] == 0x3352) || (bc[off] == 0x5233) || 393 (bc[off] == 0x3662) || (bc[off] == 0x6236) || 394 (bc[off] == 0x3883) || (bc[off] == 0x8338) || 395 (bc[off] == 0x5350) || (bc[off] == 0x5053)) 396 { 397 /* vendor: RaLink */ 398 id->vendor_id = 0x1814; 399 id->subsystem_vendor_id = 0x1814; 400 401 /* device */ 402 if (((bc[off] & 0xf0) == 0x30) || 403 ((bc[off] & 0xff) == 0x53)) 404 id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8; 405 else 406 id->device_id = bc[off]; 407 408 /* subsystem from EEPROM_NIC_CONF0_RF_TYPE */ 409 id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8; 410 } else if ((bc[off] == 0x7620) || (bc[off] == 0x2076) || 411 (bc[off] == 0x7628) || (bc[off] == 0x2876) || 412 (bc[off] == 0x7688) || (bc[off] == 0x8876)) { 413 /* vendor: MediaTek */ 414 id->vendor_id = 0x14c3; 415 id->subsystem_vendor_id = 0x14c3; 416 417 /* device */ 418 if ((bc[off] & 0xff) == 0x76) 419 id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8; 420 else 421 id->device_id = bc[off]; 422 423 /* subsystem from EEPROM_NIC_CONF0_RF_TYPE */ 424 id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8; 425 } 426 } 427 428 munmap(bc, len); 429 } 430 431 close(fd); 432 433 return (id->vendor_id && id->device_id) ? 0 : -1; 434 } 435 436 static void iwinfo_parse_rsn_cipher(uint8_t idx, uint16_t *ciphers) 437 { 438 switch (idx) 439 { 440 case 0: 441 *ciphers |= IWINFO_CIPHER_NONE; 442 break; 443 444 case 1: 445 *ciphers |= IWINFO_CIPHER_WEP40; 446 break; 447 448 case 2: 449 *ciphers |= IWINFO_CIPHER_TKIP; 450 break; 451 452 case 3: /* WRAP */ 453 break; 454 455 case 4: 456 *ciphers |= IWINFO_CIPHER_CCMP; 457 break; 458 459 case 5: 460 *ciphers |= IWINFO_CIPHER_WEP104; 461 break; 462 463 case 8: 464 *ciphers |= IWINFO_CIPHER_GCMP; 465 break; 466 467 case 9: 468 *ciphers |= IWINFO_CIPHER_GCMP256; 469 break; 470 471 case 10: 472 *ciphers |= IWINFO_CIPHER_CCMP256; 473 break; 474 475 case 6: /* AES-128-CMAC */ 476 case 7: /* No group addressed */ 477 case 11: /* BIP-GMAC-128 */ 478 case 12: /* BIP-GMAC-256 */ 479 case 13: /* BIP-CMAC-256 */ 480 break; 481 } 482 } 483 484 void iwinfo_parse_rsn(struct iwinfo_crypto_entry *c, uint8_t *data, uint8_t len, 485 uint16_t defcipher, uint8_t defauth) 486 { 487 uint16_t i, count; 488 uint8_t wpa_version = 0; 489 490 static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 }; 491 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac }; 492 493 data += 2; 494 len -= 2; 495 496 if (!memcmp(data, ms_oui, 3)) 497 wpa_version |= 1; 498 else if (!memcmp(data, ieee80211_oui, 3)) 499 wpa_version |= 2; 500 501 if (len < 4) 502 { 503 c->group_ciphers |= defcipher; 504 c->pair_ciphers |= defcipher; 505 c->auth_suites |= defauth; 506 return; 507 } 508 509 if (!memcmp(data, ms_oui, 3) || !memcmp(data, ieee80211_oui, 3)) 510 iwinfo_parse_rsn_cipher(data[3], &c->group_ciphers); 511 512 data += 4; 513 len -= 4; 514 515 if (len < 2) 516 { 517 c->pair_ciphers |= defcipher; 518 c->auth_suites |= defauth; 519 return; 520 } 521 522 count = data[0] | (data[1] << 8); 523 if (2 + (count * 4) > len) 524 return; 525 526 for (i = 0; i < count; i++) 527 if (!memcmp(data + 2 + (i * 4), ms_oui, 3) || 528 !memcmp(data + 2 + (i * 4), ieee80211_oui, 3)) 529 iwinfo_parse_rsn_cipher(data[2 + (i * 4) + 3], &c->pair_ciphers); 530 531 data += 2 + (count * 4); 532 len -= 2 + (count * 4); 533 534 if (len < 2) 535 { 536 c->auth_suites |= defauth; 537 return; 538 } 539 540 count = data[0] | (data[1] << 8); 541 if (2 + (count * 4) > len) 542 return; 543 544 for (i = 0; i < count; i++) 545 { 546 if (!memcmp(data + 2 + (i * 4), ms_oui, 3) || 547 !memcmp(data + 2 + (i * 4), ieee80211_oui, 3)) 548 { 549 switch (data[2 + (i * 4) + 3]) 550 { 551 case 1: /* IEEE 802.1x */ 552 c->wpa_version |= wpa_version; 553 c->auth_suites |= IWINFO_KMGMT_8021x; 554 break; 555 556 case 2: /* PSK */ 557 c->wpa_version |= wpa_version; 558 c->auth_suites |= IWINFO_KMGMT_PSK; 559 break; 560 561 case 3: /* FT/IEEE 802.1X */ 562 case 4: /* FT/PSK */ 563 case 5: /* IEEE 802.1X/SHA-256 */ 564 case 6: /* PSK/SHA-256 */ 565 case 7: /* TPK Handshake */ 566 break; 567 568 case 8: /* SAE */ 569 c->wpa_version |= 4; 570 c->auth_suites |= IWINFO_KMGMT_SAE; 571 break; 572 573 case 9: /* FT/SAE */ 574 case 10: /* undefined */ 575 break; 576 577 case 11: /* 802.1x Suite-B */ 578 case 12: /* 802.1x Suite-B-192 */ 579 case 13: /* FT/802.1x SHA-384 */ 580 c->wpa_version |= 4; 581 c->auth_suites |= IWINFO_KMGMT_8021x; 582 break; 583 584 case 14: /* FILS SHA-256 */ 585 case 15: /* FILS SHA-384 */ 586 case 16: /* FT/FILS SHA-256 */ 587 case 17: /* FT/FILS SHA-384 */ 588 break; 589 590 case 18: /* OWE */ 591 c->wpa_version |= 4; 592 c->auth_suites |= IWINFO_KMGMT_OWE; 593 break; 594 } 595 } 596 } 597 598 data += 2 + (count * 4); 599 len -= 2 + (count * 4); 600 } 601 602 struct uci_section *iwinfo_uci_get_radio(const char *name, const char *type) 603 { 604 struct uci_ptr ptr = { 605 .package = "wireless", 606 .section = name, 607 .flags = (name && *name == '@') ? UCI_LOOKUP_EXTENDED : 0, 608 }; 609 const char *opt; 610 611 if (!uci_ctx) { 612 uci_ctx = uci_alloc_context(); 613 if (!uci_ctx) 614 return NULL; 615 } 616 617 if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true)) 618 return NULL; 619 620 if (!ptr.s || strcmp(ptr.s->type, "wifi-device") != 0) 621 return NULL; 622 623 opt = uci_lookup_option_string(uci_ctx, ptr.s, "type"); 624 if (!opt || strcmp(opt, type) != 0) 625 return NULL; 626 627 return ptr.s; 628 } 629 630 void iwinfo_uci_free(void) 631 { 632 if (!uci_ctx) 633 return; 634 635 uci_free_context(uci_ctx); 636 uci_ctx = NULL; 637 } 638 639 640 struct iwinfo_ubus_query_state { 641 const char *ifname; 642 const char *field; 643 size_t len; 644 char *buf; 645 }; 646 647 static void iwinfo_ubus_query_cb(struct ubus_request *req, int type, 648 struct blob_attr *msg) 649 { 650 struct iwinfo_ubus_query_state *st = req->priv; 651 652 struct blobmsg_policy pol1[2] = { 653 { "ifname", BLOBMSG_TYPE_STRING }, 654 { "config", BLOBMSG_TYPE_TABLE } 655 }; 656 657 struct blobmsg_policy pol2 = { st->field, BLOBMSG_TYPE_STRING }; 658 struct blob_attr *cur, *cur2, *cur3, *cfg[2], *res; 659 int rem, rem2, rem3; 660 661 blobmsg_for_each_attr(cur, msg, rem) { 662 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) 663 continue; 664 665 blobmsg_for_each_attr(cur2, cur, rem2) { 666 if (blobmsg_type(cur2) != BLOBMSG_TYPE_ARRAY) 667 continue; 668 669 if (strcmp(blobmsg_name(cur2), "interfaces")) 670 continue; 671 672 blobmsg_for_each_attr(cur3, cur2, rem3) { 673 blobmsg_parse(pol1, sizeof(pol1) / sizeof(pol1[0]), cfg, 674 blobmsg_data(cur3), blobmsg_len(cur3)); 675 676 if (!cfg[0] || !cfg[1] || 677 strcmp(blobmsg_get_string(cfg[0]), st->ifname)) 678 continue; 679 680 blobmsg_parse(&pol2, 1, &res, 681 blobmsg_data(cfg[1]), blobmsg_len(cfg[1])); 682 683 if (!res) 684 continue; 685 686 strncpy(st->buf, blobmsg_get_string(res), st->len); 687 return; 688 } 689 } 690 } 691 } 692 693 int iwinfo_ubus_query(const char *ifname, const char *field, 694 char *buf, size_t len) 695 { 696 struct iwinfo_ubus_query_state st = { 697 .ifname = ifname, 698 .field = field, 699 .buf = buf, 700 .len = len 701 }; 702 703 struct ubus_context *ctx = NULL; 704 struct blob_buf b = { }; 705 int rv = -1; 706 uint32_t id; 707 708 blob_buf_init(&b, 0); 709 710 ctx = ubus_connect(NULL); 711 712 if (!ctx) 713 goto out; 714 715 if (ubus_lookup_id(ctx, "network.wireless", &id)) 716 goto out; 717 718 if (ubus_invoke(ctx, id, "status", b.head, iwinfo_ubus_query_cb, &st, 250)) 719 goto out; 720 721 rv = 0; 722 723 out: 724 if (ctx) 725 ubus_free(ctx); 726 727 blob_buf_free(&b); 728 729 return rv; 730 } 731
This page was automatically generated by LXR 0.3.1. • OpenWrt