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 int iwinfo_ifup(const char *ifname) 81 { 82 struct ifreq ifr; 83 84 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 85 86 if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr)) 87 return 0; 88 89 ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); 90 91 return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr); 92 } 93 94 int iwinfo_ifdown(const char *ifname) 95 { 96 struct ifreq ifr; 97 98 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 99 100 if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr)) 101 return 0; 102 103 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING); 104 105 return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr); 106 } 107 108 int iwinfo_ifmac(const char *ifname) 109 { 110 struct ifreq ifr; 111 112 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 113 114 if (iwinfo_ioctl(SIOCGIFHWADDR, &ifr)) 115 return 0; 116 117 ifr.ifr_hwaddr.sa_data[0] |= 0x02; 118 ifr.ifr_hwaddr.sa_data[1]++; 119 ifr.ifr_hwaddr.sa_data[2]++; 120 121 return !iwinfo_ioctl(SIOCSIFHWADDR, &ifr); 122 } 123 124 void iwinfo_close(void) 125 { 126 if (ioctl_socket > -1) 127 close(ioctl_socket); 128 129 ioctl_socket = -1; 130 } 131 132 struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id) 133 { 134 FILE *db; 135 char buf[256] = { 0 }; 136 static struct iwinfo_hardware_entry e; 137 struct iwinfo_hardware_entry *rv = NULL; 138 139 if (!(db = fopen(IWINFO_HARDWARE_FILE, "r"))) 140 return NULL; 141 142 while (fgets(buf, sizeof(buf) - 1, db) != NULL) 143 { 144 memset(&e, 0, sizeof(e)); 145 146 if (sscanf(buf, "%hx %hx %hx %hx %hd %hd \"%63[^\"]\" \"%63[^\"]\"", 147 &e.vendor_id, &e.device_id, 148 &e.subsystem_vendor_id, &e.subsystem_device_id, 149 &e.txpower_offset, &e.frequency_offset, 150 e.vendor_name, e.device_name) < 8) 151 continue; 152 153 if ((e.vendor_id != 0xffff) && (e.vendor_id != id->vendor_id)) 154 continue; 155 156 if ((e.device_id != 0xffff) && (e.device_id != id->device_id)) 157 continue; 158 159 if ((e.subsystem_vendor_id != 0xffff) && 160 (e.subsystem_vendor_id != id->subsystem_vendor_id)) 161 continue; 162 163 if ((e.subsystem_device_id != 0xffff) && 164 (e.subsystem_device_id != id->subsystem_device_id)) 165 continue; 166 167 rv = &e; 168 break; 169 } 170 171 fclose(db); 172 return rv; 173 } 174 175 int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id) 176 { 177 FILE *mtd; 178 uint16_t *bc; 179 180 int fd, off; 181 unsigned int len; 182 char buf[128]; 183 184 if (!(mtd = fopen("/proc/mtd", "r"))) 185 return -1; 186 187 while (fgets(buf, sizeof(buf), mtd) != NULL) 188 { 189 if (fscanf(mtd, "mtd%d: %x %*x %127s", &off, &len, buf) < 3 || 190 (strcmp(buf, "\"boardconfig\"") && strcmp(buf, "\"EEPROM\"") && 191 strcmp(buf, "\"factory\""))) 192 { 193 off = -1; 194 continue; 195 } 196 197 break; 198 } 199 200 fclose(mtd); 201 202 if (off < 0) 203 return -1; 204 205 snprintf(buf, sizeof(buf), "/dev/mtdblock%d", off); 206 207 if ((fd = open(buf, O_RDONLY)) < 0) 208 return -1; 209 210 bc = mmap(NULL, len, PROT_READ, MAP_PRIVATE|MAP_LOCKED, fd, 0); 211 212 if ((void *)bc != MAP_FAILED) 213 { 214 id->vendor_id = 0; 215 id->device_id = 0; 216 217 for (off = len / 2 - 0x800; off >= 0; off -= 0x800) 218 { 219 /* AR531X board data magic */ 220 if ((bc[off] == 0x3533) && (bc[off + 1] == 0x3131)) 221 { 222 id->vendor_id = bc[off + 0x7d]; 223 id->device_id = bc[off + 0x7c]; 224 id->subsystem_vendor_id = bc[off + 0x84]; 225 id->subsystem_device_id = bc[off + 0x83]; 226 break; 227 } 228 229 /* AR5416 EEPROM magic */ 230 else if ((bc[off] == 0xA55A) || (bc[off] == 0x5AA5)) 231 { 232 id->vendor_id = bc[off + 0x0D]; 233 id->device_id = bc[off + 0x0E]; 234 id->subsystem_vendor_id = bc[off + 0x13]; 235 id->subsystem_device_id = bc[off + 0x14]; 236 break; 237 } 238 239 /* Rt3xxx SoC */ 240 else if ((bc[off] == 0x3050) || (bc[off] == 0x5030) || 241 (bc[off] == 0x3051) || (bc[off] == 0x5130) || 242 (bc[off] == 0x3052) || (bc[off] == 0x5230) || 243 (bc[off] == 0x3350) || (bc[off] == 0x5033) || 244 (bc[off] == 0x3352) || (bc[off] == 0x5233) || 245 (bc[off] == 0x3662) || (bc[off] == 0x6236) || 246 (bc[off] == 0x3883) || (bc[off] == 0x8338) || 247 (bc[off] == 0x5350) || (bc[off] == 0x5053)) 248 { 249 /* vendor: RaLink */ 250 id->vendor_id = 0x1814; 251 id->subsystem_vendor_id = 0x1814; 252 253 /* device */ 254 if (((bc[off] & 0xf0) == 0x30) || 255 ((bc[off] & 0xff) == 0x53)) 256 id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8; 257 else 258 id->device_id = bc[off]; 259 260 /* subsystem from EEPROM_NIC_CONF0_RF_TYPE */ 261 id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8; 262 } else if ((bc[off] == 0x7620) || (bc[off] == 0x2076) || 263 (bc[off] == 0x7628) || (bc[off] == 0x2876) || 264 (bc[off] == 0x7688) || (bc[off] == 0x8876)) { 265 /* vendor: MediaTek */ 266 id->vendor_id = 0x14c3; 267 id->subsystem_vendor_id = 0x14c3; 268 269 /* device */ 270 if ((bc[off] & 0xff) == 0x76) 271 id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8; 272 else 273 id->device_id = bc[off]; 274 275 /* subsystem from EEPROM_NIC_CONF0_RF_TYPE */ 276 id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8; 277 } 278 } 279 280 munmap(bc, len); 281 } 282 283 close(fd); 284 285 return (id->vendor_id && id->device_id) ? 0 : -1; 286 } 287 288 static void iwinfo_parse_rsn_cipher(uint8_t idx, uint16_t *ciphers) 289 { 290 switch (idx) 291 { 292 case 0: 293 *ciphers |= IWINFO_CIPHER_NONE; 294 break; 295 296 case 1: 297 *ciphers |= IWINFO_CIPHER_WEP40; 298 break; 299 300 case 2: 301 *ciphers |= IWINFO_CIPHER_TKIP; 302 break; 303 304 case 3: /* WRAP */ 305 break; 306 307 case 4: 308 *ciphers |= IWINFO_CIPHER_CCMP; 309 break; 310 311 case 5: 312 *ciphers |= IWINFO_CIPHER_WEP104; 313 break; 314 315 case 8: 316 *ciphers |= IWINFO_CIPHER_GCMP; 317 break; 318 319 case 6: /* AES-128-CMAC */ 320 case 7: /* No group addressed */ 321 case 9: /* GCMP-256 */ 322 case 10: /* CCMP-256 */ 323 case 11: /* BIP-GMAC-128 */ 324 case 12: /* BIP-GMAC-256 */ 325 case 13: /* BIP-CMAC-256 */ 326 break; 327 } 328 } 329 330 void iwinfo_parse_rsn(struct iwinfo_crypto_entry *c, uint8_t *data, uint8_t len, 331 uint16_t defcipher, uint8_t defauth) 332 { 333 uint16_t i, count; 334 uint8_t wpa_version = 0; 335 336 static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 }; 337 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac }; 338 339 data += 2; 340 len -= 2; 341 342 if (!memcmp(data, ms_oui, 3)) 343 wpa_version |= 1; 344 else if (!memcmp(data, ieee80211_oui, 3)) 345 wpa_version |= 2; 346 347 if (len < 4) 348 { 349 c->group_ciphers |= defcipher; 350 c->pair_ciphers |= defcipher; 351 c->auth_suites |= defauth; 352 return; 353 } 354 355 if (!memcmp(data, ms_oui, 3) || !memcmp(data, ieee80211_oui, 3)) 356 iwinfo_parse_rsn_cipher(data[3], &c->group_ciphers); 357 358 data += 4; 359 len -= 4; 360 361 if (len < 2) 362 { 363 c->pair_ciphers |= defcipher; 364 c->auth_suites |= defauth; 365 return; 366 } 367 368 count = data[0] | (data[1] << 8); 369 if (2 + (count * 4) > len) 370 return; 371 372 for (i = 0; i < count; i++) 373 if (!memcmp(data + 2 + (i * 4), ms_oui, 3) || 374 !memcmp(data + 2 + (i * 4), ieee80211_oui, 3)) 375 iwinfo_parse_rsn_cipher(data[2 + (i * 4) + 3], &c->pair_ciphers); 376 377 data += 2 + (count * 4); 378 len -= 2 + (count * 4); 379 380 if (len < 2) 381 { 382 c->auth_suites |= defauth; 383 return; 384 } 385 386 count = data[0] | (data[1] << 8); 387 if (2 + (count * 4) > len) 388 return; 389 390 for (i = 0; i < count; i++) 391 { 392 if (!memcmp(data + 2 + (i * 4), ms_oui, 3) || 393 !memcmp(data + 2 + (i * 4), ieee80211_oui, 3)) 394 { 395 switch (data[2 + (i * 4) + 3]) 396 { 397 case 1: /* IEEE 802.1x */ 398 c->wpa_version |= wpa_version; 399 c->auth_suites |= IWINFO_KMGMT_8021x; 400 break; 401 402 case 2: /* PSK */ 403 c->wpa_version |= wpa_version; 404 c->auth_suites |= IWINFO_KMGMT_PSK; 405 break; 406 407 case 3: /* FT/IEEE 802.1X */ 408 case 4: /* FT/PSK */ 409 case 5: /* IEEE 802.1X/SHA-256 */ 410 case 6: /* PSK/SHA-256 */ 411 case 7: /* TPK Handshake */ 412 break; 413 414 case 8: /* SAE */ 415 c->wpa_version |= 4; 416 c->auth_suites |= IWINFO_KMGMT_SAE; 417 break; 418 419 case 9: /* FT/SAE */ 420 case 10: /* undefined */ 421 break; 422 423 case 11: /* 802.1x Suite-B */ 424 case 12: /* 802.1x Suite-B-192 */ 425 c->wpa_version |= 4; 426 c->auth_suites |= IWINFO_KMGMT_8021x; 427 break; 428 429 case 13: /* FT/802.1x SHA-384 */ 430 case 14: /* FILS SHA-256 */ 431 case 15: /* FILS SHA-384 */ 432 case 16: /* FT/FILS SHA-256 */ 433 case 17: /* FT/FILS SHA-384 */ 434 break; 435 436 case 18: /* OWE */ 437 c->wpa_version |= 4; 438 c->auth_suites |= IWINFO_KMGMT_OWE; 439 break; 440 } 441 } 442 } 443 444 data += 2 + (count * 4); 445 len -= 2 + (count * 4); 446 } 447 448 struct uci_section *iwinfo_uci_get_radio(const char *name, const char *type) 449 { 450 struct uci_ptr ptr = { 451 .package = "wireless", 452 .section = name, 453 .flags = (name && *name == '@') ? UCI_LOOKUP_EXTENDED : 0, 454 }; 455 const char *opt; 456 457 if (!uci_ctx) { 458 uci_ctx = uci_alloc_context(); 459 if (!uci_ctx) 460 return NULL; 461 } 462 463 if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true)) 464 return NULL; 465 466 if (!ptr.s || strcmp(ptr.s->type, "wifi-device") != 0) 467 return NULL; 468 469 opt = uci_lookup_option_string(uci_ctx, ptr.s, "type"); 470 if (!opt || strcmp(opt, type) != 0) 471 return NULL; 472 473 return ptr.s; 474 } 475 476 void iwinfo_uci_free(void) 477 { 478 if (!uci_ctx) 479 return; 480 481 uci_free_context(uci_ctx); 482 uci_ctx = NULL; 483 } 484 485 486 struct iwinfo_ubus_query_state { 487 const char *ifname; 488 const char *field; 489 size_t len; 490 char *buf; 491 }; 492 493 static void iwinfo_ubus_query_cb(struct ubus_request *req, int type, 494 struct blob_attr *msg) 495 { 496 struct iwinfo_ubus_query_state *st = req->priv; 497 498 struct blobmsg_policy pol1[2] = { 499 { "ifname", BLOBMSG_TYPE_STRING }, 500 { "config", BLOBMSG_TYPE_TABLE } 501 }; 502 503 struct blobmsg_policy pol2 = { st->field, BLOBMSG_TYPE_STRING }; 504 struct blob_attr *cur, *cur2, *cur3, *cfg[2], *res; 505 int rem, rem2, rem3; 506 507 blobmsg_for_each_attr(cur, msg, rem) { 508 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) 509 continue; 510 511 blobmsg_for_each_attr(cur2, cur, rem2) { 512 if (blobmsg_type(cur2) != BLOBMSG_TYPE_ARRAY) 513 continue; 514 515 if (strcmp(blobmsg_name(cur2), "interfaces")) 516 continue; 517 518 blobmsg_for_each_attr(cur3, cur2, rem3) { 519 blobmsg_parse(pol1, sizeof(pol1) / sizeof(pol1[0]), cfg, 520 blobmsg_data(cur3), blobmsg_len(cur3)); 521 522 if (!cfg[0] || !cfg[1] || 523 strcmp(blobmsg_get_string(cfg[0]), st->ifname)) 524 continue; 525 526 blobmsg_parse(&pol2, 1, &res, 527 blobmsg_data(cfg[1]), blobmsg_len(cfg[1])); 528 529 if (!res) 530 continue; 531 532 strncpy(st->buf, blobmsg_get_string(res), st->len); 533 return; 534 } 535 } 536 } 537 } 538 539 int iwinfo_ubus_query(const char *ifname, const char *field, 540 char *buf, size_t len) 541 { 542 struct iwinfo_ubus_query_state st = { 543 .ifname = ifname, 544 .field = field, 545 .buf = buf, 546 .len = len 547 }; 548 549 struct ubus_context *ctx = NULL; 550 struct blob_buf b = { }; 551 int rv = -1; 552 uint32_t id; 553 554 blob_buf_init(&b, 0); 555 556 ctx = ubus_connect(NULL); 557 558 if (!ctx) 559 goto out; 560 561 if (ubus_lookup_id(ctx, "network.wireless", &id)) 562 goto out; 563 564 if (ubus_invoke(ctx, id, "status", b.head, iwinfo_ubus_query_cb, &st, 250)) 565 goto out; 566 567 rv = 0; 568 569 out: 570 if (ctx) 571 ubus_free(ctx); 572 573 blob_buf_free(&b); 574 575 return rv; 576 } 577
This page was automatically generated by LXR 0.3.1. • OpenWrt