ifieee80211.c revision 147795
1171168Smlaier/* 2130610Smlaier * Copyright 2001 The Aerospace Corporation. All rights reserved. 3130610Smlaier * 4171168Smlaier * Redistribution and use in source and binary forms, with or without 5171168Smlaier * modification, are permitted provided that the following conditions 6130610Smlaier * are met: 7130610Smlaier * 1. Redistributions of source code must retain the above copyright 8130610Smlaier * notice, this list of conditions and the following disclaimer. 9130610Smlaier * 2. Redistributions in binary form must reproduce the above copyright 10130610Smlaier * notice, this list of conditions and the following disclaimer in the 11130610Smlaier * documentation and/or other materials provided with the distribution. 12130610Smlaier * 3. The name of The Aerospace Corporation may not be used to endorse or 13130610Smlaier * promote products derived from this software. 14130610Smlaier * 15130610Smlaier * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND 16130610Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17130610Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18130610Smlaier * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE 19130610Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20130610Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21130610Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22130610Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23130610Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24130610Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25130610Smlaier * SUCH DAMAGE. 26130610Smlaier * 27130610Smlaier * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 147795 2005-07-06 15:39:11Z sam $ 28130610Smlaier */ 29130610Smlaier 30130610Smlaier/*- 31130610Smlaier * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 32130610Smlaier * All rights reserved. 33130610Smlaier * 34130610Smlaier * This code is derived from software contributed to The NetBSD Foundation 35130613Smlaier * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 36130613Smlaier * NASA Ames Research Center. 37130613Smlaier * 38171168Smlaier * Redistribution and use in source and binary forms, with or without 39171168Smlaier * modification, are permitted provided that the following conditions 40171168Smlaier * are met: 41130613Smlaier * 1. Redistributions of source code must retain the above copyright 42130613Smlaier * notice, this list of conditions and the following disclaimer. 43130610Smlaier * 2. Redistributions in binary form must reproduce the above copyright 44130610Smlaier * notice, this list of conditions and the following disclaimer in the 45130613Smlaier * documentation and/or other materials provided with the distribution. 46130613Smlaier * 3. All advertising materials mentioning features or use of this software 47130613Smlaier * must display the following acknowledgement: 48130610Smlaier * This product includes software developed by the NetBSD 49130610Smlaier * Foundation, Inc. and its contributors. 50130610Smlaier * 4. Neither the name of The NetBSD Foundation nor the names of its 51130610Smlaier * contributors may be used to endorse or promote products derived 52130610Smlaier * from this software without specific prior written permission. 53130613Smlaier * 54130610Smlaier * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 55130613Smlaier * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 56130610Smlaier * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 57181803Sbz * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 58130610Smlaier * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 59130610Smlaier * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 60130610Smlaier * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 61130610Smlaier * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 62130610Smlaier * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 63130610Smlaier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64130610Smlaier * POSSIBILITY OF SUCH DAMAGE. 65130610Smlaier */ 66130610Smlaier 67130610Smlaier#include <sys/param.h> 68130610Smlaier#include <sys/ioctl.h> 69130610Smlaier#include <sys/socket.h> 70130610Smlaier#include <sys/sysctl.h> 71130610Smlaier#include <sys/time.h> 72130610Smlaier 73130610Smlaier#include <net/ethernet.h> 74171168Smlaier#include <net/if.h> 75130610Smlaier#include <net/if_dl.h> 76130613Smlaier#include <net/if_types.h> 77130613Smlaier#include <net/if_media.h> 78130613Smlaier#include <net/route.h> 79130610Smlaier 80130613Smlaier#include <net80211/ieee80211.h> 81171168Smlaier#include <net80211/ieee80211_crypto.h> 82130610Smlaier#include <net80211/ieee80211_ioctl.h> 83130610Smlaier 84130610Smlaier#include <ctype.h> 85130610Smlaier#include <err.h> 86130613Smlaier#include <errno.h> 87171168Smlaier#include <fcntl.h> 88171168Smlaier#include <inttypes.h> 89171168Smlaier#include <stdio.h> 90171168Smlaier#include <stdlib.h> 91171168Smlaier#include <string.h> 92171168Smlaier#include <unistd.h> 93130613Smlaier 94130610Smlaier#include "ifconfig.h" 95171168Smlaier 96171168Smlaierstatic void set80211(int s, int type, int val, int len, u_int8_t *data); 97130610Smlaierstatic const char *get_string(const char *val, const char *sep, 98130610Smlaier u_int8_t *buf, int *lenp); 99171168Smlaierstatic void print_string(const u_int8_t *buf, int len); 100130610Smlaier 101130610Smlaierstatic int 102130610Smlaierisanyarg(const char *arg) 103171168Smlaier{ 104130610Smlaier return (strcmp(arg, "-") == 0 || 105130613Smlaier strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0); 106130613Smlaier} 107130613Smlaier 108171168Smlaierstatic void 109171168Smlaierset80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 110171168Smlaier{ 111171168Smlaier int ssid; 112171168Smlaier int len; 113171168Smlaier u_int8_t data[33]; 114130613Smlaier 115130610Smlaier ssid = 0; 116130610Smlaier len = strlen(val); 117130610Smlaier if (len > 2 && isdigit(val[0]) && val[1] == ':') { 118130610Smlaier ssid = atoi(val)-1; 119130610Smlaier val += 2; 120130610Smlaier } 121130610Smlaier 122130610Smlaier bzero(data, sizeof(data)); 123130610Smlaier len = sizeof(data); 124130610Smlaier get_string(val, NULL, data, &len); 125171168Smlaier 126130610Smlaier set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 127130610Smlaier} 128130610Smlaier 129130613Smlaierstatic void 130130610Smlaierset80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 131130610Smlaier{ 132130613Smlaier int len; 133130610Smlaier u_int8_t data[33]; 134130610Smlaier 135130610Smlaier bzero(data, sizeof(data)); 136171168Smlaier len = sizeof(data); 137171168Smlaier get_string(val, NULL, data, &len); 138171168Smlaier 139171168Smlaier set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 140130613Smlaier} 141171168Smlaier 142171168Smlaier/* 143171168Smlaier * Convert IEEE channel number to MHz frequency. 144130613Smlaier */ 145181803Sbzstatic u_int 146171168Smlaierieee80211_ieee2mhz(u_int chan) 147181803Sbz{ 148137159Smlaier if (chan == 14) 149130613Smlaier return 2484; 150171168Smlaier if (chan < 14) /* 0-13 */ 151130613Smlaier return 2407 + chan*5; 152130613Smlaier if (chan < 27) /* 15-26 */ 153130613Smlaier return 2512 + ((chan-15)*20); 154130613Smlaier return 5000 + (chan*5); 155171168Smlaier} 156171168Smlaier 157171168Smlaier/* 158171168Smlaier * Convert MHz frequency to IEEE channel number. 159171168Smlaier */ 160171168Smlaierstatic u_int 161171168Smlaierieee80211_mhz2ieee(u_int freq) 162171168Smlaier{ 163130613Smlaier if (freq == 2484) 164130610Smlaier return 14; 165130610Smlaier if (freq < 2484) 166173822Smlaier return (freq - 2407) / 5; 167173822Smlaier if (freq < 5000) 168173822Smlaier return 15 + ((freq - 2512) / 20); 169173822Smlaier return (freq - 5000) / 5; 170173822Smlaier} 171173822Smlaier 172173822Smlaierstatic void 173173822Smlaierset80211channel(const char *val, int d, int s, const struct afswtch *rafp) 174173822Smlaier{ 175173822Smlaier if (!isanyarg(val)) { 176173822Smlaier int v = atoi(val); 177173822Smlaier if (v > 255) /* treat as frequency */ 178173822Smlaier v = ieee80211_mhz2ieee(v); 179173822Smlaier set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL); 180173822Smlaier } else 181173822Smlaier set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); 182173822Smlaier} 183173822Smlaier 184173822Smlaierstatic void 185173822Smlaierset80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 186173822Smlaier{ 187173822Smlaier int mode; 188173822Smlaier 189173822Smlaier if (strcasecmp(val, "none") == 0) { 190173822Smlaier mode = IEEE80211_AUTH_NONE; 191173822Smlaier } else if (strcasecmp(val, "open") == 0) { 192173822Smlaier mode = IEEE80211_AUTH_OPEN; 193173822Smlaier } else if (strcasecmp(val, "shared") == 0) { 194173822Smlaier mode = IEEE80211_AUTH_SHARED; 195173822Smlaier } else if (strcasecmp(val, "8021x") == 0) { 196171168Smlaier mode = IEEE80211_AUTH_8021X; 197171168Smlaier } else if (strcasecmp(val, "wpa") == 0) { 198130613Smlaier mode = IEEE80211_AUTH_WPA; 199171168Smlaier } else { 200171168Smlaier err(1, "unknown authmode"); 201130613Smlaier } 202171168Smlaier 203171168Smlaier set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 204171168Smlaier} 205171168Smlaier 206132567Smlaierstatic void 207171168Smlaierset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 208171168Smlaier{ 209171168Smlaier int mode; 210171168Smlaier 211171168Smlaier if (strcasecmp(val, "off") == 0) { 212171168Smlaier mode = IEEE80211_POWERSAVE_OFF; 213171168Smlaier } else if (strcasecmp(val, "on") == 0) { 214130613Smlaier mode = IEEE80211_POWERSAVE_ON; 215171168Smlaier } else if (strcasecmp(val, "cam") == 0) { 216171168Smlaier mode = IEEE80211_POWERSAVE_CAM; 217173825Smlaier } else if (strcasecmp(val, "psp") == 0) { 218173825Smlaier mode = IEEE80211_POWERSAVE_PSP; 219173825Smlaier } else if (strcasecmp(val, "psp-cam") == 0) { 220173825Smlaier mode = IEEE80211_POWERSAVE_PSP_CAM; 221173825Smlaier } else { 222173825Smlaier err(1, "unknown powersavemode"); 223173825Smlaier } 224173825Smlaier 225173825Smlaier set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 226173825Smlaier} 227171168Smlaier 228173825Smlaierstatic void 229171168Smlaierset80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 230130613Smlaier{ 231171168Smlaier if (d == 0) 232171168Smlaier set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 233130613Smlaier 0, NULL); 234130613Smlaier else 235130613Smlaier set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 236171168Smlaier 0, NULL); 237130613Smlaier} 238171168Smlaier 239171168Smlaierstatic void 240171168Smlaierset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 241171168Smlaier{ 242171168Smlaier set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 243171168Smlaier} 244171168Smlaier 245171168Smlaierstatic void 246171168Smlaierset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 247171168Smlaier{ 248171168Smlaier int mode; 249130613Smlaier 250130613Smlaier if (strcasecmp(val, "off") == 0) { 251130613Smlaier mode = IEEE80211_WEP_OFF; 252171168Smlaier } else if (strcasecmp(val, "on") == 0) { 253130613Smlaier mode = IEEE80211_WEP_ON; 254171168Smlaier } else if (strcasecmp(val, "mixed") == 0) { 255171168Smlaier mode = IEEE80211_WEP_MIXED; 256130613Smlaier } else { 257171168Smlaier err(1, "unknown wep mode"); 258171168Smlaier } 259171168Smlaier 260171168Smlaier set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 261171168Smlaier} 262171168Smlaier 263171168Smlaierstatic void 264171168Smlaierset80211wep(const char *val, int d, int s, const struct afswtch *rafp) 265171168Smlaier{ 266171168Smlaier set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 267171168Smlaier} 268171168Smlaier 269171168Smlaierstatic int 270171168Smlaierisundefarg(const char *arg) 271171168Smlaier{ 272171168Smlaier return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 273171168Smlaier} 274171168Smlaier 275171168Smlaierstatic void 276171168Smlaierset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 277171168Smlaier{ 278171168Smlaier if (isundefarg(val)) 279171168Smlaier set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 280171168Smlaier else 281171168Smlaier set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 282171168Smlaier} 283171168Smlaier 284171168Smlaierstatic void 285171168Smlaierset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 286171168Smlaier{ 287130613Smlaier int key = 0; 288130613Smlaier int len; 289171168Smlaier u_int8_t data[IEEE80211_KEYBUF_SIZE]; 290171168Smlaier 291130613Smlaier if (isdigit(val[0]) && val[1] == ':') { 292171168Smlaier key = atoi(val)-1; 293130613Smlaier val += 2; 294171168Smlaier } 295171168Smlaier 296171168Smlaier bzero(data, sizeof(data)); 297171168Smlaier len = sizeof(data); 298171168Smlaier get_string(val, NULL, data, &len); 299171168Smlaier 300171168Smlaier set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 301171168Smlaier} 302171168Smlaier 303130610Smlaier/* 304130610Smlaier * This function is purly a NetBSD compatability interface. The NetBSD 305130610Smlaier * iterface is too inflexable, but it's there so we'll support it since 306130610Smlaier * it's not all that hard. 307130610Smlaier */ 308171168Smlaierstatic void 309171168Smlaierset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 310130610Smlaier{ 311130610Smlaier int txkey; 312130610Smlaier int i, len; 313130610Smlaier u_int8_t data[IEEE80211_KEYBUF_SIZE]; 314171168Smlaier 315171168Smlaier set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 316130610Smlaier 317171168Smlaier if (isdigit(val[0]) && val[1] == ':') { 318171168Smlaier txkey = val[0]-'0'-1; 319130610Smlaier val += 2; 320171168Smlaier 321171168Smlaier for (i = 0; i < 4; i++) { 322171168Smlaier bzero(data, sizeof(data)); 323171168Smlaier len = sizeof(data); 324171168Smlaier val = get_string(val, ",", data, &len); 325130613Smlaier 326130610Smlaier set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 327171168Smlaier } 328130613Smlaier } else { 329130610Smlaier bzero(data, sizeof(data)); 330130610Smlaier len = sizeof(data); 331130610Smlaier get_string(val, NULL, data, &len); 332130610Smlaier txkey = 0; 333130610Smlaier 334130610Smlaier set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 335171168Smlaier 336171168Smlaier bzero(data, sizeof(data)); 337130610Smlaier for (i = 1; i < 4; i++) 338171168Smlaier set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 339171168Smlaier } 340130610Smlaier 341130610Smlaier set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 342130610Smlaier} 343171168Smlaier 344171168Smlaierstatic void 345130613Smlaierset80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 346171168Smlaier{ 347171168Smlaier set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL); 348171168Smlaier} 349171168Smlaier 350171168Smlaierstatic void 351130610Smlaierset80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 352130610Smlaier{ 353130610Smlaier int mode; 354171168Smlaier 355171168Smlaier if (strcasecmp(val, "off") == 0) { 356130610Smlaier mode = IEEE80211_PROTMODE_OFF; 357171168Smlaier } else if (strcasecmp(val, "cts") == 0) { 358130610Smlaier mode = IEEE80211_PROTMODE_CTS; 359130610Smlaier } else if (strcasecmp(val, "rtscts") == 0) { 360171168Smlaier mode = IEEE80211_PROTMODE_RTSCTS; 361130610Smlaier } else { 362171168Smlaier err(1, "unknown protection mode"); 363171168Smlaier } 364171168Smlaier 365130610Smlaier set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 366171168Smlaier} 367171168Smlaier 368130610Smlaierstatic void 369171168Smlaierset80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 370130610Smlaier{ 371130610Smlaier set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); 372130610Smlaier} 373171168Smlaier 374130610Smlaier#define IEEE80211_ROAMING_DEVICE 0 375171168Smlaier#define IEEE80211_ROAMING_AUTO 1 376171168Smlaier#define IEEE80211_ROAMING_MANUAL 2 377171168Smlaier 378171168Smlaierstatic void 379130610Smlaierset80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 380171168Smlaier{ 381171168Smlaier int mode; 382171168Smlaier 383171168Smlaier if (strcasecmp(val, "device") == 0) { 384171168Smlaier mode = IEEE80211_ROAMING_DEVICE; 385171168Smlaier } else if (strcasecmp(val, "auto") == 0) { 386171168Smlaier mode = IEEE80211_ROAMING_AUTO; 387171168Smlaier } else if (strcasecmp(val, "manual") == 0) { 388130610Smlaier mode = IEEE80211_ROAMING_MANUAL; 389130610Smlaier } else { 390130610Smlaier err(1, "unknown roaming mode"); 391171168Smlaier } 392130610Smlaier set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 393171168Smlaier} 394171168Smlaier 395171168Smlaierstatic void 396171168Smlaierset80211wme(const char *val, int d, int s, const struct afswtch *rafp) 397171168Smlaier{ 398171168Smlaier set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 399171168Smlaier} 400171168Smlaier 401171168Smlaierstatic void 402171168Smlaierset80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 403171168Smlaier{ 404130610Smlaier set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 405130610Smlaier} 406171168Smlaier 407171168Smlaierstatic void 408130610Smlaierset80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 409171168Smlaier{ 410171168Smlaier set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 411171168Smlaier} 412171168Smlaier 413171168Smlaierstatic void 414171168Smlaierset80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 415171168Smlaier{ 416171168Smlaier struct ieee80211req_chanlist chanlist; 417171168Smlaier#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) 418171168Smlaier char *temp, *cp, *tp; 419171168Smlaier 420171168Smlaier temp = malloc(strlen(val) + 1); 421171168Smlaier if (temp == NULL) 422171168Smlaier errx(1, "malloc failed"); 423171168Smlaier strcpy(temp, val); 424171168Smlaier memset(&chanlist, 0, sizeof(chanlist)); 425171168Smlaier cp = temp; 426171168Smlaier for (;;) { 427171168Smlaier int first, last, f; 428171168Smlaier 429171168Smlaier tp = strchr(cp, ','); 430171168Smlaier if (tp != NULL) 431171168Smlaier *tp++ = '\0'; 432171168Smlaier switch (sscanf(cp, "%u-%u", &first, &last)) { 433171168Smlaier case 1: 434171168Smlaier if (first > MAXCHAN) 435171168Smlaier errx(-1, "channel %u out of range, max %zu", 436171168Smlaier first, MAXCHAN); 437171168Smlaier setbit(chanlist.ic_channels, first); 438130610Smlaier break; 439130610Smlaier case 2: 440130610Smlaier if (first > MAXCHAN) 441130610Smlaier errx(-1, "channel %u out of range, max %zu", 442130610Smlaier first, MAXCHAN); 443130610Smlaier if (last > MAXCHAN) 444130610Smlaier errx(-1, "channel %u out of range, max %zu", 445130610Smlaier last, MAXCHAN); 446130610Smlaier if (first > last) 447130610Smlaier errx(-1, "void channel range, %u > %u", 448130610Smlaier first, last); 449130610Smlaier for (f = first; f <= last; f++) 450130610Smlaier setbit(chanlist.ic_channels, f); 451171168Smlaier break; 452130610Smlaier } 453130610Smlaier if (tp == NULL) 454130610Smlaier break; 455130610Smlaier while (isspace(*tp)) 456171168Smlaier tp++; 457171168Smlaier if (!isdigit(*tp)) 458171168Smlaier break; 459171168Smlaier cp = tp; 460171168Smlaier } 461171168Smlaier set80211(s, IEEE80211_IOC_CHANLIST, 0, 462171168Smlaier sizeof(chanlist), (uint8_t *) &chanlist); 463171168Smlaier#undef MAXCHAN 464171168Smlaier} 465130610Smlaier 466130610Smlaierstatic void 467130610Smlaierset80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 468130610Smlaier{ 469130610Smlaier 470130610Smlaier if (!isanyarg(val)) { 471130610Smlaier char *temp; 472130610Smlaier struct sockaddr_dl sdl; 473130610Smlaier 474130610Smlaier temp = malloc(strlen(val) + 1); 475130610Smlaier if (temp == NULL) 476130610Smlaier errx(1, "malloc failed"); 477130610Smlaier temp[0] = ':'; 478130610Smlaier strcpy(temp + 1, val); 479130610Smlaier sdl.sdl_len = sizeof(sdl); 480130610Smlaier link_addr(temp, &sdl); 481171168Smlaier free(temp); 482171168Smlaier if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 483171168Smlaier errx(1, "malformed link-level address"); 484171168Smlaier set80211(s, IEEE80211_IOC_BSSID, 0, 485130610Smlaier IEEE80211_ADDR_LEN, LLADDR(&sdl)); 486171168Smlaier } else { 487171168Smlaier uint8_t zerobssid[IEEE80211_ADDR_LEN]; 488171168Smlaier memset(zerobssid, 0, sizeof(zerobssid)); 489171168Smlaier set80211(s, IEEE80211_IOC_BSSID, 0, 490130610Smlaier IEEE80211_ADDR_LEN, zerobssid); 491130610Smlaier } 492130610Smlaier} 493130610Smlaier 494130610Smlaierstatic int 495171168Smlaiergetac(const char *ac) 496130610Smlaier{ 497171168Smlaier if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 498130610Smlaier return WME_AC_BE; 499130610Smlaier if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 500130610Smlaier return WME_AC_BK; 501130610Smlaier if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 502130610Smlaier return WME_AC_VI; 503130610Smlaier if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 504130610Smlaier return WME_AC_VO; 505130610Smlaier errx(1, "unknown wme access class %s", ac); 506130610Smlaier} 507171168Smlaier 508130610Smlaierstatic 509130610SmlaierDECL_CMD_FUNC2(set80211cwmin, ac, val) 510130610Smlaier{ 511130610Smlaier set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 512130610Smlaier} 513130610Smlaier 514171168Smlaierstatic 515130610SmlaierDECL_CMD_FUNC2(set80211cwmax, ac, val) 516171168Smlaier{ 517171168Smlaier set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 518171168Smlaier} 519171168Smlaier 520171168Smlaierstatic 521171168SmlaierDECL_CMD_FUNC2(set80211aifs, ac, val) 522171168Smlaier{ 523171168Smlaier set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 524171168Smlaier} 525171168Smlaier 526171168Smlaierstatic 527171168SmlaierDECL_CMD_FUNC2(set80211txoplimit, ac, val) 528171168Smlaier{ 529171168Smlaier set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 530171168Smlaier} 531171168Smlaier 532171168Smlaierstatic 533145836SmlaierDECL_CMD_FUNC(set80211acm, val, d) 534145836Smlaier{ 535130610Smlaier set80211(s, IEEE80211_IOC_WME_ACM, d, WME_AC_BE, NULL); 536145836Smlaier} 537130610Smlaier 538145836Smlaierstatic 539145836SmlaierDECL_CMD_FUNC(set80211ackpolicy, val, d) 540145836Smlaier{ 541171168Smlaier set80211(s, IEEE80211_IOC_WME_ACKPOLICY, d, WME_AC_BE, NULL); 542130610Smlaier} 543130610Smlaier 544130610Smlaierstatic 545130610SmlaierDECL_CMD_FUNC2(set80211bsscwmin, ac, val) 546130610Smlaier{ 547130610Smlaier set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 548130610Smlaier getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 549130610Smlaier} 550130610Smlaier 551130610Smlaierstatic 552130610SmlaierDECL_CMD_FUNC2(set80211bsscwmax, ac, val) 553130610Smlaier{ 554171168Smlaier set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 555130610Smlaier getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 556130610Smlaier} 557171168Smlaier 558171168Smlaierstatic 559130610SmlaierDECL_CMD_FUNC2(set80211bssaifs, ac, val) 560171168Smlaier{ 561171168Smlaier set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 562171168Smlaier getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 563171168Smlaier} 564171168Smlaier 565171168Smlaierstatic 566130610SmlaierDECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 567130610Smlaier{ 568130610Smlaier set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 569130610Smlaier getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 570130610Smlaier} 571130610Smlaier 572130610Smlaierstatic 573130610SmlaierDECL_CMD_FUNC(set80211dtimperiod, val, d) 574130610Smlaier{ 575130610Smlaier set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 576130610Smlaier} 577130610Smlaier 578130610Smlaierstatic 579130610SmlaierDECL_CMD_FUNC(set80211bintval, val, d) 580130610Smlaier{ 581130610Smlaier set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 582130610Smlaier} 583130610Smlaier 584130610Smlaierstatic void 585173825Smlaierset80211macmac(int s, int op, const char *val) 586173825Smlaier{ 587173825Smlaier char *temp; 588173825Smlaier struct sockaddr_dl sdl; 589173825Smlaier 590173825Smlaier temp = malloc(strlen(val) + 1); 591173825Smlaier if (temp == NULL) 592173825Smlaier errx(1, "malloc failed"); 593173825Smlaier temp[0] = ':'; 594173825Smlaier strcpy(temp + 1, val); 595173825Smlaier sdl.sdl_len = sizeof(sdl); 596173825Smlaier link_addr(temp, &sdl); 597130610Smlaier free(temp); 598130610Smlaier if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 599130610Smlaier errx(1, "malformed link-level address"); 600130610Smlaier set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 601130610Smlaier} 602130610Smlaier 603130610Smlaierstatic 604130610SmlaierDECL_CMD_FUNC(set80211addmac, val, d) 605130610Smlaier{ 606130610Smlaier set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 607130610Smlaier} 608130610Smlaier 609130610Smlaierstatic 610130610SmlaierDECL_CMD_FUNC(set80211delmac, val, d) 611130610Smlaier{ 612130610Smlaier set80211macmac(s, IEEE80211_IOC_DELMAC, val); 613130610Smlaier} 614130610Smlaier 615130610Smlaierstatic 616130610SmlaierDECL_CMD_FUNC(set80211maccmd, val, d) 617145836Smlaier{ 618130610Smlaier set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 619130610Smlaier} 620130610Smlaier 621171168Smlaierstatic void 622130610Smlaierset80211pureg(const char *val, int d, int s, const struct afswtch *rafp) 623130610Smlaier{ 624171168Smlaier set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); 625130610Smlaier} 626130610Smlaier 627130610Smlaierstatic int 628130610Smlaiergetmaxrate(uint8_t rates[15], uint8_t nrates) 629130610Smlaier{ 630130610Smlaier int i, maxrate = -1; 631130610Smlaier 632130610Smlaier for (i = 0; i < nrates; i++) { 633130610Smlaier int rate = rates[i] & IEEE80211_RATE_VAL; 634130610Smlaier if (rate > maxrate) 635130610Smlaier maxrate = rate; 636130610Smlaier } 637130610Smlaier return maxrate / 2; 638130610Smlaier} 639130610Smlaier 640130610Smlaierstatic const char * 641130610Smlaiergetcaps(int capinfo) 642130610Smlaier{ 643130610Smlaier static char capstring[32]; 644130610Smlaier char *cp = capstring; 645130610Smlaier 646130610Smlaier if (capinfo & IEEE80211_CAPINFO_ESS) 647130610Smlaier *cp++ = 'E'; 648130610Smlaier if (capinfo & IEEE80211_CAPINFO_IBSS) 649130610Smlaier *cp++ = 'I'; 650130610Smlaier if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 651130610Smlaier *cp++ = 'c'; 652130610Smlaier if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 653171168Smlaier *cp++ = 'C'; 654130613Smlaier if (capinfo & IEEE80211_CAPINFO_PRIVACY) 655130613Smlaier *cp++ = 'P'; 656130613Smlaier if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 657130610Smlaier *cp++ = 'S'; 658130613Smlaier if (capinfo & IEEE80211_CAPINFO_PBCC) 659130610Smlaier *cp++ = 'B'; 660130610Smlaier if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 661130610Smlaier *cp++ = 'A'; 662130610Smlaier if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 663130610Smlaier *cp++ = 's'; 664130610Smlaier if (capinfo & IEEE80211_CAPINFO_RSN) 665130610Smlaier *cp++ = 'R'; 666130610Smlaier if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 667130610Smlaier *cp++ = 'D'; 668130610Smlaier *cp = '\0'; 669130610Smlaier return capstring; 670130610Smlaier} 671130610Smlaier 672130610Smlaierstatic void 673130610Smlaierprintie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 674130610Smlaier{ 675130610Smlaier printf("%s", tag); 676130610Smlaier if (verbose) { 677130610Smlaier maxlen -= strlen(tag)+2; 678171168Smlaier if (2*ielen > maxlen) 679130610Smlaier maxlen--; 680171168Smlaier printf("<"); 681130610Smlaier for (; ielen > 0; ie++, ielen--) { 682130610Smlaier if (maxlen-- <= 0) 683130610Smlaier break; 684130610Smlaier printf("%02x", *ie); 685130610Smlaier } 686130610Smlaier if (ielen != 0) 687130610Smlaier printf("-"); 688130610Smlaier printf(">"); 689130610Smlaier } 690130610Smlaier} 691130610Smlaier 692130610Smlaier/* 693130610Smlaier * Copy the ssid string contents into buf, truncating to fit. If the 694130610Smlaier * ssid is entirely printable then just copy intact. Otherwise convert 695130610Smlaier * to hexadecimal. If the result is truncated then replace the last 696130610Smlaier * three characters with "...". 697130610Smlaier */ 698130610Smlaierstatic int 699130610Smlaiercopy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 700171168Smlaier{ 701171168Smlaier const u_int8_t *p; 702130610Smlaier size_t maxlen; 703130610Smlaier int i; 704130610Smlaier 705130610Smlaier if (essid_len > bufsize) 706130610Smlaier maxlen = bufsize; 707130610Smlaier else 708130610Smlaier maxlen = essid_len; 709130610Smlaier /* determine printable or not */ 710130610Smlaier for (i = 0, p = essid; i < maxlen; i++, p++) { 711130610Smlaier if (*p < ' ' || *p > 0x7e) 712130610Smlaier break; 713130610Smlaier } 714130610Smlaier if (i != maxlen) { /* not printable, print as hex */ 715130610Smlaier if (bufsize < 3) 716130610Smlaier return 0; 717130610Smlaier strlcpy(buf, "0x", bufsize); 718130610Smlaier bufsize -= 2; 719130610Smlaier p = essid; 720130610Smlaier for (i = 0; i < maxlen && bufsize >= 2; i++) { 721130610Smlaier sprintf(&buf[2+2*i], "%02x", p[i]); 722171168Smlaier bufsize -= 2; 723171168Smlaier } 724130610Smlaier if (i != essid_len) 725130610Smlaier memcpy(&buf[2+2*i-3], "...", 3); 726130610Smlaier } else { /* printable, truncate as needed */ 727171168Smlaier memcpy(buf, essid, maxlen); 728130610Smlaier if (maxlen != essid_len) 729130610Smlaier memcpy(&buf[maxlen-3], "...", 3); 730130610Smlaier } 731130610Smlaier return maxlen; 732130610Smlaier} 733130610Smlaier 734130610Smlaier/* unalligned little endian access */ 735130610Smlaier#define LE_READ_4(p) \ 736130610Smlaier ((u_int32_t) \ 737130610Smlaier ((((const u_int8_t *)(p))[0] ) | \ 738130610Smlaier (((const u_int8_t *)(p))[1] << 8) | \ 739130610Smlaier (((const u_int8_t *)(p))[2] << 16) | \ 740171168Smlaier (((const u_int8_t *)(p))[3] << 24))) 741171168Smlaier 742171168Smlaierstatic int __inline 743130610Smlaieriswpaoui(const u_int8_t *frm) 744130610Smlaier{ 745130610Smlaier return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 746171168Smlaier} 747130610Smlaier 748130610Smlaierstatic int __inline 749130610Smlaieriswmeoui(const u_int8_t *frm) 750130610Smlaier{ 751130610Smlaier return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); 752130610Smlaier} 753130610Smlaier 754130610Smlaierstatic int __inline 755130610Smlaierisatherosoui(const u_int8_t *frm) 756130610Smlaier{ 757130610Smlaier return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 758130610Smlaier} 759130610Smlaier 760130610Smlaierstatic void 761130610Smlaierprinties(const u_int8_t *vp, int ielen, int maxcols) 762130610Smlaier{ 763130610Smlaier while (ielen > 0) { 764130610Smlaier switch (vp[0]) { 765171168Smlaier case IEEE80211_ELEMID_VENDOR: 766130610Smlaier if (iswpaoui(vp)) 767130610Smlaier printie(" WPA", vp, 2+vp[1], maxcols); 768171168Smlaier else if (iswmeoui(vp)) 769130610Smlaier printie(" WME", vp, 2+vp[1], maxcols); 770130610Smlaier else if (isatherosoui(vp)) 771130610Smlaier printie(" ATH", vp, 2+vp[1], maxcols); 772171168Smlaier else 773130610Smlaier printie(" VEN", vp, 2+vp[1], maxcols); 774130610Smlaier break; 775130610Smlaier case IEEE80211_ELEMID_RSN: 776171168Smlaier printie(" RSN", vp, 2+vp[1], maxcols); 777130610Smlaier break; 778130610Smlaier default: 779130610Smlaier printie(" ???", vp, 2+vp[1], maxcols); 780145836Smlaier break; 781145836Smlaier } 782145836Smlaier ielen -= 2+vp[1]; 783145836Smlaier vp += 2+vp[1]; 784171168Smlaier } 785145836Smlaier} 786171168Smlaier 787130610Smlaierstatic void 788172933Smlaierlist_scan(int s) 789172933Smlaier{ 790172933Smlaier uint8_t buf[24*1024]; 791130610Smlaier struct ieee80211req ireq; 792130610Smlaier char ssid[14]; 793171168Smlaier uint8_t *cp; 794171168Smlaier int len; 795171168Smlaier 796130610Smlaier (void) memset(&ireq, 0, sizeof(ireq)); 797130610Smlaier (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 798130610Smlaier ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; 799145836Smlaier ireq.i_data = buf; 800171168Smlaier ireq.i_len = sizeof(buf); 801172933Smlaier if (ioctl(s, SIOCG80211, &ireq) < 0) 802172933Smlaier errx(1, "unable to get scan results"); 803172933Smlaier len = ireq.i_len; 804172933Smlaier if (len < sizeof(struct ieee80211req_scan_result)) 805130610Smlaier return; 806172933Smlaier 807171168Smlaier printf("%-14.14s %-17.17s %4s %4s %-5s %3s %4s\n" 808130610Smlaier , "SSID" 809130610Smlaier , "BSSID" 810130610Smlaier , "CHAN" 811171168Smlaier , "RATE" 812171168Smlaier , "S:N" 813130610Smlaier , "INT" 814130610Smlaier , "CAPS" 815130610Smlaier ); 816130610Smlaier cp = buf; 817130610Smlaier do { 818130610Smlaier struct ieee80211req_scan_result *sr; 819130610Smlaier uint8_t *vp; 820130610Smlaier 821171168Smlaier sr = (struct ieee80211req_scan_result *) cp; 822130610Smlaier vp = (u_int8_t *)(sr+1); 823130610Smlaier printf("%-14.*s %s %3d %3dM %2d:%-2d %3d %-4.4s" 824130610Smlaier , copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len) 825130610Smlaier , ssid 826130610Smlaier , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 827130610Smlaier , ieee80211_mhz2ieee(sr->isr_freq) 828130610Smlaier , getmaxrate(sr->isr_rates, sr->isr_nrates) 829130610Smlaier , sr->isr_rssi, sr->isr_noise 830130610Smlaier , sr->isr_intval 831130610Smlaier , getcaps(sr->isr_capinfo) 832130610Smlaier ); 833130610Smlaier printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);; 834130610Smlaier printf("\n"); 835130610Smlaier cp += sr->isr_len, len -= sr->isr_len; 836130610Smlaier } while (len >= sizeof(struct ieee80211req_scan_result)); 837130610Smlaier} 838130610Smlaier 839171168Smlaier#include <net80211/ieee80211_freebsd.h> 840171168Smlaier 841171168Smlaierstatic void 842171168Smlaierscan_and_wait(int s) 843171168Smlaier{ 844171168Smlaier struct ieee80211req ireq; 845171168Smlaier int sroute; 846171168Smlaier 847171168Smlaier sroute = socket(PF_ROUTE, SOCK_RAW, 0); 848171168Smlaier if (sroute < 0) { 849171168Smlaier perror("socket(PF_ROUTE,SOCK_RAW)"); 850171168Smlaier return; 851171168Smlaier } 852171168Smlaier (void) memset(&ireq, 0, sizeof(ireq)); 853171168Smlaier (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 854171168Smlaier ireq.i_type = IEEE80211_IOC_SCAN_REQ; 855171168Smlaier /* NB: only root can trigger a scan so ignore errors */ 856171168Smlaier if (ioctl(s, SIOCS80211, &ireq) >= 0) { 857171168Smlaier char buf[2048]; 858171168Smlaier struct if_announcemsghdr *ifan; 859171168Smlaier struct rt_msghdr *rtm; 860171168Smlaier 861171168Smlaier do { 862171168Smlaier if (read(sroute, buf, sizeof(buf)) < 0) { 863171168Smlaier perror("read(PF_ROUTE)"); 864171168Smlaier break; 865171168Smlaier } 866171168Smlaier rtm = (struct rt_msghdr *) buf; 867171168Smlaier if (rtm->rtm_version != RTM_VERSION) 868171168Smlaier break; 869171168Smlaier ifan = (struct if_announcemsghdr *) rtm; 870171168Smlaier } while (rtm->rtm_type != RTM_IEEE80211 || 871130610Smlaier ifan->ifan_what != RTM_IEEE80211_SCAN); 872130610Smlaier } 873130610Smlaier close(sroute); 874130610Smlaier} 875130610Smlaier 876130610Smlaierstatic 877130610SmlaierDECL_CMD_FUNC(set80211scan, val, d) 878130610Smlaier{ 879130610Smlaier scan_and_wait(s); 880130610Smlaier list_scan(s); 881130610Smlaier} 882130610Smlaier 883130610Smlaierstatic void 884130610Smlaierlist_stations(int s) 885130610Smlaier{ 886130610Smlaier uint8_t buf[24*1024]; 887130610Smlaier struct ieee80211req ireq; 888130610Smlaier uint8_t *cp; 889130610Smlaier int len; 890130610Smlaier 891171168Smlaier (void) memset(&ireq, 0, sizeof(ireq)); 892130610Smlaier (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 893171168Smlaier ireq.i_type = IEEE80211_IOC_STA_INFO; 894130610Smlaier ireq.i_data = buf; 895171168Smlaier ireq.i_len = sizeof(buf); 896171168Smlaier if (ioctl(s, SIOCG80211, &ireq) < 0) 897177700Smlaier errx(1, "unable to get station information"); 898177700Smlaier len = ireq.i_len; 899177700Smlaier if (len < sizeof(struct ieee80211req_sta_info)) 900171168Smlaier return; 901130610Smlaier 902130610Smlaier printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n" 903171168Smlaier , "ADDR" 904171168Smlaier , "AID" 905130610Smlaier , "CHAN" 906171168Smlaier , "RATE" 907171168Smlaier , "RSSI" 908177700Smlaier , "IDLE" 909177700Smlaier , "TXSEQ" 910177700Smlaier , "RXSEQ" 911171168Smlaier , "CAPS" 912130610Smlaier , "ERP" 913171168Smlaier ); 914171168Smlaier cp = buf; 915171168Smlaier do { 916171168Smlaier struct ieee80211req_sta_info *si; 917171168Smlaier uint8_t *vp; 918171168Smlaier 919171168Smlaier si = (struct ieee80211req_sta_info *) cp; 920171168Smlaier vp = (u_int8_t *)(si+1); 921171168Smlaier printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x" 922171168Smlaier , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 923171168Smlaier , IEEE80211_AID(si->isi_associd) 924171168Smlaier , ieee80211_mhz2ieee(si->isi_freq) 925171168Smlaier , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2 926171168Smlaier , si->isi_rssi 927171168Smlaier , si->isi_inact 928171168Smlaier , si->isi_txseqs[0] 929171168Smlaier , si->isi_rxseqs[0] 930171168Smlaier , getcaps(si->isi_capinfo) 931171168Smlaier , si->isi_erp 932171168Smlaier ); 933171168Smlaier printies(vp, si->isi_ie_len, 24); 934171168Smlaier printf("\n"); 935171168Smlaier cp += si->isi_len, len -= si->isi_len; 936171168Smlaier } while (len >= sizeof(struct ieee80211req_sta_info)); 937171168Smlaier} 938171168Smlaier 939171168Smlaierstatic void 940171168Smlaierprint_chaninfo(const struct ieee80211_channel *c) 941171168Smlaier{ 942171168Smlaier#define IEEE80211_IS_CHAN_PASSIVE(_c) \ 943171168Smlaier (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE)) 944171168Smlaier char buf[14]; 945171168Smlaier 946171168Smlaier buf[0] = '\0'; 947 if (IEEE80211_IS_CHAN_FHSS(c)) 948 strlcat(buf, " FHSS", sizeof(buf)); 949 if (IEEE80211_IS_CHAN_A(c)) 950 strlcat(buf, " 11a", sizeof(buf)); 951 /* XXX 11g schizophrenia */ 952 if (IEEE80211_IS_CHAN_G(c) || 953 IEEE80211_IS_CHAN_PUREG(c)) 954 strlcat(buf, " 11g", sizeof(buf)); 955 else if (IEEE80211_IS_CHAN_B(c)) 956 strlcat(buf, " 11b", sizeof(buf)); 957 if (IEEE80211_IS_CHAN_T(c)) 958 strlcat(buf, " Turbo", sizeof(buf)); 959 printf("Channel %3u : %u%c Mhz%-14.14s", 960 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq, 961 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf); 962#undef IEEE80211_IS_CHAN_PASSIVE 963} 964 965static void 966list_channels(int s, int allchans) 967{ 968 struct ieee80211req ireq; 969 struct ieee80211req_chaninfo chans; 970 struct ieee80211req_chaninfo achans; 971 const struct ieee80211_channel *c; 972 int i, half; 973 974 (void) memset(&ireq, 0, sizeof(ireq)); 975 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 976 ireq.i_type = IEEE80211_IOC_CHANINFO; 977 ireq.i_data = &chans; 978 ireq.i_len = sizeof(chans); 979 if (ioctl(s, SIOCG80211, &ireq) < 0) 980 errx(1, "unable to get channel information"); 981 if (!allchans) { 982 struct ieee80211req_chanlist active; 983 984 ireq.i_type = IEEE80211_IOC_CHANLIST; 985 ireq.i_data = &active; 986 ireq.i_len = sizeof(active); 987 if (ioctl(s, SIOCG80211, &ireq) < 0) 988 errx(1, "unable to get active channel list"); 989 memset(&achans, 0, sizeof(achans)); 990 for (i = 0; i < chans.ic_nchans; i++) { 991 c = &chans.ic_chans[i]; 992 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans) 993 achans.ic_chans[achans.ic_nchans++] = *c; 994 } 995 } else 996 achans = chans; 997 half = achans.ic_nchans / 2; 998 if (achans.ic_nchans % 2) 999 half++; 1000 for (i = 0; i < achans.ic_nchans / 2; i++) { 1001 print_chaninfo(&achans.ic_chans[i]); 1002 print_chaninfo(&achans.ic_chans[half+i]); 1003 printf("\n"); 1004 } 1005 if (achans.ic_nchans % 2) { 1006 print_chaninfo(&achans.ic_chans[i]); 1007 printf("\n"); 1008 } 1009} 1010 1011static void 1012list_keys(int s) 1013{ 1014} 1015 1016#define IEEE80211_C_BITS \ 1017"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \ 1018"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \ 1019"\31WPA2\32BURST\33WME" 1020 1021static void 1022list_capabilities(int s) 1023{ 1024 struct ieee80211req ireq; 1025 u_int32_t caps; 1026 1027 (void) memset(&ireq, 0, sizeof(ireq)); 1028 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1029 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS; 1030 if (ioctl(s, SIOCG80211, &ireq) < 0) 1031 errx(1, "unable to get driver capabilities"); 1032 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len); 1033 printb(name, caps, IEEE80211_C_BITS); 1034 putchar('\n'); 1035} 1036 1037static void 1038list_wme(int s) 1039{ 1040 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 1041 struct ieee80211req ireq; 1042 int ac; 1043 1044 (void) memset(&ireq, 0, sizeof(ireq)); 1045 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1046 ireq.i_len = 0; 1047 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 1048again: 1049 if (ireq.i_len & IEEE80211_WMEPARAM_BSS) 1050 printf("\t%s", " "); 1051 else 1052 printf("\t%s", acnames[ac]); 1053 1054 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac; 1055 1056 /* show WME BSS parameters */ 1057 ireq.i_type = IEEE80211_IOC_WME_CWMIN; 1058 if (ioctl(s, SIOCG80211, &ireq) != -1) 1059 printf(" cwmin %2u", ireq.i_val); 1060 ireq.i_type = IEEE80211_IOC_WME_CWMAX; 1061 if (ioctl(s, SIOCG80211, &ireq) != -1) 1062 printf(" cwmax %2u", ireq.i_val); 1063 ireq.i_type = IEEE80211_IOC_WME_AIFS; 1064 if (ioctl(s, SIOCG80211, &ireq) != -1) 1065 printf(" aifs %2u", ireq.i_val); 1066 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT; 1067 if (ioctl(s, SIOCG80211, &ireq) != -1) 1068 printf(" txopLimit %3u", ireq.i_val); 1069 ireq.i_type = IEEE80211_IOC_WME_ACM; 1070 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1071 if (ireq.i_val) 1072 printf(" acm"); 1073 else if (verbose) 1074 printf(" -acm"); 1075 } 1076 /* !BSS only */ 1077 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1078 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY; 1079 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1080 if (!ireq.i_val) 1081 printf(" -ack"); 1082 else if (verbose) 1083 printf(" ack"); 1084 } 1085 } 1086 printf("\n"); 1087 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1088 ireq.i_len |= IEEE80211_WMEPARAM_BSS; 1089 goto again; 1090 } else 1091 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS; 1092 } 1093} 1094 1095static 1096DECL_CMD_FUNC(set80211list, arg, d) 1097{ 1098#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 1099 1100 if (iseq(arg, "sta")) 1101 list_stations(s); 1102 else if (iseq(arg, "scan") || iseq(arg, "ap")) 1103 list_scan(s); 1104 else if (iseq(arg, "chan") || iseq(arg, "freq")) 1105 list_channels(s, 1); 1106 else if (iseq(arg, "active")) 1107 list_channels(s, 0); 1108 else if (iseq(arg, "keys")) 1109 list_keys(s); 1110 else if (iseq(arg, "caps")) 1111 list_capabilities(s); 1112 else if (iseq(arg, "wme")) 1113 list_wme(s); 1114 else 1115 errx(1, "Don't know how to list %s for %s", arg, name); 1116#undef iseq 1117} 1118 1119static enum ieee80211_opmode 1120get80211opmode(int s) 1121{ 1122 struct ifmediareq ifmr; 1123 1124 (void) memset(&ifmr, 0, sizeof(ifmr)); 1125 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 1126 1127 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 1128 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 1129 return IEEE80211_M_IBSS; /* XXX ahdemo */ 1130 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 1131 return IEEE80211_M_HOSTAP; 1132 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 1133 return IEEE80211_M_MONITOR; 1134 } 1135 return IEEE80211_M_STA; 1136} 1137 1138static const struct ieee80211_channel * 1139getchaninfo(int s, int chan) 1140{ 1141 struct ieee80211req ireq; 1142 static struct ieee80211req_chaninfo chans; 1143 static struct ieee80211_channel undef; 1144 const struct ieee80211_channel *c; 1145 int i, freq; 1146 1147 (void) memset(&ireq, 0, sizeof(ireq)); 1148 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1149 ireq.i_type = IEEE80211_IOC_CHANINFO; 1150 ireq.i_data = &chans; 1151 ireq.i_len = sizeof(chans); 1152 if (ioctl(s, SIOCG80211, &ireq) < 0) 1153 errx(1, "unable to get channel information"); 1154 freq = ieee80211_ieee2mhz(chan); 1155 for (i = 0; i < chans.ic_nchans; i++) { 1156 c = &chans.ic_chans[i]; 1157 if (c->ic_freq == freq) 1158 return c; 1159 } 1160 return &undef; 1161} 1162 1163#if 0 1164static void 1165printcipher(int s, struct ieee80211req *ireq, int keylenop) 1166{ 1167 switch (ireq->i_val) { 1168 case IEEE80211_CIPHER_WEP: 1169 ireq->i_type = keylenop; 1170 if (ioctl(s, SIOCG80211, ireq) != -1) 1171 printf("WEP-%s", 1172 ireq->i_len <= 5 ? "40" : 1173 ireq->i_len <= 13 ? "104" : "128"); 1174 else 1175 printf("WEP"); 1176 break; 1177 case IEEE80211_CIPHER_TKIP: 1178 printf("TKIP"); 1179 break; 1180 case IEEE80211_CIPHER_AES_OCB: 1181 printf("AES-OCB"); 1182 break; 1183 case IEEE80211_CIPHER_AES_CCM: 1184 printf("AES-CCM"); 1185 break; 1186 case IEEE80211_CIPHER_CKIP: 1187 printf("CKIP"); 1188 break; 1189 case IEEE80211_CIPHER_NONE: 1190 printf("NONE"); 1191 break; 1192 default: 1193 printf("UNKNOWN (0x%x)", ireq->i_val); 1194 break; 1195 } 1196} 1197#endif 1198 1199#define MAXCOL 78 1200int col; 1201char spacer; 1202 1203#define LINE_BREAK() do { \ 1204 if (spacer != '\t') { \ 1205 printf("\n"); \ 1206 spacer = '\t'; \ 1207 } \ 1208 col = 8; /* 8-col tab */ \ 1209} while (0) 1210#define LINE_CHECK(fmt, ...) do { \ 1211 col += sizeof(fmt)-2; \ 1212 if (col > MAXCOL) { \ 1213 LINE_BREAK(); \ 1214 col += sizeof(fmt)-2; \ 1215 } \ 1216 printf(fmt, __VA_ARGS__); \ 1217 spacer = ' '; \ 1218} while (0) 1219 1220static void 1221printkey(const struct ieee80211req_key *ik) 1222{ 1223 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 1224 int keylen = ik->ik_keylen; 1225 int printcontents; 1226 1227 printcontents = 1228 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 1229 if (printcontents) 1230 LINE_BREAK(); 1231 switch (ik->ik_type) { 1232 case IEEE80211_CIPHER_WEP: 1233 /* compatibility */ 1234 LINE_CHECK("%cwepkey %u:%s", spacer, ik->ik_keyix+1, 1235 keylen <= 5 ? "40-bit" : 1236 keylen <= 13 ? "104-bit" : "128-bit"); 1237 break; 1238 case IEEE80211_CIPHER_TKIP: 1239 if (keylen > 128/8) 1240 keylen -= 128/8; /* ignore MIC for now */ 1241 LINE_CHECK("%cTKIP %u:%u-bit", 1242 spacer, ik->ik_keyix+1, 8*keylen); 1243 break; 1244 case IEEE80211_CIPHER_AES_OCB: 1245 LINE_CHECK("%cAES-OCB %u:%u-bit", 1246 spacer, ik->ik_keyix+1, 8*keylen); 1247 break; 1248 case IEEE80211_CIPHER_AES_CCM: 1249 LINE_CHECK("%cAES-CCM %u:%u-bit", 1250 spacer, ik->ik_keyix+1, 8*keylen); 1251 break; 1252 case IEEE80211_CIPHER_CKIP: 1253 LINE_CHECK("%cCKIP %u:%u-bit", 1254 spacer, ik->ik_keyix+1, 8*keylen); 1255 break; 1256 case IEEE80211_CIPHER_NONE: 1257 LINE_CHECK("%cNULL %u:%u-bit", 1258 spacer, ik->ik_keyix+1, 8*keylen); 1259 break; 1260 default: 1261 LINE_CHECK("%cUNKNOWN (0x%x) %u:%u-bit", spacer, 1262 ik->ik_type, ik->ik_keyix+1, 8*keylen); 1263 break; 1264 } 1265 if (printcontents) { 1266 int i; 1267 1268 printf(" <"); 1269 for (i = 0; i < keylen; i++) 1270 printf("%02x", ik->ik_keydata[i]); 1271 printf(">"); 1272 if (ik->ik_type != IEEE80211_CIPHER_WEP && 1273 (ik->ik_keyrsc != 0 || verbose)) 1274 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 1275 if (ik->ik_type != IEEE80211_CIPHER_WEP && 1276 (ik->ik_keytsc != 0 || verbose)) 1277 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 1278 if (ik->ik_flags != 0 && verbose) { 1279 const char *sep = " "; 1280 1281 if (ik->ik_flags & IEEE80211_KEY_XMIT) 1282 printf("%stx", sep), sep = "+"; 1283 if (ik->ik_flags & IEEE80211_KEY_RECV) 1284 printf("%srx", sep), sep = "+"; 1285 if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 1286 printf("%sdef", sep), sep = "+"; 1287 } 1288 LINE_BREAK(); 1289 } 1290} 1291 1292static void 1293ieee80211_status(int s) 1294{ 1295 static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 1296 enum ieee80211_opmode opmode = get80211opmode(s); 1297 int i, num, wpa, wme; 1298 struct ieee80211req ireq; 1299 u_int8_t data[32]; 1300 const struct ieee80211_channel *c; 1301 1302 (void) memset(&ireq, 0, sizeof(ireq)); 1303 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1304 ireq.i_data = &data; 1305 1306 wpa = 0; /* unknown/not set */ 1307 1308 ireq.i_type = IEEE80211_IOC_SSID; 1309 ireq.i_val = -1; 1310 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1311 /* If we can't get the SSID, the this isn't an 802.11 device. */ 1312 return; 1313 } 1314 num = 0; 1315 ireq.i_type = IEEE80211_IOC_NUMSSIDS; 1316 if (ioctl(s, SIOCG80211, &ireq) >= 0) 1317 num = ireq.i_val; 1318 printf("\tssid "); 1319 if (num > 1) { 1320 ireq.i_type = IEEE80211_IOC_SSID; 1321 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 1322 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 1323 printf(" %d:", ireq.i_val + 1); 1324 print_string(data, ireq.i_len); 1325 } 1326 } 1327 } else 1328 print_string(data, ireq.i_len); 1329 1330 ireq.i_type = IEEE80211_IOC_CHANNEL; 1331 if (ioctl(s, SIOCG80211, &ireq) < 0) 1332 goto end; 1333 c = getchaninfo(s, ireq.i_val); 1334 if (ireq.i_val != -1) { 1335 printf(" channel %d", ireq.i_val); 1336 if (verbose) 1337 printf(" (%u)", c->ic_freq); 1338 } else if (verbose) 1339 printf(" channel UNDEF"); 1340 1341 ireq.i_type = IEEE80211_IOC_BSSID; 1342 ireq.i_len = IEEE80211_ADDR_LEN; 1343 if (ioctl(s, SIOCG80211, &ireq) >= 0 && 1344 memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0) 1345 printf(" bssid %s", ether_ntoa(ireq.i_data)); 1346 1347 ireq.i_type = IEEE80211_IOC_STATIONNAME; 1348 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1349 printf("\n\tstationname "); 1350 print_string(data, ireq.i_len); 1351 } 1352 1353 spacer = ' '; /* force first break */ 1354 LINE_BREAK(); 1355 1356 ireq.i_type = IEEE80211_IOC_AUTHMODE; 1357 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1358 switch (ireq.i_val) { 1359 case IEEE80211_AUTH_NONE: 1360 LINE_CHECK("%cauthmode NONE", spacer); 1361 break; 1362 case IEEE80211_AUTH_OPEN: 1363 LINE_CHECK("%cauthmode OPEN", spacer); 1364 break; 1365 case IEEE80211_AUTH_SHARED: 1366 LINE_CHECK("%cauthmode SHARED", spacer); 1367 break; 1368 case IEEE80211_AUTH_8021X: 1369 LINE_CHECK("%cauthmode 802.1x", spacer); 1370 break; 1371 case IEEE80211_AUTH_WPA: 1372 ireq.i_type = IEEE80211_IOC_WPA; 1373 if (ioctl(s, SIOCG80211, &ireq) != -1) 1374 wpa = ireq.i_val; 1375 if (!wpa) 1376 wpa = 1; /* default to WPA1 */ 1377 switch (wpa) { 1378 case 2: 1379 LINE_CHECK("%cauthmode WPA2/802.11i", 1380 spacer); 1381 break; 1382 case 3: 1383 LINE_CHECK("%cauthmode WPA1+WPA2/802.11i", 1384 spacer); 1385 break; 1386 default: 1387 LINE_CHECK("%cauthmode WPA", spacer); 1388 break; 1389 } 1390 break; 1391 case IEEE80211_AUTH_AUTO: 1392 LINE_CHECK("%cauthmode AUTO", spacer); 1393 break; 1394 default: 1395 LINE_CHECK("%cauthmode UNKNOWN (0x%x)", 1396 spacer, ireq.i_val); 1397 break; 1398 } 1399 } 1400 1401 ireq.i_type = IEEE80211_IOC_WEP; 1402 if (ioctl(s, SIOCG80211, &ireq) != -1 && 1403 ireq.i_val != IEEE80211_WEP_NOSUP) { 1404 int firstkey, wepmode; 1405 1406 wepmode = ireq.i_val; 1407 switch (wepmode) { 1408 case IEEE80211_WEP_OFF: 1409 LINE_CHECK("%cprivacy OFF", spacer); 1410 break; 1411 case IEEE80211_WEP_ON: 1412 LINE_CHECK("%cprivacy ON", spacer); 1413 break; 1414 case IEEE80211_WEP_MIXED: 1415 LINE_CHECK("%cprivacy MIXED", spacer); 1416 break; 1417 default: 1418 LINE_CHECK("%cprivacy UNKNOWN (0x%x)", 1419 spacer, wepmode); 1420 break; 1421 } 1422 1423 /* 1424 * If we get here then we've got WEP support so we need 1425 * to print WEP status. 1426 */ 1427 1428 ireq.i_type = IEEE80211_IOC_WEPTXKEY; 1429 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1430 warn("WEP support, but no tx key!"); 1431 goto end; 1432 } 1433 if (ireq.i_val != -1) 1434 LINE_CHECK("%cdeftxkey %d", spacer, ireq.i_val+1); 1435 else if (wepmode != IEEE80211_WEP_OFF || verbose) 1436 LINE_CHECK("%cdeftxkey UNDEF", spacer); 1437 1438 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 1439 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1440 warn("WEP support, but no NUMWEPKEYS support!"); 1441 goto end; 1442 } 1443 num = ireq.i_val; 1444 1445 firstkey = 1; 1446 for (i = 0; i < num; i++) { 1447 struct ieee80211req_key ik; 1448 1449 memset(&ik, 0, sizeof(ik)); 1450 ik.ik_keyix = i; 1451 ireq.i_type = IEEE80211_IOC_WPAKEY; 1452 ireq.i_data = &ik; 1453 ireq.i_len = sizeof(ik); 1454 if (ioctl(s, SIOCG80211, &ireq) < 0) { 1455 warn("WEP support, but can get keys!"); 1456 goto end; 1457 } 1458 if (ik.ik_keylen != 0) { 1459 if (verbose) 1460 LINE_BREAK(); 1461 printkey(&ik); 1462 firstkey = 0; 1463 } 1464 } 1465 } 1466 1467 ireq.i_type = IEEE80211_IOC_POWERSAVE; 1468 if (ioctl(s, SIOCG80211, &ireq) != -1 && 1469 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 1470 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) { 1471 switch (ireq.i_val) { 1472 case IEEE80211_POWERSAVE_OFF: 1473 LINE_CHECK("%cpowersavemode OFF", 1474 spacer); 1475 break; 1476 case IEEE80211_POWERSAVE_CAM: 1477 LINE_CHECK("%cpowersavemode CAM", 1478 spacer); 1479 break; 1480 case IEEE80211_POWERSAVE_PSP: 1481 LINE_CHECK("%cpowersavemode PSP", 1482 spacer); 1483 break; 1484 case IEEE80211_POWERSAVE_PSP_CAM: 1485 LINE_CHECK("%cpowersavemode PSP-CAM", 1486 spacer); 1487 break; 1488 } 1489 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 1490 if (ioctl(s, SIOCG80211, &ireq) != -1) 1491 LINE_CHECK("%cpowersavesleep %d", 1492 spacer, ireq.i_val); 1493 } 1494 } 1495 1496 ireq.i_type = IEEE80211_IOC_TXPOWMAX; 1497 if (ioctl(s, SIOCG80211, &ireq) != -1) 1498 LINE_CHECK("%ctxpowmax %d", spacer, ireq.i_val); 1499 1500 if (verbose) { 1501 ireq.i_type = IEEE80211_IOC_TXPOWER; 1502 if (ioctl(s, SIOCG80211, &ireq) != -1) 1503 LINE_CHECK("%ctxpower %d", spacer, ireq.i_val); 1504 } 1505 1506 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; 1507 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1508 if (ireq.i_val != IEEE80211_RTS_MAX || verbose) 1509 LINE_CHECK("%crtsthreshold %d", spacer, ireq.i_val); 1510 } 1511 1512 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) { 1513 ireq.i_type = IEEE80211_IOC_PUREG; 1514 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1515 if (ireq.i_val) 1516 LINE_CHECK("%cpureg", spacer); 1517 else if (verbose) 1518 LINE_CHECK("%c-pureg", spacer); 1519 } 1520 ireq.i_type = IEEE80211_IOC_PROTMODE; 1521 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1522 switch (ireq.i_val) { 1523 case IEEE80211_PROTMODE_OFF: 1524 LINE_CHECK("%cprotmode OFF", spacer); 1525 break; 1526 case IEEE80211_PROTMODE_CTS: 1527 LINE_CHECK("%cprotmode CTS", spacer); 1528 break; 1529 case IEEE80211_PROTMODE_RTSCTS: 1530 LINE_CHECK("%cprotmode RTSCTS", spacer); 1531 break; 1532 default: 1533 LINE_CHECK("%cprotmode UNKNOWN (0x%x)", 1534 spacer, ireq.i_val); 1535 break; 1536 } 1537 } 1538 } 1539 1540 ireq.i_type = IEEE80211_IOC_WME; 1541 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1542 wme = ireq.i_val; 1543 if (wme) 1544 LINE_CHECK("%cwme", spacer); 1545 else if (verbose) 1546 LINE_CHECK("%c-wme", spacer); 1547 } else 1548 wme = 0; 1549 1550 if (opmode == IEEE80211_M_HOSTAP) { 1551 ireq.i_type = IEEE80211_IOC_HIDESSID; 1552 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1553 if (ireq.i_val) 1554 LINE_CHECK("%cssid HIDE", spacer); 1555 else if (verbose) 1556 LINE_CHECK("%cssid SHOW", spacer); 1557 } 1558 1559 ireq.i_type = IEEE80211_IOC_APBRIDGE; 1560 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1561 if (!ireq.i_val) 1562 LINE_CHECK("%c-apbridge", spacer); 1563 else if (verbose) 1564 LINE_CHECK("%capbridge", spacer); 1565 } 1566 1567 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD; 1568 if (ioctl(s, SIOCG80211, &ireq) != -1) 1569 LINE_CHECK("%cdtimperiod %u", spacer, ireq.i_val); 1570 } else { 1571 ireq.i_type = IEEE80211_IOC_ROAMING; 1572 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1573 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) { 1574 switch (ireq.i_val) { 1575 case IEEE80211_ROAMING_DEVICE: 1576 LINE_CHECK("%croaming DEVICE", spacer); 1577 break; 1578 case IEEE80211_ROAMING_AUTO: 1579 LINE_CHECK("%croaming AUTO", spacer); 1580 break; 1581 case IEEE80211_ROAMING_MANUAL: 1582 LINE_CHECK("%croaming MANUAL", spacer); 1583 break; 1584 default: 1585 LINE_CHECK("%croaming UNKNOWN (0x%x)", 1586 spacer, ireq.i_val); 1587 break; 1588 } 1589 } 1590 } 1591 } 1592 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL; 1593 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1594 if (ireq.i_val) 1595 LINE_CHECK("%cbintval %u", spacer, ireq.i_val); 1596 else if (verbose) 1597 LINE_CHECK("%cbintval %u", spacer, ireq.i_val); 1598 } 1599 1600 if (wme && verbose) { 1601 LINE_BREAK(); 1602 list_wme(s); 1603 } 1604 1605 if (wpa) { 1606 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES; 1607 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1608 if (ireq.i_val) 1609 LINE_CHECK("%ccountermeasures", spacer); 1610 else if (verbose) 1611 LINE_CHECK("%c-countermeasures", spacer); 1612 } 1613#if 0 1614 /* XXX not interesting with WPA done in user space */ 1615 ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 1616 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1617 } 1618 1619 ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 1620 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1621 printf("%cmcastcipher ", spacer); 1622 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 1623 spacer = ' '; 1624 } 1625 1626 ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 1627 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1628 printf("%cucastcipher ", spacer); 1629 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 1630 } 1631 1632 if (wpa & 2) { 1633 ireq.i_type = IEEE80211_IOC_RSNCAPS; 1634 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1635 printf("%cRSN caps 0x%x", spacer, ireq.i_val); 1636 spacer = ' '; 1637 } 1638 } 1639 1640 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 1641 if (ioctl(s, SIOCG80211, &ireq) != -1) { 1642 } 1643#endif 1644 LINE_BREAK(); 1645 } 1646 LINE_BREAK(); 1647 1648end: 1649 return; 1650} 1651 1652static void 1653set80211(int s, int type, int val, int len, u_int8_t *data) 1654{ 1655 struct ieee80211req ireq; 1656 1657 (void) memset(&ireq, 0, sizeof(ireq)); 1658 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1659 ireq.i_type = type; 1660 ireq.i_val = val; 1661 ireq.i_len = len; 1662 ireq.i_data = data; 1663 if (ioctl(s, SIOCS80211, &ireq) < 0) 1664 err(1, "SIOCS80211"); 1665} 1666 1667static const char * 1668get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 1669{ 1670 int len; 1671 int hexstr; 1672 u_int8_t *p; 1673 1674 len = *lenp; 1675 p = buf; 1676 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 1677 if (hexstr) 1678 val += 2; 1679 for (;;) { 1680 if (*val == '\0') 1681 break; 1682 if (sep != NULL && strchr(sep, *val) != NULL) { 1683 val++; 1684 break; 1685 } 1686 if (hexstr) { 1687 if (!isxdigit((u_char)val[0])) { 1688 warnx("bad hexadecimal digits"); 1689 return NULL; 1690 } 1691 if (!isxdigit((u_char)val[1])) { 1692 warnx("odd count hexadecimal digits"); 1693 return NULL; 1694 } 1695 } 1696 if (p >= buf + len) { 1697 if (hexstr) 1698 warnx("hexadecimal digits too long"); 1699 else 1700 warnx("string too long"); 1701 return NULL; 1702 } 1703 if (hexstr) { 1704#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 1705 *p++ = (tohex((u_char)val[0]) << 4) | 1706 tohex((u_char)val[1]); 1707#undef tohex 1708 val += 2; 1709 } else 1710 *p++ = *val++; 1711 } 1712 len = p - buf; 1713 /* The string "-" is treated as the empty string. */ 1714 if (!hexstr && len == 1 && buf[0] == '-') 1715 len = 0; 1716 if (len < *lenp) 1717 memset(p, 0, *lenp - len); 1718 *lenp = len; 1719 return val; 1720} 1721 1722static void 1723print_string(const u_int8_t *buf, int len) 1724{ 1725 int i; 1726 int hasspc; 1727 1728 i = 0; 1729 hasspc = 0; 1730 for (; i < len; i++) { 1731 if (!isprint(buf[i]) && buf[i] != '\0') 1732 break; 1733 if (isspace(buf[i])) 1734 hasspc++; 1735 } 1736 if (i == len) { 1737 if (hasspc || len == 0 || buf[0] == '\0') 1738 printf("\"%.*s\"", len, buf); 1739 else 1740 printf("%.*s", len, buf); 1741 } else { 1742 printf("0x"); 1743 for (i = 0; i < len; i++) 1744 printf("%02x", buf[i]); 1745 } 1746} 1747 1748static struct cmd ieee80211_cmds[] = { 1749 DEF_CMD_ARG("ssid", set80211ssid), 1750 DEF_CMD_ARG("nwid", set80211ssid), 1751 DEF_CMD_ARG("stationname", set80211stationname), 1752 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 1753 DEF_CMD_ARG("channel", set80211channel), 1754 DEF_CMD_ARG("authmode", set80211authmode), 1755 DEF_CMD_ARG("powersavemode", set80211powersavemode), 1756 DEF_CMD("powersave", 1, set80211powersave), 1757 DEF_CMD("-powersave", 0, set80211powersave), 1758 DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 1759 DEF_CMD_ARG("wepmode", set80211wepmode), 1760 DEF_CMD("wep", 1, set80211wep), 1761 DEF_CMD("-wep", 0, set80211wep), 1762 DEF_CMD_ARG("deftxkey", set80211weptxkey), 1763 DEF_CMD_ARG("weptxkey", set80211weptxkey), 1764 DEF_CMD_ARG("wepkey", set80211wepkey), 1765 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 1766 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 1767 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 1768 DEF_CMD_ARG("protmode", set80211protmode), 1769 DEF_CMD_ARG("txpower", set80211txpower), 1770 DEF_CMD_ARG("roaming", set80211roaming), 1771 DEF_CMD("wme", 1, set80211wme), 1772 DEF_CMD("-wme", 0, set80211wme), 1773 DEF_CMD("hidessid", 1, set80211hidessid), 1774 DEF_CMD("-hidessid", 0, set80211hidessid), 1775 DEF_CMD("apbridge", 1, set80211apbridge), 1776 DEF_CMD("-apbridge", 0, set80211apbridge), 1777 DEF_CMD_ARG("chanlist", set80211chanlist), 1778 DEF_CMD_ARG("bssid", set80211bssid), 1779 DEF_CMD_ARG("ap", set80211bssid), 1780 DEF_CMD("scan", 0, set80211scan), 1781 DEF_CMD_ARG("list", set80211list), 1782 DEF_CMD_ARG2("cwmin", set80211cwmin), 1783 DEF_CMD_ARG2("cwmax", set80211cwmax), 1784 DEF_CMD_ARG2("aifs", set80211aifs), 1785 DEF_CMD_ARG2("txoplimit", set80211txoplimit), 1786 DEF_CMD("acm", 1, set80211acm), 1787 DEF_CMD("-acm", 0, set80211acm), 1788 DEF_CMD("ack", 1, set80211ackpolicy), 1789 DEF_CMD("-ack", 0, set80211ackpolicy), 1790 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 1791 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 1792 DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 1793 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 1794 DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 1795 DEF_CMD_ARG("bintval", set80211bintval), 1796 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 1797 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 1798 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 1799 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 1800 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 1801 DEF_CMD_ARG("mac:add", set80211addmac), 1802 DEF_CMD_ARG("mac:del", set80211delmac), 1803#if 0 1804 DEF_CMD_ARG("mac:kick", set80211kickmac), 1805#endif 1806 DEF_CMD("pureg", 1, set80211pureg), 1807 DEF_CMD("-pureg", 0, set80211pureg), 1808}; 1809static struct afswtch af_ieee80211 = { 1810 .af_name = "af_ieee80211", 1811 .af_af = AF_UNSPEC, 1812 .af_other_status = ieee80211_status, 1813}; 1814 1815static __constructor void 1816ieee80211_ctor(void) 1817{ 1818#define N(a) (sizeof(a) / sizeof(a[0])) 1819 int i; 1820 1821 for (i = 0; i < N(ieee80211_cmds); i++) 1822 cmd_register(&ieee80211_cmds[i]); 1823 af_register(&af_ieee80211); 1824#undef N 1825} 1826