ifieee80211.c revision 166015
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 166015 2007-01-15 01:20:28Z 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> 88146873Sjhb#include <inttypes.h> 8977218Sphk#include <stdio.h> 9077218Sphk#include <stdlib.h> 9177218Sphk#include <string.h> 9277218Sphk#include <unistd.h> 93155931Ssam#include <stdarg.h> 9477218Sphk 9577218Sphk#include "ifconfig.h" 9677218Sphk 9777218Sphkstatic void set80211(int s, int type, int val, int len, u_int8_t *data); 9877218Sphkstatic const char *get_string(const char *val, const char *sep, 9977218Sphk u_int8_t *buf, int *lenp); 10077218Sphkstatic void print_string(const u_int8_t *buf, int len); 10177218Sphk 102138593Ssamstatic int 103138593Ssamisanyarg(const char *arg) 104138593Ssam{ 105138593Ssam return (strcmp(arg, "-") == 0 || 106138593Ssam strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0); 107138593Ssam} 108138593Ssam 109138593Ssamstatic void 11077218Sphkset80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 11177218Sphk{ 11277218Sphk int ssid; 11377218Sphk int len; 114151883Sbrooks u_int8_t data[IEEE80211_NWID_LEN]; 11577218Sphk 11677218Sphk ssid = 0; 117121827Sbrooks len = strlen(val); 11888748Sambrisko if (len > 2 && isdigit(val[0]) && val[1] == ':') { 11988748Sambrisko ssid = atoi(val)-1; 12088748Sambrisko val += 2; 12188748Sambrisko } 12277218Sphk 12377218Sphk bzero(data, sizeof(data)); 12477218Sphk len = sizeof(data); 125151883Sbrooks if (get_string(val, NULL, data, &len) == NULL) 126151883Sbrooks exit(1); 12777218Sphk 12877218Sphk set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 12977218Sphk} 13077218Sphk 131138593Ssamstatic void 13277218Sphkset80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 13377218Sphk{ 13477218Sphk int len; 13577218Sphk u_int8_t data[33]; 13677218Sphk 13777218Sphk bzero(data, sizeof(data)); 13877218Sphk len = sizeof(data); 13977218Sphk get_string(val, NULL, data, &len); 14077218Sphk 14177218Sphk set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 14277218Sphk} 14377218Sphk 144138593Ssam/* 145138593Ssam * Convert IEEE channel number to MHz frequency. 146138593Ssam */ 147138593Ssamstatic u_int 148138593Ssamieee80211_ieee2mhz(u_int chan) 149138593Ssam{ 150138593Ssam if (chan == 14) 151138593Ssam return 2484; 152138593Ssam if (chan < 14) /* 0-13 */ 153138593Ssam return 2407 + chan*5; 154138593Ssam if (chan < 27) /* 15-26 */ 155138593Ssam return 2512 + ((chan-15)*20); 156138593Ssam return 5000 + (chan*5); 157138593Ssam} 158138593Ssam 159166015Ssamstatic __inline int 160166015Ssammapgsm(u_int freq, u_int flags) 161166015Ssam{ 162166015Ssam freq *= 10; 163166015Ssam if (flags & IEEE80211_CHAN_QUARTER) 164166015Ssam freq += 5; 165166015Ssam else if (flags & IEEE80211_CHAN_HALF) 166166015Ssam freq += 10; 167166015Ssam else 168166015Ssam freq += 20; 169166015Ssam /* NB: there is no 907/20 wide but leave room */ 170166015Ssam return (freq - 906*10) / 5; 171166015Ssam} 172166015Ssam 173166015Ssamstatic __inline int 174166015Ssammappsb(u_int freq, u_int flags) 175166015Ssam{ 176166015Ssam return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5; 177166015Ssam} 178166015Ssam 179138593Ssam/* 180138593Ssam * Convert MHz frequency to IEEE channel number. 181138593Ssam */ 182138593Ssamstatic u_int 183165570Ssamieee80211_mhz2ieee(u_int freq, u_int flags) 184138593Ssam{ 185166015Ssam if ((flags & IEEE80211_CHAN_GSM) || (907 <= freq && freq <= 922)) 186166015Ssam return mapgsm(freq, flags); 187138593Ssam if (freq == 2484) 188138593Ssam return 14; 189138593Ssam if (freq < 2484) 190138593Ssam return (freq - 2407) / 5; 191165570Ssam if (freq < 5000) { 192166015Ssam if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) 193166015Ssam return mappsb(freq, flags); 194166015Ssam else if (freq > 4900) 195166015Ssam return (freq - 4000) / 5; 196165570Ssam else 197165570Ssam return 15 + ((freq - 2512) / 20); 198165570Ssam } 199138593Ssam return (freq - 5000) / 5; 200138593Ssam} 201138593Ssam 202138593Ssamstatic void 20377218Sphkset80211channel(const char *val, int d, int s, const struct afswtch *rafp) 20477218Sphk{ 205138593Ssam if (!isanyarg(val)) { 206138593Ssam int v = atoi(val); 207138593Ssam if (v > 255) /* treat as frequency */ 208165570Ssam v = ieee80211_mhz2ieee(v, 0); 209138593Ssam set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL); 210138593Ssam } else 211116957Ssam set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); 21277218Sphk} 21377218Sphk 214138593Ssamstatic void 21577218Sphkset80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 21677218Sphk{ 21777218Sphk int mode; 21877218Sphk 21991454Sbrooks if (strcasecmp(val, "none") == 0) { 22077218Sphk mode = IEEE80211_AUTH_NONE; 22191454Sbrooks } else if (strcasecmp(val, "open") == 0) { 22277218Sphk mode = IEEE80211_AUTH_OPEN; 22391454Sbrooks } else if (strcasecmp(val, "shared") == 0) { 22477218Sphk mode = IEEE80211_AUTH_SHARED; 225138593Ssam } else if (strcasecmp(val, "8021x") == 0) { 226138593Ssam mode = IEEE80211_AUTH_8021X; 227138593Ssam } else if (strcasecmp(val, "wpa") == 0) { 228138593Ssam mode = IEEE80211_AUTH_WPA; 22977218Sphk } else { 230150708Sru errx(1, "unknown authmode"); 23177218Sphk } 23277218Sphk 23377218Sphk set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 23477218Sphk} 23577218Sphk 236138593Ssamstatic void 23777218Sphkset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 23877218Sphk{ 23977218Sphk int mode; 24077218Sphk 24191454Sbrooks if (strcasecmp(val, "off") == 0) { 24277218Sphk mode = IEEE80211_POWERSAVE_OFF; 24391454Sbrooks } else if (strcasecmp(val, "on") == 0) { 24477218Sphk mode = IEEE80211_POWERSAVE_ON; 24591454Sbrooks } else if (strcasecmp(val, "cam") == 0) { 24677218Sphk mode = IEEE80211_POWERSAVE_CAM; 24791454Sbrooks } else if (strcasecmp(val, "psp") == 0) { 24877218Sphk mode = IEEE80211_POWERSAVE_PSP; 24991454Sbrooks } else if (strcasecmp(val, "psp-cam") == 0) { 25077218Sphk mode = IEEE80211_POWERSAVE_PSP_CAM; 25177218Sphk } else { 252150708Sru errx(1, "unknown powersavemode"); 25377218Sphk } 25477218Sphk 25577218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 25677218Sphk} 25777218Sphk 258138593Ssamstatic void 25977218Sphkset80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 26077218Sphk{ 26177218Sphk if (d == 0) 26277218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 26377218Sphk 0, NULL); 26477218Sphk else 26577218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 26677218Sphk 0, NULL); 26777218Sphk} 26877218Sphk 269138593Ssamstatic void 27077218Sphkset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 27177218Sphk{ 27277218Sphk set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 27377218Sphk} 27477218Sphk 275138593Ssamstatic void 27677218Sphkset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 27777218Sphk{ 27877218Sphk int mode; 27977218Sphk 28091454Sbrooks if (strcasecmp(val, "off") == 0) { 28177218Sphk mode = IEEE80211_WEP_OFF; 28291454Sbrooks } else if (strcasecmp(val, "on") == 0) { 28377218Sphk mode = IEEE80211_WEP_ON; 28491454Sbrooks } else if (strcasecmp(val, "mixed") == 0) { 28577218Sphk mode = IEEE80211_WEP_MIXED; 28677218Sphk } else { 287150708Sru errx(1, "unknown wep mode"); 28877218Sphk } 28977218Sphk 29077218Sphk set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 29177218Sphk} 29277218Sphk 293138593Ssamstatic void 29477218Sphkset80211wep(const char *val, int d, int s, const struct afswtch *rafp) 29577218Sphk{ 29677218Sphk set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 29777218Sphk} 29877218Sphk 299139493Ssamstatic int 300139493Ssamisundefarg(const char *arg) 301139493Ssam{ 302139493Ssam return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 303139493Ssam} 304139493Ssam 305138593Ssamstatic void 30677218Sphkset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 30777218Sphk{ 308139493Ssam if (isundefarg(val)) 309139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 310139493Ssam else 311139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 31277218Sphk} 31377218Sphk 314138593Ssamstatic void 31577218Sphkset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 31677218Sphk{ 31777218Sphk int key = 0; 31877218Sphk int len; 319120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 32077218Sphk 32191454Sbrooks if (isdigit(val[0]) && val[1] == ':') { 32277218Sphk key = atoi(val)-1; 32377218Sphk val += 2; 32477218Sphk } 32577218Sphk 32677218Sphk bzero(data, sizeof(data)); 32777218Sphk len = sizeof(data); 32877218Sphk get_string(val, NULL, data, &len); 32977218Sphk 33077218Sphk set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 33177218Sphk} 33277218Sphk 33377218Sphk/* 334148686Sstefanf * This function is purely a NetBSD compatability interface. The NetBSD 335148686Sstefanf * interface is too inflexible, but it's there so we'll support it since 33677218Sphk * it's not all that hard. 33777218Sphk */ 338138593Ssamstatic void 33977218Sphkset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 34077218Sphk{ 34177218Sphk int txkey; 34277218Sphk int i, len; 343120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 34477218Sphk 34577218Sphk set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 34677218Sphk 34791454Sbrooks if (isdigit(val[0]) && val[1] == ':') { 34877218Sphk txkey = val[0]-'0'-1; 34977218Sphk val += 2; 35077218Sphk 35191454Sbrooks for (i = 0; i < 4; i++) { 35277218Sphk bzero(data, sizeof(data)); 35377218Sphk len = sizeof(data); 35477218Sphk val = get_string(val, ",", data, &len); 355151827Sbrooks if (val == NULL) 356151827Sbrooks exit(1); 35777218Sphk 35877218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 35977218Sphk } 36077218Sphk } else { 36177218Sphk bzero(data, sizeof(data)); 36277218Sphk len = sizeof(data); 36377218Sphk get_string(val, NULL, data, &len); 36477218Sphk txkey = 0; 36577218Sphk 36677218Sphk set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 36777218Sphk 36877218Sphk bzero(data, sizeof(data)); 36991454Sbrooks for (i = 1; i < 4; i++) 37077218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 37177218Sphk } 37277218Sphk 37377218Sphk set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 37477218Sphk} 37577218Sphk 376138593Ssamstatic void 377127649Ssamset80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 378127649Ssam{ 379148416Ssam set80211(s, IEEE80211_IOC_RTSTHRESHOLD, 380148416Ssam isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL); 381127649Ssam} 382127649Ssam 383138593Ssamstatic void 384127649Ssamset80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 385127649Ssam{ 386127649Ssam int mode; 387127649Ssam 388127649Ssam if (strcasecmp(val, "off") == 0) { 389127649Ssam mode = IEEE80211_PROTMODE_OFF; 390127649Ssam } else if (strcasecmp(val, "cts") == 0) { 391127649Ssam mode = IEEE80211_PROTMODE_CTS; 392127649Ssam } else if (strcasecmp(val, "rtscts") == 0) { 393127649Ssam mode = IEEE80211_PROTMODE_RTSCTS; 394127649Ssam } else { 395150708Sru errx(1, "unknown protection mode"); 396127649Ssam } 397127649Ssam 398127649Ssam set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 399127649Ssam} 400127649Ssam 401138593Ssamstatic void 402127649Ssamset80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 403127649Ssam{ 404127649Ssam set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); 405127649Ssam} 406127649Ssam 407138593Ssam#define IEEE80211_ROAMING_DEVICE 0 408138593Ssam#define IEEE80211_ROAMING_AUTO 1 409138593Ssam#define IEEE80211_ROAMING_MANUAL 2 410138593Ssam 411138593Ssamstatic void 412138593Ssamset80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 41377218Sphk{ 414138593Ssam int mode; 41577218Sphk 416138593Ssam if (strcasecmp(val, "device") == 0) { 417138593Ssam mode = IEEE80211_ROAMING_DEVICE; 418138593Ssam } else if (strcasecmp(val, "auto") == 0) { 419138593Ssam mode = IEEE80211_ROAMING_AUTO; 420138593Ssam } else if (strcasecmp(val, "manual") == 0) { 421138593Ssam mode = IEEE80211_ROAMING_MANUAL; 422138593Ssam } else { 423150708Sru errx(1, "unknown roaming mode"); 424138593Ssam } 425138593Ssam set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 426138593Ssam} 427138593Ssam 428138593Ssamstatic void 429138593Ssamset80211wme(const char *val, int d, int s, const struct afswtch *rafp) 430138593Ssam{ 431138593Ssam set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 432138593Ssam} 433138593Ssam 434138593Ssamstatic void 435138593Ssamset80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 436138593Ssam{ 437138593Ssam set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 438138593Ssam} 439138593Ssam 440138593Ssamstatic void 441138593Ssamset80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 442138593Ssam{ 443138593Ssam set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 444138593Ssam} 445138593Ssam 446138593Ssamstatic void 447138593Ssamset80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 448138593Ssam{ 449138593Ssam struct ieee80211req_chanlist chanlist; 450138593Ssam#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) 451138593Ssam char *temp, *cp, *tp; 452138593Ssam 453138593Ssam temp = malloc(strlen(val) + 1); 454138593Ssam if (temp == NULL) 455138593Ssam errx(1, "malloc failed"); 456138593Ssam strcpy(temp, val); 457138593Ssam memset(&chanlist, 0, sizeof(chanlist)); 458138593Ssam cp = temp; 459138593Ssam for (;;) { 460138593Ssam int first, last, f; 461138593Ssam 462138593Ssam tp = strchr(cp, ','); 463138593Ssam if (tp != NULL) 464138593Ssam *tp++ = '\0'; 465138593Ssam switch (sscanf(cp, "%u-%u", &first, &last)) { 466138593Ssam case 1: 467138593Ssam if (first > MAXCHAN) 468146873Sjhb errx(-1, "channel %u out of range, max %zu", 469138593Ssam first, MAXCHAN); 470138593Ssam setbit(chanlist.ic_channels, first); 471138593Ssam break; 472138593Ssam case 2: 473138593Ssam if (first > MAXCHAN) 474146873Sjhb errx(-1, "channel %u out of range, max %zu", 475138593Ssam first, MAXCHAN); 476138593Ssam if (last > MAXCHAN) 477146873Sjhb errx(-1, "channel %u out of range, max %zu", 478138593Ssam last, MAXCHAN); 479138593Ssam if (first > last) 480138593Ssam errx(-1, "void channel range, %u > %u", 481138593Ssam first, last); 482138593Ssam for (f = first; f <= last; f++) 483138593Ssam setbit(chanlist.ic_channels, f); 484138593Ssam break; 485138593Ssam } 486138593Ssam if (tp == NULL) 487138593Ssam break; 488138593Ssam while (isspace(*tp)) 489138593Ssam tp++; 490138593Ssam if (!isdigit(*tp)) 491138593Ssam break; 492138593Ssam cp = tp; 493138593Ssam } 494138593Ssam set80211(s, IEEE80211_IOC_CHANLIST, 0, 495138593Ssam sizeof(chanlist), (uint8_t *) &chanlist); 496138593Ssam#undef MAXCHAN 497138593Ssam} 498138593Ssam 499138593Ssamstatic void 500138593Ssamset80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 501138593Ssam{ 502138593Ssam 503138593Ssam if (!isanyarg(val)) { 504138593Ssam char *temp; 505138593Ssam struct sockaddr_dl sdl; 506138593Ssam 507155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 508138593Ssam if (temp == NULL) 509138593Ssam errx(1, "malloc failed"); 510138593Ssam temp[0] = ':'; 511138593Ssam strcpy(temp + 1, val); 512138593Ssam sdl.sdl_len = sizeof(sdl); 513138593Ssam link_addr(temp, &sdl); 514138593Ssam free(temp); 515138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 516138593Ssam errx(1, "malformed link-level address"); 517138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 518138593Ssam IEEE80211_ADDR_LEN, LLADDR(&sdl)); 519138593Ssam } else { 520138593Ssam uint8_t zerobssid[IEEE80211_ADDR_LEN]; 521138593Ssam memset(zerobssid, 0, sizeof(zerobssid)); 522138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 523138593Ssam IEEE80211_ADDR_LEN, zerobssid); 524138593Ssam } 525138593Ssam} 526138593Ssam 527138593Ssamstatic int 528138593Ssamgetac(const char *ac) 529138593Ssam{ 530138593Ssam if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 531138593Ssam return WME_AC_BE; 532138593Ssam if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 533138593Ssam return WME_AC_BK; 534138593Ssam if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 535138593Ssam return WME_AC_VI; 536138593Ssam if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 537138593Ssam return WME_AC_VO; 538138593Ssam errx(1, "unknown wme access class %s", ac); 539138593Ssam} 540138593Ssam 541138593Ssamstatic 542138593SsamDECL_CMD_FUNC2(set80211cwmin, ac, val) 543138593Ssam{ 544138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 545138593Ssam} 546138593Ssam 547138593Ssamstatic 548138593SsamDECL_CMD_FUNC2(set80211cwmax, ac, val) 549138593Ssam{ 550138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 551138593Ssam} 552138593Ssam 553138593Ssamstatic 554138593SsamDECL_CMD_FUNC2(set80211aifs, ac, val) 555138593Ssam{ 556138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 557138593Ssam} 558138593Ssam 559138593Ssamstatic 560138593SsamDECL_CMD_FUNC2(set80211txoplimit, ac, val) 561138593Ssam{ 562138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 563138593Ssam} 564138593Ssam 565138593Ssamstatic 566148621SsamDECL_CMD_FUNC(set80211acm, ac, d) 567138593Ssam{ 568148621Ssam set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL); 569138593Ssam} 570148621Ssamstatic 571148621SsamDECL_CMD_FUNC(set80211noacm, ac, d) 572148621Ssam{ 573148621Ssam set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL); 574148621Ssam} 575138593Ssam 576138593Ssamstatic 577148621SsamDECL_CMD_FUNC(set80211ackpolicy, ac, d) 578138593Ssam{ 579148621Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL); 580138593Ssam} 581148621Ssamstatic 582148621SsamDECL_CMD_FUNC(set80211noackpolicy, ac, d) 583148621Ssam{ 584148621Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL); 585148621Ssam} 586138593Ssam 587138593Ssamstatic 588138593SsamDECL_CMD_FUNC2(set80211bsscwmin, ac, val) 589138593Ssam{ 590138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 591138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 592138593Ssam} 593138593Ssam 594138593Ssamstatic 595138593SsamDECL_CMD_FUNC2(set80211bsscwmax, ac, val) 596138593Ssam{ 597138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 598138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 599138593Ssam} 600138593Ssam 601138593Ssamstatic 602138593SsamDECL_CMD_FUNC2(set80211bssaifs, ac, val) 603138593Ssam{ 604138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 605138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 606138593Ssam} 607138593Ssam 608138593Ssamstatic 609138593SsamDECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 610138593Ssam{ 611138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 612138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 613138593Ssam} 614138593Ssam 615138593Ssamstatic 616138593SsamDECL_CMD_FUNC(set80211dtimperiod, val, d) 617138593Ssam{ 618138593Ssam set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 619138593Ssam} 620138593Ssam 621138593Ssamstatic 622138593SsamDECL_CMD_FUNC(set80211bintval, val, d) 623138593Ssam{ 624138593Ssam set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 625138593Ssam} 626138593Ssam 627138593Ssamstatic void 628138593Ssamset80211macmac(int s, int op, const char *val) 629138593Ssam{ 630138593Ssam char *temp; 631138593Ssam struct sockaddr_dl sdl; 632138593Ssam 633155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 634138593Ssam if (temp == NULL) 635138593Ssam errx(1, "malloc failed"); 636138593Ssam temp[0] = ':'; 637138593Ssam strcpy(temp + 1, val); 638138593Ssam sdl.sdl_len = sizeof(sdl); 639138593Ssam link_addr(temp, &sdl); 640138593Ssam free(temp); 641138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 642138593Ssam errx(1, "malformed link-level address"); 643138593Ssam set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 644138593Ssam} 645138593Ssam 646138593Ssamstatic 647138593SsamDECL_CMD_FUNC(set80211addmac, val, d) 648138593Ssam{ 649138593Ssam set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 650138593Ssam} 651138593Ssam 652138593Ssamstatic 653138593SsamDECL_CMD_FUNC(set80211delmac, val, d) 654138593Ssam{ 655138593Ssam set80211macmac(s, IEEE80211_IOC_DELMAC, val); 656138593Ssam} 657138593Ssam 658138593Ssamstatic 659149029SsamDECL_CMD_FUNC(set80211kickmac, val, d) 660149029Ssam{ 661149029Ssam char *temp; 662149029Ssam struct sockaddr_dl sdl; 663149029Ssam struct ieee80211req_mlme mlme; 664149029Ssam 665155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 666149029Ssam if (temp == NULL) 667149029Ssam errx(1, "malloc failed"); 668149029Ssam temp[0] = ':'; 669149029Ssam strcpy(temp + 1, val); 670149029Ssam sdl.sdl_len = sizeof(sdl); 671149029Ssam link_addr(temp, &sdl); 672149029Ssam free(temp); 673149029Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 674149029Ssam errx(1, "malformed link-level address"); 675149029Ssam memset(&mlme, 0, sizeof(mlme)); 676149029Ssam mlme.im_op = IEEE80211_MLME_DEAUTH; 677149029Ssam mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; 678149029Ssam memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN); 679149029Ssam set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme); 680149029Ssam} 681149029Ssam 682149029Ssamstatic 683138593SsamDECL_CMD_FUNC(set80211maccmd, val, d) 684138593Ssam{ 685138593Ssam set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 686138593Ssam} 687138593Ssam 688147795Ssamstatic void 689147795Ssamset80211pureg(const char *val, int d, int s, const struct afswtch *rafp) 690147795Ssam{ 691147795Ssam set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); 692147795Ssam} 693147795Ssam 694153422Ssamstatic void 695153422Ssamset80211burst(const char *val, int d, int s, const struct afswtch *rafp) 696153422Ssam{ 697153422Ssam set80211(s, IEEE80211_IOC_BURST, d, 0, NULL); 698153422Ssam} 699153422Ssam 700148416Ssamstatic 701153354SsamDECL_CMD_FUNC(set80211mcastrate, val, d) 702153354Ssam{ 703153354Ssam set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL); 704153354Ssam} 705153354Ssam 706153354Ssamstatic 707148416SsamDECL_CMD_FUNC(set80211fragthreshold, val, d) 708148416Ssam{ 709148416Ssam set80211(s, IEEE80211_IOC_FRAGTHRESHOLD, 710148416Ssam isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL); 711148416Ssam} 712148416Ssam 713160687Ssamstatic 714160687SsamDECL_CMD_FUNC(set80211bmissthreshold, val, d) 715160687Ssam{ 716160687Ssam set80211(s, IEEE80211_IOC_BMISSTHRESHOLD, 717160687Ssam isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL); 718160687Ssam} 719160687Ssam 720138593Ssamstatic int 721138593Ssamgetmaxrate(uint8_t rates[15], uint8_t nrates) 722138593Ssam{ 723138593Ssam int i, maxrate = -1; 724138593Ssam 725138593Ssam for (i = 0; i < nrates; i++) { 726138593Ssam int rate = rates[i] & IEEE80211_RATE_VAL; 727138593Ssam if (rate > maxrate) 728138593Ssam maxrate = rate; 729138593Ssam } 730138593Ssam return maxrate / 2; 731138593Ssam} 732138593Ssam 733138593Ssamstatic const char * 734138593Ssamgetcaps(int capinfo) 735138593Ssam{ 736138593Ssam static char capstring[32]; 737138593Ssam char *cp = capstring; 738138593Ssam 739138593Ssam if (capinfo & IEEE80211_CAPINFO_ESS) 740138593Ssam *cp++ = 'E'; 741138593Ssam if (capinfo & IEEE80211_CAPINFO_IBSS) 742138593Ssam *cp++ = 'I'; 743138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 744138593Ssam *cp++ = 'c'; 745138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 746138593Ssam *cp++ = 'C'; 747138593Ssam if (capinfo & IEEE80211_CAPINFO_PRIVACY) 748138593Ssam *cp++ = 'P'; 749138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 750138593Ssam *cp++ = 'S'; 751138593Ssam if (capinfo & IEEE80211_CAPINFO_PBCC) 752138593Ssam *cp++ = 'B'; 753138593Ssam if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 754138593Ssam *cp++ = 'A'; 755138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 756138593Ssam *cp++ = 's'; 757138593Ssam if (capinfo & IEEE80211_CAPINFO_RSN) 758138593Ssam *cp++ = 'R'; 759138593Ssam if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 760138593Ssam *cp++ = 'D'; 761138593Ssam *cp = '\0'; 762138593Ssam return capstring; 763138593Ssam} 764138593Ssam 765159885Ssamstatic const char * 766159885Ssamgetflags(int flags) 767159885Ssam{ 768159885Ssam/* XXX need these publicly defined or similar */ 769159885Ssam#define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */ 770159885Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 771159885Ssam#define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */ 772159885Ssam#define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */ 773159885Ssam static char flagstring[32]; 774159885Ssam char *cp = flagstring; 775159885Ssam 776159885Ssam if (flags & IEEE80211_NODE_AUTH) 777159885Ssam *cp++ = 'A'; 778159885Ssam if (flags & IEEE80211_NODE_QOS) 779159885Ssam *cp++ = 'Q'; 780159885Ssam if (flags & IEEE80211_NODE_ERP) 781159885Ssam *cp++ = 'E'; 782159885Ssam if (flags & IEEE80211_NODE_PWR_MGT) 783159885Ssam *cp++ = 'P'; 784159885Ssam *cp = '\0'; 785159885Ssam return flagstring; 786159885Ssam#undef IEEE80211_NODE_AUTH 787159885Ssam#undef IEEE80211_NODE_QOS 788159885Ssam#undef IEEE80211_NODE_ERP 789159885Ssam#undef IEEE80211_NODE_PWR_MGT 790159885Ssam} 791159885Ssam 792138593Ssamstatic void 793138593Ssamprintie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 794138593Ssam{ 795138593Ssam printf("%s", tag); 796138593Ssam if (verbose) { 797138593Ssam maxlen -= strlen(tag)+2; 798138593Ssam if (2*ielen > maxlen) 799138593Ssam maxlen--; 800138593Ssam printf("<"); 801138593Ssam for (; ielen > 0; ie++, ielen--) { 802138593Ssam if (maxlen-- <= 0) 803138593Ssam break; 804138593Ssam printf("%02x", *ie); 805138593Ssam } 806138593Ssam if (ielen != 0) 807138593Ssam printf("-"); 808138593Ssam printf(">"); 809138593Ssam } 810138593Ssam} 811138593Ssam 812138593Ssam/* 813138593Ssam * Copy the ssid string contents into buf, truncating to fit. If the 814138593Ssam * ssid is entirely printable then just copy intact. Otherwise convert 815138593Ssam * to hexadecimal. If the result is truncated then replace the last 816138593Ssam * three characters with "...". 817138593Ssam */ 818146873Sjhbstatic int 819138593Ssamcopy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 820138593Ssam{ 821138593Ssam const u_int8_t *p; 822138593Ssam size_t maxlen; 823138593Ssam int i; 824138593Ssam 825138593Ssam if (essid_len > bufsize) 826138593Ssam maxlen = bufsize; 827138593Ssam else 828138593Ssam maxlen = essid_len; 829138593Ssam /* determine printable or not */ 830138593Ssam for (i = 0, p = essid; i < maxlen; i++, p++) { 831138593Ssam if (*p < ' ' || *p > 0x7e) 832138593Ssam break; 833138593Ssam } 834138593Ssam if (i != maxlen) { /* not printable, print as hex */ 835138593Ssam if (bufsize < 3) 836138593Ssam return 0; 837138593Ssam strlcpy(buf, "0x", bufsize); 838138593Ssam bufsize -= 2; 839138593Ssam p = essid; 840138593Ssam for (i = 0; i < maxlen && bufsize >= 2; i++) { 841147489Savatar sprintf(&buf[2+2*i], "%02x", p[i]); 842138593Ssam bufsize -= 2; 843138593Ssam } 844147489Savatar if (i != essid_len) 845147489Savatar memcpy(&buf[2+2*i-3], "...", 3); 846138593Ssam } else { /* printable, truncate as needed */ 847138593Ssam memcpy(buf, essid, maxlen); 848147489Savatar if (maxlen != essid_len) 849147489Savatar memcpy(&buf[maxlen-3], "...", 3); 850138593Ssam } 851138593Ssam return maxlen; 852138593Ssam} 853138593Ssam 854148686Sstefanf/* unaligned little endian access */ 855138593Ssam#define LE_READ_4(p) \ 856138593Ssam ((u_int32_t) \ 857138593Ssam ((((const u_int8_t *)(p))[0] ) | \ 858138593Ssam (((const u_int8_t *)(p))[1] << 8) | \ 859138593Ssam (((const u_int8_t *)(p))[2] << 16) | \ 860138593Ssam (((const u_int8_t *)(p))[3] << 24))) 861138593Ssam 862138593Ssamstatic int __inline 863138593Ssamiswpaoui(const u_int8_t *frm) 864138593Ssam{ 865138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 866138593Ssam} 867138593Ssam 868138593Ssamstatic int __inline 869138593Ssamiswmeoui(const u_int8_t *frm) 870138593Ssam{ 871138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); 872138593Ssam} 873138593Ssam 874138593Ssamstatic int __inline 875138593Ssamisatherosoui(const u_int8_t *frm) 876138593Ssam{ 877138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 878138593Ssam} 879138593Ssam 880138593Ssamstatic void 881138593Ssamprinties(const u_int8_t *vp, int ielen, int maxcols) 882138593Ssam{ 883138593Ssam while (ielen > 0) { 884138593Ssam switch (vp[0]) { 885138593Ssam case IEEE80211_ELEMID_VENDOR: 886138593Ssam if (iswpaoui(vp)) 887138593Ssam printie(" WPA", vp, 2+vp[1], maxcols); 888138593Ssam else if (iswmeoui(vp)) 889138593Ssam printie(" WME", vp, 2+vp[1], maxcols); 890139492Ssam else if (isatherosoui(vp)) 891139492Ssam printie(" ATH", vp, 2+vp[1], maxcols); 892138593Ssam else 893138593Ssam printie(" VEN", vp, 2+vp[1], maxcols); 894138593Ssam break; 895138593Ssam case IEEE80211_ELEMID_RSN: 896138593Ssam printie(" RSN", vp, 2+vp[1], maxcols); 897138593Ssam break; 898138593Ssam default: 899138593Ssam printie(" ???", vp, 2+vp[1], maxcols); 900138593Ssam break; 901138593Ssam } 902138593Ssam ielen -= 2+vp[1]; 903138593Ssam vp += 2+vp[1]; 904138593Ssam } 905138593Ssam} 906138593Ssam 907138593Ssamstatic void 908138593Ssamlist_scan(int s) 909138593Ssam{ 910138593Ssam uint8_t buf[24*1024]; 911138593Ssam struct ieee80211req ireq; 912153892Srwatson char ssid[IEEE80211_NWID_LEN+1]; 913138593Ssam uint8_t *cp; 914154522Ssam int len, ssidmax; 915138593Ssam 91677218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 91777218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 918138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; 919138593Ssam ireq.i_data = buf; 920138593Ssam ireq.i_len = sizeof(buf); 921138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 922138593Ssam errx(1, "unable to get scan results"); 923138593Ssam len = ireq.i_len; 924138593Ssam if (len < sizeof(struct ieee80211req_scan_result)) 925138593Ssam return; 926138593Ssam 927154522Ssam ssidmax = verbose ? IEEE80211_NWID_LEN : 14; 928154522Ssam printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n" 929154522Ssam , ssidmax, ssidmax, "SSID" 930138593Ssam , "BSSID" 931138593Ssam , "CHAN" 932138593Ssam , "RATE" 933138593Ssam , "S:N" 934138593Ssam , "INT" 935138593Ssam , "CAPS" 936138593Ssam ); 937138593Ssam cp = buf; 938138593Ssam do { 939138593Ssam struct ieee80211req_scan_result *sr; 940138593Ssam uint8_t *vp; 941138593Ssam 942138593Ssam sr = (struct ieee80211req_scan_result *) cp; 943138593Ssam vp = (u_int8_t *)(sr+1); 944154522Ssam printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s" 945154522Ssam , ssidmax 946155461Ssam , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len) 947154522Ssam , ssid 948138593Ssam , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 949165570Ssam , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) 950138593Ssam , getmaxrate(sr->isr_rates, sr->isr_nrates) 951138593Ssam , sr->isr_rssi, sr->isr_noise 952138593Ssam , sr->isr_intval 953138593Ssam , getcaps(sr->isr_capinfo) 954138593Ssam ); 955138593Ssam printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);; 956138593Ssam printf("\n"); 957138593Ssam cp += sr->isr_len, len -= sr->isr_len; 958138593Ssam } while (len >= sizeof(struct ieee80211req_scan_result)); 959138593Ssam} 960138593Ssam 961138593Ssam#include <net80211/ieee80211_freebsd.h> 962138593Ssam 963138593Ssamstatic void 964138593Ssamscan_and_wait(int s) 965138593Ssam{ 966138593Ssam struct ieee80211req ireq; 967138593Ssam int sroute; 968138593Ssam 969138593Ssam sroute = socket(PF_ROUTE, SOCK_RAW, 0); 970138593Ssam if (sroute < 0) { 971138593Ssam perror("socket(PF_ROUTE,SOCK_RAW)"); 972138593Ssam return; 973138593Ssam } 974138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 975138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 976138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_REQ; 977138593Ssam /* NB: only root can trigger a scan so ignore errors */ 978138593Ssam if (ioctl(s, SIOCS80211, &ireq) >= 0) { 979138593Ssam char buf[2048]; 980138593Ssam struct if_announcemsghdr *ifan; 981138593Ssam struct rt_msghdr *rtm; 982138593Ssam 983138593Ssam do { 984138593Ssam if (read(sroute, buf, sizeof(buf)) < 0) { 985138593Ssam perror("read(PF_ROUTE)"); 986138593Ssam break; 987138593Ssam } 988138593Ssam rtm = (struct rt_msghdr *) buf; 989138593Ssam if (rtm->rtm_version != RTM_VERSION) 990138593Ssam break; 991138593Ssam ifan = (struct if_announcemsghdr *) rtm; 992138593Ssam } while (rtm->rtm_type != RTM_IEEE80211 || 993138593Ssam ifan->ifan_what != RTM_IEEE80211_SCAN); 994138593Ssam } 995138593Ssam close(sroute); 996138593Ssam} 997138593Ssam 998138593Ssamstatic 999138593SsamDECL_CMD_FUNC(set80211scan, val, d) 1000138593Ssam{ 1001138593Ssam scan_and_wait(s); 1002138593Ssam list_scan(s); 1003138593Ssam} 1004138593Ssam 1005161147Ssamstatic enum ieee80211_opmode get80211opmode(int s); 1006161147Ssam 1007138593Ssamstatic void 1008138593Ssamlist_stations(int s) 1009138593Ssam{ 1010161147Ssam union { 1011161147Ssam struct ieee80211req_sta_req req; 1012161147Ssam uint8_t buf[24*1024]; 1013161147Ssam } u; 1014161147Ssam enum ieee80211_opmode opmode = get80211opmode(s); 1015138593Ssam struct ieee80211req ireq; 1016138593Ssam uint8_t *cp; 1017138593Ssam int len; 1018138593Ssam 1019138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1020138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1021161147Ssam /* broadcast address =>'s get all stations */ 1022161147Ssam (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); 1023161147Ssam if (opmode == IEEE80211_M_STA) { 1024161147Ssam /* 1025161147Ssam * Get information about the associated AP. 1026161147Ssam */ 1027161147Ssam ireq.i_type = IEEE80211_IOC_BSSID; 1028161147Ssam ireq.i_data = u.req.is_u.macaddr; 1029161147Ssam ireq.i_len = IEEE80211_ADDR_LEN; 1030161147Ssam (void) ioctl(s, SIOCG80211, &ireq); 1031161147Ssam } 1032138593Ssam ireq.i_type = IEEE80211_IOC_STA_INFO; 1033161147Ssam ireq.i_data = &u; 1034161147Ssam ireq.i_len = sizeof(u); 1035138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1036138593Ssam errx(1, "unable to get station information"); 1037138593Ssam len = ireq.i_len; 1038138593Ssam if (len < sizeof(struct ieee80211req_sta_info)) 1039138593Ssam return; 1040138593Ssam 1041159885Ssam printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n" 1042138593Ssam , "ADDR" 1043138593Ssam , "AID" 1044138593Ssam , "CHAN" 1045138593Ssam , "RATE" 1046138593Ssam , "RSSI" 1047138593Ssam , "IDLE" 1048138593Ssam , "TXSEQ" 1049138593Ssam , "RXSEQ" 1050138593Ssam , "CAPS" 1051159885Ssam , "FLAG" 1052138593Ssam ); 1053161147Ssam cp = (uint8_t *) u.req.info; 1054138593Ssam do { 1055138593Ssam struct ieee80211req_sta_info *si; 1056138593Ssam uint8_t *vp; 1057138593Ssam 1058138593Ssam si = (struct ieee80211req_sta_info *) cp; 1059161147Ssam if (si->isi_len < sizeof(*si)) 1060161147Ssam break; 1061138593Ssam vp = (u_int8_t *)(si+1); 1062159885Ssam printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %-4.4s" 1063138593Ssam , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 1064138593Ssam , IEEE80211_AID(si->isi_associd) 1065166015Ssam , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags) 1066138593Ssam , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2 1067138593Ssam , si->isi_rssi 1068138593Ssam , si->isi_inact 1069138593Ssam , si->isi_txseqs[0] 1070138593Ssam , si->isi_rxseqs[0] 1071138593Ssam , getcaps(si->isi_capinfo) 1072159885Ssam , getflags(si->isi_state) 1073138593Ssam ); 1074138593Ssam printies(vp, si->isi_ie_len, 24); 1075138593Ssam printf("\n"); 1076138593Ssam cp += si->isi_len, len -= si->isi_len; 1077138593Ssam } while (len >= sizeof(struct ieee80211req_sta_info)); 1078138593Ssam} 1079138593Ssam 1080138593Ssamstatic void 1081138593Ssamprint_chaninfo(const struct ieee80211_channel *c) 1082138593Ssam{ 1083138593Ssam#define IEEE80211_IS_CHAN_PASSIVE(_c) \ 1084138593Ssam (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE)) 1085138593Ssam char buf[14]; 1086138593Ssam 1087138593Ssam buf[0] = '\0'; 1088138593Ssam if (IEEE80211_IS_CHAN_FHSS(c)) 1089138593Ssam strlcat(buf, " FHSS", sizeof(buf)); 1090165570Ssam if (IEEE80211_IS_CHAN_A(c)) { 1091165570Ssam if (IEEE80211_IS_CHAN_HALF(c)) 1092165570Ssam strlcat(buf, " 11a/10Mhz", sizeof(buf)); 1093165570Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 1094165570Ssam strlcat(buf, " 11a/5Mhz", sizeof(buf)); 1095165570Ssam else 1096165570Ssam strlcat(buf, " 11a", sizeof(buf)); 1097165570Ssam } 1098166015Ssam if (IEEE80211_IS_CHAN_ANYG(c)) { 1099166015Ssam if (IEEE80211_IS_CHAN_HALF(c)) 1100166015Ssam strlcat(buf, " 11g/10Mhz", sizeof(buf)); 1101166015Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 1102166015Ssam strlcat(buf, " 11g/5Mhz", sizeof(buf)); 1103166015Ssam else 1104166015Ssam strlcat(buf, " 11g", sizeof(buf)); 1105166015Ssam } else if (IEEE80211_IS_CHAN_B(c)) 1106138593Ssam strlcat(buf, " 11b", sizeof(buf)); 1107138593Ssam if (IEEE80211_IS_CHAN_T(c)) 1108138593Ssam strlcat(buf, " Turbo", sizeof(buf)); 1109138593Ssam printf("Channel %3u : %u%c Mhz%-14.14s", 1110165570Ssam ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, 1111138593Ssam IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf); 1112138593Ssam#undef IEEE80211_IS_CHAN_PASSIVE 1113138593Ssam} 1114138593Ssam 1115138593Ssamstatic void 1116138593Ssamlist_channels(int s, int allchans) 1117138593Ssam{ 1118138593Ssam struct ieee80211req ireq; 1119138593Ssam struct ieee80211req_chaninfo chans; 1120138593Ssam struct ieee80211req_chaninfo achans; 1121138593Ssam const struct ieee80211_channel *c; 1122165570Ssam int i, half, ieee; 1123138593Ssam 1124138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1125138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1126138593Ssam ireq.i_type = IEEE80211_IOC_CHANINFO; 1127138593Ssam ireq.i_data = &chans; 1128138593Ssam ireq.i_len = sizeof(chans); 1129138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1130138593Ssam errx(1, "unable to get channel information"); 1131138593Ssam if (!allchans) { 1132138593Ssam struct ieee80211req_chanlist active; 1133138593Ssam 1134138593Ssam ireq.i_type = IEEE80211_IOC_CHANLIST; 1135138593Ssam ireq.i_data = &active; 1136138593Ssam ireq.i_len = sizeof(active); 1137138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1138138593Ssam errx(1, "unable to get active channel list"); 1139138593Ssam memset(&achans, 0, sizeof(achans)); 1140138593Ssam for (i = 0; i < chans.ic_nchans; i++) { 1141138593Ssam c = &chans.ic_chans[i]; 1142165570Ssam ieee = ieee80211_mhz2ieee(c->ic_freq, c->ic_flags); 1143165570Ssam if (isset(active.ic_channels, ieee) || allchans) 1144138593Ssam achans.ic_chans[achans.ic_nchans++] = *c; 1145138593Ssam } 1146138593Ssam } else 1147138593Ssam achans = chans; 1148138593Ssam half = achans.ic_nchans / 2; 1149138593Ssam if (achans.ic_nchans % 2) 1150138593Ssam half++; 1151138593Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 1152138593Ssam print_chaninfo(&achans.ic_chans[i]); 1153138593Ssam print_chaninfo(&achans.ic_chans[half+i]); 1154138593Ssam printf("\n"); 1155138593Ssam } 1156138593Ssam if (achans.ic_nchans % 2) { 1157138593Ssam print_chaninfo(&achans.ic_chans[i]); 1158138593Ssam printf("\n"); 1159138593Ssam } 1160138593Ssam} 1161138593Ssam 1162138593Ssamstatic void 1163138593Ssamlist_keys(int s) 1164138593Ssam{ 1165138593Ssam} 1166138593Ssam 1167138593Ssam#define IEEE80211_C_BITS \ 1168138593Ssam"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \ 1169138593Ssam"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \ 1170138593Ssam"\31WPA2\32BURST\33WME" 1171138593Ssam 1172138593Ssamstatic void 1173138593Ssamlist_capabilities(int s) 1174138593Ssam{ 1175138593Ssam struct ieee80211req ireq; 1176138593Ssam u_int32_t caps; 1177138593Ssam 1178138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1179138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1180138593Ssam ireq.i_type = IEEE80211_IOC_DRIVER_CAPS; 1181138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1182138593Ssam errx(1, "unable to get driver capabilities"); 1183138593Ssam caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len); 1184138593Ssam printb(name, caps, IEEE80211_C_BITS); 1185138593Ssam putchar('\n'); 1186138593Ssam} 1187138593Ssam 1188138593Ssamstatic void 1189138593Ssamlist_wme(int s) 1190138593Ssam{ 1191138593Ssam static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 1192138593Ssam struct ieee80211req ireq; 1193138593Ssam int ac; 1194138593Ssam 1195138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1196138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1197138593Ssam ireq.i_len = 0; 1198138593Ssam for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 1199138593Ssamagain: 1200138593Ssam if (ireq.i_len & IEEE80211_WMEPARAM_BSS) 1201138593Ssam printf("\t%s", " "); 1202138593Ssam else 1203138593Ssam printf("\t%s", acnames[ac]); 1204138593Ssam 1205138593Ssam ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac; 1206138593Ssam 1207138593Ssam /* show WME BSS parameters */ 1208138593Ssam ireq.i_type = IEEE80211_IOC_WME_CWMIN; 1209138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1210138593Ssam printf(" cwmin %2u", ireq.i_val); 1211138593Ssam ireq.i_type = IEEE80211_IOC_WME_CWMAX; 1212138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1213138593Ssam printf(" cwmax %2u", ireq.i_val); 1214138593Ssam ireq.i_type = IEEE80211_IOC_WME_AIFS; 1215138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1216138593Ssam printf(" aifs %2u", ireq.i_val); 1217138593Ssam ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT; 1218138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1219138593Ssam printf(" txopLimit %3u", ireq.i_val); 1220138593Ssam ireq.i_type = IEEE80211_IOC_WME_ACM; 1221138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1222138593Ssam if (ireq.i_val) 1223138593Ssam printf(" acm"); 1224138593Ssam else if (verbose) 1225138593Ssam printf(" -acm"); 1226138593Ssam } 1227138593Ssam /* !BSS only */ 1228138593Ssam if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1229138593Ssam ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY; 1230138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1231138593Ssam if (!ireq.i_val) 1232138593Ssam printf(" -ack"); 1233138593Ssam else if (verbose) 1234138593Ssam printf(" ack"); 1235138593Ssam } 1236138593Ssam } 1237138593Ssam printf("\n"); 1238138593Ssam if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1239138593Ssam ireq.i_len |= IEEE80211_WMEPARAM_BSS; 1240138593Ssam goto again; 1241138593Ssam } else 1242138593Ssam ireq.i_len &= ~IEEE80211_WMEPARAM_BSS; 1243138593Ssam } 1244138593Ssam} 1245138593Ssam 1246149029Ssamstatic void 1247149029Ssamlist_mac(int s) 1248149029Ssam{ 1249149029Ssam struct ieee80211req ireq; 1250149029Ssam struct ieee80211req_maclist *acllist; 1251149029Ssam int i, nacls, policy; 1252149029Ssam char c; 1253149029Ssam 1254149029Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1255149029Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 1256149029Ssam ireq.i_type = IEEE80211_IOC_MACCMD; 1257149029Ssam ireq.i_val = IEEE80211_MACCMD_POLICY; 1258149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) { 1259149029Ssam if (errno == EINVAL) { 1260149029Ssam printf("No acl policy loaded\n"); 1261149029Ssam return; 1262149029Ssam } 1263149029Ssam err(1, "unable to get mac policy"); 1264149029Ssam } 1265149029Ssam policy = ireq.i_val; 1266149029Ssam 1267149029Ssam ireq.i_val = IEEE80211_MACCMD_LIST; 1268149029Ssam ireq.i_len = 0; 1269149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1270149029Ssam err(1, "unable to get mac acl list size"); 1271149029Ssam if (ireq.i_len == 0) /* NB: no acls */ 1272149029Ssam return; 1273149029Ssam 1274149029Ssam ireq.i_data = malloc(ireq.i_len); 1275149029Ssam if (ireq.i_data == NULL) 1276149029Ssam err(1, "out of memory for acl list"); 1277149029Ssam 1278149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1279149029Ssam err(1, "unable to get mac acl list"); 1280149029Ssam if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 1281149029Ssam if (verbose) 1282149029Ssam printf("policy: open\n"); 1283149029Ssam c = '*'; 1284149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 1285149029Ssam if (verbose) 1286149029Ssam printf("policy: allow\n"); 1287149029Ssam c = '+'; 1288149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 1289149029Ssam if (verbose) 1290149029Ssam printf("policy: deny\n"); 1291149029Ssam c = '-'; 1292149029Ssam } else { 1293149029Ssam printf("policy: unknown (%u)\n", policy); 1294149029Ssam c = '?'; 1295149029Ssam } 1296149029Ssam nacls = ireq.i_len / sizeof(*acllist); 1297149029Ssam acllist = (struct ieee80211req_maclist *) ireq.i_data; 1298149029Ssam for (i = 0; i < nacls; i++) 1299149029Ssam printf("%c%s\n", c, ether_ntoa( 1300149029Ssam (const struct ether_addr *) acllist[i].ml_macaddr)); 1301149029Ssam} 1302149029Ssam 1303138593Ssamstatic 1304138593SsamDECL_CMD_FUNC(set80211list, arg, d) 1305138593Ssam{ 1306138593Ssam#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 1307138593Ssam 1308138593Ssam if (iseq(arg, "sta")) 1309138593Ssam list_stations(s); 1310138593Ssam else if (iseq(arg, "scan") || iseq(arg, "ap")) 1311138593Ssam list_scan(s); 1312138593Ssam else if (iseq(arg, "chan") || iseq(arg, "freq")) 1313138593Ssam list_channels(s, 1); 1314138593Ssam else if (iseq(arg, "active")) 1315138593Ssam list_channels(s, 0); 1316138593Ssam else if (iseq(arg, "keys")) 1317138593Ssam list_keys(s); 1318138593Ssam else if (iseq(arg, "caps")) 1319138593Ssam list_capabilities(s); 1320138593Ssam else if (iseq(arg, "wme")) 1321138593Ssam list_wme(s); 1322149029Ssam else if (iseq(arg, "mac")) 1323149029Ssam list_mac(s); 1324138593Ssam else 1325138593Ssam errx(1, "Don't know how to list %s for %s", arg, name); 1326138593Ssam#undef iseq 1327138593Ssam} 1328138593Ssam 1329138593Ssamstatic enum ieee80211_opmode 1330138593Ssamget80211opmode(int s) 1331138593Ssam{ 1332138593Ssam struct ifmediareq ifmr; 1333138593Ssam 1334138593Ssam (void) memset(&ifmr, 0, sizeof(ifmr)); 1335138593Ssam (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 1336138593Ssam 1337138593Ssam if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 1338138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 1339138593Ssam return IEEE80211_M_IBSS; /* XXX ahdemo */ 1340138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 1341138593Ssam return IEEE80211_M_HOSTAP; 1342138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 1343138593Ssam return IEEE80211_M_MONITOR; 1344138593Ssam } 1345138593Ssam return IEEE80211_M_STA; 1346138593Ssam} 1347138593Ssam 1348138593Ssamstatic const struct ieee80211_channel * 1349138593Ssamgetchaninfo(int s, int chan) 1350138593Ssam{ 1351138593Ssam struct ieee80211req ireq; 1352138593Ssam static struct ieee80211req_chaninfo chans; 1353138593Ssam static struct ieee80211_channel undef; 1354138593Ssam const struct ieee80211_channel *c; 1355138593Ssam int i, freq; 1356138593Ssam 1357138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1358138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1359138593Ssam ireq.i_type = IEEE80211_IOC_CHANINFO; 1360138593Ssam ireq.i_data = &chans; 1361138593Ssam ireq.i_len = sizeof(chans); 1362138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1363138593Ssam errx(1, "unable to get channel information"); 1364138593Ssam freq = ieee80211_ieee2mhz(chan); 1365138593Ssam for (i = 0; i < chans.ic_nchans; i++) { 1366138593Ssam c = &chans.ic_chans[i]; 1367138593Ssam if (c->ic_freq == freq) 1368138593Ssam return c; 1369138593Ssam } 1370138593Ssam return &undef; 1371138593Ssam} 1372138593Ssam 1373138593Ssam#if 0 1374138593Ssamstatic void 1375138593Ssamprintcipher(int s, struct ieee80211req *ireq, int keylenop) 1376138593Ssam{ 1377138593Ssam switch (ireq->i_val) { 1378138593Ssam case IEEE80211_CIPHER_WEP: 1379138593Ssam ireq->i_type = keylenop; 1380138593Ssam if (ioctl(s, SIOCG80211, ireq) != -1) 1381138593Ssam printf("WEP-%s", 1382138593Ssam ireq->i_len <= 5 ? "40" : 1383138593Ssam ireq->i_len <= 13 ? "104" : "128"); 1384138593Ssam else 1385138593Ssam printf("WEP"); 1386138593Ssam break; 1387138593Ssam case IEEE80211_CIPHER_TKIP: 1388138593Ssam printf("TKIP"); 1389138593Ssam break; 1390138593Ssam case IEEE80211_CIPHER_AES_OCB: 1391138593Ssam printf("AES-OCB"); 1392138593Ssam break; 1393138593Ssam case IEEE80211_CIPHER_AES_CCM: 1394138593Ssam printf("AES-CCM"); 1395138593Ssam break; 1396138593Ssam case IEEE80211_CIPHER_CKIP: 1397138593Ssam printf("CKIP"); 1398138593Ssam break; 1399138593Ssam case IEEE80211_CIPHER_NONE: 1400138593Ssam printf("NONE"); 1401138593Ssam break; 1402138593Ssam default: 1403138593Ssam printf("UNKNOWN (0x%x)", ireq->i_val); 1404138593Ssam break; 1405138593Ssam } 1406138593Ssam} 1407138593Ssam#endif 1408138593Ssam 1409138593Ssam#define MAXCOL 78 1410155931Ssamstatic int col; 1411155931Ssamstatic char spacer; 1412138593Ssam 1413155931Ssamstatic void 1414155931SsamLINE_BREAK(void) 1415155931Ssam{ 1416155931Ssam if (spacer != '\t') { 1417155931Ssam printf("\n"); 1418155931Ssam spacer = '\t'; 1419155931Ssam } 1420155931Ssam col = 8; /* 8-col tab */ 1421155931Ssam} 1422138593Ssam 1423138593Ssamstatic void 1424155931SsamLINE_CHECK(const char *fmt, ...) 1425155931Ssam{ 1426155931Ssam char buf[80]; 1427155931Ssam va_list ap; 1428155931Ssam int n; 1429155931Ssam 1430155931Ssam va_start(ap, fmt); 1431155931Ssam n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap); 1432155931Ssam va_end(ap); 1433155931Ssam col += 1+n; 1434155931Ssam if (col > MAXCOL) { 1435155931Ssam LINE_BREAK(); 1436155931Ssam col += n; 1437155931Ssam } 1438155931Ssam buf[0] = spacer; 1439155931Ssam printf("%s", buf); 1440155931Ssam spacer = ' '; 1441155931Ssam} 1442155931Ssam 1443155931Ssamstatic void 1444138593Ssamprintkey(const struct ieee80211req_key *ik) 1445138593Ssam{ 1446138593Ssam static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 1447138593Ssam int keylen = ik->ik_keylen; 1448138593Ssam int printcontents; 1449138593Ssam 1450148001Srwatson printcontents = printkeys && 1451138593Ssam (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 1452138593Ssam if (printcontents) 1453138593Ssam LINE_BREAK(); 1454138593Ssam switch (ik->ik_type) { 1455138593Ssam case IEEE80211_CIPHER_WEP: 1456138593Ssam /* compatibility */ 1457155931Ssam LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1, 1458138593Ssam keylen <= 5 ? "40-bit" : 1459138593Ssam keylen <= 13 ? "104-bit" : "128-bit"); 1460138593Ssam break; 1461138593Ssam case IEEE80211_CIPHER_TKIP: 1462138593Ssam if (keylen > 128/8) 1463138593Ssam keylen -= 128/8; /* ignore MIC for now */ 1464155931Ssam LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1465138593Ssam break; 1466138593Ssam case IEEE80211_CIPHER_AES_OCB: 1467155931Ssam LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1468138593Ssam break; 1469138593Ssam case IEEE80211_CIPHER_AES_CCM: 1470155931Ssam LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1471138593Ssam break; 1472138593Ssam case IEEE80211_CIPHER_CKIP: 1473155931Ssam LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1474138593Ssam break; 1475138593Ssam case IEEE80211_CIPHER_NONE: 1476155931Ssam LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1477138593Ssam break; 1478138593Ssam default: 1479155931Ssam LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit", 1480138593Ssam ik->ik_type, ik->ik_keyix+1, 8*keylen); 1481138593Ssam break; 1482138593Ssam } 1483138593Ssam if (printcontents) { 1484138593Ssam int i; 1485138593Ssam 1486138593Ssam printf(" <"); 1487138593Ssam for (i = 0; i < keylen; i++) 1488138593Ssam printf("%02x", ik->ik_keydata[i]); 1489138593Ssam printf(">"); 1490138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 1491138593Ssam (ik->ik_keyrsc != 0 || verbose)) 1492146873Sjhb printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 1493138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 1494138593Ssam (ik->ik_keytsc != 0 || verbose)) 1495146873Sjhb printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 1496138593Ssam if (ik->ik_flags != 0 && verbose) { 1497138593Ssam const char *sep = " "; 1498138593Ssam 1499138593Ssam if (ik->ik_flags & IEEE80211_KEY_XMIT) 1500138593Ssam printf("%stx", sep), sep = "+"; 1501138593Ssam if (ik->ik_flags & IEEE80211_KEY_RECV) 1502138593Ssam printf("%srx", sep), sep = "+"; 1503138593Ssam if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 1504138593Ssam printf("%sdef", sep), sep = "+"; 1505138593Ssam } 1506138593Ssam LINE_BREAK(); 1507138593Ssam } 1508138593Ssam} 1509138593Ssam 1510138593Ssamstatic void 1511139494Ssamieee80211_status(int s) 1512138593Ssam{ 1513138593Ssam static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 1514138593Ssam enum ieee80211_opmode opmode = get80211opmode(s); 1515138593Ssam int i, num, wpa, wme; 1516138593Ssam struct ieee80211req ireq; 1517138593Ssam u_int8_t data[32]; 1518138593Ssam const struct ieee80211_channel *c; 1519138593Ssam 1520138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1521138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 152277218Sphk ireq.i_data = &data; 152377218Sphk 1524138593Ssam wpa = 0; /* unknown/not set */ 1525138593Ssam 152677218Sphk ireq.i_type = IEEE80211_IOC_SSID; 152777218Sphk ireq.i_val = -1; 152877218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 1529148686Sstefanf /* If we can't get the SSID, this isn't an 802.11 device. */ 153077218Sphk return; 153177218Sphk } 153288748Sambrisko num = 0; 153388748Sambrisko ireq.i_type = IEEE80211_IOC_NUMSSIDS; 1534138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0) 153588748Sambrisko num = ireq.i_val; 1536138593Ssam printf("\tssid "); 1537138593Ssam if (num > 1) { 1538138593Ssam ireq.i_type = IEEE80211_IOC_SSID; 1539138593Ssam for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 1540138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 1541138593Ssam printf(" %d:", ireq.i_val + 1); 1542138593Ssam print_string(data, ireq.i_len); 1543138593Ssam } 154488748Sambrisko } 1545138593Ssam } else 1546138593Ssam print_string(data, ireq.i_len); 154777218Sphk 1548138593Ssam ireq.i_type = IEEE80211_IOC_CHANNEL; 1549138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1550138593Ssam goto end; 1551138593Ssam c = getchaninfo(s, ireq.i_val); 1552138593Ssam if (ireq.i_val != -1) { 1553138593Ssam printf(" channel %d", ireq.i_val); 1554138593Ssam if (verbose) 1555138593Ssam printf(" (%u)", c->ic_freq); 1556138593Ssam } else if (verbose) 1557138593Ssam printf(" channel UNDEF"); 1558138593Ssam 1559138593Ssam ireq.i_type = IEEE80211_IOC_BSSID; 1560138593Ssam ireq.i_len = IEEE80211_ADDR_LEN; 1561138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0 && 1562153405Ssam (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) 1563138593Ssam printf(" bssid %s", ether_ntoa(ireq.i_data)); 1564138593Ssam 156577218Sphk ireq.i_type = IEEE80211_IOC_STATIONNAME; 156677218Sphk if (ioctl(s, SIOCG80211, &ireq) != -1) { 1567138593Ssam printf("\n\tstationname "); 156877218Sphk print_string(data, ireq.i_len); 156977218Sphk } 157077218Sphk 1571138593Ssam spacer = ' '; /* force first break */ 1572138593Ssam LINE_BREAK(); 157377218Sphk 157477218Sphk ireq.i_type = IEEE80211_IOC_AUTHMODE; 157577218Sphk if (ioctl(s, SIOCG80211, &ireq) != -1) { 157677218Sphk switch (ireq.i_val) { 157777218Sphk case IEEE80211_AUTH_NONE: 1578155931Ssam LINE_CHECK("authmode NONE"); 157977218Sphk break; 158077218Sphk case IEEE80211_AUTH_OPEN: 1581155931Ssam LINE_CHECK("authmode OPEN"); 158277218Sphk break; 158377218Sphk case IEEE80211_AUTH_SHARED: 1584155931Ssam LINE_CHECK("authmode SHARED"); 158577218Sphk break; 1586138593Ssam case IEEE80211_AUTH_8021X: 1587155931Ssam LINE_CHECK("authmode 802.1x"); 158877218Sphk break; 1589138593Ssam case IEEE80211_AUTH_WPA: 1590138593Ssam ireq.i_type = IEEE80211_IOC_WPA; 1591138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1592138593Ssam wpa = ireq.i_val; 1593138593Ssam if (!wpa) 1594138593Ssam wpa = 1; /* default to WPA1 */ 1595138593Ssam switch (wpa) { 1596138593Ssam case 2: 1597155931Ssam LINE_CHECK("authmode WPA2/802.11i"); 1598138593Ssam break; 1599138593Ssam case 3: 1600155931Ssam LINE_CHECK("authmode WPA1+WPA2/802.11i"); 1601138593Ssam break; 1602138593Ssam default: 1603155931Ssam LINE_CHECK("authmode WPA"); 1604138593Ssam break; 1605138593Ssam } 160677218Sphk break; 1607138593Ssam case IEEE80211_AUTH_AUTO: 1608155931Ssam LINE_CHECK("authmode AUTO"); 160977218Sphk break; 1610127649Ssam default: 1611155931Ssam LINE_CHECK("authmode UNKNOWN (0x%x)", 1612155931Ssam ireq.i_val); 1613127649Ssam break; 1614127649Ssam } 1615127649Ssam } 1616127649Ssam 161777218Sphk ireq.i_type = IEEE80211_IOC_WEP; 161880315Sbrooks if (ioctl(s, SIOCG80211, &ireq) != -1 && 161980315Sbrooks ireq.i_val != IEEE80211_WEP_NOSUP) { 1620138718Ssam int firstkey, wepmode; 1621138593Ssam 1622138718Ssam wepmode = ireq.i_val; 1623138718Ssam switch (wepmode) { 162477218Sphk case IEEE80211_WEP_OFF: 1625155931Ssam LINE_CHECK("privacy OFF"); 162677218Sphk break; 162777218Sphk case IEEE80211_WEP_ON: 1628155931Ssam LINE_CHECK("privacy ON"); 162977218Sphk break; 163077218Sphk case IEEE80211_WEP_MIXED: 1631155931Ssam LINE_CHECK("privacy MIXED"); 163277218Sphk break; 163377218Sphk default: 1634155931Ssam LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); 163577218Sphk break; 163677218Sphk } 163777218Sphk 163877218Sphk /* 163977218Sphk * If we get here then we've got WEP support so we need 164077218Sphk * to print WEP status. 164191454Sbrooks */ 164277218Sphk 164377218Sphk ireq.i_type = IEEE80211_IOC_WEPTXKEY; 164477218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 164577218Sphk warn("WEP support, but no tx key!"); 164677218Sphk goto end; 164777218Sphk } 1648138593Ssam if (ireq.i_val != -1) 1649155931Ssam LINE_CHECK("deftxkey %d", ireq.i_val+1); 1650138718Ssam else if (wepmode != IEEE80211_WEP_OFF || verbose) 1651155931Ssam LINE_CHECK("deftxkey UNDEF"); 165277218Sphk 165377218Sphk ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 165477218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 165577218Sphk warn("WEP support, but no NUMWEPKEYS support!"); 165677218Sphk goto end; 165777218Sphk } 165877218Sphk num = ireq.i_val; 165977218Sphk 1660138593Ssam firstkey = 1; 1661138593Ssam for (i = 0; i < num; i++) { 1662138593Ssam struct ieee80211req_key ik; 166377218Sphk 1664138593Ssam memset(&ik, 0, sizeof(ik)); 1665138593Ssam ik.ik_keyix = i; 1666138593Ssam ireq.i_type = IEEE80211_IOC_WPAKEY; 1667138593Ssam ireq.i_data = &ik; 1668138593Ssam ireq.i_len = sizeof(ik); 166977218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 167077218Sphk warn("WEP support, but can get keys!"); 167177218Sphk goto end; 167277218Sphk } 1673138593Ssam if (ik.ik_keylen != 0) { 1674138593Ssam if (verbose) 1675138593Ssam LINE_BREAK(); 1676138593Ssam printkey(&ik); 1677138593Ssam firstkey = 0; 1678138593Ssam } 1679138593Ssam } 1680138593Ssam } 1681138593Ssam 1682138593Ssam ireq.i_type = IEEE80211_IOC_POWERSAVE; 1683138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1 && 1684138593Ssam ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 1685138593Ssam if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) { 1686138593Ssam switch (ireq.i_val) { 1687138593Ssam case IEEE80211_POWERSAVE_OFF: 1688155931Ssam LINE_CHECK("powersavemode OFF"); 1689138593Ssam break; 1690138593Ssam case IEEE80211_POWERSAVE_CAM: 1691155931Ssam LINE_CHECK("powersavemode CAM"); 1692138593Ssam break; 1693138593Ssam case IEEE80211_POWERSAVE_PSP: 1694155931Ssam LINE_CHECK("powersavemode PSP"); 1695138593Ssam break; 1696138593Ssam case IEEE80211_POWERSAVE_PSP_CAM: 1697155931Ssam LINE_CHECK("powersavemode PSP-CAM"); 1698138593Ssam break; 1699138593Ssam } 1700138593Ssam ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 1701138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1702155931Ssam LINE_CHECK("powersavesleep %d", ireq.i_val); 1703138593Ssam } 1704138593Ssam } 1705138593Ssam 1706138593Ssam ireq.i_type = IEEE80211_IOC_TXPOWMAX; 1707138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1708155931Ssam LINE_CHECK("txpowmax %d", ireq.i_val); 1709138593Ssam 1710138593Ssam if (verbose) { 1711138593Ssam ireq.i_type = IEEE80211_IOC_TXPOWER; 1712138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1713155931Ssam LINE_CHECK("txpower %d", ireq.i_val); 1714138593Ssam } 1715138593Ssam 1716138593Ssam ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; 1717138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1718138593Ssam if (ireq.i_val != IEEE80211_RTS_MAX || verbose) 1719155931Ssam LINE_CHECK("rtsthreshold %d", ireq.i_val); 1720138593Ssam } 1721138593Ssam 1722153354Ssam ireq.i_type = IEEE80211_IOC_MCAST_RATE; 1723153354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1724153354Ssam if (ireq.i_val != 2*1 || verbose) { 1725153354Ssam if (ireq.i_val == 11) 1726155931Ssam LINE_CHECK("mcastrate 5.5"); 1727153354Ssam else 1728155931Ssam LINE_CHECK("mcastrate %d", ireq.i_val/2); 1729153354Ssam } 1730153354Ssam } 1731153354Ssam 1732148416Ssam ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD; 1733148416Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1734148416Ssam if (ireq.i_val != IEEE80211_FRAG_MAX || verbose) 1735155931Ssam LINE_CHECK("fragthreshold %d", ireq.i_val); 1736148416Ssam } 1737148416Ssam 1738160687Ssam ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD; 1739160687Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1740160687Ssam if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose) 1741160687Ssam LINE_CHECK("bmiss %d", ireq.i_val); 1742160687Ssam } 1743160687Ssam 1744165570Ssam if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { 1745147795Ssam ireq.i_type = IEEE80211_IOC_PUREG; 1746147795Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1747147795Ssam if (ireq.i_val) 1748155931Ssam LINE_CHECK("pureg"); 1749147795Ssam else if (verbose) 1750155931Ssam LINE_CHECK("-pureg"); 1751147795Ssam } 1752138593Ssam ireq.i_type = IEEE80211_IOC_PROTMODE; 1753138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1754138593Ssam switch (ireq.i_val) { 1755138593Ssam case IEEE80211_PROTMODE_OFF: 1756155931Ssam LINE_CHECK("protmode OFF"); 1757138593Ssam break; 1758138593Ssam case IEEE80211_PROTMODE_CTS: 1759155931Ssam LINE_CHECK("protmode CTS"); 1760138593Ssam break; 1761138593Ssam case IEEE80211_PROTMODE_RTSCTS: 1762155931Ssam LINE_CHECK("protmode RTSCTS"); 1763138593Ssam break; 1764138593Ssam default: 1765155931Ssam LINE_CHECK("protmode UNKNOWN (0x%x)", 1766155931Ssam ireq.i_val); 1767138593Ssam break; 1768138593Ssam } 1769138593Ssam } 1770138593Ssam } 1771138593Ssam 1772138593Ssam ireq.i_type = IEEE80211_IOC_WME; 1773138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1774138593Ssam wme = ireq.i_val; 1775138593Ssam if (wme) 1776155931Ssam LINE_CHECK("wme"); 1777138593Ssam else if (verbose) 1778155931Ssam LINE_CHECK("-wme"); 1779138593Ssam } else 1780138593Ssam wme = 0; 1781138593Ssam 1782153422Ssam ireq.i_type = IEEE80211_IOC_BURST; 1783153422Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1784153422Ssam if (ireq.i_val) 1785155931Ssam LINE_CHECK("burst"); 1786153422Ssam else if (verbose) 1787155931Ssam LINE_CHECK("-burst"); 1788153422Ssam } 1789153422Ssam 1790138593Ssam if (opmode == IEEE80211_M_HOSTAP) { 1791138593Ssam ireq.i_type = IEEE80211_IOC_HIDESSID; 1792138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1793138593Ssam if (ireq.i_val) 1794155931Ssam LINE_CHECK("ssid HIDE"); 1795138593Ssam else if (verbose) 1796155931Ssam LINE_CHECK("ssid SHOW"); 1797138593Ssam } 1798138593Ssam 1799138593Ssam ireq.i_type = IEEE80211_IOC_APBRIDGE; 1800138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1801138593Ssam if (!ireq.i_val) 1802155931Ssam LINE_CHECK("-apbridge"); 1803138593Ssam else if (verbose) 1804155931Ssam LINE_CHECK("apbridge"); 1805138593Ssam } 1806138593Ssam 1807138593Ssam ireq.i_type = IEEE80211_IOC_DTIM_PERIOD; 1808138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1809155931Ssam LINE_CHECK("dtimperiod %u", ireq.i_val); 1810138593Ssam } else { 1811138593Ssam ireq.i_type = IEEE80211_IOC_ROAMING; 1812138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1813138593Ssam if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) { 1814138593Ssam switch (ireq.i_val) { 1815138593Ssam case IEEE80211_ROAMING_DEVICE: 1816155931Ssam LINE_CHECK("roaming DEVICE"); 1817138593Ssam break; 1818138593Ssam case IEEE80211_ROAMING_AUTO: 1819155931Ssam LINE_CHECK("roaming AUTO"); 1820138593Ssam break; 1821138593Ssam case IEEE80211_ROAMING_MANUAL: 1822155931Ssam LINE_CHECK("roaming MANUAL"); 1823138593Ssam break; 1824138593Ssam default: 1825155931Ssam LINE_CHECK("roaming UNKNOWN (0x%x)", 1826155931Ssam ireq.i_val); 1827138593Ssam break; 1828138593Ssam } 1829138593Ssam } 1830138593Ssam } 1831138593Ssam } 1832138593Ssam ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL; 1833138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1834138593Ssam if (ireq.i_val) 1835155931Ssam LINE_CHECK("bintval %u", ireq.i_val); 1836138593Ssam else if (verbose) 1837155931Ssam LINE_CHECK("bintval %u", ireq.i_val); 1838138593Ssam } 1839138593Ssam 1840138593Ssam if (wme && verbose) { 1841138593Ssam LINE_BREAK(); 1842138593Ssam list_wme(s); 1843138593Ssam } 1844138593Ssam 1845138593Ssam if (wpa) { 1846138593Ssam ireq.i_type = IEEE80211_IOC_COUNTERMEASURES; 1847138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1848138593Ssam if (ireq.i_val) 1849155931Ssam LINE_CHECK("countermeasures"); 1850138593Ssam else if (verbose) 1851155931Ssam LINE_CHECK("-countermeasures"); 1852138593Ssam } 1853138593Ssam#if 0 1854138593Ssam /* XXX not interesting with WPA done in user space */ 1855138593Ssam ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 1856138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1857138593Ssam } 1858138593Ssam 1859138593Ssam ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 1860138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1861155931Ssam LINE_CHECK("mcastcipher "); 1862138593Ssam printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 1863138593Ssam spacer = ' '; 1864138593Ssam } 1865138593Ssam 1866138593Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 1867138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1868155931Ssam LINE_CHECK("ucastcipher "); 1869138593Ssam printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 1870138593Ssam } 1871138593Ssam 1872138593Ssam if (wpa & 2) { 1873138593Ssam ireq.i_type = IEEE80211_IOC_RSNCAPS; 1874138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1875155931Ssam LINE_CHECK("RSN caps 0x%x", ireq.i_val); 187677218Sphk spacer = ' '; 1877138593Ssam } 187877218Sphk } 1879138593Ssam 1880138593Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 1881138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1882138593Ssam } 1883138593Ssam#endif 1884138593Ssam LINE_BREAK(); 188577218Sphk } 1886138593Ssam LINE_BREAK(); 188777218Sphk 188877218Sphkend: 188977218Sphk return; 189077218Sphk} 189177218Sphk 189277218Sphkstatic void 189377218Sphkset80211(int s, int type, int val, int len, u_int8_t *data) 189477218Sphk{ 189577218Sphk struct ieee80211req ireq; 189677218Sphk 189777218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 189877218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 189977218Sphk ireq.i_type = type; 190077218Sphk ireq.i_val = val; 190177218Sphk ireq.i_len = len; 190277218Sphk ireq.i_data = data; 190391454Sbrooks if (ioctl(s, SIOCS80211, &ireq) < 0) 190477218Sphk err(1, "SIOCS80211"); 190577218Sphk} 190677218Sphk 190777218Sphkstatic const char * 190877218Sphkget_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 190977218Sphk{ 191077218Sphk int len; 191177218Sphk int hexstr; 191277218Sphk u_int8_t *p; 191377218Sphk 191477218Sphk len = *lenp; 191577218Sphk p = buf; 191677218Sphk hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 191777218Sphk if (hexstr) 191877218Sphk val += 2; 191977218Sphk for (;;) { 192077218Sphk if (*val == '\0') 192177218Sphk break; 192277218Sphk if (sep != NULL && strchr(sep, *val) != NULL) { 192377218Sphk val++; 192477218Sphk break; 192577218Sphk } 192677218Sphk if (hexstr) { 1927127831Sphk if (!isxdigit((u_char)val[0])) { 192877218Sphk warnx("bad hexadecimal digits"); 192977218Sphk return NULL; 193077218Sphk } 1931127831Sphk if (!isxdigit((u_char)val[1])) { 1932127831Sphk warnx("odd count hexadecimal digits"); 1933127831Sphk return NULL; 1934127831Sphk } 193577218Sphk } 1936127831Sphk if (p >= buf + len) { 193777218Sphk if (hexstr) 193877218Sphk warnx("hexadecimal digits too long"); 193977218Sphk else 1940127831Sphk warnx("string too long"); 194177218Sphk return NULL; 194277218Sphk } 194377218Sphk if (hexstr) { 194477218Sphk#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 194577218Sphk *p++ = (tohex((u_char)val[0]) << 4) | 194677218Sphk tohex((u_char)val[1]); 194777218Sphk#undef tohex 194877218Sphk val += 2; 194977218Sphk } else 195077218Sphk *p++ = *val++; 195177218Sphk } 195277218Sphk len = p - buf; 195377218Sphk /* The string "-" is treated as the empty string. */ 1954165045Ssam if (!hexstr && len == 1 && buf[0] == '-') { 195577218Sphk len = 0; 1956165045Ssam memset(buf, 0, *lenp); 1957165045Ssam } else if (len < *lenp) 195877218Sphk memset(p, 0, *lenp - len); 195977218Sphk *lenp = len; 196077218Sphk return val; 196177218Sphk} 196277218Sphk 196377218Sphkstatic void 196477218Sphkprint_string(const u_int8_t *buf, int len) 196577218Sphk{ 196677218Sphk int i; 196777218Sphk int hasspc; 196877218Sphk 196977218Sphk i = 0; 197077218Sphk hasspc = 0; 197191454Sbrooks for (; i < len; i++) { 197277218Sphk if (!isprint(buf[i]) && buf[i] != '\0') 197377218Sphk break; 197477218Sphk if (isspace(buf[i])) 197577218Sphk hasspc++; 197677218Sphk } 197777218Sphk if (i == len) { 197877218Sphk if (hasspc || len == 0 || buf[0] == '\0') 197977218Sphk printf("\"%.*s\"", len, buf); 198077218Sphk else 198177218Sphk printf("%.*s", len, buf); 198277218Sphk } else { 198377218Sphk printf("0x"); 198477218Sphk for (i = 0; i < len; i++) 198577218Sphk printf("%02x", buf[i]); 198677218Sphk } 198777218Sphk} 198877218Sphk 1989138593Ssamstatic struct cmd ieee80211_cmds[] = { 1990138593Ssam DEF_CMD_ARG("ssid", set80211ssid), 1991138593Ssam DEF_CMD_ARG("nwid", set80211ssid), 1992138593Ssam DEF_CMD_ARG("stationname", set80211stationname), 1993138593Ssam DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 1994138593Ssam DEF_CMD_ARG("channel", set80211channel), 1995138593Ssam DEF_CMD_ARG("authmode", set80211authmode), 1996138593Ssam DEF_CMD_ARG("powersavemode", set80211powersavemode), 1997138593Ssam DEF_CMD("powersave", 1, set80211powersave), 1998138593Ssam DEF_CMD("-powersave", 0, set80211powersave), 1999138593Ssam DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 2000138593Ssam DEF_CMD_ARG("wepmode", set80211wepmode), 2001138593Ssam DEF_CMD("wep", 1, set80211wep), 2002138593Ssam DEF_CMD("-wep", 0, set80211wep), 2003139493Ssam DEF_CMD_ARG("deftxkey", set80211weptxkey), 2004138593Ssam DEF_CMD_ARG("weptxkey", set80211weptxkey), 2005138593Ssam DEF_CMD_ARG("wepkey", set80211wepkey), 2006138593Ssam DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 2007138593Ssam DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 2008138593Ssam DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 2009138593Ssam DEF_CMD_ARG("protmode", set80211protmode), 2010138593Ssam DEF_CMD_ARG("txpower", set80211txpower), 2011138593Ssam DEF_CMD_ARG("roaming", set80211roaming), 2012138593Ssam DEF_CMD("wme", 1, set80211wme), 2013138593Ssam DEF_CMD("-wme", 0, set80211wme), 2014138593Ssam DEF_CMD("hidessid", 1, set80211hidessid), 2015138593Ssam DEF_CMD("-hidessid", 0, set80211hidessid), 2016138593Ssam DEF_CMD("apbridge", 1, set80211apbridge), 2017138593Ssam DEF_CMD("-apbridge", 0, set80211apbridge), 2018138593Ssam DEF_CMD_ARG("chanlist", set80211chanlist), 2019138593Ssam DEF_CMD_ARG("bssid", set80211bssid), 2020138593Ssam DEF_CMD_ARG("ap", set80211bssid), 2021138593Ssam DEF_CMD("scan", 0, set80211scan), 2022138593Ssam DEF_CMD_ARG("list", set80211list), 2023138593Ssam DEF_CMD_ARG2("cwmin", set80211cwmin), 2024138593Ssam DEF_CMD_ARG2("cwmax", set80211cwmax), 2025138593Ssam DEF_CMD_ARG2("aifs", set80211aifs), 2026138593Ssam DEF_CMD_ARG2("txoplimit", set80211txoplimit), 2027148621Ssam DEF_CMD_ARG("acm", set80211acm), 2028148621Ssam DEF_CMD_ARG("-acm", set80211noacm), 2029148621Ssam DEF_CMD_ARG("ack", set80211ackpolicy), 2030148621Ssam DEF_CMD_ARG("-ack", set80211noackpolicy), 2031138593Ssam DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 2032138593Ssam DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 2033138593Ssam DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 2034138593Ssam DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 2035138593Ssam DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 2036138593Ssam DEF_CMD_ARG("bintval", set80211bintval), 2037138593Ssam DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 2038138593Ssam DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 2039138593Ssam DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 2040138593Ssam DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 2041138593Ssam DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 2042138593Ssam DEF_CMD_ARG("mac:add", set80211addmac), 2043138593Ssam DEF_CMD_ARG("mac:del", set80211delmac), 2044138593Ssam DEF_CMD_ARG("mac:kick", set80211kickmac), 2045147795Ssam DEF_CMD("pureg", 1, set80211pureg), 2046147795Ssam DEF_CMD("-pureg", 0, set80211pureg), 2047153354Ssam DEF_CMD_ARG("mcastrate", set80211mcastrate), 2048148416Ssam DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 2049153422Ssam DEF_CMD("burst", 1, set80211burst), 2050153422Ssam DEF_CMD("-burst", 0, set80211burst), 2051160687Ssam DEF_CMD_ARG("bmiss", set80211bmissthreshold), 2052160687Ssam DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), 2053138593Ssam}; 2054138593Ssamstatic struct afswtch af_ieee80211 = { 2055138593Ssam .af_name = "af_ieee80211", 2056138593Ssam .af_af = AF_UNSPEC, 2057139494Ssam .af_other_status = ieee80211_status, 2058138593Ssam}; 2059138593Ssam 2060138593Ssamstatic __constructor void 2061138593Ssamieee80211_ctor(void) 2062138593Ssam{ 2063138593Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 2064138593Ssam int i; 2065138593Ssam 2066138593Ssam for (i = 0; i < N(ieee80211_cmds); i++) 2067138593Ssam cmd_register(&ieee80211_cmds[i]); 2068138593Ssam af_register(&af_ieee80211); 2069138593Ssam#undef N 2070138593Ssam} 2071