1 /* $NetBSD: ieee80211.c,v 1.10 2007/01/09 09:25:56 dyoung Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: ieee80211.c,v 1.10 2007/01/09 09:25:56 dyoung Exp $"); 35 #endif /* not lint */ 36 37 #include <sys/param.h> 38 #include <sys/ioctl.h> 39 #include <sys/socket.h> 40 41 #include <net/if.h> 42 #include <net/if_ether.h> 43 #include <net/if_media.h> 44 #include <net80211/ieee80211.h> 45 #include <net80211/ieee80211_ioctl.h> 46 47 #include <ctype.h> 48 #include <err.h> 49 #include <netdb.h> 50 #include <string.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 #include <util.h> 54 55 #include "extern.h" 56 #include "ieee80211.h" 57 58 static void set80211(int, int, int, uint8_t *); 59 60 static void 61 set80211(int type, int val, int len, u_int8_t *data) 62 { 63 struct ieee80211req ireq; 64 65 (void) memset(&ireq, 0, sizeof(ireq)); 66 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 67 ireq.i_type = type; 68 ireq.i_val = val; 69 ireq.i_len = len; 70 ireq.i_data = data; 71 if (ioctl(s, SIOCS80211, &ireq) < 0) 72 err(1, "SIOCS80211"); 73 } 74 75 void 76 sethidessid(const char *val, int d) 77 { 78 set80211(IEEE80211_IOC_HIDESSID, d, 0, NULL); 79 } 80 81 void 82 setapbridge(const char *val, int d) 83 { 84 set80211(IEEE80211_IOC_APBRIDGE, d, 0, NULL); 85 } 86 87 static enum ieee80211_opmode 88 get80211opmode(void) 89 { 90 struct ifmediareq ifmr; 91 92 (void) memset(&ifmr, 0, sizeof(ifmr)); 93 estrlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 94 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 95 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 96 return IEEE80211_M_IBSS; /* XXX ahdemo */ 97 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 98 return IEEE80211_M_HOSTAP; 99 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 100 return IEEE80211_M_MONITOR; 101 } 102 103 return IEEE80211_M_STA; 104 } 105 106 void 107 setifnwid(const char *val, int d) 108 { 109 struct ieee80211_nwid nwid; 110 int len; 111 112 len = sizeof(nwid.i_nwid); 113 if (get_string(val, NULL, nwid.i_nwid, &len) == NULL) 114 return; 115 nwid.i_len = len; 116 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 117 ifr.ifr_data = (void *)&nwid; 118 if (ioctl(s, SIOCS80211NWID, &ifr) == -1) 119 err(EXIT_FAILURE, "SIOCS80211NWID"); 120 } 121 122 void 123 setifbssid(const char *val, int d) 124 { 125 struct ieee80211_bssid bssid; 126 struct ether_addr *ea; 127 128 if (d != 0) { 129 /* no BSSID is especially desired */ 130 memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid)); 131 } else { 132 ea = ether_aton(val); 133 if (ea == NULL) { 134 errx(EXIT_FAILURE, "malformed BSSID: %s", val); 135 return; 136 } 137 memcpy(&bssid.i_bssid, ea->ether_addr_octet, 138 sizeof(bssid.i_bssid)); 139 } 140 estrlcpy(bssid.i_name, name, sizeof(bssid.i_name)); 141 if (ioctl(s, SIOCS80211BSSID, &bssid) == -1) 142 err(EXIT_FAILURE, "SIOCS80211BSSID"); 143 } 144 145 void 146 setiffrag(const char *val, int d) 147 { 148 struct ieee80211req ireq; 149 int thr; 150 151 if (d != 0) 152 thr = IEEE80211_FRAG_MAX; 153 else { 154 thr = atoi(val); 155 if (thr < IEEE80211_FRAG_MIN || thr > IEEE80211_FRAG_MAX) { 156 errx(EXIT_FAILURE, "invalid fragmentation threshold: %s", val); 157 return; 158 } 159 } 160 161 (void)strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 162 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD; 163 ireq.i_val = thr; 164 if (ioctl(s, SIOCS80211, &ireq) == -1) 165 err(EXIT_FAILURE, "IEEE80211_IOC_FRAGTHRESHOLD"); 166 } 167 168 void 169 setifchan(const char *val, int d) 170 { 171 struct ieee80211chanreq channel; 172 int chan; 173 174 if (d != 0) 175 chan = IEEE80211_CHAN_ANY; 176 else { 177 chan = atoi(val); 178 if (chan < 0 || chan > 0xffff) { 179 errx(EXIT_FAILURE, "invalid channel: %s", val); 180 } 181 } 182 183 estrlcpy(channel.i_name, name, sizeof(channel.i_name)); 184 channel.i_channel = (u_int16_t) chan; 185 if (ioctl(s, SIOCS80211CHANNEL, &channel) == -1) 186 err(EXIT_FAILURE, "SIOCS80211CHANNEL"); 187 } 188 189 void 190 setifnwkey(const char *val, int d) 191 { 192 struct ieee80211_nwkey nwkey; 193 int i; 194 u_int8_t keybuf[IEEE80211_WEP_NKID][16]; 195 196 nwkey.i_wepon = IEEE80211_NWKEY_WEP; 197 nwkey.i_defkid = 1; 198 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 199 nwkey.i_key[i].i_keylen = sizeof(keybuf[i]); 200 nwkey.i_key[i].i_keydat = keybuf[i]; 201 } 202 if (d != 0) { 203 /* disable WEP encryption */ 204 nwkey.i_wepon = 0; 205 i = 0; 206 } else if (strcasecmp("persist", val) == 0) { 207 /* use all values from persistent memory */ 208 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST; 209 nwkey.i_defkid = 0; 210 for (i = 0; i < IEEE80211_WEP_NKID; i++) 211 nwkey.i_key[i].i_keylen = -1; 212 } else if (strncasecmp("persist:", val, 8) == 0) { 213 val += 8; 214 /* program keys in persistent memory */ 215 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST; 216 goto set_nwkey; 217 } else { 218 set_nwkey: 219 if (isdigit((unsigned char)val[0]) && val[1] == ':') { 220 /* specifying a full set of four keys */ 221 nwkey.i_defkid = val[0] - '0'; 222 val += 2; 223 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 224 val = get_string(val, ",", keybuf[i], 225 &nwkey.i_key[i].i_keylen); 226 if (val == NULL) 227 return; 228 } 229 if (*val != '\0') { 230 errx(EXIT_FAILURE, "SIOCS80211NWKEY: too many keys."); 231 } 232 } else { 233 val = get_string(val, NULL, keybuf[0], 234 &nwkey.i_key[0].i_keylen); 235 if (val == NULL) 236 return; 237 i = 1; 238 } 239 } 240 for (; i < IEEE80211_WEP_NKID; i++) 241 nwkey.i_key[i].i_keylen = 0; 242 estrlcpy(nwkey.i_name, name, sizeof(nwkey.i_name)); 243 if (ioctl(s, SIOCS80211NWKEY, &nwkey) == -1) 244 err(EXIT_FAILURE, "SIOCS80211NWKEY"); 245 } 246 247 void 248 setifpowersave(const char *val, int d) 249 { 250 struct ieee80211_power power; 251 252 estrlcpy(power.i_name, name, sizeof(power.i_name)); 253 if (ioctl(s, SIOCG80211POWER, &power) == -1) { 254 err(EXIT_FAILURE, "SIOCG80211POWER"); 255 } 256 257 power.i_enabled = d; 258 if (ioctl(s, SIOCS80211POWER, &power) == -1) 259 err(EXIT_FAILURE, "SIOCS80211POWER"); 260 } 261 262 void 263 setifpowersavesleep(const char *val, int d) 264 { 265 struct ieee80211_power power; 266 267 estrlcpy(power.i_name, name, sizeof(power.i_name)); 268 if (ioctl(s, SIOCG80211POWER, &power) == -1) { 269 err(EXIT_FAILURE, "SIOCG80211POWER"); 270 } 271 272 power.i_maxsleep = atoi(val); 273 if (ioctl(s, SIOCS80211POWER, &power) == -1) 274 err(EXIT_FAILURE, "SIOCS80211POWER"); 275 } 276 277 void 278 ieee80211_statistics(void) 279 { 280 struct ieee80211_stats stats; 281 282 memset(&ifr, 0, sizeof(ifr)); 283 ifr.ifr_buflen = sizeof(stats); 284 ifr.ifr_buf = (caddr_t)&stats; 285 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 286 if (ioctl(s, (zflag) ? SIOCG80211ZSTATS : SIOCG80211STATS, 287 (caddr_t)&ifr) == -1) 288 return; 289 #define STAT_PRINT(_member, _desc) \ 290 printf("\t" _desc ": %" PRIu32 "\n", stats._member) 291 292 STAT_PRINT(is_rx_badversion, "rx frame with bad version"); 293 STAT_PRINT(is_rx_tooshort, "rx frame too short"); 294 STAT_PRINT(is_rx_wrongbss, "rx from wrong bssid"); 295 STAT_PRINT(is_rx_dup, "rx discard 'cuz dup"); 296 STAT_PRINT(is_rx_wrongdir, "rx w/ wrong direction"); 297 STAT_PRINT(is_rx_mcastecho, "rx discard 'cuz mcast echo"); 298 STAT_PRINT(is_rx_notassoc, "rx discard 'cuz sta !assoc"); 299 STAT_PRINT(is_rx_noprivacy, "rx w/ wep but privacy off"); 300 STAT_PRINT(is_rx_unencrypted, "rx w/o wep and privacy on"); 301 STAT_PRINT(is_rx_wepfail, "rx wep processing failed"); 302 STAT_PRINT(is_rx_decap, "rx decapsulation failed"); 303 STAT_PRINT(is_rx_mgtdiscard, "rx discard mgt frames"); 304 STAT_PRINT(is_rx_ctl, "rx discard ctrl frames"); 305 STAT_PRINT(is_rx_beacon, "rx beacon frames"); 306 STAT_PRINT(is_rx_rstoobig, "rx rate set truncated"); 307 STAT_PRINT(is_rx_elem_missing, "rx required element missing"); 308 STAT_PRINT(is_rx_elem_toobig, "rx element too big"); 309 STAT_PRINT(is_rx_elem_toosmall, "rx element too small"); 310 STAT_PRINT(is_rx_elem_unknown, "rx element unknown"); 311 STAT_PRINT(is_rx_badchan, "rx frame w/ invalid chan"); 312 STAT_PRINT(is_rx_chanmismatch, "rx frame chan mismatch"); 313 STAT_PRINT(is_rx_nodealloc, "rx frame dropped"); 314 STAT_PRINT(is_rx_ssidmismatch, "rx frame ssid mismatch "); 315 STAT_PRINT(is_rx_auth_unsupported, "rx w/ unsupported auth alg"); 316 STAT_PRINT(is_rx_auth_fail, "rx sta auth failure"); 317 STAT_PRINT(is_rx_auth_countermeasures, "rx auth discard 'cuz CM"); 318 STAT_PRINT(is_rx_assoc_bss, "rx assoc from wrong bssid"); 319 STAT_PRINT(is_rx_assoc_notauth, "rx assoc w/o auth"); 320 STAT_PRINT(is_rx_assoc_capmismatch, "rx assoc w/ cap mismatch"); 321 STAT_PRINT(is_rx_assoc_norate, "rx assoc w/ no rate match"); 322 STAT_PRINT(is_rx_assoc_badwpaie, "rx assoc w/ bad WPA IE"); 323 STAT_PRINT(is_rx_deauth, "rx deauthentication"); 324 STAT_PRINT(is_rx_disassoc, "rx disassociation"); 325 STAT_PRINT(is_rx_badsubtype, "rx frame w/ unknown subtyp"); 326 STAT_PRINT(is_rx_nobuf, "rx failed for lack of buf"); 327 STAT_PRINT(is_rx_decryptcrc, "rx decrypt failed on crc"); 328 STAT_PRINT(is_rx_ahdemo_mgt, "rx discard ahdemo mgt fram"); 329 STAT_PRINT(is_rx_bad_auth, "rx bad auth request"); 330 STAT_PRINT(is_rx_unauth, "rx on unauthorized port"); 331 STAT_PRINT(is_rx_badkeyid, "rx w/ incorrect keyid"); 332 STAT_PRINT(is_rx_ccmpreplay, "rx seq# violation (CCMP)"); 333 STAT_PRINT(is_rx_ccmpformat, "rx format bad (CCMP)"); 334 STAT_PRINT(is_rx_ccmpmic, "rx MIC check failed (CCMP)"); 335 STAT_PRINT(is_rx_tkipreplay, "rx seq# violation (TKIP)"); 336 STAT_PRINT(is_rx_tkipformat, "rx format bad (TKIP)"); 337 STAT_PRINT(is_rx_tkipmic, "rx MIC check failed (TKIP)"); 338 STAT_PRINT(is_rx_tkipicv, "rx ICV check failed (TKIP)"); 339 STAT_PRINT(is_rx_badcipher, "rx failed 'cuz key type"); 340 STAT_PRINT(is_rx_nocipherctx, "rx failed 'cuz key !setup"); 341 STAT_PRINT(is_rx_acl, "rx discard 'cuz acl policy"); 342 343 STAT_PRINT(is_tx_nobuf, "tx failed for lack of buf"); 344 STAT_PRINT(is_tx_nonode, "tx failed for no node"); 345 STAT_PRINT(is_tx_unknownmgt, "tx of unknown mgt frame"); 346 STAT_PRINT(is_tx_badcipher, "tx failed 'cuz key type"); 347 STAT_PRINT(is_tx_nodefkey, "tx failed 'cuz no defkey"); 348 STAT_PRINT(is_tx_noheadroom, "tx failed 'cuz no space"); 349 STAT_PRINT(is_tx_fragframes, "tx frames fragmented"); 350 STAT_PRINT(is_tx_frags, "tx fragments created"); 351 352 STAT_PRINT(is_scan_active, "active scans started"); 353 STAT_PRINT(is_scan_passive, "passive scans started"); 354 STAT_PRINT(is_node_timeout, "nodes timed out inactivity"); 355 STAT_PRINT(is_crypto_nomem, "no memory for crypto ctx"); 356 STAT_PRINT(is_crypto_tkip, "tkip crypto done in s/w"); 357 STAT_PRINT(is_crypto_tkipenmic, "tkip en-MIC done in s/w"); 358 STAT_PRINT(is_crypto_tkipdemic, "tkip de-MIC done in s/w"); 359 STAT_PRINT(is_crypto_tkipcm, "tkip counter measures"); 360 STAT_PRINT(is_crypto_ccmp, "ccmp crypto done in s/w"); 361 STAT_PRINT(is_crypto_wep, "wep crypto done in s/w"); 362 STAT_PRINT(is_crypto_setkey_cipher, "cipher rejected key"); 363 STAT_PRINT(is_crypto_setkey_nokey, "no key index for setkey"); 364 STAT_PRINT(is_crypto_delkey, "driver key delete failed"); 365 STAT_PRINT(is_crypto_badcipher, "unknown cipher"); 366 STAT_PRINT(is_crypto_nocipher, "cipher not available"); 367 STAT_PRINT(is_crypto_attachfail, "cipher attach failed"); 368 STAT_PRINT(is_crypto_swfallback, "cipher fallback to s/w"); 369 STAT_PRINT(is_crypto_keyfail, "driver key alloc failed"); 370 STAT_PRINT(is_crypto_enmicfail, "en-MIC failed"); 371 STAT_PRINT(is_ibss_capmismatch, "merge failed-cap mismatch"); 372 STAT_PRINT(is_ibss_norate, "merge failed-rate mismatch"); 373 STAT_PRINT(is_ps_unassoc, "ps-poll for unassoc. sta"); 374 STAT_PRINT(is_ps_badaid, "ps-poll w/ incorrect aid"); 375 STAT_PRINT(is_ps_qempty, "ps-poll w/ nothing to send"); 376 STAT_PRINT(is_ff_badhdr, "fast frame rx'd w/ bad hdr"); 377 STAT_PRINT(is_ff_tooshort, "fast frame rx decap error"); 378 STAT_PRINT(is_ff_split, "fast frame rx split error"); 379 STAT_PRINT(is_ff_decap, "fast frames decap'd"); 380 STAT_PRINT(is_ff_encap, "fast frames encap'd for tx"); 381 STAT_PRINT(is_rx_badbintval, "rx frame w/ bogus bintval"); 382 } 383 384 void 385 ieee80211_status(void) 386 { 387 int i, nwkey_verbose; 388 struct ieee80211_nwid nwid; 389 struct ieee80211_nwkey nwkey; 390 struct ieee80211_power power; 391 u_int8_t keybuf[IEEE80211_WEP_NKID][16]; 392 struct ieee80211_bssid bssid; 393 struct ieee80211chanreq channel; 394 struct ieee80211req ireq; 395 struct ether_addr ea; 396 static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN]; 397 enum ieee80211_opmode opmode = get80211opmode(); 398 extern int vflag; 399 400 memset(&ifr, 0, sizeof(ifr)); 401 ifr.ifr_data = (void *)&nwid; 402 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 403 if (ioctl(s, SIOCG80211NWID, &ifr) == -1) 404 return; 405 if (nwid.i_len > IEEE80211_NWID_LEN) { 406 errx(EXIT_FAILURE, "SIOCG80211NWID: wrong length of nwid (%d)", nwid.i_len); 407 } 408 printf("\tssid "); 409 print_string(nwid.i_nwid, nwid.i_len); 410 411 if (opmode == IEEE80211_M_HOSTAP) { 412 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 413 ireq.i_type = IEEE80211_IOC_HIDESSID; 414 if (ioctl(s, SIOCG80211, &ireq) != -1) { 415 if (ireq.i_val) 416 printf(" [hidden]"); 417 else if (vflag) 418 printf(" [shown]"); 419 } 420 421 ireq.i_type = IEEE80211_IOC_APBRIDGE; 422 if (ioctl(s, SIOCG80211, &ireq) != -1) { 423 if (ireq.i_val) 424 printf(" apbridge"); 425 else if (vflag) 426 printf(" -apbridge"); 427 } 428 } 429 430 estrlcpy(ireq.i_name, name, sizeof(ireq.i_name)); 431 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD; 432 if (ioctl(s, SIOCG80211, &ireq) == -1) 433 ; 434 else if (ireq.i_val < IEEE80211_FRAG_MAX) 435 printf(" frag %d", ireq.i_val); 436 else if (vflag) 437 printf(" -frag"); 438 439 memset(&nwkey, 0, sizeof(nwkey)); 440 estrlcpy(nwkey.i_name, name, sizeof(nwkey.i_name)); 441 /* show nwkey only when WEP is enabled */ 442 if (ioctl(s, SIOCG80211NWKEY, &nwkey) == -1 || 443 nwkey.i_wepon == 0) { 444 printf("\n"); 445 goto skip_wep; 446 } 447 448 printf(" nwkey "); 449 /* try to retrieve WEP keys */ 450 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 451 nwkey.i_key[i].i_keydat = keybuf[i]; 452 nwkey.i_key[i].i_keylen = sizeof(keybuf[i]); 453 } 454 if (ioctl(s, SIOCG80211NWKEY, &nwkey) == -1) { 455 printf("*****"); 456 } else { 457 nwkey_verbose = 0; 458 /* check to see non default key or multiple keys defined */ 459 if (nwkey.i_defkid != 1) { 460 nwkey_verbose = 1; 461 } else { 462 for (i = 1; i < IEEE80211_WEP_NKID; i++) { 463 if (nwkey.i_key[i].i_keylen != 0) { 464 nwkey_verbose = 1; 465 break; 466 } 467 } 468 } 469 /* check extra ambiguity with keywords */ 470 if (!nwkey_verbose) { 471 if (nwkey.i_key[0].i_keylen >= 2 && 472 isdigit(nwkey.i_key[0].i_keydat[0]) && 473 nwkey.i_key[0].i_keydat[1] == ':') 474 nwkey_verbose = 1; 475 else if (nwkey.i_key[0].i_keylen >= 7 && 476 strncasecmp("persist", 477 (const char *)nwkey.i_key[0].i_keydat, 7) == 0) 478 nwkey_verbose = 1; 479 } 480 if (nwkey_verbose) 481 printf("%d:", nwkey.i_defkid); 482 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 483 if (i > 0) 484 printf(","); 485 if (nwkey.i_key[i].i_keylen < 0) 486 printf("persist"); 487 else 488 print_string(nwkey.i_key[i].i_keydat, 489 nwkey.i_key[i].i_keylen); 490 if (!nwkey_verbose) 491 break; 492 } 493 } 494 printf("\n"); 495 496 skip_wep: 497 estrlcpy(power.i_name, name, sizeof(power.i_name)); 498 if (ioctl(s, SIOCG80211POWER, &power) == -1) 499 goto skip_power; 500 printf("\tpowersave "); 501 if (power.i_enabled) 502 printf("on (%dms sleep)", power.i_maxsleep); 503 else 504 printf("off"); 505 printf("\n"); 506 507 skip_power: 508 estrlcpy(bssid.i_name, name, sizeof(bssid.i_name)); 509 if (ioctl(s, SIOCG80211BSSID, &bssid) == -1) 510 return; 511 estrlcpy(channel.i_name, name, sizeof(channel.i_name)); 512 if (ioctl(s, SIOCG80211CHANNEL, &channel) == -1) 513 return; 514 if (memcmp(bssid.i_bssid, zero_macaddr, IEEE80211_ADDR_LEN) == 0) { 515 if (channel.i_channel != (u_int16_t)-1) 516 printf("\tchan %d\n", channel.i_channel); 517 } else { 518 memcpy(ea.ether_addr_octet, bssid.i_bssid, 519 sizeof(ea.ether_addr_octet)); 520 printf("\tbssid %s", ether_ntoa(&ea)); 521 if (channel.i_channel != IEEE80211_CHAN_ANY) 522 printf(" chan %d", channel.i_channel); 523 printf("\n"); 524 } 525 } 526