1 2 /* 3 * Copyright (c) 1983, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 #ifndef lint 33 __RCSID("$NetBSD: ieee80211.c,v 1.11 2007/12/16 13:49:21 degroote Exp $"); 34 #endif /* not lint */ 35 36 #include <sys/param.h> 37 #include <sys/ioctl.h> 38 #include <sys/socket.h> 39 40 #include <net/if.h> 41 #include <net/if_ether.h> 42 #include <net/if_media.h> 43 #include <net/route.h> 44 #include <net80211/ieee80211.h> 45 #include <net80211/ieee80211_ioctl.h> 46 #include <net80211/ieee80211_netbsd.h> 47 48 #include <ctype.h> 49 #include <err.h> 50 #include <netdb.h> 51 #include <string.h> 52 #include <stddef.h> 53 #include <stdlib.h> 54 #include <stdio.h> 55 #include <unistd.h> 56 #include <util.h> 57 58 #include "extern.h" 59 #include "ieee80211.h" 60 61 static void set80211(int, int, int, u_int8_t *); 62 static u_int ieee80211_mhz2ieee(u_int, u_int); 63 static int getmaxrate(const uint8_t [15], u_int8_t); 64 static const char * getcaps(int); 65 static void printie(const char*, const uint8_t *, size_t, int); 66 static int copy_essid(char [], size_t, const u_int8_t *, size_t); 67 static void scan_and_wait(void); 68 static void list_scan(void); 69 static int mappsb(u_int , u_int); 70 static int mapgsm(u_int , u_int); 71 72 static void printies(const u_int8_t *, int, int); 73 static void printie(const char* , const uint8_t *, size_t , int); 74 static void printwmeparam(const char *, const u_int8_t *, size_t , int); 75 static void printwmeinfo(const char *, const u_int8_t *, size_t , int); 76 static const char * wpa_cipher(const u_int8_t *); 77 static const char * wpa_keymgmt(const u_int8_t *); 78 static void printwpaie(const char *, const u_int8_t *, size_t , int); 79 static const char * rsn_cipher(const u_int8_t *); 80 static const char * rsn_keymgmt(const u_int8_t *); 81 static void printrsnie(const char *, const u_int8_t *, size_t , int); 82 static void printssid(const char *, const u_int8_t *, size_t , int); 83 static void printrates(const char *, const u_int8_t *, size_t , int); 84 static void printcountry(const char *, const u_int8_t *, size_t , int); 85 static int iswpaoui(const u_int8_t *); 86 static int iswmeinfo(const u_int8_t *); 87 static int iswmeparam(const u_int8_t *); 88 static const char * iename(int); 89 90 extern int vflag; 91 92 static void 93 set80211(int type, int val, int len, u_int8_t *data) 94 { 95 struct ieee80211req ireq; 96 97 (void) memset(&ireq, 0, sizeof(ireq)); 98 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 99 ireq.i_type = type; 100 ireq.i_val = val; 101 ireq.i_len = len; 102 ireq.i_data = data; 103 if (ioctl(s, SIOCS80211, &ireq) < 0) 104 err(1, "SIOCS80211"); 105 } 106 107 void 108 sethidessid(const char *val, int d) 109 { 110 set80211(IEEE80211_IOC_HIDESSID, d, 0, NULL); 111 } 112 113 void 114 setapbridge(const char *val, int d) 115 { 116 set80211(IEEE80211_IOC_APBRIDGE, d, 0, NULL); 117 } 118 119 static enum ieee80211_opmode 120 get80211opmode(void) 121 { 122 struct ifmediareq ifmr; 123 124 (void) memset(&ifmr, 0, sizeof(ifmr)); 125 estrlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 126 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 127 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 128 return IEEE80211_M_IBSS; /* XXX ahdemo */ 129 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 130 return IEEE80211_M_HOSTAP; 131 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 132 return IEEE80211_M_MONITOR; 133 } 134 135 return IEEE80211_M_STA; 136 } 137 138 void 139 setifnwid(const char *val, int d) 140 { 141 struct ieee80211_nwid nwid; 142 int len; 143 144 len = sizeof(nwid.i_nwid); 145 if (get_string(val, NULL, nwid.i_nwid, &len) == NULL) 146 return; 147 nwid.i_len = len; 148 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 149 ifr.ifr_data = (void *)&nwid; 150 if (ioctl(s, SIOCS80211NWID, &ifr) == -1) 151 err(EXIT_FAILURE, "SIOCS80211NWID"); 152 } 153 154 void 155 setifbssid(const char *val, int d) 156 { 157 struct ieee80211_bssid bssid; 158 struct ether_addr *ea; 159 160 if (d != 0) { 161 /* no BSSID is especially desired */ 162 memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid)); 163 } else { 164 ea = ether_aton(val); 165 if (ea == NULL) { 166 errx(EXIT_FAILURE, "malformed BSSID: %s", val); 167 return; 168 } 169 memcpy(&bssid.i_bssid, ea->ether_addr_octet, 170 sizeof(bssid.i_bssid)); 171 } 172 estrlcpy(bssid.i_name, name, sizeof(bssid.i_name)); 173 if (ioctl(s, SIOCS80211BSSID, &bssid) == -1) 174 err(EXIT_FAILURE, "SIOCS80211BSSID"); 175 } 176 177 void 178 setiffrag(const char *val, int d) 179 { 180 struct ieee80211req ireq; 181 int thr; 182 183 if (d != 0) 184 thr = IEEE80211_FRAG_MAX; 185 else { 186 thr = atoi(val); 187 if (thr < IEEE80211_FRAG_MIN || thr > IEEE80211_FRAG_MAX) { 188 errx(EXIT_FAILURE, "invalid fragmentation threshold: %s", val); 189 return; 190 } 191 } 192 193 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 194 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD; 195 ireq.i_val = thr; 196 if (ioctl(s, SIOCS80211, &ireq) == -1) 197 err(EXIT_FAILURE, "IEEE80211_IOC_FRAGTHRESHOLD"); 198 } 199 200 void 201 setifchan(const char *val, int d) 202 { 203 struct ieee80211chanreq channel; 204 int chan; 205 206 if (d != 0) 207 chan = IEEE80211_CHAN_ANY; 208 else { 209 chan = atoi(val); 210 if (chan < 0 || chan > 0xffff) { 211 errx(EXIT_FAILURE, "invalid channel: %s", val); 212 } 213 } 214 215 estrlcpy(channel.i_name, name, sizeof(channel.i_name)); 216 channel.i_channel = (u_int16_t) chan; 217 if (ioctl(s, SIOCS80211CHANNEL, &channel) == -1) 218 err(EXIT_FAILURE, "SIOCS80211CHANNEL"); 219 } 220 221 void 222 setifnwkey(const char *val, int d) 223 { 224 struct ieee80211_nwkey nwkey; 225 int i; 226 u_int8_t keybuf[IEEE80211_WEP_NKID][16]; 227 228 nwkey.i_wepon = IEEE80211_NWKEY_WEP; 229 nwkey.i_defkid = 1; 230 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 231 nwkey.i_key[i].i_keylen = sizeof(keybuf[i]); 232 nwkey.i_key[i].i_keydat = keybuf[i]; 233 } 234 if (d != 0) { 235 /* disable WEP encryption */ 236 nwkey.i_wepon = 0; 237 i = 0; 238 } else if (strcasecmp("persist", val) == 0) { 239 /* use all values from persistent memory */ 240 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST; 241 nwkey.i_defkid = 0; 242 for (i = 0; i < IEEE80211_WEP_NKID; i++) 243 nwkey.i_key[i].i_keylen = -1; 244 } else if (strncasecmp("persist:", val, 8) == 0) { 245 val += 8; 246 /* program keys in persistent memory */ 247 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST; 248 goto set_nwkey; 249 } else { 250 set_nwkey: 251 if (isdigit((unsigned char)val[0]) && val[1] == ':') { 252 /* specifying a full set of four keys */ 253 nwkey.i_defkid = val[0] - '0'; 254 val += 2; 255 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 256 val = get_string(val, ",", keybuf[i], 257 &nwkey.i_key[i].i_keylen); 258 if (val == NULL) 259 return; 260 } 261 if (*val != '\0') { 262 errx(EXIT_FAILURE, "SIOCS80211NWKEY: too many keys."); 263 } 264 } else { 265 val = get_string(val, NULL, keybuf[0], 266 &nwkey.i_key[0].i_keylen); 267 if (val == NULL) 268 return; 269 i = 1; 270 } 271 } 272 for (; i < IEEE80211_WEP_NKID; i++) 273 nwkey.i_key[i].i_keylen = 0; 274 estrlcpy(nwkey.i_name, name, sizeof(nwkey.i_name)); 275 if (ioctl(s, SIOCS80211NWKEY, &nwkey) == -1) 276 err(EXIT_FAILURE, "SIOCS80211NWKEY"); 277 } 278 279 void 280 setifpowersave(const char *val, int d) 281 { 282 struct ieee80211_power power; 283 284 estrlcpy(power.i_name, name, sizeof(power.i_name)); 285 if (ioctl(s, SIOCG80211POWER, &power) == -1) { 286 err(EXIT_FAILURE, "SIOCG80211POWER"); 287 } 288 289 power.i_enabled = d; 290 if (ioctl(s, SIOCS80211POWER, &power) == -1) 291 err(EXIT_FAILURE, "SIOCS80211POWER"); 292 } 293 294 void 295 setifpowersavesleep(const char *val, int d) 296 { 297 struct ieee80211_power power; 298 299 estrlcpy(power.i_name, name, sizeof(power.i_name)); 300 if (ioctl(s, SIOCG80211POWER, &power) == -1) { 301 err(EXIT_FAILURE, "SIOCG80211POWER"); 302 } 303 304 power.i_maxsleep = atoi(val); 305 if (ioctl(s, SIOCS80211POWER, &power) == -1) 306 err(EXIT_FAILURE, "SIOCS80211POWER"); 307 } 308 309 void 310 setiflist(const char *val, int dummy) 311 { 312 if (strncasecmp("scan", val, 4) == 0) { 313 /* Get list of pre-scanned stations. */ 314 scan_and_wait(); 315 list_scan(); 316 } 317 else 318 errx(EXIT_FAILURE, "Don't know how to list %s for %s", val, name); 319 } 320 321 void 322 ieee80211_statistics(void) 323 { 324 struct ieee80211_stats stats; 325 326 memset(&ifr, 0, sizeof(ifr)); 327 ifr.ifr_buflen = sizeof(stats); 328 ifr.ifr_buf = (caddr_t)&stats; 329 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 330 if (ioctl(s, (zflag) ? SIOCG80211ZSTATS : SIOCG80211STATS, 331 (caddr_t)&ifr) == -1) 332 return; 333 #define STAT_PRINT(_member, _desc) \ 334 printf("\t" _desc ": %" PRIu32 "\n", stats._member) 335 336 STAT_PRINT(is_rx_badversion, "rx frame with bad version"); 337 STAT_PRINT(is_rx_tooshort, "rx frame too short"); 338 STAT_PRINT(is_rx_wrongbss, "rx from wrong bssid"); 339 STAT_PRINT(is_rx_dup, "rx discard 'cuz dup"); 340 STAT_PRINT(is_rx_wrongdir, "rx w/ wrong direction"); 341 STAT_PRINT(is_rx_mcastecho, "rx discard 'cuz mcast echo"); 342 STAT_PRINT(is_rx_notassoc, "rx discard 'cuz sta !assoc"); 343 STAT_PRINT(is_rx_noprivacy, "rx w/ wep but privacy off"); 344 STAT_PRINT(is_rx_unencrypted, "rx w/o wep and privacy on"); 345 STAT_PRINT(is_rx_wepfail, "rx wep processing failed"); 346 STAT_PRINT(is_rx_decap, "rx decapsulation failed"); 347 STAT_PRINT(is_rx_mgtdiscard, "rx discard mgt frames"); 348 STAT_PRINT(is_rx_ctl, "rx discard ctrl frames"); 349 STAT_PRINT(is_rx_beacon, "rx beacon frames"); 350 STAT_PRINT(is_rx_rstoobig, "rx rate set truncated"); 351 STAT_PRINT(is_rx_elem_missing, "rx required element missing"); 352 STAT_PRINT(is_rx_elem_toobig, "rx element too big"); 353 STAT_PRINT(is_rx_elem_toosmall, "rx element too small"); 354 STAT_PRINT(is_rx_elem_unknown, "rx element unknown"); 355 STAT_PRINT(is_rx_badchan, "rx frame w/ invalid chan"); 356 STAT_PRINT(is_rx_chanmismatch, "rx frame chan mismatch"); 357 STAT_PRINT(is_rx_nodealloc, "rx frame dropped"); 358 STAT_PRINT(is_rx_ssidmismatch, "rx frame ssid mismatch "); 359 STAT_PRINT(is_rx_auth_unsupported, "rx w/ unsupported auth alg"); 360 STAT_PRINT(is_rx_auth_fail, "rx sta auth failure"); 361 STAT_PRINT(is_rx_auth_countermeasures, "rx auth discard 'cuz CM"); 362 STAT_PRINT(is_rx_assoc_bss, "rx assoc from wrong bssid"); 363 STAT_PRINT(is_rx_assoc_notauth, "rx assoc w/o auth"); 364 STAT_PRINT(is_rx_assoc_capmismatch, "rx assoc w/ cap mismatch"); 365 STAT_PRINT(is_rx_assoc_norate, "rx assoc w/ no rate match"); 366 STAT_PRINT(is_rx_assoc_badwpaie, "rx assoc w/ bad WPA IE"); 367 STAT_PRINT(is_rx_deauth, "rx deauthentication"); 368 STAT_PRINT(is_rx_disassoc, "rx disassociation"); 369 STAT_PRINT(is_rx_badsubtype, "rx frame w/ unknown subtyp"); 370 STAT_PRINT(is_rx_nobuf, "rx failed for lack of buf"); 371 STAT_PRINT(is_rx_decryptcrc, "rx decrypt failed on crc"); 372 STAT_PRINT(is_rx_ahdemo_mgt, "rx discard ahdemo mgt fram"); 373 STAT_PRINT(is_rx_bad_auth, "rx bad auth request"); 374 STAT_PRINT(is_rx_unauth, "rx on unauthorized port"); 375 STAT_PRINT(is_rx_badkeyid, "rx w/ incorrect keyid"); 376 STAT_PRINT(is_rx_ccmpreplay, "rx seq# violation (CCMP)"); 377 STAT_PRINT(is_rx_ccmpformat, "rx format bad (CCMP)"); 378 STAT_PRINT(is_rx_ccmpmic, "rx MIC check failed (CCMP)"); 379 STAT_PRINT(is_rx_tkipreplay, "rx seq# violation (TKIP)"); 380 STAT_PRINT(is_rx_tkipformat, "rx format bad (TKIP)"); 381 STAT_PRINT(is_rx_tkipmic, "rx MIC check failed (TKIP)"); 382 STAT_PRINT(is_rx_tkipicv, "rx ICV check failed (TKIP)"); 383 STAT_PRINT(is_rx_badcipher, "rx failed 'cuz key type"); 384 STAT_PRINT(is_rx_nocipherctx, "rx failed 'cuz key !setup"); 385 STAT_PRINT(is_rx_acl, "rx discard 'cuz acl policy"); 386 387 STAT_PRINT(is_tx_nobuf, "tx failed for lack of buf"); 388 STAT_PRINT(is_tx_nonode, "tx failed for no node"); 389 STAT_PRINT(is_tx_unknownmgt, "tx of unknown mgt frame"); 390 STAT_PRINT(is_tx_badcipher, "tx failed 'cuz key type"); 391 STAT_PRINT(is_tx_nodefkey, "tx failed 'cuz no defkey"); 392 STAT_PRINT(is_tx_noheadroom, "tx failed 'cuz no space"); 393 STAT_PRINT(is_tx_fragframes, "tx frames fragmented"); 394 STAT_PRINT(is_tx_frags, "tx fragments created"); 395 396 STAT_PRINT(is_scan_active, "active scans started"); 397 STAT_PRINT(is_scan_passive, "passive scans started"); 398 STAT_PRINT(is_node_timeout, "nodes timed out inactivity"); 399 STAT_PRINT(is_crypto_nomem, "no memory for crypto ctx"); 400 STAT_PRINT(is_crypto_tkip, "tkip crypto done in s/w"); 401 STAT_PRINT(is_crypto_tkipenmic, "tkip en-MIC done in s/w"); 402 STAT_PRINT(is_crypto_tkipdemic, "tkip de-MIC done in s/w"); 403 STAT_PRINT(is_crypto_tkipcm, "tkip counter measures"); 404 STAT_PRINT(is_crypto_ccmp, "ccmp crypto done in s/w"); 405 STAT_PRINT(is_crypto_wep, "wep crypto done in s/w"); 406 STAT_PRINT(is_crypto_setkey_cipher, "cipher rejected key"); 407 STAT_PRINT(is_crypto_setkey_nokey, "no key index for setkey"); 408 STAT_PRINT(is_crypto_delkey, "driver key delete failed"); 409 STAT_PRINT(is_crypto_badcipher, "unknown cipher"); 410 STAT_PRINT(is_crypto_nocipher, "cipher not available"); 411 STAT_PRINT(is_crypto_attachfail, "cipher attach failed"); 412 STAT_PRINT(is_crypto_swfallback, "cipher fallback to s/w"); 413 STAT_PRINT(is_crypto_keyfail, "driver key alloc failed"); 414 STAT_PRINT(is_crypto_enmicfail, "en-MIC failed"); 415 STAT_PRINT(is_ibss_capmismatch, "merge failed-cap mismatch"); 416 STAT_PRINT(is_ibss_norate, "merge failed-rate mismatch"); 417 STAT_PRINT(is_ps_unassoc, "ps-poll for unassoc. sta"); 418 STAT_PRINT(is_ps_badaid, "ps-poll w/ incorrect aid"); 419 STAT_PRINT(is_ps_qempty, "ps-poll w/ nothing to send"); 420 STAT_PRINT(is_ff_badhdr, "fast frame rx'd w/ bad hdr"); 421 STAT_PRINT(is_ff_tooshort, "fast frame rx decap error"); 422 STAT_PRINT(is_ff_split, "fast frame rx split error"); 423 STAT_PRINT(is_ff_decap, "fast frames decap'd"); 424 STAT_PRINT(is_ff_encap, "fast frames encap'd for tx"); 425 STAT_PRINT(is_rx_badbintval, "rx frame w/ bogus bintval"); 426 } 427 428 void 429 ieee80211_status(void) 430 { 431 int i, nwkey_verbose; 432 struct ieee80211_nwid nwid; 433 struct ieee80211_nwkey nwkey; 434 struct ieee80211_power power; 435 u_int8_t keybuf[IEEE80211_WEP_NKID][16]; 436 struct ieee80211_bssid bssid; 437 struct ieee80211chanreq channel; 438 struct ieee80211req ireq; 439 struct ether_addr ea; 440 static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN]; 441 enum ieee80211_opmode opmode = get80211opmode(); 442 443 memset(&ifr, 0, sizeof(ifr)); 444 ifr.ifr_data = (void *)&nwid; 445 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 446 if (ioctl(s, SIOCG80211NWID, &ifr) == -1) 447 return; 448 if (nwid.i_len > IEEE80211_NWID_LEN) { 449 errx(EXIT_FAILURE, "SIOCG80211NWID: wrong length of nwid (%d)", nwid.i_len); 450 } 451 printf("\tssid "); 452 print_string(nwid.i_nwid, nwid.i_len); 453 454 if (opmode == IEEE80211_M_HOSTAP) { 455 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 456 ireq.i_type = IEEE80211_IOC_HIDESSID; 457 if (ioctl(s, SIOCG80211, &ireq) != -1) { 458 if (ireq.i_val) 459 printf(" [hidden]"); 460 else if (vflag) 461 printf(" [shown]"); 462 } 463 464 ireq.i_type = IEEE80211_IOC_APBRIDGE; 465 if (ioctl(s, SIOCG80211, &ireq) != -1) { 466 if (ireq.i_val) 467 printf(" apbridge"); 468 else if (vflag) 469 printf(" -apbridge"); 470 } 471 } 472 473 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 474 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD; 475 if (ioctl(s, SIOCG80211, &ireq) == -1) 476 ; 477 else if (ireq.i_val < IEEE80211_FRAG_MAX) 478 printf(" frag %d", ireq.i_val); 479 else if (vflag) 480 printf(" -frag"); 481 482 memset(&nwkey, 0, sizeof(nwkey)); 483 estrlcpy(nwkey.i_name, name, sizeof(nwkey.i_name)); 484 /* show nwkey only when WEP is enabled */ 485 if (ioctl(s, SIOCG80211NWKEY, &nwkey) == -1 || 486 nwkey.i_wepon == 0) { 487 printf("\n"); 488 goto skip_wep; 489 } 490 491 printf(" nwkey "); 492 /* try to retrieve WEP keys */ 493 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 494 nwkey.i_key[i].i_keydat = keybuf[i]; 495 nwkey.i_key[i].i_keylen = sizeof(keybuf[i]); 496 } 497 if (ioctl(s, SIOCG80211NWKEY, &nwkey) == -1) { 498 printf("*****"); 499 } else { 500 nwkey_verbose = 0; 501 /* check to see non default key or multiple keys defined */ 502 if (nwkey.i_defkid != 1) { 503 nwkey_verbose = 1; 504 } else { 505 for (i = 1; i < IEEE80211_WEP_NKID; i++) { 506 if (nwkey.i_key[i].i_keylen != 0) { 507 nwkey_verbose = 1; 508 break; 509 } 510 } 511 } 512 /* check extra ambiguity with keywords */ 513 if (!nwkey_verbose) { 514 if (nwkey.i_key[0].i_keylen >= 2 && 515 isdigit(nwkey.i_key[0].i_keydat[0]) && 516 nwkey.i_key[0].i_keydat[1] == ':') 517 nwkey_verbose = 1; 518 else if (nwkey.i_key[0].i_keylen >= 7 && 519 strncasecmp("persist", 520 (const char *)nwkey.i_key[0].i_keydat, 7) == 0) 521 nwkey_verbose = 1; 522 } 523 if (nwkey_verbose) 524 printf("%d:", nwkey.i_defkid); 525 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 526 if (i > 0) 527 printf(","); 528 if (nwkey.i_key[i].i_keylen < 0) 529 printf("persist"); 530 else 531 print_string(nwkey.i_key[i].i_keydat, 532 nwkey.i_key[i].i_keylen); 533 if (!nwkey_verbose) 534 break; 535 } 536 } 537 printf("\n"); 538 539 skip_wep: 540 estrlcpy(power.i_name, name, sizeof(power.i_name)); 541 if (ioctl(s, SIOCG80211POWER, &power) == -1) 542 goto skip_power; 543 printf("\tpowersave "); 544 if (power.i_enabled) 545 printf("on (%dms sleep)", power.i_maxsleep); 546 else 547 printf("off"); 548 printf("\n"); 549 550 skip_power: 551 estrlcpy(bssid.i_name, name, sizeof(bssid.i_name)); 552 if (ioctl(s, SIOCG80211BSSID, &bssid) == -1) 553 return; 554 estrlcpy(channel.i_name, name, sizeof(channel.i_name)); 555 if (ioctl(s, SIOCG80211CHANNEL, &channel) == -1) 556 return; 557 if (memcmp(bssid.i_bssid, zero_macaddr, IEEE80211_ADDR_LEN) == 0) { 558 if (channel.i_channel != (u_int16_t)-1) 559 printf("\tchan %d\n", channel.i_channel); 560 } else { 561 memcpy(ea.ether_addr_octet, bssid.i_bssid, 562 sizeof(ea.ether_addr_octet)); 563 printf("\tbssid %s", ether_ntoa(&ea)); 564 if (channel.i_channel != IEEE80211_CHAN_ANY) 565 printf(" chan %d", channel.i_channel); 566 printf("\n"); 567 } 568 } 569 570 static void 571 scan_and_wait(void) 572 { 573 struct ieee80211req ireq; 574 int sroute; 575 576 sroute = socket(PF_ROUTE, SOCK_RAW, 0); 577 if (sroute < 0) { 578 perror("socket(PF_ROUTE,SOCK_RAW)"); 579 return; 580 } 581 (void) memset(&ireq, 0, sizeof(ireq)); 582 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 583 ireq.i_type = IEEE80211_IOC_SCAN_REQ; 584 /* NB: only root can trigger a scan so ignore errors */ 585 if (ioctl(s, SIOCS80211, &ireq) >= 0) { 586 char buf[2048]; 587 struct if_announcemsghdr *ifan; 588 struct rt_msghdr *rtm; 589 590 do { 591 if (read(sroute, buf, sizeof(buf)) < 0) { 592 perror("read(PF_ROUTE)"); 593 break; 594 } 595 rtm = (struct rt_msghdr *) buf; 596 if (rtm->rtm_version != RTM_VERSION) 597 break; 598 ifan = (struct if_announcemsghdr *) rtm; 599 } while (rtm->rtm_type != RTM_IEEE80211 || 600 ifan->ifan_what != RTM_IEEE80211_SCAN); 601 } 602 close(sroute); 603 } 604 605 static void 606 list_scan(void) 607 { 608 u_int8_t buf[24*1024]; 609 struct ieee80211req ireq; 610 char ssid[IEEE80211_NWID_LEN+1]; 611 const u_int8_t *cp; 612 int len, ssidmax; 613 614 (void) memset(&ireq, 0, sizeof(ireq)); 615 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 616 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; 617 ireq.i_data = buf; 618 ireq.i_len = sizeof(buf); 619 if (ioctl(s, SIOCG80211, &ireq) < 0) 620 errx(1, "unable to get scan results"); 621 len = ireq.i_len; 622 if (len < sizeof(struct ieee80211req_scan_result)) 623 return; 624 625 ssidmax = IEEE80211_NWID_LEN; 626 printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n" 627 , ssidmax, ssidmax, "SSID" 628 , "BSSID" 629 , "CHAN" 630 , "RATE" 631 , "S:N" 632 , "INT" 633 , "CAPS" 634 ); 635 cp = buf; 636 do { 637 const struct ieee80211req_scan_result *sr; 638 const uint8_t *vp; 639 640 sr = (const struct ieee80211req_scan_result *) cp; 641 vp = (const u_int8_t *)(sr+1); 642 printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s" 643 , ssidmax 644 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len) 645 , ssid 646 , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 647 , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) 648 , getmaxrate(sr->isr_rates, sr->isr_nrates) 649 , sr->isr_rssi, sr->isr_noise 650 , sr->isr_intval 651 , getcaps(sr->isr_capinfo) 652 ); 653 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);; 654 printf("\n"); 655 cp += sr->isr_len, len -= sr->isr_len; 656 } while (len >= sizeof(struct ieee80211req_scan_result)); 657 } 658 /* 659 * Convert MHz frequency to IEEE channel number. 660 */ 661 static u_int 662 ieee80211_mhz2ieee(u_int isrfreq, u_int isrflags) 663 { 664 if ((isrflags & IEEE80211_CHAN_GSM) || (907 <= isrfreq && isrfreq <= 922)) 665 return mapgsm(isrfreq, isrflags); 666 if (isrfreq == 2484) 667 return 14; 668 if (isrfreq < 2484) 669 return (isrfreq - 2407) / 5; 670 if (isrfreq < 5000) { 671 if (isrflags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) 672 return mappsb(isrfreq, isrflags); 673 else if (isrfreq > 4900) 674 return (isrfreq - 4000) / 5; 675 else 676 return 15 + ((isrfreq - 2512) / 20); 677 } 678 return (isrfreq - 5000) / 5; 679 } 680 681 static int 682 getmaxrate(const u_int8_t rates[15], u_int8_t nrates) 683 { 684 int i, maxrate = -1; 685 686 for (i = 0; i < nrates; i++) { 687 int rate = rates[i] & IEEE80211_RATE_VAL; 688 if (rate > maxrate) 689 maxrate = rate; 690 } 691 return maxrate / 2; 692 } 693 694 static const char * 695 getcaps(int capinfo) 696 { 697 static char capstring[32]; 698 char *cp = capstring; 699 700 if (capinfo & IEEE80211_CAPINFO_ESS) 701 *cp++ = 'E'; 702 if (capinfo & IEEE80211_CAPINFO_IBSS) 703 *cp++ = 'I'; 704 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 705 *cp++ = 'c'; 706 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 707 *cp++ = 'C'; 708 if (capinfo & IEEE80211_CAPINFO_PRIVACY) 709 *cp++ = 'P'; 710 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 711 *cp++ = 'S'; 712 if (capinfo & IEEE80211_CAPINFO_PBCC) 713 *cp++ = 'B'; 714 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 715 *cp++ = 'A'; 716 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 717 *cp++ = 's'; 718 if (capinfo & IEEE80211_CAPINFO_RSN) 719 *cp++ = 'R'; 720 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 721 *cp++ = 'D'; 722 *cp = '\0'; 723 return capstring; 724 } 725 726 static void 727 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 728 { 729 printf("%s", tag); 730 731 maxlen -= strlen(tag)+2; 732 if (2*ielen > maxlen) 733 maxlen--; 734 printf("<"); 735 for (; ielen > 0; ie++, ielen--) { 736 if (maxlen-- <= 0) 737 break; 738 printf("%02x", *ie); 739 } 740 if (ielen != 0) 741 printf("-"); 742 printf(">"); 743 } 744 745 #define LE_READ_2(p) \ 746 ((u_int16_t) \ 747 ((((const u_int8_t *)(p))[0] ) | \ 748 (((const u_int8_t *)(p))[1] << 8))) 749 #define LE_READ_4(p) \ 750 ((u_int32_t) \ 751 ((((const u_int8_t *)(p))[0] ) | \ 752 (((const u_int8_t *)(p))[1] << 8) | \ 753 (((const u_int8_t *)(p))[2] << 16) | \ 754 (((const u_int8_t *)(p))[3] << 24))) 755 756 /* 757 * NB: The decoding routines assume a properly formatted ie 758 * which should be safe as the kernel only retains them 759 * if they parse ok. 760 */ 761 762 static void 763 printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 764 { 765 #define MS(_v, _f) (((_v) & _f) >> _f##_S) 766 static const char *acnames[] = { "BE", "BK", "VO", "VI" }; 767 const struct ieee80211_wme_param *wme = 768 (const struct ieee80211_wme_param *) ie; 769 int i; 770 771 printf("%s", tag); 772 if (!vflag) 773 return; 774 printf("<qosinfo 0x%x", wme->param_qosInfo); 775 ie += offsetof(struct ieee80211_wme_param, params_acParams); 776 for (i = 0; i < WME_NUM_AC; i++) { 777 const struct ieee80211_wme_acparams *ac = 778 &wme->params_acParams[i]; 779 780 printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]" 781 , acnames[i] 782 , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : "" 783 , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN) 784 , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN) 785 , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX) 786 , LE_READ_2(&ac->acp_txop) 787 ); 788 } 789 printf(">"); 790 #undef MS 791 } 792 793 static void 794 printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 795 { 796 printf("%s", tag); 797 if (vflag) { 798 const struct ieee80211_wme_info *wme = 799 (const struct ieee80211_wme_info *) ie; 800 printf("<version 0x%x info 0x%x>", 801 wme->wme_version, wme->wme_info); 802 } 803 } 804 805 static const char * 806 wpa_cipher(const u_int8_t *sel) 807 { 808 #define WPA_SEL(x) (((x)<<24)|WPA_OUI) 809 u_int32_t w = LE_READ_4(sel); 810 811 switch (w) { 812 case WPA_SEL(WPA_CSE_NULL): 813 return "NONE"; 814 case WPA_SEL(WPA_CSE_WEP40): 815 return "WEP40"; 816 case WPA_SEL(WPA_CSE_WEP104): 817 return "WEP104"; 818 case WPA_SEL(WPA_CSE_TKIP): 819 return "TKIP"; 820 case WPA_SEL(WPA_CSE_CCMP): 821 return "AES-CCMP"; 822 } 823 return "?"; /* NB: so 1<< is discarded */ 824 #undef WPA_SEL 825 } 826 827 static const char * 828 wpa_keymgmt(const u_int8_t *sel) 829 { 830 #define WPA_SEL(x) (((x)<<24)|WPA_OUI) 831 u_int32_t w = LE_READ_4(sel); 832 833 switch (w) { 834 case WPA_SEL(WPA_ASE_8021X_UNSPEC): 835 return "8021X-UNSPEC"; 836 case WPA_SEL(WPA_ASE_8021X_PSK): 837 return "8021X-PSK"; 838 case WPA_SEL(WPA_ASE_NONE): 839 return "NONE"; 840 } 841 return "?"; 842 #undef WPA_SEL 843 } 844 845 static void 846 printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 847 { 848 u_int8_t len = ie[1]; 849 850 printf("%s", tag); 851 if (vflag) { 852 const char *sep; 853 int n; 854 855 ie += 6, len -= 4; /* NB: len is payload only */ 856 857 printf("<v%u", LE_READ_2(ie)); 858 ie += 2, len -= 2; 859 860 printf(" mc:%s", wpa_cipher(ie)); 861 ie += 4, len -= 4; 862 863 /* unicast ciphers */ 864 n = LE_READ_2(ie); 865 ie += 2, len -= 2; 866 sep = " uc:"; 867 for (; n > 0; n--) { 868 printf("%s%s", sep, wpa_cipher(ie)); 869 ie += 4, len -= 4; 870 sep = "+"; 871 } 872 873 /* key management algorithms */ 874 n = LE_READ_2(ie); 875 ie += 2, len -= 2; 876 sep = " km:"; 877 for (; n > 0; n--) { 878 printf("%s%s", sep, wpa_keymgmt(ie)); 879 ie += 4, len -= 4; 880 sep = "+"; 881 } 882 883 if (len > 2) /* optional capabilities */ 884 printf(", caps 0x%x", LE_READ_2(ie)); 885 printf(">"); 886 } 887 } 888 889 static const char * 890 rsn_cipher(const u_int8_t *sel) 891 { 892 #define RSN_SEL(x) (((x)<<24)|RSN_OUI) 893 u_int32_t w = LE_READ_4(sel); 894 895 switch (w) { 896 case RSN_SEL(RSN_CSE_NULL): 897 return "NONE"; 898 case RSN_SEL(RSN_CSE_WEP40): 899 return "WEP40"; 900 case RSN_SEL(RSN_CSE_WEP104): 901 return "WEP104"; 902 case RSN_SEL(RSN_CSE_TKIP): 903 return "TKIP"; 904 case RSN_SEL(RSN_CSE_CCMP): 905 return "AES-CCMP"; 906 case RSN_SEL(RSN_CSE_WRAP): 907 return "AES-OCB"; 908 } 909 return "?"; 910 #undef WPA_SEL 911 } 912 913 static const char * 914 rsn_keymgmt(const u_int8_t *sel) 915 { 916 #define RSN_SEL(x) (((x)<<24)|RSN_OUI) 917 u_int32_t w = LE_READ_4(sel); 918 919 switch (w) { 920 case RSN_SEL(RSN_ASE_8021X_UNSPEC): 921 return "8021X-UNSPEC"; 922 case RSN_SEL(RSN_ASE_8021X_PSK): 923 return "8021X-PSK"; 924 case RSN_SEL(RSN_ASE_NONE): 925 return "NONE"; 926 } 927 return "?"; 928 #undef RSN_SEL 929 } 930 931 static void 932 printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 933 { 934 printf("%s", tag); 935 if (vflag) { 936 const char *sep; 937 int n; 938 939 ie += 2, ielen -= 2; 940 941 printf("<v%u", LE_READ_2(ie)); 942 ie += 2, ielen -= 2; 943 944 printf(" mc:%s", rsn_cipher(ie)); 945 ie += 4, ielen -= 4; 946 947 /* unicast ciphers */ 948 n = LE_READ_2(ie); 949 ie += 2, ielen -= 2; 950 sep = " uc:"; 951 for (; n > 0; n--) { 952 printf("%s%s", sep, rsn_cipher(ie)); 953 ie += 4, ielen -= 4; 954 sep = "+"; 955 } 956 957 /* key management algorithms */ 958 n = LE_READ_2(ie); 959 ie += 2, ielen -= 2; 960 sep = " km:"; 961 for (; n > 0; n--) { 962 printf("%s%s", sep, rsn_keymgmt(ie)); 963 ie += 4, ielen -= 4; 964 sep = "+"; 965 } 966 967 if (ielen > 2) /* optional capabilities */ 968 printf(", caps 0x%x", LE_READ_2(ie)); 969 /* XXXPMKID */ 970 printf(">"); 971 } 972 } 973 974 /* 975 * Copy the ssid string contents into buf, truncating to fit. If the 976 * ssid is entirely printable then just copy intact. Otherwise convert 977 * to hexadecimal. If the result is truncated then replace the last 978 * three characters with "...". 979 */ 980 static int 981 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 982 { 983 const u_int8_t *p; 984 size_t maxlen; 985 int i; 986 987 if (essid_len > bufsize) 988 maxlen = bufsize; 989 else 990 maxlen = essid_len; 991 /* determine printable or not */ 992 for (i = 0, p = essid; i < maxlen; i++, p++) { 993 if (*p < ' ' || *p > 0x7e) 994 break; 995 } 996 if (i != maxlen) { /* not printable, print as hex */ 997 if (bufsize < 3) 998 return 0; 999 strlcpy(buf, "0x", bufsize); 1000 bufsize -= 2; 1001 p = essid; 1002 for (i = 0; i < maxlen && bufsize >= 2; i++) { 1003 sprintf(&buf[2+2*i], "%02x", p[i]); 1004 bufsize -= 2; 1005 } 1006 if (i != essid_len) 1007 memcpy(&buf[2+2*i-3], "...", 3); 1008 } else { /* printable, truncate as needed */ 1009 memcpy(buf, essid, maxlen); 1010 if (maxlen != essid_len) 1011 memcpy(&buf[maxlen-3], "...", 3); 1012 } 1013 return maxlen; 1014 } 1015 1016 static void 1017 printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1018 { 1019 char ssid[2*IEEE80211_NWID_LEN+1]; 1020 1021 printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid); 1022 } 1023 1024 static void 1025 printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1026 { 1027 const char *sep; 1028 int i; 1029 1030 printf("%s", tag); 1031 sep = "<"; 1032 for (i = 2; i < ielen; i++) { 1033 printf("%s%s%d", sep, 1034 ie[i] & IEEE80211_RATE_BASIC ? "B" : "", 1035 ie[i] & IEEE80211_RATE_VAL); 1036 sep = ","; 1037 } 1038 printf(">"); 1039 } 1040 1041 static void 1042 printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1043 { 1044 const struct ieee80211_country_ie *cie = 1045 (const struct ieee80211_country_ie *) ie; 1046 int i, nbands, schan, nchan; 1047 1048 printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]); 1049 nbands = (cie->len - 3) / sizeof(cie->band[0]); 1050 for (i = 0; i < nbands; i++) { 1051 schan = cie->band[i].schan; 1052 nchan = cie->band[i].nchan; 1053 if (nchan != 1) 1054 printf(" %u-%u,%u", schan, schan + nchan-1, 1055 cie->band[i].maxtxpwr); 1056 else 1057 printf(" %u,%u", schan, cie->band[i].maxtxpwr); 1058 } 1059 printf(">"); 1060 } 1061 1062 /* unaligned little endian access */ 1063 #define LE_READ_4(p) \ 1064 ((u_int32_t) \ 1065 ((((const u_int8_t *)(p))[0] ) | \ 1066 (((const u_int8_t *)(p))[1] << 8) | \ 1067 (((const u_int8_t *)(p))[2] << 16) | \ 1068 (((const u_int8_t *)(p))[3] << 24))) 1069 1070 static int 1071 iswpaoui(const u_int8_t *frm) 1072 { 1073 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 1074 } 1075 1076 static int 1077 iswmeinfo(const u_int8_t *frm) 1078 { 1079 return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 1080 frm[6] == WME_INFO_OUI_SUBTYPE; 1081 } 1082 1083 static int 1084 iswmeparam(const u_int8_t *frm) 1085 { 1086 return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 1087 frm[6] == WME_PARAM_OUI_SUBTYPE; 1088 } 1089 1090 static const char * 1091 iename(int elemid) 1092 { 1093 switch (elemid) { 1094 case IEEE80211_ELEMID_FHPARMS: return " FHPARMS"; 1095 case IEEE80211_ELEMID_CFPARMS: return " CFPARMS"; 1096 case IEEE80211_ELEMID_TIM: return " TIM"; 1097 case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS"; 1098 case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE"; 1099 case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR"; 1100 case IEEE80211_ELEMID_PWRCAP: return " PWRCAP"; 1101 case IEEE80211_ELEMID_TPCREQ: return " TPCREQ"; 1102 case IEEE80211_ELEMID_TPCREP: return " TPCREP"; 1103 case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN"; 1104 case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA"; 1105 case IEEE80211_ELEMID_MEASREQ: return " MEASREQ"; 1106 case IEEE80211_ELEMID_MEASREP: return " MEASREP"; 1107 case IEEE80211_ELEMID_QUIET: return " QUIET"; 1108 case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS"; 1109 case IEEE80211_ELEMID_TPC: return " TPC"; 1110 case IEEE80211_ELEMID_CCKM: return " CCKM"; 1111 } 1112 return " ???"; 1113 } 1114 1115 static void 1116 printies(const u_int8_t *vp, int ielen, int maxcols) 1117 { 1118 while (ielen > 0) { 1119 switch (vp[0]) { 1120 case IEEE80211_ELEMID_SSID: 1121 if (vflag) 1122 printssid(" SSID", vp, 2+vp[1], maxcols); 1123 break; 1124 case IEEE80211_ELEMID_RATES: 1125 case IEEE80211_ELEMID_XRATES: 1126 if (vflag) 1127 printrates(vp[0] == IEEE80211_ELEMID_RATES ? 1128 " RATES" : " XRATES", vp, 2+vp[1], maxcols); 1129 break; 1130 case IEEE80211_ELEMID_DSPARMS: 1131 if (vflag) 1132 printf(" DSPARMS<%u>", vp[2]); 1133 break; 1134 case IEEE80211_ELEMID_COUNTRY: 1135 if (vflag) 1136 printcountry(" COUNTRY", vp, 2+vp[1], maxcols); 1137 break; 1138 case IEEE80211_ELEMID_ERP: 1139 if (vflag) 1140 printf(" ERP<0x%x>", vp[2]); 1141 break; 1142 case IEEE80211_ELEMID_VENDOR: 1143 if (iswpaoui(vp)) 1144 printwpaie(" WPA", vp, 2+vp[1], maxcols); 1145 else if (iswmeinfo(vp)) 1146 printwmeinfo(" WME", vp, 2+vp[1], maxcols); 1147 else if (iswmeparam(vp)) 1148 printwmeparam(" WME", vp, 2+vp[1], maxcols); 1149 else if (vflag) 1150 printie(" VEN", vp, 2+vp[1], maxcols); 1151 break; 1152 case IEEE80211_ELEMID_RSN: 1153 printrsnie(" RSN", vp, 2+vp[1], maxcols); 1154 break; 1155 default: 1156 if (vflag) 1157 printie(iename(vp[0]), vp, 2+vp[1], maxcols); 1158 break; 1159 } 1160 ielen -= 2+vp[1]; 1161 vp += 2+vp[1]; 1162 } 1163 } 1164 1165 static int 1166 mapgsm(u_int isrfreq, u_int isrflags) 1167 { 1168 isrfreq *= 10; 1169 if (isrflags & IEEE80211_CHAN_QUARTER) 1170 isrfreq += 5; 1171 else if (isrflags & IEEE80211_CHAN_HALF) 1172 isrfreq += 10; 1173 else 1174 isrfreq += 20; 1175 /* NB: there is no 907/20 wide but leave room */ 1176 return (isrfreq - 906*10) / 5; 1177 } 1178 1179 static int 1180 mappsb(u_int isrfreq, u_int isrflags) 1181 { 1182 return 37 + ((isrfreq * 10) + ((isrfreq % 5) == 2 ? 5 : 0) - 49400) / 5; 1183 } 1184