ifieee80211.c revision 151827
150476Speter/* 220031Sphk * Copyright 2001 The Aerospace Corporation. All rights reserved. 320031Sphk * 420031Sphk * Redistribution and use in source and binary forms, with or without 520031Sphk * modification, are permitted provided that the following conditions 6174990Sache * are met: 720031Sphk * 1. Redistributions of source code must retain the above copyright 8163086Sflz * notice, this list of conditions and the following disclaimer. 9163086Sflz * 2. Redistributions in binary form must reproduce the above copyright 10163086Sflz * notice, this list of conditions and the following disclaimer in the 11163086Sflz * documentation and/or other materials provided with the distribution. 12163086Sflz * 3. The name of The Aerospace Corporation may not be used to endorse or 13163086Sflz * promote products derived from this software. 14163086Sflz * 15163086Sflz * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND 16163086Sflz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17163086Sflz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18163086Sflz * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE 19163086Sflz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2020031Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21174990Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2220031Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23163086Sflz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24163086Sflz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25163086Sflz * SUCH DAMAGE. 26163086Sflz * 27163086Sflz * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 151827 2005-10-28 21:57:04Z brooks $ 28163086Sflz */ 29163086Sflz 30163086Sflz/*- 31163086Sflz * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 32163086Sflz * All rights reserved. 33163086Sflz * 34163086Sflz * This code is derived from software contributed to The NetBSD Foundation 3520031Sphk * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 36174990Sache * NASA Ames Research Center. 3774606Sache * 38163086Sflz * Redistribution and use in source and binary forms, with or without 39163086Sflz * modification, are permitted provided that the following conditions 40163086Sflz * are met: 41163086Sflz * 1. Redistributions of source code must retain the above copyright 42163086Sflz * notice, this list of conditions and the following disclaimer. 43163086Sflz * 2. Redistributions in binary form must reproduce the above copyright 44163086Sflz * notice, this list of conditions and the following disclaimer in the 4520031Sphk * documentation and/or other materials provided with the distribution. 46174990Sache * 3. All advertising materials mentioning features or use of this software 4720031Sphk * must display the following acknowledgement: 48163086Sflz * This product includes software developed by the NetBSD 49163086Sflz * Foundation, Inc. and its contributors. 50163086Sflz * 4. Neither the name of The NetBSD Foundation nor the names of its 51163086Sflz * contributors may be used to endorse or promote products derived 52163086Sflz * from this software without specific prior written permission. 53163086Sflz * 54163086Sflz * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 5520031Sphk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 5620031Sphk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 5720031Sphk * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 5820031Sphk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5920031Sphk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 6020031Sphk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 6120031Sphk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 6274570Sache * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 6320031Sphk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 6420031Sphk * POSSIBILITY OF SUCH DAMAGE. 6520031Sphk */ 6654090Sache 6720031Sphk#include <sys/param.h> 6820031Sphk#include <sys/ioctl.h> 6920031Sphk#include <sys/socket.h> 7020031Sphk#include <sys/sysctl.h> 7120031Sphk#include <sys/time.h> 7220031Sphk 7320031Sphk#include <net/ethernet.h> 7420031Sphk#include <net/if.h> 7520031Sphk#include <net/if_dl.h> 7620031Sphk#include <net/if_types.h> 7720031Sphk#include <net/if_media.h> 7854090Sache#include <net/route.h> 7953943Sache 80174990Sache#include <net80211/ieee80211.h> 8153943Sache#include <net80211/ieee80211_crypto.h> 82163086Sflz#include <net80211/ieee80211_ioctl.h> 83163086Sflz 84163086Sflz#include <ctype.h> 85163086Sflz#include <err.h> 86163086Sflz#include <errno.h> 87163086Sflz#include <fcntl.h> 88163086Sflz#include <inttypes.h> 89163086Sflz#include <stdio.h> 90163086Sflz#include <stdlib.h> 91163086Sflz#include <string.h> 92163086Sflz#include <unistd.h> 93163086Sflz 9453943Sache#include "ifconfig.h" 9574413Sache 9653943Sachestatic void set80211(int s, int type, int val, int len, u_int8_t *data); 9774413Sachestatic const char *get_string(const char *val, const char *sep, 9853961Sache u_int8_t *buf, int *lenp); 9974413Sachestatic void print_string(const u_int8_t *buf, int len); 10053961Sache 10174413Sachestatic int 10274413Sacheisanyarg(const char *arg) 103{ 104 return (strcmp(arg, "-") == 0 || 105 strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0); 106} 107 108static void 109set80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 110{ 111 int ssid; 112 int len; 113 u_int8_t data[33]; 114 115 ssid = 0; 116 len = strlen(val); 117 if (len > 2 && isdigit(val[0]) && val[1] == ':') { 118 ssid = atoi(val)-1; 119 val += 2; 120 } 121 122 bzero(data, sizeof(data)); 123 len = sizeof(data); 124 get_string(val, NULL, data, &len); 125 126 set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 127} 128 129static void 130set80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 131{ 132 int len; 133 u_int8_t data[33]; 134 135 bzero(data, sizeof(data)); 136 len = sizeof(data); 137 get_string(val, NULL, data, &len); 138 139 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 140} 141 142/* 143 * Convert IEEE channel number to MHz frequency. 144 */ 145static u_int 146ieee80211_ieee2mhz(u_int chan) 147{ 148 if (chan == 14) 149 return 2484; 150 if (chan < 14) /* 0-13 */ 151 return 2407 + chan*5; 152 if (chan < 27) /* 15-26 */ 153 return 2512 + ((chan-15)*20); 154 return 5000 + (chan*5); 155} 156 157/* 158 * Convert MHz frequency to IEEE channel number. 159 */ 160static u_int 161ieee80211_mhz2ieee(u_int freq) 162{ 163 if (freq == 2484) 164 return 14; 165 if (freq < 2484) 166 return (freq - 2407) / 5; 167 if (freq < 5000) 168 return 15 + ((freq - 2512) / 20); 169 return (freq - 5000) / 5; 170} 171 172static void 173set80211channel(const char *val, int d, int s, const struct afswtch *rafp) 174{ 175 if (!isanyarg(val)) { 176 int v = atoi(val); 177 if (v > 255) /* treat as frequency */ 178 v = ieee80211_mhz2ieee(v); 179 set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL); 180 } else 181 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); 182} 183 184static void 185set80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 186{ 187 int mode; 188 189 if (strcasecmp(val, "none") == 0) { 190 mode = IEEE80211_AUTH_NONE; 191 } else if (strcasecmp(val, "open") == 0) { 192 mode = IEEE80211_AUTH_OPEN; 193 } else if (strcasecmp(val, "shared") == 0) { 194 mode = IEEE80211_AUTH_SHARED; 195 } else if (strcasecmp(val, "8021x") == 0) { 196 mode = IEEE80211_AUTH_8021X; 197 } else if (strcasecmp(val, "wpa") == 0) { 198 mode = IEEE80211_AUTH_WPA; 199 } else { 200 errx(1, "unknown authmode"); 201 } 202 203 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 204} 205 206static void 207set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 208{ 209 int mode; 210 211 if (strcasecmp(val, "off") == 0) { 212 mode = IEEE80211_POWERSAVE_OFF; 213 } else if (strcasecmp(val, "on") == 0) { 214 mode = IEEE80211_POWERSAVE_ON; 215 } else if (strcasecmp(val, "cam") == 0) { 216 mode = IEEE80211_POWERSAVE_CAM; 217 } else if (strcasecmp(val, "psp") == 0) { 218 mode = IEEE80211_POWERSAVE_PSP; 219 } else if (strcasecmp(val, "psp-cam") == 0) { 220 mode = IEEE80211_POWERSAVE_PSP_CAM; 221 } else { 222 errx(1, "unknown powersavemode"); 223 } 224 225 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 226} 227 228static void 229set80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 230{ 231 if (d == 0) 232 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 233 0, NULL); 234 else 235 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 236 0, NULL); 237} 238 239static void 240set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 241{ 242 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 243} 244 245static void 246set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 247{ 248 int mode; 249 250 if (strcasecmp(val, "off") == 0) { 251 mode = IEEE80211_WEP_OFF; 252 } else if (strcasecmp(val, "on") == 0) { 253 mode = IEEE80211_WEP_ON; 254 } else if (strcasecmp(val, "mixed") == 0) { 255 mode = IEEE80211_WEP_MIXED; 256 } else { 257 errx(1, "unknown wep mode"); 258 } 259 260 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 261} 262 263static void 264set80211wep(const char *val, int d, int s, const struct afswtch *rafp) 265{ 266 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 267} 268 269static int 270isundefarg(const char *arg) 271{ 272 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 273} 274 275static void 276set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 277{ 278 if (isundefarg(val)) 279 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 280 else 281 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 282} 283 284static void 285set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 286{ 287 int key = 0; 288 int len; 289 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 290 291 if (isdigit(val[0]) && val[1] == ':') { 292 key = atoi(val)-1; 293 val += 2; 294 } 295 296 bzero(data, sizeof(data)); 297 len = sizeof(data); 298 get_string(val, NULL, data, &len); 299 300 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 301} 302 303/* 304 * This function is purely a NetBSD compatability interface. The NetBSD 305 * interface is too inflexible, but it's there so we'll support it since 306 * it's not all that hard. 307 */ 308static void 309set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 310{ 311 int txkey; 312 int i, len; 313 u_int8_t data[IEEE80211_KEYBUF_SIZE]; 314 315 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 316 317 if (isdigit(val[0]) && val[1] == ':') { 318 txkey = val[0]-'0'-1; 319 val += 2; 320 321 for (i = 0; i < 4; i++) { 322 bzero(data, sizeof(data)); 323 len = sizeof(data); 324 val = get_string(val, ",", data, &len); 325 if (val == NULL) 326 exit(1); 327 328 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 329 } 330 } else { 331 bzero(data, sizeof(data)); 332 len = sizeof(data); 333 get_string(val, NULL, data, &len); 334 txkey = 0; 335 336 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 337 338 bzero(data, sizeof(data)); 339 for (i = 1; i < 4; i++) 340 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 341 } 342 343 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 344} 345 346static void 347set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 348{ 349 set80211(s, IEEE80211_IOC_RTSTHRESHOLD, 350 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL); 351} 352 353static void 354set80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 355{ 356 int mode; 357 358 if (strcasecmp(val, "off") == 0) { 359 mode = IEEE80211_PROTMODE_OFF; 360 } else if (strcasecmp(val, "cts") == 0) { 361 mode = IEEE80211_PROTMODE_CTS; 362 } else if (strcasecmp(val, "rtscts") == 0) { 363 mode = IEEE80211_PROTMODE_RTSCTS; 364 } else { 365 errx(1, "unknown protection mode"); 366 } 367 368 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 369} 370 371static void 372set80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 373{ 374 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); 375} 376 377#define IEEE80211_ROAMING_DEVICE 0 378#define IEEE80211_ROAMING_AUTO 1 379#define IEEE80211_ROAMING_MANUAL 2 380 381static void 382set80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 383{ 384 int mode; 385 386 if (strcasecmp(val, "device") == 0) { 387 mode = IEEE80211_ROAMING_DEVICE; 388 } else if (strcasecmp(val, "auto") == 0) { 389 mode = IEEE80211_ROAMING_AUTO; 390 } else if (strcasecmp(val, "manual") == 0) { 391 mode = IEEE80211_ROAMING_MANUAL; 392 } else { 393 errx(1, "unknown roaming mode"); 394 } 395 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 396} 397 398static void 399set80211wme(const char *val, int d, int s, const struct afswtch *rafp) 400{ 401 set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 402} 403 404static void 405set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 406{ 407 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 408} 409 410static void 411set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 412{ 413 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 414} 415 416static void 417set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 418{ 419 struct ieee80211req_chanlist chanlist; 420#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) 421 char *temp, *cp, *tp; 422 423 temp = malloc(strlen(val) + 1); 424 if (temp == NULL) 425 errx(1, "malloc failed"); 426 strcpy(temp, val); 427 memset(&chanlist, 0, sizeof(chanlist)); 428 cp = temp; 429 for (;;) { 430 int first, last, f; 431 432 tp = strchr(cp, ','); 433 if (tp != NULL) 434 *tp++ = '\0'; 435 switch (sscanf(cp, "%u-%u", &first, &last)) { 436 case 1: 437 if (first > MAXCHAN) 438 errx(-1, "channel %u out of range, max %zu", 439 first, MAXCHAN); 440 setbit(chanlist.ic_channels, first); 441 break; 442 case 2: 443 if (first > MAXCHAN) 444 errx(-1, "channel %u out of range, max %zu", 445 first, MAXCHAN); 446 if (last > MAXCHAN) 447 errx(-1, "channel %u out of range, max %zu", 448 last, MAXCHAN); 449 if (first > last) 450 errx(-1, "void channel range, %u > %u", 451 first, last); 452 for (f = first; f <= last; f++) 453 setbit(chanlist.ic_channels, f); 454 break; 455 } 456 if (tp == NULL) 457 break; 458 while (isspace(*tp)) 459 tp++; 460 if (!isdigit(*tp)) 461 break; 462 cp = tp; 463 } 464 set80211(s, IEEE80211_IOC_CHANLIST, 0, 465 sizeof(chanlist), (uint8_t *) &chanlist); 466#undef MAXCHAN 467} 468 469static void 470set80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 471{ 472 473 if (!isanyarg(val)) { 474 char *temp; 475 struct sockaddr_dl sdl; 476 477 temp = malloc(strlen(val) + 1); 478 if (temp == NULL) 479 errx(1, "malloc failed"); 480 temp[0] = ':'; 481 strcpy(temp + 1, val); 482 sdl.sdl_len = sizeof(sdl); 483 link_addr(temp, &sdl); 484 free(temp); 485 if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 486 errx(1, "malformed link-level address"); 487 set80211(s, IEEE80211_IOC_BSSID, 0, 488 IEEE80211_ADDR_LEN, LLADDR(&sdl)); 489 } else { 490 uint8_t zerobssid[IEEE80211_ADDR_LEN]; 491 memset(zerobssid, 0, sizeof(zerobssid)); 492 set80211(s, IEEE80211_IOC_BSSID, 0, 493 IEEE80211_ADDR_LEN, zerobssid); 494 } 495} 496 497static int 498getac(const char *ac) 499{ 500 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 501 return WME_AC_BE; 502 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 503 return WME_AC_BK; 504 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 505 return WME_AC_VI; 506 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 507 return WME_AC_VO; 508 errx(1, "unknown wme access class %s", ac); 509} 510 511static 512DECL_CMD_FUNC2(set80211cwmin, ac, val) 513{ 514 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 515} 516 517static 518DECL_CMD_FUNC2(set80211cwmax, ac, val) 519{ 520 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 521} 522 523static 524DECL_CMD_FUNC2(set80211aifs, ac, val) 525{ 526 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 527} 528 529static 530DECL_CMD_FUNC2(set80211txoplimit, ac, val) 531{ 532 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 533} 534 535static 536DECL_CMD_FUNC(set80211acm, ac, d) 537{ 538 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL); 539} 540static 541DECL_CMD_FUNC(set80211noacm, ac, d) 542{ 543 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL); 544} 545 546static 547DECL_CMD_FUNC(set80211ackpolicy, ac, d) 548{ 549 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL); 550} 551static 552DECL_CMD_FUNC(set80211noackpolicy, ac, d) 553{ 554 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL); 555} 556 557static 558DECL_CMD_FUNC2(set80211bsscwmin, ac, val) 559{ 560 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 561 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 562} 563 564static 565DECL_CMD_FUNC2(set80211bsscwmax, ac, val) 566{ 567 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 568 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 569} 570 571static 572DECL_CMD_FUNC2(set80211bssaifs, ac, val) 573{ 574 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 575 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 576} 577 578static 579DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 580{ 581 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 582 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 583} 584 585static 586DECL_CMD_FUNC(set80211dtimperiod, val, d) 587{ 588 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 589} 590 591static 592DECL_CMD_FUNC(set80211bintval, val, d) 593{ 594 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 595} 596 597static void 598set80211macmac(int s, int op, const char *val) 599{ 600 char *temp; 601 struct sockaddr_dl sdl; 602 603 temp = malloc(strlen(val) + 1); 604 if (temp == NULL) 605 errx(1, "malloc failed"); 606 temp[0] = ':'; 607 strcpy(temp + 1, val); 608 sdl.sdl_len = sizeof(sdl); 609 link_addr(temp, &sdl); 610 free(temp); 611 if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 612 errx(1, "malformed link-level address"); 613 set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 614} 615 616static 617DECL_CMD_FUNC(set80211addmac, val, d) 618{ 619 set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 620} 621 622static 623DECL_CMD_FUNC(set80211delmac, val, d) 624{ 625 set80211macmac(s, IEEE80211_IOC_DELMAC, val); 626} 627 628static 629DECL_CMD_FUNC(set80211kickmac, val, d) 630{ 631 char *temp; 632 struct sockaddr_dl sdl; 633 struct ieee80211req_mlme mlme; 634 635 temp = malloc(strlen(val) + 1); 636 if (temp == NULL) 637 errx(1, "malloc failed"); 638 temp[0] = ':'; 639 strcpy(temp + 1, val); 640 sdl.sdl_len = sizeof(sdl); 641 link_addr(temp, &sdl); 642 free(temp); 643 if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 644 errx(1, "malformed link-level address"); 645 memset(&mlme, 0, sizeof(mlme)); 646 mlme.im_op = IEEE80211_MLME_DEAUTH; 647 mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; 648 memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN); 649 set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme); 650} 651 652static 653DECL_CMD_FUNC(set80211maccmd, val, d) 654{ 655 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 656} 657 658static void 659set80211pureg(const char *val, int d, int s, const struct afswtch *rafp) 660{ 661 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); 662} 663 664static 665DECL_CMD_FUNC(set80211fragthreshold, val, d) 666{ 667 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD, 668 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL); 669} 670 671static int 672getmaxrate(uint8_t rates[15], uint8_t nrates) 673{ 674 int i, maxrate = -1; 675 676 for (i = 0; i < nrates; i++) { 677 int rate = rates[i] & IEEE80211_RATE_VAL; 678 if (rate > maxrate) 679 maxrate = rate; 680 } 681 return maxrate / 2; 682} 683 684static const char * 685getcaps(int capinfo) 686{ 687 static char capstring[32]; 688 char *cp = capstring; 689 690 if (capinfo & IEEE80211_CAPINFO_ESS) 691 *cp++ = 'E'; 692 if (capinfo & IEEE80211_CAPINFO_IBSS) 693 *cp++ = 'I'; 694 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 695 *cp++ = 'c'; 696 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 697 *cp++ = 'C'; 698 if (capinfo & IEEE80211_CAPINFO_PRIVACY) 699 *cp++ = 'P'; 700 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 701 *cp++ = 'S'; 702 if (capinfo & IEEE80211_CAPINFO_PBCC) 703 *cp++ = 'B'; 704 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 705 *cp++ = 'A'; 706 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 707 *cp++ = 's'; 708 if (capinfo & IEEE80211_CAPINFO_RSN) 709 *cp++ = 'R'; 710 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 711 *cp++ = 'D'; 712 *cp = '\0'; 713 return capstring; 714} 715 716static void 717printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 718{ 719 printf("%s", tag); 720 if (verbose) { 721 maxlen -= strlen(tag)+2; 722 if (2*ielen > maxlen) 723 maxlen--; 724 printf("<"); 725 for (; ielen > 0; ie++, ielen--) { 726 if (maxlen-- <= 0) 727 break; 728 printf("%02x", *ie); 729 } 730 if (ielen != 0) 731 printf("-"); 732 printf(">"); 733 } 734} 735 736/* 737 * Copy the ssid string contents into buf, truncating to fit. If the 738 * ssid is entirely printable then just copy intact. Otherwise convert 739 * to hexadecimal. If the result is truncated then replace the last 740 * three characters with "...". 741 */ 742static int 743copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 744{ 745 const u_int8_t *p; 746 size_t maxlen; 747 int i; 748 749 if (essid_len > bufsize) 750 maxlen = bufsize; 751 else 752 maxlen = essid_len; 753 /* determine printable or not */ 754 for (i = 0, p = essid; i < maxlen; i++, p++) { 755 if (*p < ' ' || *p > 0x7e) 756 break; 757 } 758 if (i != maxlen) { /* not printable, print as hex */ 759 if (bufsize < 3) 760 return 0; 761 strlcpy(buf, "0x", bufsize); 762 bufsize -= 2; 763 p = essid; 764 for (i = 0; i < maxlen && bufsize >= 2; i++) { 765 sprintf(&buf[2+2*i], "%02x", p[i]); 766 bufsize -= 2; 767 } 768 if (i != essid_len) 769 memcpy(&buf[2+2*i-3], "...", 3); 770 } else { /* printable, truncate as needed */ 771 memcpy(buf, essid, maxlen); 772 if (maxlen != essid_len) 773 memcpy(&buf[maxlen-3], "...", 3); 774 } 775 return maxlen; 776} 777 778/* unaligned little endian access */ 779#define LE_READ_4(p) \ 780 ((u_int32_t) \ 781 ((((const u_int8_t *)(p))[0] ) | \ 782 (((const u_int8_t *)(p))[1] << 8) | \ 783 (((const u_int8_t *)(p))[2] << 16) | \ 784 (((const u_int8_t *)(p))[3] << 24))) 785 786static int __inline 787iswpaoui(const u_int8_t *frm) 788{ 789 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 790} 791 792static int __inline 793iswmeoui(const u_int8_t *frm) 794{ 795 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); 796} 797 798static int __inline 799isatherosoui(const u_int8_t *frm) 800{ 801 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 802} 803 804static void 805printies(const u_int8_t *vp, int ielen, int maxcols) 806{ 807 while (ielen > 0) { 808 switch (vp[0]) { 809 case IEEE80211_ELEMID_VENDOR: 810 if (iswpaoui(vp)) 811 printie(" WPA", vp, 2+vp[1], maxcols); 812 else if (iswmeoui(vp)) 813 printie(" WME", vp, 2+vp[1], maxcols); 814 else if (isatherosoui(vp)) 815 printie(" ATH", vp, 2+vp[1], maxcols); 816 else 817 printie(" VEN", vp, 2+vp[1], maxcols); 818 break; 819 case IEEE80211_ELEMID_RSN: 820 printie(" RSN", vp, 2+vp[1], maxcols); 821 break; 822 default: 823 printie(" ???", vp, 2+vp[1], maxcols); 824 break; 825 } 826 ielen -= 2+vp[1]; 827 vp += 2+vp[1]; 828 } 829} 830 831static void 832list_scan(int s) 833{ 834 uint8_t buf[24*1024]; 835 struct ieee80211req ireq; 836 char ssid[14]; 837 uint8_t *cp; 838 int len; 839 840 (void) memset(&ireq, 0, sizeof(ireq)); 841 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 842 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; 843 ireq.i_data = buf; 844 ireq.i_len = sizeof(buf); 845 if (ioctl(s, SIOCG80211, &ireq) < 0) 846 errx(1, "unable to get scan results"); 847 len = ireq.i_len; 848 if (len < sizeof(struct ieee80211req_scan_result)) 849 return; 850 851 printf("%-14.14s %-17.17s %4s %4s %-5s %3s %4s\n" 852 , "SSID" 853 , "BSSID" 854 , "CHAN" 855 , "RATE" 856 , "S:N" 857 , "INT" 858 , "CAPS" 859 ); 860 cp = buf; 861 do { 862 struct ieee80211req_scan_result *sr; 863 uint8_t *vp; 864 865 sr = (struct ieee80211req_scan_result *) cp; 866 vp = (u_int8_t *)(sr+1); 867 printf("%-14.*s %s %3d %3dM %2d:%-2d %3d %-4.4s" 868 , copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len) 869 , ssid 870 , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 871 , ieee80211_mhz2ieee(sr->isr_freq) 872 , getmaxrate(sr->isr_rates, sr->isr_nrates) 873 , sr->isr_rssi, sr->isr_noise 874 , sr->isr_intval 875 , getcaps(sr->isr_capinfo) 876 ); 877 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);; 878 printf("\n"); 879 cp += sr->isr_len, len -= sr->isr_len; 880 } while (len >= sizeof(struct ieee80211req_scan_result)); 881} 882 883#include <net80211/ieee80211_freebsd.h> 884 885static void 886scan_and_wait(int s) 887{ 888 struct ieee80211req ireq; 889 int sroute; 890 891 sroute = socket(PF_ROUTE, SOCK_RAW, 0); 892 if (sroute < 0) { 893 perror("socket(PF_ROUTE,SOCK_RAW)"); 894 return; 895 } 896 (void) memset(&ireq, 0, sizeof(ireq)); 897 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 898 ireq.i_type = IEEE80211_IOC_SCAN_REQ; 899 /* NB: only root can trigger a scan so ignore errors */ 900 if (ioctl(s, SIOCS80211, &ireq) >= 0) { 901 char buf[2048]; 902 struct if_announcemsghdr *ifan; 903 struct rt_msghdr *rtm; 904 905 do { 906 if (read(sroute, buf, sizeof(buf)) < 0) { 907 perror("read(PF_ROUTE)"); 908 break; 909 } 910 rtm = (struct rt_msghdr *) buf; 911 if (rtm->rtm_version != RTM_VERSION) 912 break; 913 ifan = (struct if_announcemsghdr *) rtm; 914 } while (rtm->rtm_type != RTM_IEEE80211 || 915 ifan->ifan_what != RTM_IEEE80211_SCAN); 916 } 917 close(sroute); 918} 919 920static 921DECL_CMD_FUNC(set80211scan, val, d) 922{ 923 scan_and_wait(s); 924 list_scan(s); 925} 926 927static void 928list_stations(int s) 929{ 930 uint8_t buf[24*1024]; 931 struct ieee80211req ireq; 932 uint8_t *cp; 933 int len; 934 935 (void) memset(&ireq, 0, sizeof(ireq)); 936 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 937 ireq.i_type = IEEE80211_IOC_STA_INFO; 938 ireq.i_data = buf; 939 ireq.i_len = sizeof(buf); 940 if (ioctl(s, SIOCG80211, &ireq) < 0) 941 errx(1, "unable to get station information"); 942 len = ireq.i_len; 943 if (len < sizeof(struct ieee80211req_sta_info)) 944 return; 945 946 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n" 947 , "ADDR" 948 , "AID" 949 , "CHAN" 950 , "RATE" 951 , "RSSI" 952 , "IDLE" 953 , "TXSEQ" 954 , "RXSEQ" 955 , "CAPS" 956 , "ERP" 957 ); 958 cp = buf; 959 do { 960 struct ieee80211req_sta_info *si; 961 uint8_t *vp; 962 963 si = (struct ieee80211req_sta_info *) cp; 964 vp = (u_int8_t *)(si+1); 965 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x" 966 , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 967 , IEEE80211_AID(si->isi_associd) 968 , ieee80211_mhz2ieee(si->isi_freq) 969 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2 970 , si->isi_rssi 971 , si->isi_inact 972 , si->isi_txseqs[0] 973 , si->isi_rxseqs[0] 974 , getcaps(si->isi_capinfo) 975 , si->isi_erp 976 ); 977 printies(vp, si->isi_ie_len, 24); 978 printf("\n"); 979 cp += si->isi_len, len -= si->isi_len; 980 } while (len >= sizeof(struct ieee80211req_sta_info)); 981} 982 983static void 984print_chaninfo(const struct ieee80211_channel *c) 985{ 986#define IEEE80211_IS_CHAN_PASSIVE(_c) \ 987 (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE)) 988 char buf[14]; 989 990 buf[0] = '\0'; 991 if (IEEE80211_IS_CHAN_FHSS(c)) 992 strlcat(buf, " FHSS", sizeof(buf)); 993 if (IEEE80211_IS_CHAN_A(c)) 994 strlcat(buf, " 11a", sizeof(buf)); 995 /* XXX 11g schizophrenia */ 996 if (IEEE80211_IS_CHAN_G(c) || 997 IEEE80211_IS_CHAN_PUREG(c)) 998 strlcat(buf, " 11g", sizeof(buf)); 999 else if (IEEE80211_IS_CHAN_B(c)) 1000 strlcat(buf, " 11b", sizeof(buf)); 1001 if (IEEE80211_IS_CHAN_T(c)) 1002 strlcat(buf, " Turbo", sizeof(buf)); 1003 printf("Channel %3u : %u%c Mhz%-14.14s", 1004 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq, 1005 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf); 1006#undef IEEE80211_IS_CHAN_PASSIVE 1007} 1008 1009static void 1010list_channels(int s, int allchans) 1011{ 1012 struct ieee80211req ireq; 1013 struct ieee80211req_chaninfo chans; 1014 struct ieee80211req_chaninfo achans; 1015 const struct ieee80211_channel *c; 1016 int i, half; 1017 1018 (void) memset(&ireq, 0, sizeof(ireq)); 1019 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1020 ireq.i_type = IEEE80211_IOC_CHANINFO; 1021 ireq.i_data = &chans; 1022 ireq.i_len = sizeof(chans); 1023 if (ioctl(s, SIOCG80211, &ireq) < 0) 1024 errx(1, "unable to get channel information"); 1025 if (!allchans) { 1026 struct ieee80211req_chanlist active; 1027 1028 ireq.i_type = IEEE80211_IOC_CHANLIST; 1029 ireq.i_data = &active; 1030 ireq.i_len = sizeof(active); 1031 if (ioctl(s, SIOCG80211, &ireq) < 0) 1032 errx(1, "unable to get active channel list"); 1033 memset(&achans, 0, sizeof(achans)); 1034 for (i = 0; i < chans.ic_nchans; i++) { 1035 c = &chans.ic_chans[i]; 1036 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans) 1037 achans.ic_chans[achans.ic_nchans++] = *c; 1038 } 1039 } else 1040 achans = chans; 1041 half = achans.ic_nchans / 2; 1042 if (achans.ic_nchans % 2) 1043 half++; 1044 for (i = 0; i < achans.ic_nchans / 2; i++) { 1045 print_chaninfo(&achans.ic_chans[i]); 1046 print_chaninfo(&achans.ic_chans[half+i]); 1047 printf("\n"); 1048 } 1049 if (achans.ic_nchans % 2) { 1050 print_chaninfo(&achans.ic_chans[i]); 1051 printf("\n"); 1052 } 1053} 1054 1055static void 1056list_keys(int s) 1057{ 1058} 1059 1060#define IEEE80211_C_BITS \ 1061"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \ 1062"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \ 1063"\31WPA2\32BURST\33WME" 1064 1065static void 1066list_capabilities(int s) 1067{ 1068 struct ieee80211req ireq; 1069 u_int32_t caps; 1070 1071 (void) memset(&ireq, 0, sizeof(ireq)); 1072 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1073 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS; 1074 if (ioctl(s, SIOCG80211, &ireq) < 0) 1075 errx(1, "unable to get driver capabilities"); 1076 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len); 1077 printb(name, caps, IEEE80211_C_BITS); 1078 putchar('\n'); 1079} 1080 1081static void 1082list_wme(int s) 1083{ 1084 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 1085 struct ieee80211req ireq; 1086 int ac; 1087 1088 (void) memset(&ireq, 0, sizeof(ireq)); 1089 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1090 ireq.i_len = 0; 1091 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 1092again: 1093 if (ireq.i_len & IEEE80211_WMEPARAM_BSS) 1094 printf("\t%s", " "); 1095 else 1096 printf("\t%s", acnames[ac]); 1097 1098 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac; 1099 1100 /* show WME BSS parameters */ 1101 ireq.i_type = IEEE80211_IOC_WME_CWMIN; 1102 if (ioctl(s, SIOCG80211, &ireq) != -1) 1103 printf(" cwmin %2u", ireq.i_val); 1104 ireq.i_type = IEEE80211_IOC_WME_CWMAX; 1105 if (ioctl(s, SIOCG80211, &ireq) != -1) 1106 printf(" cwmax %2u", ireq.i_val); 1107 ireq.i_type = IEEE80211_IOC_WME_AIFS; 1108 if (ioctl(s, SIOCG80211, &ireq) != -1) 1109 printf(" aifs %2u", ireq.i_val); 1110 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT; 1111 if (ioctl(s, SIOCG80211, &ireq) != -1) 1112 printf(" txopLimit %3u", ireq.i_val); 1113 ireq.i_type = IEEE80211_IOC_WME_ACM; 1114 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1115 if (ireq.i_val) 1116 printf(" acm"); 1117 else if (verbose) 1118 printf(" -acm"); 1119 } 1120 /* !BSS only */ 1121 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1122 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY; 1123 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1124 if (!ireq.i_val) 1125 printf(" -ack"); 1126 else if (verbose) 1127 printf(" ack"); 1128 } 1129 } 1130 printf("\n"); 1131 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1132 ireq.i_len |= IEEE80211_WMEPARAM_BSS; 1133 goto again; 1134 } else 1135 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS; 1136 } 1137} 1138 1139static void 1140list_mac(int s) 1141{ 1142 struct ieee80211req ireq; 1143 struct ieee80211req_maclist *acllist; 1144 int i, nacls, policy; 1145 char c; 1146 1147 (void) memset(&ireq, 0, sizeof(ireq)); 1148 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 1149 ireq.i_type = IEEE80211_IOC_MACCMD; 1150 ireq.i_val = IEEE80211_MACCMD_POLICY; 1151 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1152 if (errno == EINVAL) { 1153 printf("No acl policy loaded\n"); 1154 return; 1155 } 1156 err(1, "unable to get mac policy"); 1157 } 1158 policy = ireq.i_val; 1159 1160 ireq.i_val = IEEE80211_MACCMD_LIST; 1161 ireq.i_len = 0; 1162 if (ioctl(s, SIOCG80211, &ireq) < 0) 1163 err(1, "unable to get mac acl list size"); 1164 if (ireq.i_len == 0) /* NB: no acls */ 1165 return; 1166 1167 ireq.i_data = malloc(ireq.i_len); 1168 if (ireq.i_data == NULL) 1169 err(1, "out of memory for acl list"); 1170 1171 if (ioctl(s, SIOCG80211, &ireq) < 0) 1172 err(1, "unable to get mac acl list"); 1173 if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 1174 if (verbose) 1175 printf("policy: open\n"); 1176 c = '*'; 1177 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 1178 if (verbose) 1179 printf("policy: allow\n"); 1180 c = '+'; 1181 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 1182 if (verbose) 1183 printf("policy: deny\n"); 1184 c = '-'; 1185 } else { 1186 printf("policy: unknown (%u)\n", policy); 1187 c = '?'; 1188 } 1189 nacls = ireq.i_len / sizeof(*acllist); 1190 acllist = (struct ieee80211req_maclist *) ireq.i_data; 1191 for (i = 0; i < nacls; i++) 1192 printf("%c%s\n", c, ether_ntoa( 1193 (const struct ether_addr *) acllist[i].ml_macaddr)); 1194} 1195 1196static 1197DECL_CMD_FUNC(set80211list, arg, d) 1198{ 1199#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 1200 1201 if (iseq(arg, "sta")) 1202 list_stations(s); 1203 else if (iseq(arg, "scan") || iseq(arg, "ap")) 1204 list_scan(s); 1205 else if (iseq(arg, "chan") || iseq(arg, "freq")) 1206 list_channels(s, 1); 1207 else if (iseq(arg, "active")) 1208 list_channels(s, 0); 1209 else if (iseq(arg, "keys")) 1210 list_keys(s); 1211 else if (iseq(arg, "caps")) 1212 list_capabilities(s); 1213 else if (iseq(arg, "wme")) 1214 list_wme(s); 1215 else if (iseq(arg, "mac")) 1216 list_mac(s); 1217 else 1218 errx(1, "Don't know how to list %s for %s", arg, name); 1219#undef iseq 1220} 1221 1222static enum ieee80211_opmode 1223get80211opmode(int s) 1224{ 1225 struct ifmediareq ifmr; 1226 1227 (void) memset(&ifmr, 0, sizeof(ifmr)); 1228 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 1229 1230 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 1231 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 1232 return IEEE80211_M_IBSS; /* XXX ahdemo */ 1233 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 1234 return IEEE80211_M_HOSTAP; 1235 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 1236 return IEEE80211_M_MONITOR; 1237 } 1238 return IEEE80211_M_STA; 1239} 1240 1241static const struct ieee80211_channel * 1242getchaninfo(int s, int chan) 1243{ 1244 struct ieee80211req ireq; 1245 static struct ieee80211req_chaninfo chans; 1246 static struct ieee80211_channel undef; 1247 const struct ieee80211_channel *c; 1248 int i, freq; 1249 1250 (void) memset(&ireq, 0, sizeof(ireq)); 1251 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1252 ireq.i_type = IEEE80211_IOC_CHANINFO; 1253 ireq.i_data = &chans; 1254 ireq.i_len = sizeof(chans); 1255 if (ioctl(s, SIOCG80211, &ireq) < 0) 1256 errx(1, "unable to get channel information"); 1257 freq = ieee80211_ieee2mhz(chan); 1258 for (i = 0; i < chans.ic_nchans; i++) { 1259 c = &chans.ic_chans[i]; 1260 if (c->ic_freq == freq) 1261 return c; 1262 } 1263 return &undef; 1264} 1265 1266#if 0 1267static void 1268printcipher(int s, struct ieee80211req *ireq, int keylenop) 1269{ 1270 switch (ireq->i_val) { 1271 case IEEE80211_CIPHER_WEP: 1272 ireq->i_type = keylenop; 1273 if (ioctl(s, SIOCG80211, ireq) != -1) 1274 printf("WEP-%s", 1275 ireq->i_len <= 5 ? "40" : 1276 ireq->i_len <= 13 ? "104" : "128"); 1277 else 1278 printf("WEP"); 1279 break; 1280 case IEEE80211_CIPHER_TKIP: 1281 printf("TKIP"); 1282 break; 1283 case IEEE80211_CIPHER_AES_OCB: 1284 printf("AES-OCB"); 1285 break; 1286 case IEEE80211_CIPHER_AES_CCM: 1287 printf("AES-CCM"); 1288 break; 1289 case IEEE80211_CIPHER_CKIP: 1290 printf("CKIP"); 1291 break; 1292 case IEEE80211_CIPHER_NONE: 1293 printf("NONE"); 1294 break; 1295 default: 1296 printf("UNKNOWN (0x%x)", ireq->i_val); 1297 break; 1298 } 1299} 1300#endif 1301 1302#define MAXCOL 78 1303int col; 1304char spacer; 1305 1306#define LINE_BREAK() do { \ 1307 if (spacer != '\t') { \ 1308 printf("\n"); \ 1309 spacer = '\t'; \ 1310 } \ 1311 col = 8; /* 8-col tab */ \ 1312} while (0) 1313#define LINE_CHECK(fmt, ...) do { \ 1314 col += sizeof(fmt)-2; \ 1315 if (col > MAXCOL) { \ 1316 LINE_BREAK(); \ 1317 col += sizeof(fmt)-2; \ 1318 } \ 1319 printf(fmt, __VA_ARGS__); \ 1320 spacer = ' '; \ 1321} while (0) 1322 1323static void 1324printkey(const struct ieee80211req_key *ik) 1325{ 1326 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 1327 int keylen = ik->ik_keylen; 1328 int printcontents; 1329 1330 printcontents = printkeys && 1331 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 1332 if (printcontents) 1333 LINE_BREAK(); 1334 switch (ik->ik_type) { 1335 case IEEE80211_CIPHER_WEP: 1336 /* compatibility */ 1337 LINE_CHECK("%cwepkey %u:%s", spacer, ik->ik_keyix+1, 1338 keylen <= 5 ? "40-bit" : 1339 keylen <= 13 ? "104-bit" : "128-bit"); 1340 break; 1341 case IEEE80211_CIPHER_TKIP: 1342 if (keylen > 128/8) 1343 keylen -= 128/8; /* ignore MIC for now */ 1344 LINE_CHECK("%cTKIP %u:%u-bit", 1345 spacer, ik->ik_keyix+1, 8*keylen); 1346 break; 1347 case IEEE80211_CIPHER_AES_OCB: 1348 LINE_CHECK("%cAES-OCB %u:%u-bit", 1349 spacer, ik->ik_keyix+1, 8*keylen); 1350 break; 1351 case IEEE80211_CIPHER_AES_CCM: 1352 LINE_CHECK("%cAES-CCM %u:%u-bit", 1353 spacer, ik->ik_keyix+1, 8*keylen); 1354 break; 1355 case IEEE80211_CIPHER_CKIP: 1356 LINE_CHECK("%cCKIP %u:%u-bit", 1357 spacer, ik->ik_keyix+1, 8*keylen); 1358 break; 1359 case IEEE80211_CIPHER_NONE: 1360 LINE_CHECK("%cNULL %u:%u-bit", 1361 spacer, ik->ik_keyix+1, 8*keylen); 1362 break; 1363 default: 1364 LINE_CHECK("%cUNKNOWN (0x%x) %u:%u-bit", spacer, 1365 ik->ik_type, ik->ik_keyix+1, 8*keylen); 1366 break; 1367 } 1368 if (printcontents) { 1369 int i; 1370 1371 printf(" <"); 1372 for (i = 0; i < keylen; i++) 1373 printf("%02x", ik->ik_keydata[i]); 1374 printf(">"); 1375 if (ik->ik_type != IEEE80211_CIPHER_WEP && 1376 (ik->ik_keyrsc != 0 || verbose)) 1377 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 1378 if (ik->ik_type != IEEE80211_CIPHER_WEP && 1379 (ik->ik_keytsc != 0 || verbose)) 1380 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 1381 if (ik->ik_flags != 0 && verbose) { 1382 const char *sep = " "; 1383 1384 if (ik->ik_flags & IEEE80211_KEY_XMIT) 1385 printf("%stx", sep), sep = "+"; 1386 if (ik->ik_flags & IEEE80211_KEY_RECV) 1387 printf("%srx", sep), sep = "+"; 1388 if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 1389 printf("%sdef", sep), sep = "+"; 1390 } 1391 LINE_BREAK(); 1392 } 1393} 1394 1395static void 1396ieee80211_status(int s) 1397{ 1398 static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 1399 enum ieee80211_opmode opmode = get80211opmode(s); 1400 int i, num, wpa, wme; 1401 struct ieee80211req ireq; 1402 u_int8_t data[32]; 1403 const struct ieee80211_channel *c; 1404 1405 (void) memset(&ireq, 0, sizeof(ireq)); 1406 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1407 ireq.i_data = &data; 1408 1409 wpa = 0; /* unknown/not set */ 1410 1411 ireq.i_type = IEEE80211_IOC_SSID; 1412 ireq.i_val = -1; 1413 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1414 /* If we can't get the SSID, this isn't an 802.11 device. */ 1415 return; 1416 } 1417 num = 0; 1418 ireq.i_type = IEEE80211_IOC_NUMSSIDS; 1419 if (ioctl(s, SIOCG80211, &ireq) >= 0) 1420 num = ireq.i_val; 1421 printf("\tssid "); 1422 if (num > 1) { 1423 ireq.i_type = IEEE80211_IOC_SSID; 1424 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 1425 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 1426 printf(" %d:", ireq.i_val + 1); 1427 print_string(data, ireq.i_len); 1428 } 1429 } 1430 } else 1431 print_string(data, ireq.i_len); 1432 1433 ireq.i_type = IEEE80211_IOC_CHANNEL; 1434 if (ioctl(s, SIOCG80211, &ireq) < 0) 1435 goto end; 1436 c = getchaninfo(s, ireq.i_val); 1437 if (ireq.i_val != -1) { 1438 printf(" channel %d", ireq.i_val); 1439 if (verbose) 1440 printf(" (%u)", c->ic_freq); 1441 } else if (verbose) 1442 printf(" channel UNDEF"); 1443 1444 ireq.i_type = IEEE80211_IOC_BSSID; 1445 ireq.i_len = IEEE80211_ADDR_LEN; 1446 if (ioctl(s, SIOCG80211, &ireq) >= 0 && 1447 memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0) 1448 printf(" bssid %s", ether_ntoa(ireq.i_data)); 1449 1450 ireq.i_type = IEEE80211_IOC_STATIONNAME; 1451 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1452 printf("\n\tstationname "); 1453 print_string(data, ireq.i_len); 1454 } 1455 1456 spacer = ' '; /* force first break */ 1457 LINE_BREAK(); 1458 1459 ireq.i_type = IEEE80211_IOC_AUTHMODE; 1460 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1461 switch (ireq.i_val) { 1462 case IEEE80211_AUTH_NONE: 1463 LINE_CHECK("%cauthmode NONE", spacer); 1464 break; 1465 case IEEE80211_AUTH_OPEN: 1466 LINE_CHECK("%cauthmode OPEN", spacer); 1467 break; 1468 case IEEE80211_AUTH_SHARED: 1469 LINE_CHECK("%cauthmode SHARED", spacer); 1470 break; 1471 case IEEE80211_AUTH_8021X: 1472 LINE_CHECK("%cauthmode 802.1x", spacer); 1473 break; 1474 case IEEE80211_AUTH_WPA: 1475 ireq.i_type = IEEE80211_IOC_WPA; 1476 if (ioctl(s, SIOCG80211, &ireq) != -1) 1477 wpa = ireq.i_val; 1478 if (!wpa) 1479 wpa = 1; /* default to WPA1 */ 1480 switch (wpa) { 1481 case 2: 1482 LINE_CHECK("%cauthmode WPA2/802.11i", 1483 spacer); 1484 break; 1485 case 3: 1486 LINE_CHECK("%cauthmode WPA1+WPA2/802.11i", 1487 spacer); 1488 break; 1489 default: 1490 LINE_CHECK("%cauthmode WPA", spacer); 1491 break; 1492 } 1493 break; 1494 case IEEE80211_AUTH_AUTO: 1495 LINE_CHECK("%cauthmode AUTO", spacer); 1496 break; 1497 default: 1498 LINE_CHECK("%cauthmode UNKNOWN (0x%x)", 1499 spacer, ireq.i_val); 1500 break; 1501 } 1502 } 1503 1504 ireq.i_type = IEEE80211_IOC_WEP; 1505 if (ioctl(s, SIOCG80211, &ireq) != -1 && 1506 ireq.i_val != IEEE80211_WEP_NOSUP) { 1507 int firstkey, wepmode; 1508 1509 wepmode = ireq.i_val; 1510 switch (wepmode) { 1511 case IEEE80211_WEP_OFF: 1512 LINE_CHECK("%cprivacy OFF", spacer); 1513 break; 1514 case IEEE80211_WEP_ON: 1515 LINE_CHECK("%cprivacy ON", spacer); 1516 break; 1517 case IEEE80211_WEP_MIXED: 1518 LINE_CHECK("%cprivacy MIXED", spacer); 1519 break; 1520 default: 1521 LINE_CHECK("%cprivacy UNKNOWN (0x%x)", 1522 spacer, wepmode); 1523 break; 1524 } 1525 1526 /* 1527 * If we get here then we've got WEP support so we need 1528 * to print WEP status. 1529 */ 1530 1531 ireq.i_type = IEEE80211_IOC_WEPTXKEY; 1532 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1533 warn("WEP support, but no tx key!"); 1534 goto end; 1535 } 1536 if (ireq.i_val != -1) 1537 LINE_CHECK("%cdeftxkey %d", spacer, ireq.i_val+1); 1538 else if (wepmode != IEEE80211_WEP_OFF || verbose) 1539 LINE_CHECK("%cdeftxkey UNDEF", spacer); 1540 1541 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 1542 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1543 warn("WEP support, but no NUMWEPKEYS support!"); 1544 goto end; 1545 } 1546 num = ireq.i_val; 1547 1548 firstkey = 1; 1549 for (i = 0; i < num; i++) { 1550 struct ieee80211req_key ik; 1551 1552 memset(&ik, 0, sizeof(ik)); 1553 ik.ik_keyix = i; 1554 ireq.i_type = IEEE80211_IOC_WPAKEY; 1555 ireq.i_data = &ik; 1556 ireq.i_len = sizeof(ik); 1557 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1558 warn("WEP support, but can get keys!"); 1559 goto end; 1560 } 1561 if (ik.ik_keylen != 0) { 1562 if (verbose) 1563 LINE_BREAK(); 1564 printkey(&ik); 1565 firstkey = 0; 1566 } 1567 } 1568 } 1569 1570 ireq.i_type = IEEE80211_IOC_POWERSAVE; 1571 if (ioctl(s, SIOCG80211, &ireq) != -1 && 1572 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 1573 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) { 1574 switch (ireq.i_val) { 1575 case IEEE80211_POWERSAVE_OFF: 1576 LINE_CHECK("%cpowersavemode OFF", 1577 spacer); 1578 break; 1579 case IEEE80211_POWERSAVE_CAM: 1580 LINE_CHECK("%cpowersavemode CAM", 1581 spacer); 1582 break; 1583 case IEEE80211_POWERSAVE_PSP: 1584 LINE_CHECK("%cpowersavemode PSP", 1585 spacer); 1586 break; 1587 case IEEE80211_POWERSAVE_PSP_CAM: 1588 LINE_CHECK("%cpowersavemode PSP-CAM", 1589 spacer); 1590 break; 1591 } 1592 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 1593 if (ioctl(s, SIOCG80211, &ireq) != -1) 1594 LINE_CHECK("%cpowersavesleep %d", 1595 spacer, ireq.i_val); 1596 } 1597 } 1598 1599 ireq.i_type = IEEE80211_IOC_TXPOWMAX; 1600 if (ioctl(s, SIOCG80211, &ireq) != -1) 1601 LINE_CHECK("%ctxpowmax %d", spacer, ireq.i_val); 1602 1603 if (verbose) { 1604 ireq.i_type = IEEE80211_IOC_TXPOWER; 1605 if (ioctl(s, SIOCG80211, &ireq) != -1) 1606 LINE_CHECK("%ctxpower %d", spacer, ireq.i_val); 1607 } 1608 1609 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; 1610 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1611 if (ireq.i_val != IEEE80211_RTS_MAX || verbose) 1612 LINE_CHECK("%crtsthreshold %d", spacer, ireq.i_val); 1613 } 1614 1615 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD; 1616 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1617 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose) 1618 LINE_CHECK("%cfragthreshold %d", spacer, ireq.i_val); 1619 } 1620 1621 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) { 1622 ireq.i_type = IEEE80211_IOC_PUREG; 1623 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1624 if (ireq.i_val) 1625 LINE_CHECK("%cpureg", spacer); 1626 else if (verbose) 1627 LINE_CHECK("%c-pureg", spacer); 1628 } 1629 ireq.i_type = IEEE80211_IOC_PROTMODE; 1630 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1631 switch (ireq.i_val) { 1632 case IEEE80211_PROTMODE_OFF: 1633 LINE_CHECK("%cprotmode OFF", spacer); 1634 break; 1635 case IEEE80211_PROTMODE_CTS: 1636 LINE_CHECK("%cprotmode CTS", spacer); 1637 break; 1638 case IEEE80211_PROTMODE_RTSCTS: 1639 LINE_CHECK("%cprotmode RTSCTS", spacer); 1640 break; 1641 default: 1642 LINE_CHECK("%cprotmode UNKNOWN (0x%x)", 1643 spacer, ireq.i_val); 1644 break; 1645 } 1646 } 1647 } 1648 1649 ireq.i_type = IEEE80211_IOC_WME; 1650 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1651 wme = ireq.i_val; 1652 if (wme) 1653 LINE_CHECK("%cwme", spacer); 1654 else if (verbose) 1655 LINE_CHECK("%c-wme", spacer); 1656 } else 1657 wme = 0; 1658 1659 if (opmode == IEEE80211_M_HOSTAP) { 1660 ireq.i_type = IEEE80211_IOC_HIDESSID; 1661 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1662 if (ireq.i_val) 1663 LINE_CHECK("%cssid HIDE", spacer); 1664 else if (verbose) 1665 LINE_CHECK("%cssid SHOW", spacer); 1666 } 1667 1668 ireq.i_type = IEEE80211_IOC_APBRIDGE; 1669 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1670 if (!ireq.i_val) 1671 LINE_CHECK("%c-apbridge", spacer); 1672 else if (verbose) 1673 LINE_CHECK("%capbridge", spacer); 1674 } 1675 1676 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD; 1677 if (ioctl(s, SIOCG80211, &ireq) != -1) 1678 LINE_CHECK("%cdtimperiod %u", spacer, ireq.i_val); 1679 } else { 1680 ireq.i_type = IEEE80211_IOC_ROAMING; 1681 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1682 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) { 1683 switch (ireq.i_val) { 1684 case IEEE80211_ROAMING_DEVICE: 1685 LINE_CHECK("%croaming DEVICE", spacer); 1686 break; 1687 case IEEE80211_ROAMING_AUTO: 1688 LINE_CHECK("%croaming AUTO", spacer); 1689 break; 1690 case IEEE80211_ROAMING_MANUAL: 1691 LINE_CHECK("%croaming MANUAL", spacer); 1692 break; 1693 default: 1694 LINE_CHECK("%croaming UNKNOWN (0x%x)", 1695 spacer, ireq.i_val); 1696 break; 1697 } 1698 } 1699 } 1700 } 1701 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL; 1702 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1703 if (ireq.i_val) 1704 LINE_CHECK("%cbintval %u", spacer, ireq.i_val); 1705 else if (verbose) 1706 LINE_CHECK("%cbintval %u", spacer, ireq.i_val); 1707 } 1708 1709 if (wme && verbose) { 1710 LINE_BREAK(); 1711 list_wme(s); 1712 } 1713 1714 if (wpa) { 1715 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES; 1716 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1717 if (ireq.i_val) 1718 LINE_CHECK("%ccountermeasures", spacer); 1719 else if (verbose) 1720 LINE_CHECK("%c-countermeasures", spacer); 1721 } 1722#if 0 1723 /* XXX not interesting with WPA done in user space */ 1724 ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 1725 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1726 } 1727 1728 ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 1729 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1730 printf("%cmcastcipher ", spacer); 1731 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 1732 spacer = ' '; 1733 } 1734 1735 ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 1736 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1737 printf("%cucastcipher ", spacer); 1738 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 1739 } 1740 1741 if (wpa & 2) { 1742 ireq.i_type = IEEE80211_IOC_RSNCAPS; 1743 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1744 printf("%cRSN caps 0x%x", spacer, ireq.i_val); 1745 spacer = ' '; 1746 } 1747 } 1748 1749 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 1750 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1751 } 1752#endif 1753 LINE_BREAK(); 1754 } 1755 LINE_BREAK(); 1756 1757end: 1758 return; 1759} 1760 1761static void 1762set80211(int s, int type, int val, int len, u_int8_t *data) 1763{ 1764 struct ieee80211req ireq; 1765 1766 (void) memset(&ireq, 0, sizeof(ireq)); 1767 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1768 ireq.i_type = type; 1769 ireq.i_val = val; 1770 ireq.i_len = len; 1771 ireq.i_data = data; 1772 if (ioctl(s, SIOCS80211, &ireq) < 0) 1773 err(1, "SIOCS80211"); 1774} 1775 1776static const char * 1777get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 1778{ 1779 int len; 1780 int hexstr; 1781 u_int8_t *p; 1782 1783 len = *lenp; 1784 p = buf; 1785 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 1786 if (hexstr) 1787 val += 2; 1788 for (;;) { 1789 if (*val == '\0') 1790 break; 1791 if (sep != NULL && strchr(sep, *val) != NULL) { 1792 val++; 1793 break; 1794 } 1795 if (hexstr) { 1796 if (!isxdigit((u_char)val[0])) { 1797 warnx("bad hexadecimal digits"); 1798 return NULL; 1799 } 1800 if (!isxdigit((u_char)val[1])) { 1801 warnx("odd count hexadecimal digits"); 1802 return NULL; 1803 } 1804 } 1805 if (p >= buf + len) { 1806 if (hexstr) 1807 warnx("hexadecimal digits too long"); 1808 else 1809 warnx("string too long"); 1810 return NULL; 1811 } 1812 if (hexstr) { 1813#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 1814 *p++ = (tohex((u_char)val[0]) << 4) | 1815 tohex((u_char)val[1]); 1816#undef tohex 1817 val += 2; 1818 } else 1819 *p++ = *val++; 1820 } 1821 len = p - buf; 1822 /* The string "-" is treated as the empty string. */ 1823 if (!hexstr && len == 1 && buf[0] == '-') 1824 len = 0; 1825 if (len < *lenp) 1826 memset(p, 0, *lenp - len); 1827 *lenp = len; 1828 return val; 1829} 1830 1831static void 1832print_string(const u_int8_t *buf, int len) 1833{ 1834 int i; 1835 int hasspc; 1836 1837 i = 0; 1838 hasspc = 0; 1839 for (; i < len; i++) { 1840 if (!isprint(buf[i]) && buf[i] != '\0') 1841 break; 1842 if (isspace(buf[i])) 1843 hasspc++; 1844 } 1845 if (i == len) { 1846 if (hasspc || len == 0 || buf[0] == '\0') 1847 printf("\"%.*s\"", len, buf); 1848 else 1849 printf("%.*s", len, buf); 1850 } else { 1851 printf("0x"); 1852 for (i = 0; i < len; i++) 1853 printf("%02x", buf[i]); 1854 } 1855} 1856 1857static struct cmd ieee80211_cmds[] = { 1858 DEF_CMD_ARG("ssid", set80211ssid), 1859 DEF_CMD_ARG("nwid", set80211ssid), 1860 DEF_CMD_ARG("stationname", set80211stationname), 1861 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 1862 DEF_CMD_ARG("channel", set80211channel), 1863 DEF_CMD_ARG("authmode", set80211authmode), 1864 DEF_CMD_ARG("powersavemode", set80211powersavemode), 1865 DEF_CMD("powersave", 1, set80211powersave), 1866 DEF_CMD("-powersave", 0, set80211powersave), 1867 DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 1868 DEF_CMD_ARG("wepmode", set80211wepmode), 1869 DEF_CMD("wep", 1, set80211wep), 1870 DEF_CMD("-wep", 0, set80211wep), 1871 DEF_CMD_ARG("deftxkey", set80211weptxkey), 1872 DEF_CMD_ARG("weptxkey", set80211weptxkey), 1873 DEF_CMD_ARG("wepkey", set80211wepkey), 1874 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 1875 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 1876 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 1877 DEF_CMD_ARG("protmode", set80211protmode), 1878 DEF_CMD_ARG("txpower", set80211txpower), 1879 DEF_CMD_ARG("roaming", set80211roaming), 1880 DEF_CMD("wme", 1, set80211wme), 1881 DEF_CMD("-wme", 0, set80211wme), 1882 DEF_CMD("hidessid", 1, set80211hidessid), 1883 DEF_CMD("-hidessid", 0, set80211hidessid), 1884 DEF_CMD("apbridge", 1, set80211apbridge), 1885 DEF_CMD("-apbridge", 0, set80211apbridge), 1886 DEF_CMD_ARG("chanlist", set80211chanlist), 1887 DEF_CMD_ARG("bssid", set80211bssid), 1888 DEF_CMD_ARG("ap", set80211bssid), 1889 DEF_CMD("scan", 0, set80211scan), 1890 DEF_CMD_ARG("list", set80211list), 1891 DEF_CMD_ARG2("cwmin", set80211cwmin), 1892 DEF_CMD_ARG2("cwmax", set80211cwmax), 1893 DEF_CMD_ARG2("aifs", set80211aifs), 1894 DEF_CMD_ARG2("txoplimit", set80211txoplimit), 1895 DEF_CMD_ARG("acm", set80211acm), 1896 DEF_CMD_ARG("-acm", set80211noacm), 1897 DEF_CMD_ARG("ack", set80211ackpolicy), 1898 DEF_CMD_ARG("-ack", set80211noackpolicy), 1899 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 1900 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 1901 DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 1902 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 1903 DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 1904 DEF_CMD_ARG("bintval", set80211bintval), 1905 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 1906 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 1907 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 1908 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 1909 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 1910 DEF_CMD_ARG("mac:add", set80211addmac), 1911 DEF_CMD_ARG("mac:del", set80211delmac), 1912 DEF_CMD_ARG("mac:kick", set80211kickmac), 1913 DEF_CMD("pureg", 1, set80211pureg), 1914 DEF_CMD("-pureg", 0, set80211pureg), 1915 DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 1916}; 1917static struct afswtch af_ieee80211 = { 1918 .af_name = "af_ieee80211", 1919 .af_af = AF_UNSPEC, 1920 .af_other_status = ieee80211_status, 1921}; 1922 1923static __constructor void 1924ieee80211_ctor(void) 1925{ 1926#define N(a) (sizeof(a) / sizeof(a[0])) 1927 int i; 1928 1929 for (i = 0; i < N(ieee80211_cmds); i++) 1930 cmd_register(&ieee80211_cmds[i]); 1931 af_register(&af_ieee80211); 1932#undef N 1933} 1934