1 /* 2 * iwinfo - Wireless Information Library - Madwifi Backend 3 * 4 * Copyright (C) 2009-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_wext.h" 24 #include "api/madwifi.h" 25 26 27 /* 28 * Madwifi ISO 3166 to Country/Region Code mapping. 29 */ 30 31 static struct ISO3166_to_CCode 32 { 33 u_int16_t iso3166; 34 u_int16_t ccode; 35 } CountryCodes[] = { 36 { 0x3030 /* 00 */, 0 }, /* World */ 37 { 0x4145 /* AE */, 784 }, /* U.A.E. */ 38 { 0x414C /* AL */, 8 }, /* Albania */ 39 { 0x414D /* AM */, 51 }, /* Armenia */ 40 { 0x4152 /* AR */, 32 }, /* Argentina */ 41 { 0x4154 /* AT */, 40 }, /* Austria */ 42 { 0x4155 /* AU */, 36 }, /* Australia */ 43 { 0x415A /* AZ */, 31 }, /* Azerbaijan */ 44 { 0x4245 /* BE */, 56 }, /* Belgium */ 45 { 0x4247 /* BG */, 100 }, /* Bulgaria */ 46 { 0x4248 /* BH */, 48 }, /* Bahrain */ 47 { 0x424E /* BN */, 96 }, /* Brunei Darussalam */ 48 { 0x424F /* BO */, 68 }, /* Bolivia */ 49 { 0x4252 /* BR */, 76 }, /* Brazil */ 50 { 0x4259 /* BY */, 112 }, /* Belarus */ 51 { 0x425A /* BZ */, 84 }, /* Belize */ 52 { 0x4341 /* CA */, 124 }, /* Canada */ 53 { 0x4348 /* CH */, 756 }, /* Switzerland */ 54 { 0x434C /* CL */, 152 }, /* Chile */ 55 { 0x434E /* CN */, 156 }, /* People's Republic of China */ 56 { 0x434F /* CO */, 170 }, /* Colombia */ 57 { 0x4352 /* CR */, 188 }, /* Costa Rica */ 58 { 0x4359 /* CY */, 196 }, /* Cyprus */ 59 { 0x435A /* CZ */, 203 }, /* Czech Republic */ 60 { 0x4445 /* DE */, 276 }, /* Germany */ 61 { 0x444B /* DK */, 208 }, /* Denmark */ 62 { 0x444F /* DO */, 214 }, /* Dominican Republic */ 63 { 0x445A /* DZ */, 12 }, /* Algeria */ 64 { 0x4543 /* EC */, 218 }, /* Ecuador */ 65 { 0x4545 /* EE */, 233 }, /* Estonia */ 66 { 0x4547 /* EG */, 818 }, /* Egypt */ 67 { 0x4553 /* ES */, 724 }, /* Spain */ 68 { 0x4649 /* FI */, 246 }, /* Finland */ 69 { 0x464F /* FO */, 234 }, /* Faeroe Islands */ 70 { 0x4652 /* FR */, 250 }, /* France */ 71 { 0x4652 /* FR */, 255 }, /* France2 */ 72 { 0x4742 /* GB */, 826 }, /* United Kingdom */ 73 { 0x4745 /* GE */, 268 }, /* Georgia */ 74 { 0x4752 /* GR */, 300 }, /* Greece */ 75 { 0x4754 /* GT */, 320 }, /* Guatemala */ 76 { 0x484B /* HK */, 344 }, /* Hong Kong S.A.R., P.R.C. */ 77 { 0x484E /* HN */, 340 }, /* Honduras */ 78 { 0x4852 /* HR */, 191 }, /* Croatia */ 79 { 0x4855 /* HU */, 348 }, /* Hungary */ 80 { 0x4944 /* ID */, 360 }, /* Indonesia */ 81 { 0x4945 /* IE */, 372 }, /* Ireland */ 82 { 0x494C /* IL */, 376 }, /* Israel */ 83 { 0x494E /* IN */, 356 }, /* India */ 84 { 0x4951 /* IQ */, 368 }, /* Iraq */ 85 { 0x4952 /* IR */, 364 }, /* Iran */ 86 { 0x4953 /* IS */, 352 }, /* Iceland */ 87 { 0x4954 /* IT */, 380 }, /* Italy */ 88 { 0x4A4D /* JM */, 388 }, /* Jamaica */ 89 { 0x4A4F /* JO */, 400 }, /* Jordan */ 90 { 0x4A50 /* JP */, 392 }, /* Japan */ 91 { 0x4A50 /* JP */, 393 }, /* Japan (JP1) */ 92 { 0x4A50 /* JP */, 394 }, /* Japan (JP0) */ 93 { 0x4A50 /* JP */, 395 }, /* Japan (JP1-1) */ 94 { 0x4A50 /* JP */, 396 }, /* Japan (JE1) */ 95 { 0x4A50 /* JP */, 397 }, /* Japan (JE2) */ 96 { 0x4A50 /* JP */, 399 }, /* Japan (JP6) */ 97 { 0x4A50 /* JP */, 900 }, /* Japan */ 98 { 0x4A50 /* JP */, 901 }, /* Japan */ 99 { 0x4A50 /* JP */, 902 }, /* Japan */ 100 { 0x4A50 /* JP */, 903 }, /* Japan */ 101 { 0x4A50 /* JP */, 904 }, /* Japan */ 102 { 0x4A50 /* JP */, 905 }, /* Japan */ 103 { 0x4A50 /* JP */, 906 }, /* Japan */ 104 { 0x4A50 /* JP */, 907 }, /* Japan */ 105 { 0x4A50 /* JP */, 908 }, /* Japan */ 106 { 0x4A50 /* JP */, 909 }, /* Japan */ 107 { 0x4A50 /* JP */, 910 }, /* Japan */ 108 { 0x4A50 /* JP */, 911 }, /* Japan */ 109 { 0x4A50 /* JP */, 912 }, /* Japan */ 110 { 0x4A50 /* JP */, 913 }, /* Japan */ 111 { 0x4A50 /* JP */, 914 }, /* Japan */ 112 { 0x4A50 /* JP */, 915 }, /* Japan */ 113 { 0x4A50 /* JP */, 916 }, /* Japan */ 114 { 0x4A50 /* JP */, 917 }, /* Japan */ 115 { 0x4A50 /* JP */, 918 }, /* Japan */ 116 { 0x4A50 /* JP */, 919 }, /* Japan */ 117 { 0x4A50 /* JP */, 920 }, /* Japan */ 118 { 0x4A50 /* JP */, 921 }, /* Japan */ 119 { 0x4A50 /* JP */, 922 }, /* Japan */ 120 { 0x4A50 /* JP */, 923 }, /* Japan */ 121 { 0x4A50 /* JP */, 924 }, /* Japan */ 122 { 0x4A50 /* JP */, 925 }, /* Japan */ 123 { 0x4A50 /* JP */, 926 }, /* Japan */ 124 { 0x4A50 /* JP */, 927 }, /* Japan */ 125 { 0x4A50 /* JP */, 928 }, /* Japan */ 126 { 0x4A50 /* JP */, 929 }, /* Japan */ 127 { 0x4A50 /* JP */, 930 }, /* Japan */ 128 { 0x4A50 /* JP */, 931 }, /* Japan */ 129 { 0x4A50 /* JP */, 932 }, /* Japan */ 130 { 0x4A50 /* JP */, 933 }, /* Japan */ 131 { 0x4A50 /* JP */, 934 }, /* Japan */ 132 { 0x4A50 /* JP */, 935 }, /* Japan */ 133 { 0x4A50 /* JP */, 936 }, /* Japan */ 134 { 0x4A50 /* JP */, 937 }, /* Japan */ 135 { 0x4A50 /* JP */, 938 }, /* Japan */ 136 { 0x4A50 /* JP */, 939 }, /* Japan */ 137 { 0x4A50 /* JP */, 940 }, /* Japan */ 138 { 0x4A50 /* JP */, 941 }, /* Japan */ 139 { 0x4B45 /* KE */, 404 }, /* Kenya */ 140 { 0x4B50 /* KP */, 408 }, /* North Korea */ 141 { 0x4B52 /* KR */, 410 }, /* South Korea */ 142 { 0x4B52 /* KR */, 411 }, /* South Korea */ 143 { 0x4B57 /* KW */, 414 }, /* Kuwait */ 144 { 0x4B5A /* KZ */, 398 }, /* Kazakhstan */ 145 { 0x4C42 /* LB */, 422 }, /* Lebanon */ 146 { 0x4C49 /* LI */, 438 }, /* Liechtenstein */ 147 { 0x4C54 /* LT */, 440 }, /* Lithuania */ 148 { 0x4C55 /* LU */, 442 }, /* Luxembourg */ 149 { 0x4C56 /* LV */, 428 }, /* Latvia */ 150 { 0x4C59 /* LY */, 434 }, /* Libya */ 151 { 0x4D41 /* MA */, 504 }, /* Morocco */ 152 { 0x4D43 /* MC */, 492 }, /* Principality of Monaco */ 153 { 0x4D4B /* MK */, 807 }, /* the Former Yugoslav Republic of Macedonia */ 154 { 0x4D4F /* MO */, 446 }, /* Macau */ 155 { 0x4D58 /* MX */, 484 }, /* Mexico */ 156 { 0x4D59 /* MY */, 458 }, /* Malaysia */ 157 { 0x4E49 /* NI */, 558 }, /* Nicaragua */ 158 { 0x4E4C /* NL */, 528 }, /* Netherlands */ 159 { 0x4E4F /* NO */, 578 }, /* Norway */ 160 { 0x4E5A /* NZ */, 554 }, /* New Zealand */ 161 { 0x4F4D /* OM */, 512 }, /* Oman */ 162 { 0x5041 /* PA */, 591 }, /* Panama */ 163 { 0x5045 /* PE */, 604 }, /* Peru */ 164 { 0x5048 /* PH */, 608 }, /* Republic of the Philippines */ 165 { 0x504B /* PK */, 586 }, /* Islamic Republic of Pakistan */ 166 { 0x504C /* PL */, 616 }, /* Poland */ 167 { 0x5052 /* PR */, 630 }, /* Puerto Rico */ 168 { 0x5054 /* PT */, 620 }, /* Portugal */ 169 { 0x5059 /* PY */, 600 }, /* Paraguay */ 170 { 0x5141 /* QA */, 634 }, /* Qatar */ 171 { 0x524F /* RO */, 642 }, /* Romania */ 172 { 0x5255 /* RU */, 643 }, /* Russia */ 173 { 0x5341 /* SA */, 682 }, /* Saudi Arabia */ 174 { 0x5345 /* SE */, 752 }, /* Sweden */ 175 { 0x5347 /* SG */, 702 }, /* Singapore */ 176 { 0x5349 /* SI */, 705 }, /* Slovenia */ 177 { 0x534B /* SK */, 703 }, /* Slovak Republic */ 178 { 0x5356 /* SV */, 222 }, /* El Salvador */ 179 { 0x5359 /* SY */, 760 }, /* Syria */ 180 { 0x5448 /* TH */, 764 }, /* Thailand */ 181 { 0x544E /* TN */, 788 }, /* Tunisia */ 182 { 0x5452 /* TR */, 792 }, /* Turkey */ 183 { 0x5454 /* TT */, 780 }, /* Trinidad y Tobago */ 184 { 0x5457 /* TW */, 158 }, /* Taiwan */ 185 { 0x5541 /* UA */, 804 }, /* Ukraine */ 186 { 0x554B /* UK */, 826 }, /* United Kingdom */ 187 { 0x5553 /* US */, 840 }, /* United States */ 188 { 0x5553 /* US */, 842 }, /* United States (Public Safety)*/ 189 { 0x5559 /* UY */, 858 }, /* Uruguay */ 190 { 0x555A /* UZ */, 860 }, /* Uzbekistan */ 191 { 0x5645 /* VE */, 862 }, /* Venezuela */ 192 { 0x564E /* VN */, 704 }, /* Viet Nam */ 193 { 0x5945 /* YE */, 887 }, /* Yemen */ 194 { 0x5A41 /* ZA */, 710 }, /* South Africa */ 195 { 0x5A57 /* ZW */, 716 }, /* Zimbabwe */ 196 }; 197 198 199 static const char * madwifi_phyname(const char *ifname) 200 { 201 static char phyname[IFNAMSIZ]; 202 203 if (strlen(ifname) > 5 && !strncmp(ifname, "radio", 5)) 204 snprintf(phyname, sizeof(phyname), "wifi%s", ifname + 5); 205 else 206 snprintf(phyname, sizeof(phyname), "%s", ifname); 207 208 return (const char *)phyname; 209 } 210 211 static int madwifi_wrq(struct iwreq *wrq, const char *ifname, int cmd, void *data, size_t len) 212 { 213 strncpy(wrq->ifr_name, ifname, IFNAMSIZ); 214 215 if( data != NULL ) 216 { 217 if( len < IFNAMSIZ ) 218 { 219 memcpy(wrq->u.name, data, len); 220 } 221 else 222 { 223 wrq->u.data.pointer = data; 224 wrq->u.data.length = len; 225 } 226 } 227 228 return iwinfo_ioctl(cmd, wrq); 229 } 230 231 static int get80211priv(const char *ifname, int op, void *data, size_t len) 232 { 233 struct iwreq iwr; 234 235 if( madwifi_wrq(&iwr, ifname, op, data, len) < 0 ) 236 return -1; 237 238 return iwr.u.data.length; 239 } 240 241 static char * madwifi_isvap(const char *ifname, const char *wifiname) 242 { 243 int fd, ln; 244 char path[32]; 245 char *ret = NULL; 246 static char name[IFNAMSIZ]; 247 248 if( strlen(ifname) <= 9 ) 249 { 250 sprintf(path, "/proc/sys/net/%s/%%parent", ifname); 251 252 if( (fd = open(path, O_RDONLY)) > -1 ) 253 { 254 if( wifiname != NULL ) 255 { 256 if( read(fd, name, strlen(wifiname)) == strlen(wifiname) ) 257 ret = strncmp(name, wifiname, strlen(wifiname)) 258 ? NULL : name; 259 } 260 else if( (ln = read(fd, name, IFNAMSIZ)) >= 4 ) 261 { 262 name[ln-1] = 0; 263 ret = name; 264 } 265 266 (void) close(fd); 267 } 268 } 269 270 return ret; 271 } 272 273 static int madwifi_iswifi(const char *ifname) 274 { 275 int ret; 276 char path[32]; 277 struct stat s; 278 const char *phy; 279 280 ret = 0; 281 phy = madwifi_phyname(ifname); 282 283 if( strlen(phy) <= 7 ) 284 { 285 sprintf(path, "/proc/sys/dev/%s/diversity", phy); 286 287 if( ! stat(path, &s) ) 288 ret = (s.st_mode & S_IFREG); 289 } 290 291 return ret; 292 } 293 294 static char * madwifi_ifadd(const char *ifname) 295 { 296 const char *wifidev = NULL; 297 struct ifreq ifr = { 0 }; 298 struct ieee80211_clone_params cp = { 0 }; 299 static char nif[IFNAMSIZ] = { 0 }; 300 301 if( !(wifidev = madwifi_isvap(ifname, NULL)) && madwifi_iswifi(ifname) ) 302 wifidev = madwifi_phyname(ifname); 303 304 if( wifidev ) 305 { 306 snprintf(nif, sizeof(nif), "tmp.%s", ifname); 307 308 strncpy(cp.icp_name, nif, IFNAMSIZ); 309 cp.icp_opmode = IEEE80211_M_STA; 310 cp.icp_flags = IEEE80211_CLONE_BSSID; 311 312 strncpy(ifr.ifr_name, wifidev, IFNAMSIZ); 313 ifr.ifr_data = (void *)&cp; 314 315 if( !iwinfo_ioctl(SIOC80211IFCREATE, &ifr) ) 316 { 317 return nif; 318 } 319 else 320 { 321 cp.icp_opmode = IEEE80211_M_MONITOR; 322 323 if( !iwinfo_ioctl(SIOC80211IFCREATE, &ifr) ) 324 return nif; 325 } 326 } 327 328 return NULL; 329 } 330 331 static void madwifi_ifdel(const char *ifname) 332 { 333 struct ifreq ifr = { 0 }; 334 335 strncpy(ifr.ifr_name, ifname, IFNAMSIZ); 336 iwinfo_ioctl(SIOC80211IFDESTROY, &ifr); 337 } 338 339 340 static int madwifi_probe(const char *ifname) 341 { 342 return ( !!madwifi_isvap(ifname, NULL) || madwifi_iswifi(ifname) ); 343 } 344 345 static void madwifi_close(void) 346 { 347 /* Nop */ 348 } 349 350 static int madwifi_get_mode(const char *ifname, int *buf) 351 { 352 return wext_ops.mode(ifname, buf); 353 } 354 355 static int madwifi_get_ssid(const char *ifname, char *buf) 356 { 357 return wext_ops.ssid(ifname, buf); 358 } 359 360 static int madwifi_get_bssid(const char *ifname, char *buf) 361 { 362 return wext_ops.bssid(ifname, buf); 363 } 364 365 static int madwifi_get_channel(const char *ifname, int *buf) 366 { 367 int i; 368 uint16_t freq; 369 struct iwreq wrq; 370 struct ieee80211req_chaninfo chans; 371 372 if( madwifi_wrq(&wrq, ifname, SIOCGIWFREQ, NULL, 0) >= 0 ) 373 { 374 /* Madwifi returns a Hz frequency, get it's freq list to find channel index */ 375 freq = (uint16_t)(wrq.u.freq.m / 100000); 376 377 if( get80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) >= 0 ) 378 { 379 *buf = 0; 380 381 for( i = 0; i < chans.ic_nchans; i++ ) 382 { 383 if( freq == chans.ic_chans[i].ic_freq ) 384 { 385 *buf = chans.ic_chans[i].ic_ieee; 386 break; 387 } 388 } 389 390 return 0; 391 } 392 } 393 394 return -1; 395 } 396 397 static int madwifi_get_center_chan1(const char *ifname, int *buf) 398 { 399 /* Not Supported */ 400 return -1; 401 } 402 403 static int madwifi_get_center_chan2(const char *ifname, int *buf) 404 { 405 /* Not Supported */ 406 return -1; 407 } 408 409 static int madwifi_get_frequency(const char *ifname, int *buf) 410 { 411 struct iwreq wrq; 412 413 if( madwifi_wrq(&wrq, ifname, SIOCGIWFREQ, NULL, 0) >= 0 ) 414 { 415 *buf = (uint16_t)(wrq.u.freq.m / 100000); 416 return 0; 417 } 418 419 return -1; 420 } 421 422 static int madwifi_get_txpower(const char *ifname, int *buf) 423 { 424 return wext_ops.txpower(ifname, buf); 425 } 426 427 static int madwifi_get_bitrate(const char *ifname, int *buf) 428 { 429 unsigned int mode, len, rate, rate_count; 430 uint8_t tmp[24*1024]; 431 uint8_t *cp; 432 struct iwreq wrq; 433 struct ieee80211req_sta_info *si; 434 435 if( madwifi_wrq(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 ) 436 { 437 mode = wrq.u.mode; 438 439 /* Calculate bitrate average from associated stations in ad-hoc mode */ 440 if( mode == 1 ) 441 { 442 rate = rate_count = 0; 443 444 if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 ) 445 { 446 cp = tmp; 447 448 do { 449 si = (struct ieee80211req_sta_info *) cp; 450 451 if( si->isi_rssi > 0 ) 452 { 453 rate_count++; 454 rate += ((si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL) / 2); 455 } 456 457 cp += si->isi_len; 458 len -= si->isi_len; 459 } while (len >= sizeof(struct ieee80211req_sta_info)); 460 } 461 462 *buf = (rate == 0 || rate_count == 0) ? 0 : (rate / rate_count) * 1000; 463 return 0; 464 } 465 466 /* Return whatever wext tells us ... */ 467 return wext_ops.bitrate(ifname, buf); 468 } 469 470 return -1; 471 } 472 473 static int madwifi_get_signal(const char *ifname, int *buf) 474 { 475 unsigned int mode, len, rssi, rssi_count; 476 uint8_t tmp[24*1024]; 477 uint8_t *cp; 478 struct iwreq wrq; 479 struct ieee80211req_sta_info *si; 480 481 if( madwifi_wrq(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 ) 482 { 483 mode = wrq.u.mode; 484 485 /* Calculate signal average from associated stations in ap or ad-hoc mode */ 486 if( mode == 1 ) 487 { 488 rssi = rssi_count = 0; 489 490 if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 ) 491 { 492 cp = tmp; 493 494 do { 495 si = (struct ieee80211req_sta_info *) cp; 496 497 if( si->isi_rssi > 0 ) 498 { 499 rssi_count++; 500 rssi -= (si->isi_rssi - 95); 501 } 502 503 cp += si->isi_len; 504 len -= si->isi_len; 505 } while (len >= sizeof(struct ieee80211req_sta_info)); 506 } 507 508 *buf = (rssi == 0 || rssi_count == 0) ? 1 : -(rssi / rssi_count); 509 return 0; 510 } 511 512 /* Return whatever wext tells us ... */ 513 return wext_ops.signal(ifname, buf); 514 } 515 516 return -1; 517 } 518 519 static int madwifi_get_noise(const char *ifname, int *buf) 520 { 521 return wext_ops.noise(ifname, buf); 522 } 523 524 static int madwifi_get_quality(const char *ifname, int *buf) 525 { 526 unsigned int mode, len, quality, quality_count; 527 uint8_t tmp[24*1024]; 528 uint8_t *cp; 529 struct iwreq wrq; 530 struct ieee80211req_sta_info *si; 531 532 if( madwifi_wrq(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 ) 533 { 534 mode = wrq.u.mode; 535 536 /* Calculate signal average from associated stations in ad-hoc mode */ 537 if( mode == 1 ) 538 { 539 quality = quality_count = 0; 540 541 if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 ) 542 { 543 cp = tmp; 544 545 do { 546 si = (struct ieee80211req_sta_info *) cp; 547 548 if( si->isi_rssi > 0 ) 549 { 550 quality_count++; 551 quality += si->isi_rssi; 552 } 553 554 cp += si->isi_len; 555 len -= si->isi_len; 556 } while (len >= sizeof(struct ieee80211req_sta_info)); 557 } 558 559 *buf = (quality == 0 || quality_count == 0) ? 0 : (quality / quality_count); 560 return 0; 561 } 562 563 /* Return whatever wext tells us ... */ 564 return wext_ops.quality(ifname, buf); 565 } 566 567 return -1; 568 } 569 570 static int madwifi_get_quality_max(const char *ifname, int *buf) 571 { 572 return wext_ops.quality_max(ifname, buf); 573 } 574 575 static int madwifi_get_encryption(const char *ifname, char *buf) 576 { 577 int ciphers = 0, key_len = 0; 578 char keybuf[IW_ENCODING_TOKEN_MAX]; 579 struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf; 580 struct iwreq wrq; 581 struct ieee80211req_key wk; 582 583 memset(&wrq, 0, sizeof(wrq)); 584 585 /* Obtain key info */ 586 if( madwifi_wrq(&wrq, ifname, SIOCGIWENCODE, keybuf, sizeof(keybuf)) < 0 ) 587 return -1; 588 589 #if 0 590 /* Have any encryption? */ 591 if( (wrq.u.data.flags & IW_ENCODE_DISABLED) || (wrq.u.data.length == 0) ) 592 return 0; 593 #endif 594 595 /* Save key len */ 596 key_len = wrq.u.data.length; 597 598 /* Get wpa protocol version */ 599 wrq.u.mode = IEEE80211_PARAM_WPA; 600 if( madwifi_wrq(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 ) 601 c->wpa_version = wrq.u.mode; 602 603 /* Get authentication suites */ 604 wrq.u.mode = IEEE80211_PARAM_AUTHMODE; 605 if( madwifi_wrq(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 ) 606 { 607 switch(wrq.u.mode) { 608 case IEEE80211_AUTH_8021X: 609 c->auth_suites |= IWINFO_KMGMT_8021x; 610 break; 611 612 case IEEE80211_AUTH_WPA: 613 c->auth_suites |= IWINFO_KMGMT_PSK; 614 break; 615 616 case IEEE80211_AUTH_OPEN: 617 c->auth_algs |= IWINFO_AUTH_OPEN; 618 break; 619 620 case IEEE80211_AUTH_SHARED: 621 c->auth_algs |= IWINFO_AUTH_SHARED; 622 break; 623 624 default: 625 c->auth_suites |= IWINFO_KMGMT_NONE; 626 break; 627 } 628 } 629 630 memset(&wk, 0, sizeof(wk)); 631 memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 632 633 /* Get key information */ 634 if( get80211priv(ifname, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk)) >= 0 ) 635 { 636 /* Type 0 == WEP */ 637 if( (wk.ik_type == 0) && (c->auth_algs == 0) ) 638 c->auth_algs = (IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED); 639 } 640 641 /* Get used pairwise ciphers */ 642 wrq.u.mode = IEEE80211_PARAM_UCASTCIPHERS; 643 if( madwifi_wrq(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 ) 644 { 645 ciphers = wrq.u.mode; 646 647 if( c->wpa_version && ciphers & (1 << IEEE80211_CIPHER_TKIP) ) 648 c->pair_ciphers |= IWINFO_CIPHER_TKIP; 649 650 if( c->wpa_version && ciphers & (1 << IEEE80211_CIPHER_AES_CCM) ) 651 c->pair_ciphers |= IWINFO_CIPHER_CCMP; 652 653 if( c->wpa_version && ciphers & (1 << IEEE80211_CIPHER_AES_OCB) ) 654 c->pair_ciphers |= IWINFO_CIPHER_AESOCB; 655 656 if( c->wpa_version && ciphers & (1 << IEEE80211_CIPHER_CKIP) ) 657 c->pair_ciphers |= IWINFO_CIPHER_CKIP; 658 659 if( !c->pair_ciphers && ciphers & (1 << IEEE80211_CIPHER_WEP) ) 660 { 661 switch(key_len) { 662 case 13: 663 c->pair_ciphers |= IWINFO_CIPHER_WEP104; 664 break; 665 666 case 5: 667 c->pair_ciphers |= IWINFO_CIPHER_WEP40; 668 break; 669 670 case 0: 671 break; 672 673 default: 674 c->pair_ciphers = IWINFO_CIPHER_WEP40 | 675 IWINFO_CIPHER_WEP104; 676 break; 677 } 678 } 679 680 if( ciphers & (1 << IEEE80211_CIPHER_NONE) ) 681 c->pair_ciphers |= IWINFO_CIPHER_NONE; 682 } 683 684 /* Get used group cipher */ 685 wrq.u.mode = IEEE80211_PARAM_MCASTCIPHER; 686 if( madwifi_wrq(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 ) 687 { 688 ciphers = c->wpa_version ? wrq.u.mode : IEEE80211_CIPHER_WEP; 689 690 switch(ciphers) { 691 case IEEE80211_CIPHER_TKIP: 692 c->group_ciphers |= IWINFO_CIPHER_TKIP; 693 break; 694 695 case IEEE80211_CIPHER_AES_CCM: 696 c->group_ciphers |= IWINFO_CIPHER_CCMP; 697 break; 698 699 case IEEE80211_CIPHER_AES_OCB: 700 c->group_ciphers |= IWINFO_CIPHER_AESOCB; 701 break; 702 703 case IEEE80211_CIPHER_CKIP: 704 c->group_ciphers |= IWINFO_CIPHER_CKIP; 705 break; 706 707 case IEEE80211_CIPHER_WEP: 708 switch(key_len) { 709 case 13: 710 c->group_ciphers |= IWINFO_CIPHER_WEP104; 711 break; 712 713 case 5: 714 c->group_ciphers |= IWINFO_CIPHER_WEP40; 715 break; 716 717 default: 718 break; 719 } 720 break; 721 722 case IEEE80211_CIPHER_NONE: 723 c->group_ciphers |= IWINFO_CIPHER_NONE; 724 break; 725 726 default: 727 break; 728 } 729 } 730 731 c->enabled = (c->wpa_version || (c->auth_algs && c->pair_ciphers)) ? 1 : 0; 732 733 return 0; 734 } 735 736 static int madwifi_get_phyname(const char *ifname, char *buf) 737 { 738 const char *wifidev; 739 740 wifidev = madwifi_isvap(ifname, NULL); 741 742 if (wifidev) 743 { 744 strcpy(buf, wifidev); 745 return 0; 746 } 747 else if (madwifi_iswifi(ifname)) 748 { 749 strcpy(buf, madwifi_phyname(ifname)); 750 return 0; 751 } 752 753 return -1; 754 } 755 756 static int madwifi_get_assoclist(const char *ifname, char *buf, int *len) 757 { 758 int bl, tl, noise; 759 uint8_t *cp; 760 uint8_t tmp[24*1024]; 761 struct ieee80211req_sta_info *si; 762 struct iwinfo_assoclist_entry entry; 763 764 if( (tl = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 ) 765 { 766 cp = tmp; 767 bl = 0; 768 769 if( madwifi_get_noise(ifname, &noise) ) 770 noise = 0; 771 772 do { 773 si = (struct ieee80211req_sta_info *) cp; 774 775 memset(&entry, 0, sizeof(entry)); 776 777 entry.signal = (si->isi_rssi - 95); 778 entry.noise = noise; 779 memcpy(entry.mac, &si->isi_macaddr, 6); 780 781 entry.inactive = si->isi_inact * 1000; 782 783 entry.tx_packets = (si->isi_txseqs[0] & IEEE80211_SEQ_SEQ_MASK) 784 >> IEEE80211_SEQ_SEQ_SHIFT; 785 786 entry.rx_packets = (si->isi_rxseqs[0] & IEEE80211_SEQ_SEQ_MASK) 787 >> IEEE80211_SEQ_SEQ_SHIFT; 788 789 entry.tx_rate.rate = 790 (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL) * 500; 791 792 /* XXX: this is just a guess */ 793 entry.rx_rate.rate = entry.tx_rate.rate; 794 795 entry.rx_rate.mcs = -1; 796 entry.tx_rate.mcs = -1; 797 798 memcpy(&buf[bl], &entry, sizeof(struct iwinfo_assoclist_entry)); 799 800 bl += sizeof(struct iwinfo_assoclist_entry); 801 cp += si->isi_len; 802 tl -= si->isi_len; 803 } while (tl >= sizeof(struct ieee80211req_sta_info)); 804 805 *len = bl; 806 return 0; 807 } 808 809 return -1; 810 } 811 812 static int madwifi_get_txpwrlist(const char *ifname, char *buf, int *len) 813 { 814 int rc = -1; 815 char *res; 816 817 /* A wifiX device? */ 818 if( madwifi_iswifi(ifname) ) 819 { 820 if( (res = madwifi_ifadd(ifname)) != NULL ) 821 { 822 rc = wext_ops.txpwrlist(res, buf, len); 823 madwifi_ifdel(res); 824 } 825 } 826 827 /* Its an athX ... */ 828 else if( !!madwifi_isvap(ifname, NULL) ) 829 { 830 rc = wext_ops.txpwrlist(ifname, buf, len); 831 } 832 833 return rc; 834 } 835 836 static int madwifi_get_scanlist(const char *ifname, char *buf, int *len) 837 { 838 int ret; 839 char *res; 840 DIR *proc; 841 struct dirent *e; 842 843 ret = -1; 844 845 /* We got a wifiX device passed, try to lookup a vap on it */ 846 if( madwifi_iswifi(ifname) ) 847 { 848 if( (proc = opendir("/proc/sys/net/")) != NULL ) 849 { 850 while( (e = readdir(proc)) != NULL ) 851 { 852 if( !!madwifi_isvap(e->d_name, ifname) ) 853 { 854 if( iwinfo_ifup(e->d_name) ) 855 { 856 ret = wext_ops.scanlist(e->d_name, buf, len); 857 break; 858 } 859 } 860 } 861 862 closedir(proc); 863 } 864 865 /* Still nothing found, try to create a vap */ 866 if( ret == -1 ) 867 { 868 if( (res = madwifi_ifadd(ifname)) != NULL ) 869 { 870 if( iwinfo_ifup(res) ) 871 { 872 wext_ops.scanlist(res, buf, len); 873 sleep(1); 874 875 wext_ops.scanlist(res, buf, len); 876 sleep(1); 877 878 ret = wext_ops.scanlist(res, buf, len); 879 } 880 881 iwinfo_ifdown(res); 882 madwifi_ifdel(res); 883 } 884 } 885 } 886 887 /* Got athX device? */ 888 else if( !!madwifi_isvap(ifname, NULL) ) 889 { 890 ret = wext_ops.scanlist(ifname, buf, len); 891 } 892 893 return ret; 894 } 895 896 static int madwifi_get_freqlist(const char *ifname, char *buf, int *len) 897 { 898 int i, bl; 899 int rc = -1; 900 char *res; 901 struct ieee80211req_chaninfo chans; 902 struct iwinfo_freqlist_entry entry; 903 904 /* A wifiX device? */ 905 if( madwifi_iswifi(ifname) ) 906 { 907 if( (res = madwifi_ifadd(ifname)) != NULL ) 908 { 909 rc = get80211priv(res, IEEE80211_IOCTL_GETCHANINFO, 910 &chans, sizeof(chans)); 911 912 madwifi_ifdel(res); 913 } 914 } 915 916 /* Its an athX ... */ 917 else if( !!madwifi_isvap(ifname, NULL) ) 918 { 919 rc = get80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, 920 &chans, sizeof(chans)); 921 } 922 923 924 /* Got chaninfo? */ 925 if( rc >= 0 ) 926 { 927 bl = 0; 928 929 for( i = 0; i < chans.ic_nchans; i++ ) 930 { 931 entry.mhz = chans.ic_chans[i].ic_freq; 932 entry.channel = chans.ic_chans[i].ic_ieee; 933 entry.restricted = 0; 934 935 memcpy(&buf[bl], &entry, sizeof(struct iwinfo_freqlist_entry)); 936 bl += sizeof(struct iwinfo_freqlist_entry); 937 } 938 939 *len = bl; 940 return 0; 941 } 942 943 return -1; 944 } 945 946 static int madwifi_get_country(const char *ifname, char *buf) 947 { 948 int i, fd, ccode = -1; 949 char buffer[34]; 950 char *wifi = madwifi_iswifi(ifname) 951 ? (char *)ifname : madwifi_isvap(ifname, NULL); 952 953 struct ISO3166_to_CCode *e; 954 955 if( wifi ) 956 { 957 snprintf(buffer, sizeof(buffer), "/proc/sys/dev/%s/countrycode", wifi); 958 959 if( (fd = open(buffer, O_RDONLY)) > -1 ) 960 { 961 memset(buffer, 0, sizeof(buffer)); 962 963 if( read(fd, buffer, sizeof(buffer)-1) > 0 ) 964 ccode = atoi(buffer); 965 966 close(fd); 967 } 968 } 969 970 for( i = 0; i < (sizeof(CountryCodes)/sizeof(CountryCodes[0])); i++ ) 971 { 972 e = &CountryCodes[i]; 973 974 if( e->ccode == ccode ) 975 { 976 sprintf(buf, "%c%c", e->iso3166 / 256, e->iso3166 % 256); 977 return 0; 978 } 979 } 980 981 return -1; 982 } 983 984 static int madwifi_get_countrylist(const char *ifname, char *buf, int *len) 985 { 986 int i, count; 987 struct ISO3166_to_CCode *e, *p = NULL; 988 struct iwinfo_country_entry *c = (struct iwinfo_country_entry *)buf; 989 990 count = 0; 991 992 for( int i = 0; i < (sizeof(CountryCodes)/sizeof(CountryCodes[0])); i++ ) 993 { 994 e = &CountryCodes[i]; 995 996 if( !p || (e->iso3166 != p->iso3166) ) 997 { 998 c->iso3166 = e->iso3166; 999 snprintf(c->ccode, sizeof(c->ccode), "%i", e->ccode); 1000 1001 c++; 1002 count++; 1003 } 1004 1005 p = e; 1006 } 1007 1008 *len = (count * sizeof(struct iwinfo_country_entry)); 1009 return 0; 1010 } 1011 1012 static int madwifi_get_hwmodelist(const char *ifname, int *buf) 1013 { 1014 char chans[IWINFO_BUFSIZE] = { 0 }; 1015 struct iwinfo_freqlist_entry *e = NULL; 1016 int len = 0; 1017 1018 if( !madwifi_get_freqlist(ifname, chans, &len) ) 1019 { 1020 for( e = (struct iwinfo_freqlist_entry *)chans; e->channel; e++ ) 1021 { 1022 if( e->channel <= 14 ) 1023 { 1024 *buf |= IWINFO_80211_B; 1025 *buf |= IWINFO_80211_G; 1026 } 1027 else 1028 { 1029 *buf |= IWINFO_80211_A; 1030 } 1031 } 1032 1033 return 0; 1034 } 1035 1036 return -1; 1037 } 1038 1039 static int madwifi_get_htmodelist(const char *ifname, int *buf) 1040 { 1041 /* OpenWrt's madwifi did never support any HT rates */ 1042 return -1; 1043 } 1044 1045 static int madwifi_get_mbssid_support(const char *ifname, int *buf) 1046 { 1047 /* Test whether we can create another interface */ 1048 char *nif = madwifi_ifadd(ifname); 1049 1050 if( nif ) 1051 { 1052 *buf = iwinfo_ifup(nif); 1053 1054 iwinfo_ifdown(nif); 1055 madwifi_ifdel(nif); 1056 1057 return 0; 1058 } 1059 1060 return -1; 1061 } 1062 1063 static int madwifi_get_hardware_id(const char *ifname, char *buf) 1064 { 1065 char vendor[64]; 1066 char device[64]; 1067 struct iwinfo_hardware_id *ids; 1068 struct iwinfo_hardware_entry *e; 1069 const char *phy = madwifi_phyname(ifname); 1070 1071 if (wext_ops.hardware_id(phy, buf)) 1072 return iwinfo_hardware_id_from_mtd((struct iwinfo_hardware_id *)buf); 1073 1074 return 0; 1075 } 1076 1077 static const struct iwinfo_hardware_entry * 1078 madwifi_get_hardware_entry(const char *ifname) 1079 { 1080 struct iwinfo_hardware_id id; 1081 1082 if (madwifi_get_hardware_id(ifname, (char *)&id)) 1083 return NULL; 1084 1085 return iwinfo_hardware(&id); 1086 } 1087 1088 static int madwifi_get_hardware_name(const char *ifname, char *buf) 1089 { 1090 const struct iwinfo_hardware_entry *hw; 1091 1092 if (!(hw = madwifi_get_hardware_entry(ifname))) 1093 sprintf(buf, "Generic Atheros"); 1094 else 1095 sprintf(buf, "%s %s", hw->vendor_name, hw->device_name); 1096 1097 return 0; 1098 } 1099 1100 static int madwifi_get_txpower_offset(const char *ifname, int *buf) 1101 { 1102 const struct iwinfo_hardware_entry *hw; 1103 1104 if (!(hw = madwifi_get_hardware_entry(ifname))) 1105 return -1; 1106 1107 *buf = hw->txpower_offset; 1108 return 0; 1109 } 1110 1111 static int madwifi_get_frequency_offset(const char *ifname, int *buf) 1112 { 1113 const struct iwinfo_hardware_entry *hw; 1114 1115 if (!(hw = madwifi_get_hardware_entry(ifname))) 1116 return -1; 1117 1118 *buf = hw->frequency_offset; 1119 return 0; 1120 } 1121 1122 const struct iwinfo_ops madwifi_ops = { 1123 .name = "madwifi", 1124 .probe = madwifi_probe, 1125 .channel = madwifi_get_channel, 1126 .center_chan1 = madwifi_get_center_chan1, 1127 .center_chan2 = madwifi_get_center_chan2, 1128 .frequency = madwifi_get_frequency, 1129 .frequency_offset = madwifi_get_frequency_offset, 1130 .txpower = madwifi_get_txpower, 1131 .txpower_offset = madwifi_get_txpower_offset, 1132 .bitrate = madwifi_get_bitrate, 1133 .signal = madwifi_get_signal, 1134 .noise = madwifi_get_noise, 1135 .quality = madwifi_get_quality, 1136 .quality_max = madwifi_get_quality_max, 1137 .mbssid_support = madwifi_get_mbssid_support, 1138 .hwmodelist = madwifi_get_hwmodelist, 1139 .htmodelist = madwifi_get_htmodelist, 1140 .mode = madwifi_get_mode, 1141 .ssid = madwifi_get_ssid, 1142 .bssid = madwifi_get_bssid, 1143 .country = madwifi_get_country, 1144 .hardware_id = madwifi_get_hardware_id, 1145 .hardware_name = madwifi_get_hardware_name, 1146 .encryption = madwifi_get_encryption, 1147 .phyname = madwifi_get_phyname, 1148 .assoclist = madwifi_get_assoclist, 1149 .txpwrlist = madwifi_get_txpwrlist, 1150 .scanlist = madwifi_get_scanlist, 1151 .freqlist = madwifi_get_freqlist, 1152 .countrylist = madwifi_get_countrylist, 1153 .close = madwifi_close 1154 }; 1155
This page was automatically generated by LXR 0.3.1. • OpenWrt