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 be g n 155 const int order[IWINFO_80211_COUNT] = { 5, 4, 6, 0, 1, 7, 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_htmode_is_eht(int htmode) 220 { 221 switch (htmode) 222 { 223 case IWINFO_HTMODE_EHT20: 224 case IWINFO_HTMODE_EHT40: 225 case IWINFO_HTMODE_EHT80: 226 case IWINFO_HTMODE_EHT80_80: 227 case IWINFO_HTMODE_EHT160: 228 case IWINFO_HTMODE_EHT320: 229 return 1; 230 } 231 232 return 0; 233 } 234 235 int iwinfo_ifup(const char *ifname) 236 { 237 struct ifreq ifr; 238 239 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 240 241 if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr)) 242 return 0; 243 244 ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); 245 246 return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr); 247 } 248 249 int iwinfo_ifdown(const char *ifname) 250 { 251 struct ifreq ifr; 252 253 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 254 255 if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr)) 256 return 0; 257 258 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING); 259 260 return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr); 261 } 262 263 int iwinfo_ifmac(const char *ifname) 264 { 265 struct ifreq ifr; 266 267 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 268 269 if (iwinfo_ioctl(SIOCGIFHWADDR, &ifr)) 270 return 0; 271 272 ifr.ifr_hwaddr.sa_data[0] |= 0x02; 273 ifr.ifr_hwaddr.sa_data[1]++; 274 ifr.ifr_hwaddr.sa_data[2]++; 275 276 return !iwinfo_ioctl(SIOCSIFHWADDR, &ifr); 277 } 278 279 void iwinfo_close(void) 280 { 281 if (ioctl_socket > -1) 282 close(ioctl_socket); 283 284 ioctl_socket = -1; 285 } 286 287 struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id) 288 { 289 FILE *db; 290 char buf[256] = { 0 }; 291 static struct iwinfo_hardware_entry e; 292 struct iwinfo_hardware_entry *rv = NULL; 293 294 if (!(db = fopen(IWINFO_HARDWARE_FILE, "r"))) 295 return NULL; 296 297 while (fgets(buf, sizeof(buf) - 1, db) != NULL) 298 { 299 if (buf[0] == '#') 300 continue; 301 302 memset(&e, 0, sizeof(e)); 303 304 if (sscanf(buf, "%hx %hx %hx %hx %hd %hd \"%63[^\"]\" \"%63[^\"]\"", 305 &e.vendor_id, &e.device_id, 306 &e.subsystem_vendor_id, &e.subsystem_device_id, 307 &e.txpower_offset, &e.frequency_offset, 308 e.vendor_name, e.device_name) != 8 && 309 sscanf(buf, "\"%127[^\"]\" %hd %hd \"%63[^\"]\" \"%63[^\"]\"", 310 e.compatible, &e.txpower_offset, &e.frequency_offset, 311 e.vendor_name, e.device_name) != 5) 312 continue; 313 314 if ((e.vendor_id != 0xffff) && (e.vendor_id != id->vendor_id)) 315 continue; 316 317 if ((e.device_id != 0xffff) && (e.device_id != id->device_id)) 318 continue; 319 320 if ((e.subsystem_vendor_id != 0xffff) && 321 (e.subsystem_vendor_id != id->subsystem_vendor_id)) 322 continue; 323 324 if ((e.subsystem_device_id != 0xffff) && 325 (e.subsystem_device_id != id->subsystem_device_id)) 326 continue; 327 328 if (strcmp(e.compatible, id->compatible)) 329 continue; 330 331 rv = &e; 332 break; 333 } 334 335 fclose(db); 336 return rv; 337 } 338 339 int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id) 340 { 341 FILE *mtd; 342 uint16_t *bc; 343 344 int fd, off; 345 unsigned int len; 346 char buf[128]; 347 348 if (!(mtd = fopen("/proc/mtd", "r"))) 349 return -1; 350 351 while (fgets(buf, sizeof(buf), mtd) != NULL) 352 { 353 if (fscanf(mtd, "mtd%d: %x %*x %127s", &off, &len, buf) < 3 || 354 (strcmp(buf, "\"boardconfig\"") && strcmp(buf, "\"EEPROM\"") && 355 strcmp(buf, "\"factory\""))) 356 { 357 off = -1; 358 continue; 359 } 360 361 break; 362 } 363 364 fclose(mtd); 365 366 if (off < 0) 367 return -1; 368 369 snprintf(buf, sizeof(buf), "/dev/mtdblock%d", off); 370 371 if ((fd = open(buf, O_RDONLY)) < 0) 372 return -1; 373 374 bc = mmap(NULL, len, PROT_READ, MAP_PRIVATE|MAP_LOCKED, fd, 0); 375 376 if ((void *)bc != MAP_FAILED) 377 { 378 id->vendor_id = 0; 379 id->device_id = 0; 380 381 for (off = len / 2 - 0x800; off >= 0; off -= 0x800) 382 { 383 /* AR531X board data magic */ 384 if ((bc[off] == 0x3533) && (bc[off + 1] == 0x3131)) 385 { 386 id->vendor_id = bc[off + 0x7d]; 387 id->device_id = bc[off + 0x7c]; 388 id->subsystem_vendor_id = bc[off + 0x84]; 389 id->subsystem_device_id = bc[off + 0x83]; 390 break; 391 } 392 393 /* AR5416 EEPROM magic */ 394 else if ((bc[off] == 0xA55A) || (bc[off] == 0x5AA5)) 395 { 396 id->vendor_id = bc[off + 0x0D]; 397 id->device_id = bc[off + 0x0E]; 398 id->subsystem_vendor_id = bc[off + 0x13]; 399 id->subsystem_device_id = bc[off + 0x14]; 400 break; 401 } 402 403 /* Rt3xxx SoC */ 404 else if ((bc[off] == 0x3050) || (bc[off] == 0x5030) || 405 (bc[off] == 0x3051) || (bc[off] == 0x5130) || 406 (bc[off] == 0x3052) || (bc[off] == 0x5230) || 407 (bc[off] == 0x3350) || (bc[off] == 0x5033) || 408 (bc[off] == 0x3352) || (bc[off] == 0x5233) || 409 (bc[off] == 0x3662) || (bc[off] == 0x6236) || 410 (bc[off] == 0x3883) || (bc[off] == 0x8338) || 411 (bc[off] == 0x5350) || (bc[off] == 0x5053)) 412 { 413 /* vendor: RaLink */ 414 id->vendor_id = 0x1814; 415 id->subsystem_vendor_id = 0x1814; 416 417 /* device */ 418 if (((bc[off] & 0xf0) == 0x30) || 419 ((bc[off] & 0xff) == 0x53)) 420 id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8; 421 else 422 id->device_id = bc[off]; 423 424 /* subsystem from EEPROM_NIC_CONF0_RF_TYPE */ 425 id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8; 426 } else if ((bc[off] == 0x7620) || (bc[off] == 0x2076) || 427 (bc[off] == 0x7628) || (bc[off] == 0x2876) || 428 (bc[off] == 0x7688) || (bc[off] == 0x8876)) { 429 /* vendor: MediaTek */ 430 id->vendor_id = 0x14c3; 431 id->subsystem_vendor_id = 0x14c3; 432 433 /* device */ 434 if ((bc[off] & 0xff) == 0x76) 435 id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8; 436 else 437 id->device_id = bc[off]; 438 439 /* subsystem from EEPROM_NIC_CONF0_RF_TYPE */ 440 id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8; 441 } 442 } 443 444 munmap(bc, len); 445 } 446 447 close(fd); 448 449 return (id->vendor_id && id->device_id) ? 0 : -1; 450 } 451 452 static void iwinfo_parse_rsn_cipher(uint8_t idx, uint16_t *ciphers) 453 { 454 switch (idx) 455 { 456 case 0: 457 *ciphers |= IWINFO_CIPHER_NONE; 458 break; 459 460 case 1: 461 *ciphers |= IWINFO_CIPHER_WEP40; 462 break; 463 464 case 2: 465 *ciphers |= IWINFO_CIPHER_TKIP; 466 break; 467 468 case 3: /* WRAP */ 469 break; 470 471 case 4: 472 *ciphers |= IWINFO_CIPHER_CCMP; 473 break; 474 475 case 5: 476 *ciphers |= IWINFO_CIPHER_WEP104; 477 break; 478 479 case 8: 480 *ciphers |= IWINFO_CIPHER_GCMP; 481 break; 482 483 case 9: 484 *ciphers |= IWINFO_CIPHER_GCMP256; 485 break; 486 487 case 10: 488 *ciphers |= IWINFO_CIPHER_CCMP256; 489 break; 490 491 case 6: /* AES-128-CMAC */ 492 case 7: /* No group addressed */ 493 case 11: /* BIP-GMAC-128 */ 494 case 12: /* BIP-GMAC-256 */ 495 case 13: /* BIP-CMAC-256 */ 496 break; 497 } 498 } 499 500 void iwinfo_parse_rsn(struct iwinfo_crypto_entry *c, uint8_t *data, uint8_t len, 501 uint16_t defcipher, uint8_t defauth) 502 { 503 uint16_t i, count; 504 uint8_t wpa_version = 0; 505 506 static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 }; 507 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac }; 508 509 data += 2; 510 len -= 2; 511 512 if (!memcmp(data, ms_oui, 3)) 513 wpa_version |= 1; 514 else if (!memcmp(data, ieee80211_oui, 3)) 515 wpa_version |= 2; 516 517 if (len < 4) 518 { 519 c->group_ciphers |= defcipher; 520 c->pair_ciphers |= defcipher; 521 c->auth_suites |= defauth; 522 return; 523 } 524 525 if (!memcmp(data, ms_oui, 3) || !memcmp(data, ieee80211_oui, 3)) 526 iwinfo_parse_rsn_cipher(data[3], &c->group_ciphers); 527 528 data += 4; 529 len -= 4; 530 531 if (len < 2) 532 { 533 c->pair_ciphers |= defcipher; 534 c->auth_suites |= defauth; 535 return; 536 } 537 538 count = data[0] | (data[1] << 8); 539 if (2 + (count * 4) > len) 540 return; 541 542 for (i = 0; i < count; i++) 543 if (!memcmp(data + 2 + (i * 4), ms_oui, 3) || 544 !memcmp(data + 2 + (i * 4), ieee80211_oui, 3)) 545 iwinfo_parse_rsn_cipher(data[2 + (i * 4) + 3], &c->pair_ciphers); 546 547 data += 2 + (count * 4); 548 len -= 2 + (count * 4); 549 550 if (len < 2) 551 { 552 c->auth_suites |= defauth; 553 return; 554 } 555 556 count = data[0] | (data[1] << 8); 557 if (2 + (count * 4) > len) 558 return; 559 560 for (i = 0; i < count; i++) 561 { 562 if (!memcmp(data + 2 + (i * 4), ms_oui, 3) || 563 !memcmp(data + 2 + (i * 4), ieee80211_oui, 3)) 564 { 565 switch (data[2 + (i * 4) + 3]) 566 { 567 case 1: /* IEEE 802.1x */ 568 c->wpa_version |= wpa_version; 569 c->auth_suites |= IWINFO_KMGMT_8021x; 570 break; 571 572 case 2: /* PSK */ 573 c->wpa_version |= wpa_version; 574 c->auth_suites |= IWINFO_KMGMT_PSK; 575 break; 576 577 case 3: /* FT/IEEE 802.1X */ 578 case 4: /* FT/PSK */ 579 case 5: /* IEEE 802.1X/SHA-256 */ 580 case 6: /* PSK/SHA-256 */ 581 case 7: /* TPK Handshake */ 582 break; 583 584 case 8: /* SAE */ 585 c->wpa_version |= 4; 586 c->auth_suites |= IWINFO_KMGMT_SAE; 587 break; 588 589 case 9: /* FT/SAE */ 590 case 10: /* undefined */ 591 break; 592 593 case 11: /* 802.1x Suite-B */ 594 case 12: /* 802.1x Suite-B-192 */ 595 case 13: /* FT/802.1x SHA-384 */ 596 c->wpa_version |= 4; 597 c->auth_suites |= IWINFO_KMGMT_8021x; 598 break; 599 600 case 14: /* FILS SHA-256 */ 601 case 15: /* FILS SHA-384 */ 602 case 16: /* FT/FILS SHA-256 */ 603 case 17: /* FT/FILS SHA-384 */ 604 break; 605 606 case 18: /* OWE */ 607 c->wpa_version |= 4; 608 c->auth_suites |= IWINFO_KMGMT_OWE; 609 break; 610 } 611 } 612 } 613 614 data += 2 + (count * 4); 615 len -= 2 + (count * 4); 616 } 617 618 struct uci_section *iwinfo_uci_get_radio(const char *name, const char *type) 619 { 620 struct uci_ptr ptr = { 621 .package = "wireless", 622 .section = name, 623 .flags = (name && *name == '@') ? UCI_LOOKUP_EXTENDED : 0, 624 }; 625 const char *opt; 626 627 if (!uci_ctx) { 628 uci_ctx = uci_alloc_context(); 629 if (!uci_ctx) 630 return NULL; 631 } 632 633 if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true)) 634 return NULL; 635 636 if (!ptr.s || strcmp(ptr.s->type, "wifi-device") != 0) 637 return NULL; 638 639 opt = uci_lookup_option_string(uci_ctx, ptr.s, "type"); 640 if (!opt || strcmp(opt, type) != 0) 641 return NULL; 642 643 return ptr.s; 644 } 645 646 void iwinfo_uci_free(void) 647 { 648 if (!uci_ctx) 649 return; 650 651 uci_free_context(uci_ctx); 652 uci_ctx = NULL; 653 } 654 655 656 struct iwinfo_ubus_query_state { 657 const char *ifname; 658 const char *field; 659 size_t len; 660 char *buf; 661 }; 662 663 static void iwinfo_ubus_query_cb(struct ubus_request *req, int type, 664 struct blob_attr *msg) 665 { 666 struct iwinfo_ubus_query_state *st = req->priv; 667 668 struct blobmsg_policy pol1[2] = { 669 { "ifname", BLOBMSG_TYPE_STRING }, 670 { "config", BLOBMSG_TYPE_TABLE } 671 }; 672 673 struct blobmsg_policy pol2 = { st->field, BLOBMSG_TYPE_STRING }; 674 struct blob_attr *cur, *cur2, *cur3, *cfg[2], *res; 675 int rem, rem2, rem3; 676 677 blobmsg_for_each_attr(cur, msg, rem) { 678 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) 679 continue; 680 681 blobmsg_for_each_attr(cur2, cur, rem2) { 682 if (blobmsg_type(cur2) != BLOBMSG_TYPE_ARRAY) 683 continue; 684 685 if (strcmp(blobmsg_name(cur2), "interfaces")) 686 continue; 687 688 blobmsg_for_each_attr(cur3, cur2, rem3) { 689 blobmsg_parse(pol1, sizeof(pol1) / sizeof(pol1[0]), cfg, 690 blobmsg_data(cur3), blobmsg_len(cur3)); 691 692 if (!cfg[0] || !cfg[1] || 693 strcmp(blobmsg_get_string(cfg[0]), st->ifname)) 694 continue; 695 696 blobmsg_parse(&pol2, 1, &res, 697 blobmsg_data(cfg[1]), blobmsg_len(cfg[1])); 698 699 if (!res) 700 continue; 701 702 strncpy(st->buf, blobmsg_get_string(res), st->len); 703 return; 704 } 705 } 706 } 707 } 708 709 int iwinfo_ubus_query(const char *ifname, const char *field, 710 char *buf, size_t len) 711 { 712 struct iwinfo_ubus_query_state st = { 713 .ifname = ifname, 714 .field = field, 715 .buf = buf, 716 .len = len 717 }; 718 719 struct ubus_context *ctx = NULL; 720 struct blob_buf b = { }; 721 int rv = -1; 722 uint32_t id; 723 724 blob_buf_init(&b, 0); 725 726 ctx = ubus_connect(NULL); 727 728 if (!ctx) 729 goto out; 730 731 if (ubus_lookup_id(ctx, "network.wireless", &id)) 732 goto out; 733 734 if (ubus_invoke(ctx, id, "status", b.head, iwinfo_ubus_query_cb, &st, 250)) 735 goto out; 736 737 rv = 0; 738 739 out: 740 if (ctx) 741 ubus_free(ctx); 742 743 blob_buf_free(&b); 744 745 return rv; 746 } 747
This page was automatically generated by LXR 0.3.1. • OpenWrt