ifieee80211.c revision 139493
177218Sphk/* 277218Sphk * Copyright 2001 The Aerospace Corporation. All rights reserved. 377218Sphk * 477218Sphk * Redistribution and use in source and binary forms, with or without 577218Sphk * modification, are permitted provided that the following conditions 677218Sphk * are met: 777218Sphk * 1. Redistributions of source code must retain the above copyright 877218Sphk * notice, this list of conditions and the following disclaimer. 977218Sphk * 2. Redistributions in binary form must reproduce the above copyright 1077218Sphk * notice, this list of conditions and the following disclaimer in the 1177218Sphk * documentation and/or other materials provided with the distribution. 1291454Sbrooks * 3. The name of The Aerospace Corporation may not be used to endorse or 1391454Sbrooks * promote products derived from this software. 1477218Sphk * 1577218Sphk * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND 1677218Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1777218Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1877218Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE 1977218Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2077218Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2177218Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2277218Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2377218Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2477218Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2577218Sphk * SUCH DAMAGE. 2677218Sphk * 2777218Sphk * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 139493 2004-12-31 19:39:25Z sam $ 2877218Sphk */ 2977218Sphk 3077218Sphk/*- 3177218Sphk * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 3277218Sphk * All rights reserved. 3377218Sphk * 3477218Sphk * This code is derived from software contributed to The NetBSD Foundation 3577218Sphk * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 3677218Sphk * NASA Ames Research Center. 3777218Sphk * 3877218Sphk * Redistribution and use in source and binary forms, with or without 3977218Sphk * modification, are permitted provided that the following conditions 4077218Sphk * are met: 4177218Sphk * 1. Redistributions of source code must retain the above copyright 4277218Sphk * notice, this list of conditions and the following disclaimer. 4377218Sphk * 2. Redistributions in binary form must reproduce the above copyright 4477218Sphk * notice, this list of conditions and the following disclaimer in the 4577218Sphk * documentation and/or other materials provided with the distribution. 4677218Sphk * 3. All advertising materials mentioning features or use of this software 4777218Sphk * must display the following acknowledgement: 4877218Sphk * This product includes software developed by the NetBSD 4977218Sphk * Foundation, Inc. and its contributors. 5077218Sphk * 4. Neither the name of The NetBSD Foundation nor the names of its 5177218Sphk * contributors may be used to endorse or promote products derived 5277218Sphk * from this software without specific prior written permission. 5377218Sphk * 5477218Sphk * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 5577218Sphk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 5677218Sphk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 5777218Sphk * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 5877218Sphk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5977218Sphk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 6077218Sphk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 6177218Sphk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 6277218Sphk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 6377218Sphk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 6477218Sphk * POSSIBILITY OF SUCH DAMAGE. 6577218Sphk */ 6677218Sphk 6777218Sphk#include <sys/param.h> 6877218Sphk#include <sys/ioctl.h> 6977218Sphk#include <sys/socket.h> 7077218Sphk#include <sys/sysctl.h> 7177218Sphk#include <sys/time.h> 7277218Sphk 7377218Sphk#include <net/ethernet.h> 7477218Sphk#include <net/if.h> 7577218Sphk#include <net/if_dl.h> 7677218Sphk#include <net/if_types.h> 77138593Ssam#include <net/if_media.h> 7877218Sphk#include <net/route.h> 79138593Ssam 80116957Ssam#include <net80211/ieee80211.h> 81120178Ssam#include <net80211/ieee80211_crypto.h> 82116957Ssam#include <net80211/ieee80211_ioctl.h> 8377218Sphk 8477218Sphk#include <ctype.h> 8577218Sphk#include <err.h> 8677218Sphk#include <errno.h> 8777218Sphk#include <fcntl.h> 8877218Sphk#include <stdio.h> 8977218Sphk#include <stdlib.h> 9077218Sphk#include <string.h> 9177218Sphk#include <unistd.h> 9277218Sphk 9377218Sphk#include "ifconfig.h" 9477218Sphk 9577218Sphkstatic void set80211(int s, int type, int val, int len, u_int8_t *data); 9677218Sphkstatic const char *get_string(const char *val, const char *sep, 9777218Sphk u_int8_t *buf, int *lenp); 9877218Sphkstatic void print_string(const u_int8_t *buf, int len); 9977218Sphk 100138593Ssamstatic int 101138593Ssamisanyarg(const char *arg) 102138593Ssam{ 103138593Ssam return (strcmp(arg, "-") == 0 || 104138593Ssam strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0); 105138593Ssam} 106138593Ssam 107138593Ssamstatic void 10877218Sphkset80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 10977218Sphk{ 11077218Sphk int ssid; 11177218Sphk int len; 11277218Sphk u_int8_t data[33]; 11377218Sphk 11477218Sphk ssid = 0; 115121827Sbrooks len = strlen(val); 11688748Sambrisko if (len > 2 && isdigit(val[0]) && val[1] == ':') { 11788748Sambrisko ssid = atoi(val)-1; 11888748Sambrisko val += 2; 11988748Sambrisko } 12077218Sphk 12177218Sphk bzero(data, sizeof(data)); 12277218Sphk len = sizeof(data); 12377218Sphk get_string(val, NULL, data, &len); 12477218Sphk 12577218Sphk set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 12677218Sphk} 12777218Sphk 128138593Ssamstatic void 12977218Sphkset80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 13077218Sphk{ 13177218Sphk int len; 13277218Sphk u_int8_t data[33]; 13377218Sphk 13477218Sphk bzero(data, sizeof(data)); 13577218Sphk len = sizeof(data); 13677218Sphk get_string(val, NULL, data, &len); 13777218Sphk 13877218Sphk set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 13977218Sphk} 14077218Sphk 141138593Ssam/* 142138593Ssam * Convert IEEE channel number to MHz frequency. 143138593Ssam */ 144138593Ssamstatic u_int 145138593Ssamieee80211_ieee2mhz(u_int chan) 146138593Ssam{ 147138593Ssam if (chan == 14) 148138593Ssam return 2484; 149138593Ssam if (chan < 14) /* 0-13 */ 150138593Ssam return 2407 + chan*5; 151138593Ssam if (chan < 27) /* 15-26 */ 152138593Ssam return 2512 + ((chan-15)*20); 153138593Ssam return 5000 + (chan*5); 154138593Ssam} 155138593Ssam 156138593Ssam/* 157138593Ssam * Convert MHz frequency to IEEE channel number. 158138593Ssam */ 159138593Ssamstatic u_int 160138593Ssamieee80211_mhz2ieee(u_int freq) 161138593Ssam{ 162138593Ssam if (freq == 2484) 163138593Ssam return 14; 164138593Ssam if (freq < 2484) 165138593Ssam return (freq - 2407) / 5; 166138593Ssam if (freq < 5000) 167138593Ssam return 15 + ((freq - 2512) / 20); 168138593Ssam return (freq - 5000) / 5; 169138593Ssam} 170138593Ssam 171138593Ssamstatic void 17277218Sphkset80211channel(const char *val, int d, int s, const struct afswtch *rafp) 17377218Sphk{ 174138593Ssam if (!isanyarg(val)) { 175138593Ssam int v = atoi(val); 176138593Ssam if (v > 255) /* treat as frequency */ 177138593Ssam v = ieee80211_mhz2ieee(v); 178138593Ssam set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL); 179138593Ssam } else 180116957Ssam set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); 18177218Sphk} 18277218Sphk 183138593Ssamstatic void 18477218Sphkset80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 18577218Sphk{ 18677218Sphk int mode; 18777218Sphk 18891454Sbrooks if (strcasecmp(val, "none") == 0) { 18977218Sphk mode = IEEE80211_AUTH_NONE; 19091454Sbrooks } else if (strcasecmp(val, "open") == 0) { 19177218Sphk mode = IEEE80211_AUTH_OPEN; 19291454Sbrooks } else if (strcasecmp(val, "shared") == 0) { 19377218Sphk mode = IEEE80211_AUTH_SHARED; 194138593Ssam } else if (strcasecmp(val, "8021x") == 0) { 195138593Ssam mode = IEEE80211_AUTH_8021X; 196138593Ssam } else if (strcasecmp(val, "wpa") == 0) { 197138593Ssam mode = IEEE80211_AUTH_WPA; 19877218Sphk } else { 19977218Sphk err(1, "unknown authmode"); 20077218Sphk } 20177218Sphk 20277218Sphk set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 20377218Sphk} 20477218Sphk 205138593Ssamstatic void 20677218Sphkset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 20777218Sphk{ 20877218Sphk int mode; 20977218Sphk 21091454Sbrooks if (strcasecmp(val, "off") == 0) { 21177218Sphk mode = IEEE80211_POWERSAVE_OFF; 21291454Sbrooks } else if (strcasecmp(val, "on") == 0) { 21377218Sphk mode = IEEE80211_POWERSAVE_ON; 21491454Sbrooks } else if (strcasecmp(val, "cam") == 0) { 21577218Sphk mode = IEEE80211_POWERSAVE_CAM; 21691454Sbrooks } else if (strcasecmp(val, "psp") == 0) { 21777218Sphk mode = IEEE80211_POWERSAVE_PSP; 21891454Sbrooks } else if (strcasecmp(val, "psp-cam") == 0) { 21977218Sphk mode = IEEE80211_POWERSAVE_PSP_CAM; 22077218Sphk } else { 22177218Sphk err(1, "unknown powersavemode"); 22277218Sphk } 22377218Sphk 22477218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 22577218Sphk} 22677218Sphk 227138593Ssamstatic void 22877218Sphkset80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 22977218Sphk{ 23077218Sphk if (d == 0) 23177218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 23277218Sphk 0, NULL); 23377218Sphk else 23477218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 23577218Sphk 0, NULL); 23677218Sphk} 23777218Sphk 238138593Ssamstatic void 23977218Sphkset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 24077218Sphk{ 24177218Sphk set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 24277218Sphk} 24377218Sphk 244138593Ssamstatic void 24577218Sphkset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 24677218Sphk{ 24777218Sphk int mode; 24877218Sphk 24991454Sbrooks if (strcasecmp(val, "off") == 0) { 25077218Sphk mode = IEEE80211_WEP_OFF; 25191454Sbrooks } else if (strcasecmp(val, "on") == 0) { 25277218Sphk mode = IEEE80211_WEP_ON; 25391454Sbrooks } else if (strcasecmp(val, "mixed") == 0) { 25477218Sphk mode = IEEE80211_WEP_MIXED; 25577218Sphk } else { 25677218Sphk err(1, "unknown wep mode"); 25777218Sphk } 25877218Sphk 25977218Sphk set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 26077218Sphk} 26177218Sphk 262138593Ssamstatic void 26377218Sphkset80211wep(const char *val, int d, int s, const struct afswtch *rafp) 26477218Sphk{ 26577218Sphk set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 26677218Sphk} 26777218Sphk 268139493Ssamstatic int 269139493Ssamisundefarg(const char *arg) 270139493Ssam{ 271139493Ssam return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 272139493Ssam} 273139493Ssam 274138593Ssamstatic void 27577218Sphkset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 27677218Sphk{ 277139493Ssam if (isundefarg(val)) 278139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 279139493Ssam else 280139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 28177218Sphk} 28277218Sphk 283138593Ssamstatic void 28477218Sphkset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 28577218Sphk{ 28677218Sphk int key = 0; 28777218Sphk int len; 288120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 28977218Sphk 29091454Sbrooks if (isdigit(val[0]) && val[1] == ':') { 29177218Sphk key = atoi(val)-1; 29277218Sphk val += 2; 29377218Sphk } 29477218Sphk 29577218Sphk bzero(data, sizeof(data)); 29677218Sphk len = sizeof(data); 29777218Sphk get_string(val, NULL, data, &len); 29877218Sphk 29977218Sphk set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 30077218Sphk} 30177218Sphk 30277218Sphk/* 30377218Sphk * This function is purly a NetBSD compatability interface. The NetBSD 30477218Sphk * iterface is too inflexable, but it's there so we'll support it since 30577218Sphk * it's not all that hard. 30677218Sphk */ 307138593Ssamstatic void 30877218Sphkset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 30977218Sphk{ 31077218Sphk int txkey; 31177218Sphk int i, len; 312120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 31377218Sphk 31477218Sphk set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 31577218Sphk 31691454Sbrooks if (isdigit(val[0]) && val[1] == ':') { 31777218Sphk txkey = val[0]-'0'-1; 31877218Sphk val += 2; 31977218Sphk 32091454Sbrooks for (i = 0; i < 4; i++) { 32177218Sphk bzero(data, sizeof(data)); 32277218Sphk len = sizeof(data); 32377218Sphk val = get_string(val, ",", data, &len); 32477218Sphk 32577218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 32677218Sphk } 32777218Sphk } else { 32877218Sphk bzero(data, sizeof(data)); 32977218Sphk len = sizeof(data); 33077218Sphk get_string(val, NULL, data, &len); 33177218Sphk txkey = 0; 33277218Sphk 33377218Sphk set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 33477218Sphk 33577218Sphk bzero(data, sizeof(data)); 33691454Sbrooks for (i = 1; i < 4; i++) 33777218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 33877218Sphk } 33977218Sphk 34077218Sphk set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 34177218Sphk} 34277218Sphk 343138593Ssamstatic void 344127649Ssamset80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 345127649Ssam{ 346127649Ssam set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL); 347127649Ssam} 348127649Ssam 349138593Ssamstatic void 350127649Ssamset80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 351127649Ssam{ 352127649Ssam int mode; 353127649Ssam 354127649Ssam if (strcasecmp(val, "off") == 0) { 355127649Ssam mode = IEEE80211_PROTMODE_OFF; 356127649Ssam } else if (strcasecmp(val, "cts") == 0) { 357127649Ssam mode = IEEE80211_PROTMODE_CTS; 358127649Ssam } else if (strcasecmp(val, "rtscts") == 0) { 359127649Ssam mode = IEEE80211_PROTMODE_RTSCTS; 360127649Ssam } else { 361127649Ssam err(1, "unknown protection mode"); 362127649Ssam } 363127649Ssam 364127649Ssam set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 365127649Ssam} 366127649Ssam 367138593Ssamstatic void 368127649Ssamset80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 369127649Ssam{ 370127649Ssam set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); 371127649Ssam} 372127649Ssam 373138593Ssam#define IEEE80211_ROAMING_DEVICE 0 374138593Ssam#define IEEE80211_ROAMING_AUTO 1 375138593Ssam#define IEEE80211_ROAMING_MANUAL 2 376138593Ssam 377138593Ssamstatic void 378138593Ssamset80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 37977218Sphk{ 380138593Ssam int mode; 38177218Sphk 382138593Ssam if (strcasecmp(val, "device") == 0) { 383138593Ssam mode = IEEE80211_ROAMING_DEVICE; 384138593Ssam } else if (strcasecmp(val, "auto") == 0) { 385138593Ssam mode = IEEE80211_ROAMING_AUTO; 386138593Ssam } else if (strcasecmp(val, "manual") == 0) { 387138593Ssam mode = IEEE80211_ROAMING_MANUAL; 388138593Ssam } else { 389138593Ssam err(1, "unknown roaming mode"); 390138593Ssam } 391138593Ssam set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 392138593Ssam} 393138593Ssam 394138593Ssamstatic void 395138593Ssamset80211wme(const char *val, int d, int s, const struct afswtch *rafp) 396138593Ssam{ 397138593Ssam set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 398138593Ssam} 399138593Ssam 400138593Ssamstatic void 401138593Ssamset80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 402138593Ssam{ 403138593Ssam set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 404138593Ssam} 405138593Ssam 406138593Ssamstatic void 407138593Ssamset80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 408138593Ssam{ 409138593Ssam set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 410138593Ssam} 411138593Ssam 412138593Ssamstatic void 413138593Ssamset80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 414138593Ssam{ 415138593Ssam struct ieee80211req_chanlist chanlist; 416138593Ssam#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) 417138593Ssam char *temp, *cp, *tp; 418138593Ssam 419138593Ssam temp = malloc(strlen(val) + 1); 420138593Ssam if (temp == NULL) 421138593Ssam errx(1, "malloc failed"); 422138593Ssam strcpy(temp, val); 423138593Ssam memset(&chanlist, 0, sizeof(chanlist)); 424138593Ssam cp = temp; 425138593Ssam for (;;) { 426138593Ssam int first, last, f; 427138593Ssam 428138593Ssam tp = strchr(cp, ','); 429138593Ssam if (tp != NULL) 430138593Ssam *tp++ = '\0'; 431138593Ssam switch (sscanf(cp, "%u-%u", &first, &last)) { 432138593Ssam case 1: 433138593Ssam if (first > MAXCHAN) 434138593Ssam errx(-1, "channel %u out of range, max %u", 435138593Ssam first, MAXCHAN); 436138593Ssam setbit(chanlist.ic_channels, first); 437138593Ssam break; 438138593Ssam case 2: 439138593Ssam if (first > MAXCHAN) 440138593Ssam errx(-1, "channel %u out of range, max %u", 441138593Ssam first, MAXCHAN); 442138593Ssam if (last > MAXCHAN) 443138593Ssam errx(-1, "channel %u out of range, max %u", 444138593Ssam last, MAXCHAN); 445138593Ssam if (first > last) 446138593Ssam errx(-1, "void channel range, %u > %u", 447138593Ssam first, last); 448138593Ssam for (f = first; f <= last; f++) 449138593Ssam setbit(chanlist.ic_channels, f); 450138593Ssam break; 451138593Ssam } 452138593Ssam if (tp == NULL) 453138593Ssam break; 454138593Ssam while (isspace(*tp)) 455138593Ssam tp++; 456138593Ssam if (!isdigit(*tp)) 457138593Ssam break; 458138593Ssam cp = tp; 459138593Ssam } 460138593Ssam set80211(s, IEEE80211_IOC_CHANLIST, 0, 461138593Ssam sizeof(chanlist), (uint8_t *) &chanlist); 462138593Ssam#undef MAXCHAN 463138593Ssam} 464138593Ssam 465138593Ssamstatic void 466138593Ssamset80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 467138593Ssam{ 468138593Ssam 469138593Ssam if (!isanyarg(val)) { 470138593Ssam char *temp; 471138593Ssam struct sockaddr_dl sdl; 472138593Ssam 473138593Ssam temp = malloc(strlen(val) + 1); 474138593Ssam if (temp == NULL) 475138593Ssam errx(1, "malloc failed"); 476138593Ssam temp[0] = ':'; 477138593Ssam strcpy(temp + 1, val); 478138593Ssam sdl.sdl_len = sizeof(sdl); 479138593Ssam link_addr(temp, &sdl); 480138593Ssam free(temp); 481138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 482138593Ssam errx(1, "malformed link-level address"); 483138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 484138593Ssam IEEE80211_ADDR_LEN, LLADDR(&sdl)); 485138593Ssam } else { 486138593Ssam uint8_t zerobssid[IEEE80211_ADDR_LEN]; 487138593Ssam memset(zerobssid, 0, sizeof(zerobssid)); 488138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 489138593Ssam IEEE80211_ADDR_LEN, zerobssid); 490138593Ssam } 491138593Ssam} 492138593Ssam 493138593Ssamstatic int 494138593Ssamgetac(const char *ac) 495138593Ssam{ 496138593Ssam if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 497138593Ssam return WME_AC_BE; 498138593Ssam if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 499138593Ssam return WME_AC_BK; 500138593Ssam if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 501138593Ssam return WME_AC_VI; 502138593Ssam if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 503138593Ssam return WME_AC_VO; 504138593Ssam errx(1, "unknown wme access class %s", ac); 505138593Ssam} 506138593Ssam 507138593Ssamstatic 508138593SsamDECL_CMD_FUNC2(set80211cwmin, ac, val) 509138593Ssam{ 510138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 511138593Ssam} 512138593Ssam 513138593Ssamstatic 514138593SsamDECL_CMD_FUNC2(set80211cwmax, ac, val) 515138593Ssam{ 516138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 517138593Ssam} 518138593Ssam 519138593Ssamstatic 520138593SsamDECL_CMD_FUNC2(set80211aifs, ac, val) 521138593Ssam{ 522138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 523138593Ssam} 524138593Ssam 525138593Ssamstatic 526138593SsamDECL_CMD_FUNC2(set80211txoplimit, ac, val) 527138593Ssam{ 528138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 529138593Ssam} 530138593Ssam 531138593Ssamstatic 532138593SsamDECL_CMD_FUNC(set80211acm, val, d) 533138593Ssam{ 534138593Ssam set80211(s, IEEE80211_IOC_WME_ACM, d, WME_AC_BE, NULL); 535138593Ssam} 536138593Ssam 537138593Ssamstatic 538138593SsamDECL_CMD_FUNC(set80211ackpolicy, val, d) 539138593Ssam{ 540138593Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, d, WME_AC_BE, NULL); 541138593Ssam} 542138593Ssam 543138593Ssamstatic 544138593SsamDECL_CMD_FUNC2(set80211bsscwmin, ac, val) 545138593Ssam{ 546138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 547138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 548138593Ssam} 549138593Ssam 550138593Ssamstatic 551138593SsamDECL_CMD_FUNC2(set80211bsscwmax, ac, val) 552138593Ssam{ 553138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 554138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 555138593Ssam} 556138593Ssam 557138593Ssamstatic 558138593SsamDECL_CMD_FUNC2(set80211bssaifs, ac, val) 559138593Ssam{ 560138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 561138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 562138593Ssam} 563138593Ssam 564138593Ssamstatic 565138593SsamDECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 566138593Ssam{ 567138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 568138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 569138593Ssam} 570138593Ssam 571138593Ssamstatic 572138593SsamDECL_CMD_FUNC(set80211dtimperiod, val, d) 573138593Ssam{ 574138593Ssam set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 575138593Ssam} 576138593Ssam 577138593Ssamstatic 578138593SsamDECL_CMD_FUNC(set80211bintval, val, d) 579138593Ssam{ 580138593Ssam set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 581138593Ssam} 582138593Ssam 583138593Ssamstatic void 584138593Ssamset80211macmac(int s, int op, const char *val) 585138593Ssam{ 586138593Ssam char *temp; 587138593Ssam struct sockaddr_dl sdl; 588138593Ssam 589138593Ssam temp = malloc(strlen(val) + 1); 590138593Ssam if (temp == NULL) 591138593Ssam errx(1, "malloc failed"); 592138593Ssam temp[0] = ':'; 593138593Ssam strcpy(temp + 1, val); 594138593Ssam sdl.sdl_len = sizeof(sdl); 595138593Ssam link_addr(temp, &sdl); 596138593Ssam free(temp); 597138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 598138593Ssam errx(1, "malformed link-level address"); 599138593Ssam set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 600138593Ssam} 601138593Ssam 602138593Ssamstatic 603138593SsamDECL_CMD_FUNC(set80211addmac, val, d) 604138593Ssam{ 605138593Ssam set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 606138593Ssam} 607138593Ssam 608138593Ssamstatic 609138593SsamDECL_CMD_FUNC(set80211delmac, val, d) 610138593Ssam{ 611138593Ssam set80211macmac(s, IEEE80211_IOC_DELMAC, val); 612138593Ssam} 613138593Ssam 614138593Ssamstatic 615138593SsamDECL_CMD_FUNC(set80211maccmd, val, d) 616138593Ssam{ 617138593Ssam set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 618138593Ssam} 619138593Ssam 620138593Ssamstatic int 621138593Ssamgetmaxrate(uint8_t rates[15], uint8_t nrates) 622138593Ssam{ 623138593Ssam int i, maxrate = -1; 624138593Ssam 625138593Ssam for (i = 0; i < nrates; i++) { 626138593Ssam int rate = rates[i] & IEEE80211_RATE_VAL; 627138593Ssam if (rate > maxrate) 628138593Ssam maxrate = rate; 629138593Ssam } 630138593Ssam return maxrate / 2; 631138593Ssam} 632138593Ssam 633138593Ssamstatic const char * 634138593Ssamgetcaps(int capinfo) 635138593Ssam{ 636138593Ssam static char capstring[32]; 637138593Ssam char *cp = capstring; 638138593Ssam 639138593Ssam if (capinfo & IEEE80211_CAPINFO_ESS) 640138593Ssam *cp++ = 'E'; 641138593Ssam if (capinfo & IEEE80211_CAPINFO_IBSS) 642138593Ssam *cp++ = 'I'; 643138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 644138593Ssam *cp++ = 'c'; 645138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 646138593Ssam *cp++ = 'C'; 647138593Ssam if (capinfo & IEEE80211_CAPINFO_PRIVACY) 648138593Ssam *cp++ = 'P'; 649138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 650138593Ssam *cp++ = 'S'; 651138593Ssam if (capinfo & IEEE80211_CAPINFO_PBCC) 652138593Ssam *cp++ = 'B'; 653138593Ssam if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 654138593Ssam *cp++ = 'A'; 655138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 656138593Ssam *cp++ = 's'; 657138593Ssam if (capinfo & IEEE80211_CAPINFO_RSN) 658138593Ssam *cp++ = 'R'; 659138593Ssam if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 660138593Ssam *cp++ = 'D'; 661138593Ssam *cp = '\0'; 662138593Ssam return capstring; 663138593Ssam} 664138593Ssam 665138593Ssamstatic void 666138593Ssamprintie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 667138593Ssam{ 668138593Ssam printf("%s", tag); 669138593Ssam if (verbose) { 670138593Ssam maxlen -= strlen(tag)+2; 671138593Ssam if (2*ielen > maxlen) 672138593Ssam maxlen--; 673138593Ssam printf("<"); 674138593Ssam for (; ielen > 0; ie++, ielen--) { 675138593Ssam if (maxlen-- <= 0) 676138593Ssam break; 677138593Ssam printf("%02x", *ie); 678138593Ssam } 679138593Ssam if (ielen != 0) 680138593Ssam printf("-"); 681138593Ssam printf(">"); 682138593Ssam } 683138593Ssam} 684138593Ssam 685138593Ssam/* 686138593Ssam * Copy the ssid string contents into buf, truncating to fit. If the 687138593Ssam * ssid is entirely printable then just copy intact. Otherwise convert 688138593Ssam * to hexadecimal. If the result is truncated then replace the last 689138593Ssam * three characters with "...". 690138593Ssam */ 691138593Ssamstatic size_t 692138593Ssamcopy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 693138593Ssam{ 694138593Ssam const u_int8_t *p; 695138593Ssam size_t maxlen; 696138593Ssam int i; 697138593Ssam 698138593Ssam if (essid_len > bufsize) 699138593Ssam maxlen = bufsize; 700138593Ssam else 701138593Ssam maxlen = essid_len; 702138593Ssam /* determine printable or not */ 703138593Ssam for (i = 0, p = essid; i < maxlen; i++, p++) { 704138593Ssam if (*p < ' ' || *p > 0x7e) 705138593Ssam break; 706138593Ssam } 707138593Ssam if (i != maxlen) { /* not printable, print as hex */ 708138593Ssam if (bufsize < 3) 709138593Ssam return 0; 710138593Ssam strlcpy(buf, "0x", bufsize); 711138593Ssam bufsize -= 2; 712138593Ssam p = essid; 713138593Ssam for (i = 0; i < maxlen && bufsize >= 2; i++) { 714138593Ssam sprintf(&buf[2+2*i], "%02x", *p++); 715138593Ssam bufsize -= 2; 716138593Ssam } 717138593Ssam maxlen = 2+2*i; 718138593Ssam } else { /* printable, truncate as needed */ 719138593Ssam memcpy(buf, essid, maxlen); 720138593Ssam } 721138593Ssam if (maxlen != essid_len) 722138593Ssam memcpy(buf+maxlen-3, "...", 3); 723138593Ssam return maxlen; 724138593Ssam} 725138593Ssam 726138593Ssam/* unalligned little endian access */ 727138593Ssam#define LE_READ_4(p) \ 728138593Ssam ((u_int32_t) \ 729138593Ssam ((((const u_int8_t *)(p))[0] ) | \ 730138593Ssam (((const u_int8_t *)(p))[1] << 8) | \ 731138593Ssam (((const u_int8_t *)(p))[2] << 16) | \ 732138593Ssam (((const u_int8_t *)(p))[3] << 24))) 733138593Ssam 734138593Ssamstatic int __inline 735138593Ssamiswpaoui(const u_int8_t *frm) 736138593Ssam{ 737138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 738138593Ssam} 739138593Ssam 740138593Ssamstatic int __inline 741138593Ssamiswmeoui(const u_int8_t *frm) 742138593Ssam{ 743138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); 744138593Ssam} 745138593Ssam 746138593Ssamstatic int __inline 747138593Ssamisatherosoui(const u_int8_t *frm) 748138593Ssam{ 749138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 750138593Ssam} 751138593Ssam 752138593Ssamstatic void 753138593Ssamprinties(const u_int8_t *vp, int ielen, int maxcols) 754138593Ssam{ 755138593Ssam while (ielen > 0) { 756138593Ssam switch (vp[0]) { 757138593Ssam case IEEE80211_ELEMID_VENDOR: 758138593Ssam if (iswpaoui(vp)) 759138593Ssam printie(" WPA", vp, 2+vp[1], maxcols); 760138593Ssam else if (iswmeoui(vp)) 761138593Ssam printie(" WME", vp, 2+vp[1], maxcols); 762139492Ssam else if (isatherosoui(vp)) 763139492Ssam printie(" ATH", vp, 2+vp[1], maxcols); 764138593Ssam else 765138593Ssam printie(" VEN", vp, 2+vp[1], maxcols); 766138593Ssam break; 767138593Ssam case IEEE80211_ELEMID_RSN: 768138593Ssam printie(" RSN", vp, 2+vp[1], maxcols); 769138593Ssam break; 770138593Ssam default: 771138593Ssam printie(" ???", vp, 2+vp[1], maxcols); 772138593Ssam break; 773138593Ssam } 774138593Ssam ielen -= 2+vp[1]; 775138593Ssam vp += 2+vp[1]; 776138593Ssam } 777138593Ssam} 778138593Ssam 779138593Ssamstatic void 780138593Ssamlist_scan(int s) 781138593Ssam{ 782138593Ssam uint8_t buf[24*1024]; 783138593Ssam struct ieee80211req ireq; 784138593Ssam char ssid[14]; 785138593Ssam uint8_t *cp; 786138593Ssam int len; 787138593Ssam 78877218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 78977218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 790138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; 791138593Ssam ireq.i_data = buf; 792138593Ssam ireq.i_len = sizeof(buf); 793138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 794138593Ssam errx(1, "unable to get scan results"); 795138593Ssam len = ireq.i_len; 796138593Ssam if (len < sizeof(struct ieee80211req_scan_result)) 797138593Ssam return; 798138593Ssam 799138593Ssam printf("%-14.14s %-17.17s %4s %4s %-5s %3s %4s\n" 800138593Ssam , "SSID" 801138593Ssam , "BSSID" 802138593Ssam , "CHAN" 803138593Ssam , "RATE" 804138593Ssam , "S:N" 805138593Ssam , "INT" 806138593Ssam , "CAPS" 807138593Ssam ); 808138593Ssam cp = buf; 809138593Ssam do { 810138593Ssam struct ieee80211req_scan_result *sr; 811138593Ssam uint8_t *vp; 812138593Ssam 813138593Ssam sr = (struct ieee80211req_scan_result *) cp; 814138593Ssam vp = (u_int8_t *)(sr+1); 815138593Ssam printf("%-14.*s %s %3d %3dM %2d:%-2d %3d %-4.4s" 816138593Ssam , copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len) 817138593Ssam , ssid 818138593Ssam , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 819138593Ssam , ieee80211_mhz2ieee(sr->isr_freq) 820138593Ssam , getmaxrate(sr->isr_rates, sr->isr_nrates) 821138593Ssam , sr->isr_rssi, sr->isr_noise 822138593Ssam , sr->isr_intval 823138593Ssam , getcaps(sr->isr_capinfo) 824138593Ssam ); 825138593Ssam printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);; 826138593Ssam printf("\n"); 827138593Ssam cp += sr->isr_len, len -= sr->isr_len; 828138593Ssam } while (len >= sizeof(struct ieee80211req_scan_result)); 829138593Ssam} 830138593Ssam 831138593Ssam#include <net80211/ieee80211_freebsd.h> 832138593Ssam 833138593Ssamstatic void 834138593Ssamscan_and_wait(int s) 835138593Ssam{ 836138593Ssam struct ieee80211req ireq; 837138593Ssam int sroute; 838138593Ssam 839138593Ssam sroute = socket(PF_ROUTE, SOCK_RAW, 0); 840138593Ssam if (sroute < 0) { 841138593Ssam perror("socket(PF_ROUTE,SOCK_RAW)"); 842138593Ssam return; 843138593Ssam } 844138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 845138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 846138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_REQ; 847138593Ssam /* NB: only root can trigger a scan so ignore errors */ 848138593Ssam if (ioctl(s, SIOCS80211, &ireq) >= 0) { 849138593Ssam char buf[2048]; 850138593Ssam struct if_announcemsghdr *ifan; 851138593Ssam struct rt_msghdr *rtm; 852138593Ssam 853138593Ssam do { 854138593Ssam if (read(sroute, buf, sizeof(buf)) < 0) { 855138593Ssam perror("read(PF_ROUTE)"); 856138593Ssam break; 857138593Ssam } 858138593Ssam rtm = (struct rt_msghdr *) buf; 859138593Ssam if (rtm->rtm_version != RTM_VERSION) 860138593Ssam break; 861138593Ssam ifan = (struct if_announcemsghdr *) rtm; 862138593Ssam } while (rtm->rtm_type != RTM_IEEE80211 || 863138593Ssam ifan->ifan_what != RTM_IEEE80211_SCAN); 864138593Ssam } 865138593Ssam close(sroute); 866138593Ssam} 867138593Ssam 868138593Ssamstatic 869138593SsamDECL_CMD_FUNC(set80211scan, val, d) 870138593Ssam{ 871138593Ssam scan_and_wait(s); 872138593Ssam list_scan(s); 873138593Ssam} 874138593Ssam 875138593Ssamstatic void 876138593Ssamlist_stations(int s) 877138593Ssam{ 878138593Ssam uint8_t buf[24*1024]; 879138593Ssam struct ieee80211req ireq; 880138593Ssam uint8_t *cp; 881138593Ssam int len; 882138593Ssam 883138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 884138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 885138593Ssam ireq.i_type = IEEE80211_IOC_STA_INFO; 886138593Ssam ireq.i_data = buf; 887138593Ssam ireq.i_len = sizeof(buf); 888138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 889138593Ssam errx(1, "unable to get station information"); 890138593Ssam len = ireq.i_len; 891138593Ssam if (len < sizeof(struct ieee80211req_sta_info)) 892138593Ssam return; 893138593Ssam 894138593Ssam printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n" 895138593Ssam , "ADDR" 896138593Ssam , "AID" 897138593Ssam , "CHAN" 898138593Ssam , "RATE" 899138593Ssam , "RSSI" 900138593Ssam , "IDLE" 901138593Ssam , "TXSEQ" 902138593Ssam , "RXSEQ" 903138593Ssam , "CAPS" 904138593Ssam , "ERP" 905138593Ssam ); 906138593Ssam cp = buf; 907138593Ssam do { 908138593Ssam struct ieee80211req_sta_info *si; 909138593Ssam uint8_t *vp; 910138593Ssam 911138593Ssam si = (struct ieee80211req_sta_info *) cp; 912138593Ssam vp = (u_int8_t *)(si+1); 913138593Ssam printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x" 914138593Ssam , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 915138593Ssam , IEEE80211_AID(si->isi_associd) 916138593Ssam , ieee80211_mhz2ieee(si->isi_freq) 917138593Ssam , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2 918138593Ssam , si->isi_rssi 919138593Ssam , si->isi_inact 920138593Ssam , si->isi_txseqs[0] 921138593Ssam , si->isi_rxseqs[0] 922138593Ssam , getcaps(si->isi_capinfo) 923138593Ssam , si->isi_erp 924138593Ssam ); 925138593Ssam printies(vp, si->isi_ie_len, 24); 926138593Ssam printf("\n"); 927138593Ssam cp += si->isi_len, len -= si->isi_len; 928138593Ssam } while (len >= sizeof(struct ieee80211req_sta_info)); 929138593Ssam} 930138593Ssam 931138593Ssamstatic void 932138593Ssamprint_chaninfo(const struct ieee80211_channel *c) 933138593Ssam{ 934138593Ssam#define IEEE80211_IS_CHAN_PASSIVE(_c) \ 935138593Ssam (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE)) 936138593Ssam char buf[14]; 937138593Ssam 938138593Ssam buf[0] = '\0'; 939138593Ssam if (IEEE80211_IS_CHAN_FHSS(c)) 940138593Ssam strlcat(buf, " FHSS", sizeof(buf)); 941138593Ssam if (IEEE80211_IS_CHAN_A(c)) 942138593Ssam strlcat(buf, " 11a", sizeof(buf)); 943138593Ssam /* XXX 11g schizophrenia */ 944138593Ssam if (IEEE80211_IS_CHAN_G(c) || 945138593Ssam IEEE80211_IS_CHAN_PUREG(c)) 946138593Ssam strlcat(buf, " 11g", sizeof(buf)); 947138593Ssam else if (IEEE80211_IS_CHAN_B(c)) 948138593Ssam strlcat(buf, " 11b", sizeof(buf)); 949138593Ssam if (IEEE80211_IS_CHAN_T(c)) 950138593Ssam strlcat(buf, " Turbo", sizeof(buf)); 951138593Ssam printf("Channel %3u : %u%c Mhz%-14.14s", 952138593Ssam ieee80211_mhz2ieee(c->ic_freq), c->ic_freq, 953138593Ssam IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf); 954138593Ssam#undef IEEE80211_IS_CHAN_PASSIVE 955138593Ssam} 956138593Ssam 957138593Ssamstatic void 958138593Ssamlist_channels(int s, int allchans) 959138593Ssam{ 960138593Ssam struct ieee80211req ireq; 961138593Ssam struct ieee80211req_chaninfo chans; 962138593Ssam struct ieee80211req_chaninfo achans; 963138593Ssam const struct ieee80211_channel *c; 964138593Ssam int i, half; 965138593Ssam 966138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 967138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 968138593Ssam ireq.i_type = IEEE80211_IOC_CHANINFO; 969138593Ssam ireq.i_data = &chans; 970138593Ssam ireq.i_len = sizeof(chans); 971138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 972138593Ssam errx(1, "unable to get channel information"); 973138593Ssam if (!allchans) { 974138593Ssam struct ieee80211req_chanlist active; 975138593Ssam 976138593Ssam ireq.i_type = IEEE80211_IOC_CHANLIST; 977138593Ssam ireq.i_data = &active; 978138593Ssam ireq.i_len = sizeof(active); 979138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 980138593Ssam errx(1, "unable to get active channel list"); 981138593Ssam memset(&achans, 0, sizeof(achans)); 982138593Ssam for (i = 0; i < chans.ic_nchans; i++) { 983138593Ssam c = &chans.ic_chans[i]; 984138593Ssam if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans) 985138593Ssam achans.ic_chans[achans.ic_nchans++] = *c; 986138593Ssam } 987138593Ssam } else 988138593Ssam achans = chans; 989138593Ssam half = achans.ic_nchans / 2; 990138593Ssam if (achans.ic_nchans % 2) 991138593Ssam half++; 992138593Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 993138593Ssam print_chaninfo(&achans.ic_chans[i]); 994138593Ssam print_chaninfo(&achans.ic_chans[half+i]); 995138593Ssam printf("\n"); 996138593Ssam } 997138593Ssam if (achans.ic_nchans % 2) { 998138593Ssam print_chaninfo(&achans.ic_chans[i]); 999138593Ssam printf("\n"); 1000138593Ssam } 1001138593Ssam} 1002138593Ssam 1003138593Ssamstatic void 1004138593Ssamlist_keys(int s) 1005138593Ssam{ 1006138593Ssam} 1007138593Ssam 1008138593Ssam#define IEEE80211_C_BITS \ 1009138593Ssam"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \ 1010138593Ssam"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \ 1011138593Ssam"\31WPA2\32BURST\33WME" 1012138593Ssam 1013138593Ssamstatic void 1014138593Ssamlist_capabilities(int s) 1015138593Ssam{ 1016138593Ssam struct ieee80211req ireq; 1017138593Ssam u_int32_t caps; 1018138593Ssam 1019138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1020138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1021138593Ssam ireq.i_type = IEEE80211_IOC_DRIVER_CAPS; 1022138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1023138593Ssam errx(1, "unable to get driver capabilities"); 1024138593Ssam caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len); 1025138593Ssam printb(name, caps, IEEE80211_C_BITS); 1026138593Ssam putchar('\n'); 1027138593Ssam} 1028138593Ssam 1029138593Ssamstatic void 1030138593Ssamlist_wme(int s) 1031138593Ssam{ 1032138593Ssam static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 1033138593Ssam struct ieee80211req ireq; 1034138593Ssam int ac; 1035138593Ssam 1036138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1037138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1038138593Ssam ireq.i_len = 0; 1039138593Ssam for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 1040138593Ssamagain: 1041138593Ssam if (ireq.i_len & IEEE80211_WMEPARAM_BSS) 1042138593Ssam printf("\t%s", " "); 1043138593Ssam else 1044138593Ssam printf("\t%s", acnames[ac]); 1045138593Ssam 1046138593Ssam ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac; 1047138593Ssam 1048138593Ssam /* show WME BSS parameters */ 1049138593Ssam ireq.i_type = IEEE80211_IOC_WME_CWMIN; 1050138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1051138593Ssam printf(" cwmin %2u", ireq.i_val); 1052138593Ssam ireq.i_type = IEEE80211_IOC_WME_CWMAX; 1053138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1054138593Ssam printf(" cwmax %2u", ireq.i_val); 1055138593Ssam ireq.i_type = IEEE80211_IOC_WME_AIFS; 1056138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1057138593Ssam printf(" aifs %2u", ireq.i_val); 1058138593Ssam ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT; 1059138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1060138593Ssam printf(" txopLimit %3u", ireq.i_val); 1061138593Ssam ireq.i_type = IEEE80211_IOC_WME_ACM; 1062138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1063138593Ssam if (ireq.i_val) 1064138593Ssam printf(" acm"); 1065138593Ssam else if (verbose) 1066138593Ssam printf(" -acm"); 1067138593Ssam } 1068138593Ssam /* !BSS only */ 1069138593Ssam if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1070138593Ssam ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY; 1071138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1072138593Ssam if (!ireq.i_val) 1073138593Ssam printf(" -ack"); 1074138593Ssam else if (verbose) 1075138593Ssam printf(" ack"); 1076138593Ssam } 1077138593Ssam } 1078138593Ssam printf("\n"); 1079138593Ssam if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1080138593Ssam ireq.i_len |= IEEE80211_WMEPARAM_BSS; 1081138593Ssam goto again; 1082138593Ssam } else 1083138593Ssam ireq.i_len &= ~IEEE80211_WMEPARAM_BSS; 1084138593Ssam } 1085138593Ssam} 1086138593Ssam 1087138593Ssamstatic 1088138593SsamDECL_CMD_FUNC(set80211list, arg, d) 1089138593Ssam{ 1090138593Ssam#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 1091138593Ssam 1092138593Ssam if (iseq(arg, "sta")) 1093138593Ssam list_stations(s); 1094138593Ssam else if (iseq(arg, "scan") || iseq(arg, "ap")) 1095138593Ssam list_scan(s); 1096138593Ssam else if (iseq(arg, "chan") || iseq(arg, "freq")) 1097138593Ssam list_channels(s, 1); 1098138593Ssam else if (iseq(arg, "active")) 1099138593Ssam list_channels(s, 0); 1100138593Ssam else if (iseq(arg, "keys")) 1101138593Ssam list_keys(s); 1102138593Ssam else if (iseq(arg, "caps")) 1103138593Ssam list_capabilities(s); 1104138593Ssam else if (iseq(arg, "wme")) 1105138593Ssam list_wme(s); 1106138593Ssam else 1107138593Ssam errx(1, "Don't know how to list %s for %s", arg, name); 1108138593Ssam#undef iseq 1109138593Ssam} 1110138593Ssam 1111138593Ssamstatic enum ieee80211_opmode 1112138593Ssamget80211opmode(int s) 1113138593Ssam{ 1114138593Ssam struct ifmediareq ifmr; 1115138593Ssam 1116138593Ssam (void) memset(&ifmr, 0, sizeof(ifmr)); 1117138593Ssam (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 1118138593Ssam 1119138593Ssam if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 1120138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 1121138593Ssam return IEEE80211_M_IBSS; /* XXX ahdemo */ 1122138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 1123138593Ssam return IEEE80211_M_HOSTAP; 1124138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 1125138593Ssam return IEEE80211_M_MONITOR; 1126138593Ssam } 1127138593Ssam return IEEE80211_M_STA; 1128138593Ssam} 1129138593Ssam 1130138593Ssamstatic const struct ieee80211_channel * 1131138593Ssamgetchaninfo(int s, int chan) 1132138593Ssam{ 1133138593Ssam struct ieee80211req ireq; 1134138593Ssam static struct ieee80211req_chaninfo chans; 1135138593Ssam static struct ieee80211_channel undef; 1136138593Ssam const struct ieee80211_channel *c; 1137138593Ssam int i, freq; 1138138593Ssam 1139138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1140138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1141138593Ssam ireq.i_type = IEEE80211_IOC_CHANINFO; 1142138593Ssam ireq.i_data = &chans; 1143138593Ssam ireq.i_len = sizeof(chans); 1144138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1145138593Ssam errx(1, "unable to get channel information"); 1146138593Ssam freq = ieee80211_ieee2mhz(chan); 1147138593Ssam for (i = 0; i < chans.ic_nchans; i++) { 1148138593Ssam c = &chans.ic_chans[i]; 1149138593Ssam if (c->ic_freq == freq) 1150138593Ssam return c; 1151138593Ssam } 1152138593Ssam return &undef; 1153138593Ssam} 1154138593Ssam 1155138593Ssam#if 0 1156138593Ssamstatic void 1157138593Ssamprintcipher(int s, struct ieee80211req *ireq, int keylenop) 1158138593Ssam{ 1159138593Ssam switch (ireq->i_val) { 1160138593Ssam case IEEE80211_CIPHER_WEP: 1161138593Ssam ireq->i_type = keylenop; 1162138593Ssam if (ioctl(s, SIOCG80211, ireq) != -1) 1163138593Ssam printf("WEP-%s", 1164138593Ssam ireq->i_len <= 5 ? "40" : 1165138593Ssam ireq->i_len <= 13 ? "104" : "128"); 1166138593Ssam else 1167138593Ssam printf("WEP"); 1168138593Ssam break; 1169138593Ssam case IEEE80211_CIPHER_TKIP: 1170138593Ssam printf("TKIP"); 1171138593Ssam break; 1172138593Ssam case IEEE80211_CIPHER_AES_OCB: 1173138593Ssam printf("AES-OCB"); 1174138593Ssam break; 1175138593Ssam case IEEE80211_CIPHER_AES_CCM: 1176138593Ssam printf("AES-CCM"); 1177138593Ssam break; 1178138593Ssam case IEEE80211_CIPHER_CKIP: 1179138593Ssam printf("CKIP"); 1180138593Ssam break; 1181138593Ssam case IEEE80211_CIPHER_NONE: 1182138593Ssam printf("NONE"); 1183138593Ssam break; 1184138593Ssam default: 1185138593Ssam printf("UNKNOWN (0x%x)", ireq->i_val); 1186138593Ssam break; 1187138593Ssam } 1188138593Ssam} 1189138593Ssam#endif 1190138593Ssam 1191138593Ssam#define MAXCOL 78 1192138593Ssamint col; 1193138593Ssamchar spacer; 1194138593Ssam 1195138593Ssam#define LINE_BREAK() do { \ 1196138593Ssam if (spacer != '\t') { \ 1197138593Ssam printf("\n"); \ 1198138593Ssam spacer = '\t'; \ 1199138593Ssam } \ 1200138593Ssam col = 8; /* 8-col tab */ \ 1201138593Ssam} while (0) 1202138593Ssam#define LINE_CHECK(fmt, ...) do { \ 1203138593Ssam col += sizeof(fmt)-2; \ 1204138593Ssam if (col > MAXCOL) { \ 1205138593Ssam LINE_BREAK(); \ 1206138593Ssam col += sizeof(fmt)-2; \ 1207138593Ssam } \ 1208138593Ssam printf(fmt, __VA_ARGS__); \ 1209138593Ssam spacer = ' '; \ 1210138593Ssam} while (0) 1211138593Ssam 1212138593Ssamstatic void 1213138593Ssamprintkey(const struct ieee80211req_key *ik) 1214138593Ssam{ 1215138593Ssam static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 1216138593Ssam int keylen = ik->ik_keylen; 1217138593Ssam int printcontents; 1218138593Ssam 1219138593Ssam printcontents = 1220138593Ssam (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 1221138593Ssam if (printcontents) 1222138593Ssam LINE_BREAK(); 1223138593Ssam switch (ik->ik_type) { 1224138593Ssam case IEEE80211_CIPHER_WEP: 1225138593Ssam /* compatibility */ 1226138593Ssam LINE_CHECK("%cwepkey %u:%s", spacer, ik->ik_keyix+1, 1227138593Ssam keylen <= 5 ? "40-bit" : 1228138593Ssam keylen <= 13 ? "104-bit" : "128-bit"); 1229138593Ssam break; 1230138593Ssam case IEEE80211_CIPHER_TKIP: 1231138593Ssam if (keylen > 128/8) 1232138593Ssam keylen -= 128/8; /* ignore MIC for now */ 1233138593Ssam LINE_CHECK("%cTKIP %u:%u-bit", 1234138593Ssam spacer, ik->ik_keyix+1, 8*keylen); 1235138593Ssam break; 1236138593Ssam case IEEE80211_CIPHER_AES_OCB: 1237138593Ssam LINE_CHECK("%cAES-OCB %u:%u-bit", 1238138593Ssam spacer, ik->ik_keyix+1, 8*keylen); 1239138593Ssam break; 1240138593Ssam case IEEE80211_CIPHER_AES_CCM: 1241138593Ssam LINE_CHECK("%cAES-CCM %u:%u-bit", 1242138593Ssam spacer, ik->ik_keyix+1, 8*keylen); 1243138593Ssam break; 1244138593Ssam case IEEE80211_CIPHER_CKIP: 1245138593Ssam LINE_CHECK("%cCKIP %u:%u-bit", 1246138593Ssam spacer, ik->ik_keyix+1, 8*keylen); 1247138593Ssam break; 1248138593Ssam case IEEE80211_CIPHER_NONE: 1249138593Ssam LINE_CHECK("%cNULL %u:%u-bit", 1250138593Ssam spacer, ik->ik_keyix+1, 8*keylen); 1251138593Ssam break; 1252138593Ssam default: 1253138593Ssam LINE_CHECK("%cUNKNOWN (0x%x) %u:%u-bit", spacer, 1254138593Ssam ik->ik_type, ik->ik_keyix+1, 8*keylen); 1255138593Ssam break; 1256138593Ssam } 1257138593Ssam if (printcontents) { 1258138593Ssam int i; 1259138593Ssam 1260138593Ssam printf(" <"); 1261138593Ssam for (i = 0; i < keylen; i++) 1262138593Ssam printf("%02x", ik->ik_keydata[i]); 1263138593Ssam printf(">"); 1264138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 1265138593Ssam (ik->ik_keyrsc != 0 || verbose)) 1266138593Ssam printf(" rsc %llu", ik->ik_keyrsc); 1267138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 1268138593Ssam (ik->ik_keytsc != 0 || verbose)) 1269138593Ssam printf(" tsc %llu", ik->ik_keytsc); 1270138593Ssam if (ik->ik_flags != 0 && verbose) { 1271138593Ssam const char *sep = " "; 1272138593Ssam 1273138593Ssam if (ik->ik_flags & IEEE80211_KEY_XMIT) 1274138593Ssam printf("%stx", sep), sep = "+"; 1275138593Ssam if (ik->ik_flags & IEEE80211_KEY_RECV) 1276138593Ssam printf("%srx", sep), sep = "+"; 1277138593Ssam if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 1278138593Ssam printf("%sdef", sep), sep = "+"; 1279138593Ssam } 1280138593Ssam LINE_BREAK(); 1281138593Ssam } 1282138593Ssam} 1283138593Ssam 1284138593Ssamstatic void 1285138593Ssamieee80211_status(int s, const struct rt_addrinfo *info __unused) 1286138593Ssam{ 1287138593Ssam static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 1288138593Ssam enum ieee80211_opmode opmode = get80211opmode(s); 1289138593Ssam int i, num, wpa, wme; 1290138593Ssam struct ieee80211req ireq; 1291138593Ssam u_int8_t data[32]; 1292138593Ssam const struct ieee80211_channel *c; 1293138593Ssam 1294138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1295138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 129677218Sphk ireq.i_data = &data; 129777218Sphk 1298138593Ssam wpa = 0; /* unknown/not set */ 1299138593Ssam 130077218Sphk ireq.i_type = IEEE80211_IOC_SSID; 130177218Sphk ireq.i_val = -1; 130277218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 130377218Sphk /* If we can't get the SSID, the this isn't an 802.11 device. */ 130477218Sphk return; 130577218Sphk } 130688748Sambrisko num = 0; 130788748Sambrisko ireq.i_type = IEEE80211_IOC_NUMSSIDS; 1308138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0) 130988748Sambrisko num = ireq.i_val; 1310138593Ssam printf("\tssid "); 1311138593Ssam if (num > 1) { 1312138593Ssam ireq.i_type = IEEE80211_IOC_SSID; 1313138593Ssam for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 1314138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 1315138593Ssam printf(" %d:", ireq.i_val + 1); 1316138593Ssam print_string(data, ireq.i_len); 1317138593Ssam } 131888748Sambrisko } 1319138593Ssam } else 1320138593Ssam print_string(data, ireq.i_len); 132177218Sphk 1322138593Ssam ireq.i_type = IEEE80211_IOC_CHANNEL; 1323138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1324138593Ssam goto end; 1325138593Ssam c = getchaninfo(s, ireq.i_val); 1326138593Ssam if (ireq.i_val != -1) { 1327138593Ssam printf(" channel %d", ireq.i_val); 1328138593Ssam if (verbose) 1329138593Ssam printf(" (%u)", c->ic_freq); 1330138593Ssam } else if (verbose) 1331138593Ssam printf(" channel UNDEF"); 1332138593Ssam 1333138593Ssam ireq.i_type = IEEE80211_IOC_BSSID; 1334138593Ssam ireq.i_len = IEEE80211_ADDR_LEN; 1335138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0 && 1336138593Ssam memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0) 1337138593Ssam printf(" bssid %s", ether_ntoa(ireq.i_data)); 1338138593Ssam 133977218Sphk ireq.i_type = IEEE80211_IOC_STATIONNAME; 134077218Sphk if (ioctl(s, SIOCG80211, &ireq) != -1) { 1341138593Ssam printf("\n\tstationname "); 134277218Sphk print_string(data, ireq.i_len); 134377218Sphk } 134477218Sphk 1345138593Ssam spacer = ' '; /* force first break */ 1346138593Ssam LINE_BREAK(); 134777218Sphk 134877218Sphk ireq.i_type = IEEE80211_IOC_AUTHMODE; 134977218Sphk if (ioctl(s, SIOCG80211, &ireq) != -1) { 135077218Sphk switch (ireq.i_val) { 135177218Sphk case IEEE80211_AUTH_NONE: 1352138593Ssam LINE_CHECK("%cauthmode NONE", spacer); 135377218Sphk break; 135477218Sphk case IEEE80211_AUTH_OPEN: 1355138593Ssam LINE_CHECK("%cauthmode OPEN", spacer); 135677218Sphk break; 135777218Sphk case IEEE80211_AUTH_SHARED: 1358138593Ssam LINE_CHECK("%cauthmode SHARED", spacer); 135977218Sphk break; 1360138593Ssam case IEEE80211_AUTH_8021X: 1361138593Ssam LINE_CHECK("%cauthmode 802.1x", spacer); 136277218Sphk break; 1363138593Ssam case IEEE80211_AUTH_WPA: 1364138593Ssam ireq.i_type = IEEE80211_IOC_WPA; 1365138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1366138593Ssam wpa = ireq.i_val; 1367138593Ssam if (!wpa) 1368138593Ssam wpa = 1; /* default to WPA1 */ 1369138593Ssam switch (wpa) { 1370138593Ssam case 2: 1371138593Ssam LINE_CHECK("%cauthmode WPA2/802.11i", 1372138593Ssam spacer); 1373138593Ssam break; 1374138593Ssam case 3: 1375138593Ssam LINE_CHECK("%cauthmode WPA1+WPA2/802.11i", 1376138593Ssam spacer); 1377138593Ssam break; 1378138593Ssam default: 1379138593Ssam LINE_CHECK("%cauthmode WPA", spacer); 1380138593Ssam break; 1381138593Ssam } 138277218Sphk break; 1383138593Ssam case IEEE80211_AUTH_AUTO: 1384138593Ssam LINE_CHECK("%cauthmode AUTO", spacer); 138577218Sphk break; 1386127649Ssam default: 1387138593Ssam LINE_CHECK("%cauthmode UNKNOWN (0x%x)", 1388138593Ssam spacer, ireq.i_val); 1389127649Ssam break; 1390127649Ssam } 1391127649Ssam } 1392127649Ssam 139377218Sphk ireq.i_type = IEEE80211_IOC_WEP; 139480315Sbrooks if (ioctl(s, SIOCG80211, &ireq) != -1 && 139580315Sbrooks ireq.i_val != IEEE80211_WEP_NOSUP) { 1396138718Ssam int firstkey, wepmode; 1397138593Ssam 1398138718Ssam wepmode = ireq.i_val; 1399138718Ssam switch (wepmode) { 140077218Sphk case IEEE80211_WEP_OFF: 1401138593Ssam LINE_CHECK("%cprivacy OFF", spacer); 140277218Sphk break; 140377218Sphk case IEEE80211_WEP_ON: 1404138593Ssam LINE_CHECK("%cprivacy ON", spacer); 140577218Sphk break; 140677218Sphk case IEEE80211_WEP_MIXED: 1407138593Ssam LINE_CHECK("%cprivacy MIXED", spacer); 140877218Sphk break; 140977218Sphk default: 1410138593Ssam LINE_CHECK("%cprivacy UNKNOWN (0x%x)", 1411138718Ssam spacer, wepmode); 141277218Sphk break; 141377218Sphk } 141477218Sphk 141577218Sphk /* 141677218Sphk * If we get here then we've got WEP support so we need 141777218Sphk * to print WEP status. 141891454Sbrooks */ 141977218Sphk 142077218Sphk ireq.i_type = IEEE80211_IOC_WEPTXKEY; 142177218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 142277218Sphk warn("WEP support, but no tx key!"); 142377218Sphk goto end; 142477218Sphk } 1425138593Ssam if (ireq.i_val != -1) 1426138593Ssam LINE_CHECK("%cdeftxkey %d", spacer, ireq.i_val+1); 1427138718Ssam else if (wepmode != IEEE80211_WEP_OFF || verbose) 1428138593Ssam LINE_CHECK("%cdeftxkey UNDEF", spacer); 142977218Sphk 143077218Sphk ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 143177218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 143277218Sphk warn("WEP support, but no NUMWEPKEYS support!"); 143377218Sphk goto end; 143477218Sphk } 143577218Sphk num = ireq.i_val; 143677218Sphk 1437138593Ssam firstkey = 1; 1438138593Ssam for (i = 0; i < num; i++) { 1439138593Ssam struct ieee80211req_key ik; 144077218Sphk 1441138593Ssam memset(&ik, 0, sizeof(ik)); 1442138593Ssam ik.ik_keyix = i; 1443138593Ssam ireq.i_type = IEEE80211_IOC_WPAKEY; 1444138593Ssam ireq.i_data = &ik; 1445138593Ssam ireq.i_len = sizeof(ik); 144677218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 144777218Sphk warn("WEP support, but can get keys!"); 144877218Sphk goto end; 144977218Sphk } 1450138593Ssam if (ik.ik_keylen != 0) { 1451138593Ssam if (verbose) 1452138593Ssam LINE_BREAK(); 1453138593Ssam printkey(&ik); 1454138593Ssam firstkey = 0; 1455138593Ssam } 1456138593Ssam } 1457138593Ssam } 1458138593Ssam 1459138593Ssam ireq.i_type = IEEE80211_IOC_POWERSAVE; 1460138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1 && 1461138593Ssam ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 1462138593Ssam if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) { 1463138593Ssam switch (ireq.i_val) { 1464138593Ssam case IEEE80211_POWERSAVE_OFF: 1465138593Ssam LINE_CHECK("%cpowersavemode OFF", 1466138593Ssam spacer); 1467138593Ssam break; 1468138593Ssam case IEEE80211_POWERSAVE_CAM: 1469138593Ssam LINE_CHECK("%cpowersavemode CAM", 1470138593Ssam spacer); 1471138593Ssam break; 1472138593Ssam case IEEE80211_POWERSAVE_PSP: 1473138593Ssam LINE_CHECK("%cpowersavemode PSP", 1474138593Ssam spacer); 1475138593Ssam break; 1476138593Ssam case IEEE80211_POWERSAVE_PSP_CAM: 1477138593Ssam LINE_CHECK("%cpowersavemode PSP-CAM", 1478138593Ssam spacer); 1479138593Ssam break; 1480138593Ssam } 1481138593Ssam ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 1482138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1483138593Ssam LINE_CHECK("%cpowersavesleep %d", 1484138593Ssam spacer, ireq.i_val); 1485138593Ssam } 1486138593Ssam } 1487138593Ssam 1488138593Ssam ireq.i_type = IEEE80211_IOC_TXPOWMAX; 1489138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1490138593Ssam LINE_CHECK("%ctxpowmax %d", spacer, ireq.i_val); 1491138593Ssam 1492138593Ssam if (verbose) { 1493138593Ssam ireq.i_type = IEEE80211_IOC_TXPOWER; 1494138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1495138593Ssam LINE_CHECK("%ctxpower %d", spacer, ireq.i_val); 1496138593Ssam } 1497138593Ssam 1498138593Ssam ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; 1499138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1500138593Ssam if (ireq.i_val != IEEE80211_RTS_MAX || verbose) 1501138593Ssam LINE_CHECK("%crtsthreshold %d", spacer, ireq.i_val); 1502138593Ssam } 1503138593Ssam 1504138593Ssam if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) { 1505138593Ssam ireq.i_type = IEEE80211_IOC_PROTMODE; 1506138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1507138593Ssam switch (ireq.i_val) { 1508138593Ssam case IEEE80211_PROTMODE_OFF: 1509138593Ssam LINE_CHECK("%cprotmode OFF", spacer); 1510138593Ssam break; 1511138593Ssam case IEEE80211_PROTMODE_CTS: 1512138593Ssam LINE_CHECK("%cprotmode CTS", spacer); 1513138593Ssam break; 1514138593Ssam case IEEE80211_PROTMODE_RTSCTS: 1515138593Ssam LINE_CHECK("%cprotmode RTSCTS", spacer); 1516138593Ssam break; 1517138593Ssam default: 1518138593Ssam LINE_CHECK("%cprotmode UNKNOWN (0x%x)", 1519138593Ssam spacer, ireq.i_val); 1520138593Ssam break; 1521138593Ssam } 1522138593Ssam } 1523138593Ssam } 1524138593Ssam 1525138593Ssam ireq.i_type = IEEE80211_IOC_WME; 1526138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1527138593Ssam wme = ireq.i_val; 1528138593Ssam if (wme) 1529138593Ssam LINE_CHECK("%cwme", spacer); 1530138593Ssam else if (verbose) 1531138593Ssam LINE_CHECK("%c-wme", spacer); 1532138593Ssam } else 1533138593Ssam wme = 0; 1534138593Ssam 1535138593Ssam if (opmode == IEEE80211_M_HOSTAP) { 1536138593Ssam ireq.i_type = IEEE80211_IOC_HIDESSID; 1537138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1538138593Ssam if (ireq.i_val) 1539138593Ssam LINE_CHECK("%cssid HIDE", spacer); 1540138593Ssam else if (verbose) 1541138593Ssam LINE_CHECK("%cssid SHOW", spacer); 1542138593Ssam } 1543138593Ssam 1544138593Ssam ireq.i_type = IEEE80211_IOC_APBRIDGE; 1545138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1546138593Ssam if (!ireq.i_val) 1547138593Ssam LINE_CHECK("%c-apbridge", spacer); 1548138593Ssam else if (verbose) 1549138593Ssam LINE_CHECK("%capbridge", spacer); 1550138593Ssam } 1551138593Ssam 1552138593Ssam ireq.i_type = IEEE80211_IOC_DTIM_PERIOD; 1553138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1554138593Ssam LINE_CHECK("%cdtimperiod %u", spacer, ireq.i_val); 1555138593Ssam } else { 1556138593Ssam ireq.i_type = IEEE80211_IOC_ROAMING; 1557138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1558138593Ssam if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) { 1559138593Ssam switch (ireq.i_val) { 1560138593Ssam case IEEE80211_ROAMING_DEVICE: 1561138593Ssam LINE_CHECK("%croaming DEVICE", spacer); 1562138593Ssam break; 1563138593Ssam case IEEE80211_ROAMING_AUTO: 1564138593Ssam LINE_CHECK("%croaming AUTO", spacer); 1565138593Ssam break; 1566138593Ssam case IEEE80211_ROAMING_MANUAL: 1567138593Ssam LINE_CHECK("%croaming MANUAL", spacer); 1568138593Ssam break; 1569138593Ssam default: 1570138593Ssam LINE_CHECK("%croaming UNKNOWN (0x%x)", 1571138593Ssam spacer, ireq.i_val); 1572138593Ssam break; 1573138593Ssam } 1574138593Ssam } 1575138593Ssam } 1576138593Ssam } 1577138593Ssam ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL; 1578138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1579138593Ssam if (ireq.i_val) 1580138593Ssam LINE_CHECK("%cbintval %u", spacer, ireq.i_val); 1581138593Ssam else if (verbose) 1582138593Ssam LINE_CHECK("%cbintval %u", spacer, ireq.i_val); 1583138593Ssam } 1584138593Ssam 1585138593Ssam if (wme && verbose) { 1586138593Ssam LINE_BREAK(); 1587138593Ssam list_wme(s); 1588138593Ssam } 1589138593Ssam 1590138593Ssam if (wpa) { 1591138593Ssam ireq.i_type = IEEE80211_IOC_COUNTERMEASURES; 1592138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1593138593Ssam if (ireq.i_val) 1594138593Ssam LINE_CHECK("%ccountermeasures", spacer); 1595138593Ssam else if (verbose) 1596138593Ssam LINE_CHECK("%c-countermeasures", spacer); 1597138593Ssam } 1598138593Ssam#if 0 1599138593Ssam /* XXX not interesting with WPA done in user space */ 1600138593Ssam ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 1601138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1602138593Ssam } 1603138593Ssam 1604138593Ssam ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 1605138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1606138593Ssam printf("%cmcastcipher ", spacer); 1607138593Ssam printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 1608138593Ssam spacer = ' '; 1609138593Ssam } 1610138593Ssam 1611138593Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 1612138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1613138593Ssam printf("%cucastcipher ", spacer); 1614138593Ssam printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 1615138593Ssam } 1616138593Ssam 1617138593Ssam if (wpa & 2) { 1618138593Ssam ireq.i_type = IEEE80211_IOC_RSNCAPS; 1619138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1620138593Ssam printf("%cRSN caps 0x%x", spacer, ireq.i_val); 162177218Sphk spacer = ' '; 1622138593Ssam } 162377218Sphk } 1624138593Ssam 1625138593Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 1626138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1627138593Ssam } 1628138593Ssam#endif 1629138593Ssam LINE_BREAK(); 163077218Sphk } 1631138593Ssam LINE_BREAK(); 163277218Sphk 163377218Sphkend: 163477218Sphk return; 163577218Sphk} 163677218Sphk 163777218Sphkstatic void 163877218Sphkset80211(int s, int type, int val, int len, u_int8_t *data) 163977218Sphk{ 164077218Sphk struct ieee80211req ireq; 164177218Sphk 164277218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 164377218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 164477218Sphk ireq.i_type = type; 164577218Sphk ireq.i_val = val; 164677218Sphk ireq.i_len = len; 164777218Sphk ireq.i_data = data; 164891454Sbrooks if (ioctl(s, SIOCS80211, &ireq) < 0) 164977218Sphk err(1, "SIOCS80211"); 165077218Sphk} 165177218Sphk 165277218Sphkstatic const char * 165377218Sphkget_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 165477218Sphk{ 165577218Sphk int len; 165677218Sphk int hexstr; 165777218Sphk u_int8_t *p; 165877218Sphk 165977218Sphk len = *lenp; 166077218Sphk p = buf; 166177218Sphk hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 166277218Sphk if (hexstr) 166377218Sphk val += 2; 166477218Sphk for (;;) { 166577218Sphk if (*val == '\0') 166677218Sphk break; 166777218Sphk if (sep != NULL && strchr(sep, *val) != NULL) { 166877218Sphk val++; 166977218Sphk break; 167077218Sphk } 167177218Sphk if (hexstr) { 1672127831Sphk if (!isxdigit((u_char)val[0])) { 167377218Sphk warnx("bad hexadecimal digits"); 167477218Sphk return NULL; 167577218Sphk } 1676127831Sphk if (!isxdigit((u_char)val[1])) { 1677127831Sphk warnx("odd count hexadecimal digits"); 1678127831Sphk return NULL; 1679127831Sphk } 168077218Sphk } 1681127831Sphk if (p >= buf + len) { 168277218Sphk if (hexstr) 168377218Sphk warnx("hexadecimal digits too long"); 168477218Sphk else 1685127831Sphk warnx("string too long"); 168677218Sphk return NULL; 168777218Sphk } 168877218Sphk if (hexstr) { 168977218Sphk#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 169077218Sphk *p++ = (tohex((u_char)val[0]) << 4) | 169177218Sphk tohex((u_char)val[1]); 169277218Sphk#undef tohex 169377218Sphk val += 2; 169477218Sphk } else 169577218Sphk *p++ = *val++; 169677218Sphk } 169777218Sphk len = p - buf; 169877218Sphk /* The string "-" is treated as the empty string. */ 169977218Sphk if (!hexstr && len == 1 && buf[0] == '-') 170077218Sphk len = 0; 170177218Sphk if (len < *lenp) 170277218Sphk memset(p, 0, *lenp - len); 170377218Sphk *lenp = len; 170477218Sphk return val; 170577218Sphk} 170677218Sphk 170777218Sphkstatic void 170877218Sphkprint_string(const u_int8_t *buf, int len) 170977218Sphk{ 171077218Sphk int i; 171177218Sphk int hasspc; 171277218Sphk 171377218Sphk i = 0; 171477218Sphk hasspc = 0; 171591454Sbrooks for (; i < len; i++) { 171677218Sphk if (!isprint(buf[i]) && buf[i] != '\0') 171777218Sphk break; 171877218Sphk if (isspace(buf[i])) 171977218Sphk hasspc++; 172077218Sphk } 172177218Sphk if (i == len) { 172277218Sphk if (hasspc || len == 0 || buf[0] == '\0') 172377218Sphk printf("\"%.*s\"", len, buf); 172477218Sphk else 172577218Sphk printf("%.*s", len, buf); 172677218Sphk } else { 172777218Sphk printf("0x"); 172877218Sphk for (i = 0; i < len; i++) 172977218Sphk printf("%02x", buf[i]); 173077218Sphk } 173177218Sphk} 173277218Sphk 1733138593Ssamstatic struct cmd ieee80211_cmds[] = { 1734138593Ssam DEF_CMD_ARG("ssid", set80211ssid), 1735138593Ssam DEF_CMD_ARG("nwid", set80211ssid), 1736138593Ssam DEF_CMD_ARG("stationname", set80211stationname), 1737138593Ssam DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 1738138593Ssam DEF_CMD_ARG("channel", set80211channel), 1739138593Ssam DEF_CMD_ARG("authmode", set80211authmode), 1740138593Ssam DEF_CMD_ARG("powersavemode", set80211powersavemode), 1741138593Ssam DEF_CMD("powersave", 1, set80211powersave), 1742138593Ssam DEF_CMD("-powersave", 0, set80211powersave), 1743138593Ssam DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 1744138593Ssam DEF_CMD_ARG("wepmode", set80211wepmode), 1745138593Ssam DEF_CMD("wep", 1, set80211wep), 1746138593Ssam DEF_CMD("-wep", 0, set80211wep), 1747139493Ssam DEF_CMD_ARG("deftxkey", set80211weptxkey), 1748138593Ssam DEF_CMD_ARG("weptxkey", set80211weptxkey), 1749138593Ssam DEF_CMD_ARG("wepkey", set80211wepkey), 1750138593Ssam DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 1751138593Ssam DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 1752138593Ssam DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 1753138593Ssam DEF_CMD_ARG("protmode", set80211protmode), 1754138593Ssam DEF_CMD_ARG("txpower", set80211txpower), 1755138593Ssam DEF_CMD_ARG("roaming", set80211roaming), 1756138593Ssam DEF_CMD("wme", 1, set80211wme), 1757138593Ssam DEF_CMD("-wme", 0, set80211wme), 1758138593Ssam DEF_CMD("hidessid", 1, set80211hidessid), 1759138593Ssam DEF_CMD("-hidessid", 0, set80211hidessid), 1760138593Ssam DEF_CMD("apbridge", 1, set80211apbridge), 1761138593Ssam DEF_CMD("-apbridge", 0, set80211apbridge), 1762138593Ssam DEF_CMD_ARG("chanlist", set80211chanlist), 1763138593Ssam DEF_CMD_ARG("bssid", set80211bssid), 1764138593Ssam DEF_CMD_ARG("ap", set80211bssid), 1765138593Ssam DEF_CMD("scan", 0, set80211scan), 1766138593Ssam DEF_CMD_ARG("list", set80211list), 1767138593Ssam DEF_CMD_ARG2("cwmin", set80211cwmin), 1768138593Ssam DEF_CMD_ARG2("cwmax", set80211cwmax), 1769138593Ssam DEF_CMD_ARG2("aifs", set80211aifs), 1770138593Ssam DEF_CMD_ARG2("txoplimit", set80211txoplimit), 1771138593Ssam DEF_CMD("acm", 1, set80211acm), 1772138593Ssam DEF_CMD("-acm", 0, set80211acm), 1773138593Ssam DEF_CMD("ack", 1, set80211ackpolicy), 1774138593Ssam DEF_CMD("-ack", 0, set80211ackpolicy), 1775138593Ssam DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 1776138593Ssam DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 1777138593Ssam DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 1778138593Ssam DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 1779138593Ssam DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 1780138593Ssam DEF_CMD_ARG("bintval", set80211bintval), 1781138593Ssam DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 1782138593Ssam DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 1783138593Ssam DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 1784138593Ssam DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 1785138593Ssam DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 1786138593Ssam DEF_CMD_ARG("mac:add", set80211addmac), 1787138593Ssam DEF_CMD_ARG("mac:del", set80211delmac), 1788138593Ssam#if 0 1789138593Ssam DEF_CMD_ARG("mac:kick", set80211kickmac), 1790138593Ssam#endif 1791138593Ssam}; 1792138593Ssamstatic struct afswtch af_ieee80211 = { 1793138593Ssam .af_name = "af_ieee80211", 1794138593Ssam .af_af = AF_UNSPEC, 1795138593Ssam .af_status = ieee80211_status, 1796138593Ssam}; 1797138593Ssam 1798138593Ssamstatic __constructor void 1799138593Ssamieee80211_ctor(void) 1800138593Ssam{ 1801138593Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 1802138593Ssam int i; 1803138593Ssam 1804138593Ssam for (i = 0; i < N(ieee80211_cmds); i++) 1805138593Ssam cmd_register(&ieee80211_cmds[i]); 1806138593Ssam af_register(&af_ieee80211); 1807138593Ssam#undef N 1808138593Ssam} 1809