ifieee80211.c revision 165570
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 165570 2006-12-27 18:48:50Z 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 159138593Ssam/* 160138593Ssam * Convert MHz frequency to IEEE channel number. 161138593Ssam */ 162138593Ssamstatic u_int 163165570Ssamieee80211_mhz2ieee(u_int freq, u_int flags) 164138593Ssam{ 165138593Ssam if (freq == 2484) 166138593Ssam return 14; 167138593Ssam if (freq < 2484) 168138593Ssam return (freq - 2407) / 5; 169165570Ssam if (freq < 5000) { 170165570Ssam if (freq > 4900) /* XXX hack mapping of PSB */ 171165570Ssam return 37 + ((freq * 10) + 172165570Ssam (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; 173165570Ssam else 174165570Ssam return 15 + ((freq - 2512) / 20); 175165570Ssam } 176138593Ssam return (freq - 5000) / 5; 177138593Ssam} 178138593Ssam 179138593Ssamstatic void 18077218Sphkset80211channel(const char *val, int d, int s, const struct afswtch *rafp) 18177218Sphk{ 182138593Ssam if (!isanyarg(val)) { 183138593Ssam int v = atoi(val); 184138593Ssam if (v > 255) /* treat as frequency */ 185165570Ssam v = ieee80211_mhz2ieee(v, 0); 186138593Ssam set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL); 187138593Ssam } else 188116957Ssam set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL); 18977218Sphk} 19077218Sphk 191138593Ssamstatic void 19277218Sphkset80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 19377218Sphk{ 19477218Sphk int mode; 19577218Sphk 19691454Sbrooks if (strcasecmp(val, "none") == 0) { 19777218Sphk mode = IEEE80211_AUTH_NONE; 19891454Sbrooks } else if (strcasecmp(val, "open") == 0) { 19977218Sphk mode = IEEE80211_AUTH_OPEN; 20091454Sbrooks } else if (strcasecmp(val, "shared") == 0) { 20177218Sphk mode = IEEE80211_AUTH_SHARED; 202138593Ssam } else if (strcasecmp(val, "8021x") == 0) { 203138593Ssam mode = IEEE80211_AUTH_8021X; 204138593Ssam } else if (strcasecmp(val, "wpa") == 0) { 205138593Ssam mode = IEEE80211_AUTH_WPA; 20677218Sphk } else { 207150708Sru errx(1, "unknown authmode"); 20877218Sphk } 20977218Sphk 21077218Sphk set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 21177218Sphk} 21277218Sphk 213138593Ssamstatic void 21477218Sphkset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 21577218Sphk{ 21677218Sphk int mode; 21777218Sphk 21891454Sbrooks if (strcasecmp(val, "off") == 0) { 21977218Sphk mode = IEEE80211_POWERSAVE_OFF; 22091454Sbrooks } else if (strcasecmp(val, "on") == 0) { 22177218Sphk mode = IEEE80211_POWERSAVE_ON; 22291454Sbrooks } else if (strcasecmp(val, "cam") == 0) { 22377218Sphk mode = IEEE80211_POWERSAVE_CAM; 22491454Sbrooks } else if (strcasecmp(val, "psp") == 0) { 22577218Sphk mode = IEEE80211_POWERSAVE_PSP; 22691454Sbrooks } else if (strcasecmp(val, "psp-cam") == 0) { 22777218Sphk mode = IEEE80211_POWERSAVE_PSP_CAM; 22877218Sphk } else { 229150708Sru errx(1, "unknown powersavemode"); 23077218Sphk } 23177218Sphk 23277218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 23377218Sphk} 23477218Sphk 235138593Ssamstatic void 23677218Sphkset80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 23777218Sphk{ 23877218Sphk if (d == 0) 23977218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 24077218Sphk 0, NULL); 24177218Sphk else 24277218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 24377218Sphk 0, NULL); 24477218Sphk} 24577218Sphk 246138593Ssamstatic void 24777218Sphkset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 24877218Sphk{ 24977218Sphk set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 25077218Sphk} 25177218Sphk 252138593Ssamstatic void 25377218Sphkset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 25477218Sphk{ 25577218Sphk int mode; 25677218Sphk 25791454Sbrooks if (strcasecmp(val, "off") == 0) { 25877218Sphk mode = IEEE80211_WEP_OFF; 25991454Sbrooks } else if (strcasecmp(val, "on") == 0) { 26077218Sphk mode = IEEE80211_WEP_ON; 26191454Sbrooks } else if (strcasecmp(val, "mixed") == 0) { 26277218Sphk mode = IEEE80211_WEP_MIXED; 26377218Sphk } else { 264150708Sru errx(1, "unknown wep mode"); 26577218Sphk } 26677218Sphk 26777218Sphk set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 26877218Sphk} 26977218Sphk 270138593Ssamstatic void 27177218Sphkset80211wep(const char *val, int d, int s, const struct afswtch *rafp) 27277218Sphk{ 27377218Sphk set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 27477218Sphk} 27577218Sphk 276139493Ssamstatic int 277139493Ssamisundefarg(const char *arg) 278139493Ssam{ 279139493Ssam return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 280139493Ssam} 281139493Ssam 282138593Ssamstatic void 28377218Sphkset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 28477218Sphk{ 285139493Ssam if (isundefarg(val)) 286139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 287139493Ssam else 288139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 28977218Sphk} 29077218Sphk 291138593Ssamstatic void 29277218Sphkset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 29377218Sphk{ 29477218Sphk int key = 0; 29577218Sphk int len; 296120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 29777218Sphk 29891454Sbrooks if (isdigit(val[0]) && val[1] == ':') { 29977218Sphk key = atoi(val)-1; 30077218Sphk val += 2; 30177218Sphk } 30277218Sphk 30377218Sphk bzero(data, sizeof(data)); 30477218Sphk len = sizeof(data); 30577218Sphk get_string(val, NULL, data, &len); 30677218Sphk 30777218Sphk set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 30877218Sphk} 30977218Sphk 31077218Sphk/* 311148686Sstefanf * This function is purely a NetBSD compatability interface. The NetBSD 312148686Sstefanf * interface is too inflexible, but it's there so we'll support it since 31377218Sphk * it's not all that hard. 31477218Sphk */ 315138593Ssamstatic void 31677218Sphkset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 31777218Sphk{ 31877218Sphk int txkey; 31977218Sphk int i, len; 320120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 32177218Sphk 32277218Sphk set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 32377218Sphk 32491454Sbrooks if (isdigit(val[0]) && val[1] == ':') { 32577218Sphk txkey = val[0]-'0'-1; 32677218Sphk val += 2; 32777218Sphk 32891454Sbrooks for (i = 0; i < 4; i++) { 32977218Sphk bzero(data, sizeof(data)); 33077218Sphk len = sizeof(data); 33177218Sphk val = get_string(val, ",", data, &len); 332151827Sbrooks if (val == NULL) 333151827Sbrooks exit(1); 33477218Sphk 33577218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 33677218Sphk } 33777218Sphk } else { 33877218Sphk bzero(data, sizeof(data)); 33977218Sphk len = sizeof(data); 34077218Sphk get_string(val, NULL, data, &len); 34177218Sphk txkey = 0; 34277218Sphk 34377218Sphk set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 34477218Sphk 34577218Sphk bzero(data, sizeof(data)); 34691454Sbrooks for (i = 1; i < 4; i++) 34777218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 34877218Sphk } 34977218Sphk 35077218Sphk set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 35177218Sphk} 35277218Sphk 353138593Ssamstatic void 354127649Ssamset80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 355127649Ssam{ 356148416Ssam set80211(s, IEEE80211_IOC_RTSTHRESHOLD, 357148416Ssam isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL); 358127649Ssam} 359127649Ssam 360138593Ssamstatic void 361127649Ssamset80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 362127649Ssam{ 363127649Ssam int mode; 364127649Ssam 365127649Ssam if (strcasecmp(val, "off") == 0) { 366127649Ssam mode = IEEE80211_PROTMODE_OFF; 367127649Ssam } else if (strcasecmp(val, "cts") == 0) { 368127649Ssam mode = IEEE80211_PROTMODE_CTS; 369127649Ssam } else if (strcasecmp(val, "rtscts") == 0) { 370127649Ssam mode = IEEE80211_PROTMODE_RTSCTS; 371127649Ssam } else { 372150708Sru errx(1, "unknown protection mode"); 373127649Ssam } 374127649Ssam 375127649Ssam set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 376127649Ssam} 377127649Ssam 378138593Ssamstatic void 379127649Ssamset80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 380127649Ssam{ 381127649Ssam set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); 382127649Ssam} 383127649Ssam 384138593Ssam#define IEEE80211_ROAMING_DEVICE 0 385138593Ssam#define IEEE80211_ROAMING_AUTO 1 386138593Ssam#define IEEE80211_ROAMING_MANUAL 2 387138593Ssam 388138593Ssamstatic void 389138593Ssamset80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 39077218Sphk{ 391138593Ssam int mode; 39277218Sphk 393138593Ssam if (strcasecmp(val, "device") == 0) { 394138593Ssam mode = IEEE80211_ROAMING_DEVICE; 395138593Ssam } else if (strcasecmp(val, "auto") == 0) { 396138593Ssam mode = IEEE80211_ROAMING_AUTO; 397138593Ssam } else if (strcasecmp(val, "manual") == 0) { 398138593Ssam mode = IEEE80211_ROAMING_MANUAL; 399138593Ssam } else { 400150708Sru errx(1, "unknown roaming mode"); 401138593Ssam } 402138593Ssam set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 403138593Ssam} 404138593Ssam 405138593Ssamstatic void 406138593Ssamset80211wme(const char *val, int d, int s, const struct afswtch *rafp) 407138593Ssam{ 408138593Ssam set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 409138593Ssam} 410138593Ssam 411138593Ssamstatic void 412138593Ssamset80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 413138593Ssam{ 414138593Ssam set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 415138593Ssam} 416138593Ssam 417138593Ssamstatic void 418138593Ssamset80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 419138593Ssam{ 420138593Ssam set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 421138593Ssam} 422138593Ssam 423138593Ssamstatic void 424138593Ssamset80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 425138593Ssam{ 426138593Ssam struct ieee80211req_chanlist chanlist; 427138593Ssam#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) 428138593Ssam char *temp, *cp, *tp; 429138593Ssam 430138593Ssam temp = malloc(strlen(val) + 1); 431138593Ssam if (temp == NULL) 432138593Ssam errx(1, "malloc failed"); 433138593Ssam strcpy(temp, val); 434138593Ssam memset(&chanlist, 0, sizeof(chanlist)); 435138593Ssam cp = temp; 436138593Ssam for (;;) { 437138593Ssam int first, last, f; 438138593Ssam 439138593Ssam tp = strchr(cp, ','); 440138593Ssam if (tp != NULL) 441138593Ssam *tp++ = '\0'; 442138593Ssam switch (sscanf(cp, "%u-%u", &first, &last)) { 443138593Ssam case 1: 444138593Ssam if (first > MAXCHAN) 445146873Sjhb errx(-1, "channel %u out of range, max %zu", 446138593Ssam first, MAXCHAN); 447138593Ssam setbit(chanlist.ic_channels, first); 448138593Ssam break; 449138593Ssam case 2: 450138593Ssam if (first > MAXCHAN) 451146873Sjhb errx(-1, "channel %u out of range, max %zu", 452138593Ssam first, MAXCHAN); 453138593Ssam if (last > MAXCHAN) 454146873Sjhb errx(-1, "channel %u out of range, max %zu", 455138593Ssam last, MAXCHAN); 456138593Ssam if (first > last) 457138593Ssam errx(-1, "void channel range, %u > %u", 458138593Ssam first, last); 459138593Ssam for (f = first; f <= last; f++) 460138593Ssam setbit(chanlist.ic_channels, f); 461138593Ssam break; 462138593Ssam } 463138593Ssam if (tp == NULL) 464138593Ssam break; 465138593Ssam while (isspace(*tp)) 466138593Ssam tp++; 467138593Ssam if (!isdigit(*tp)) 468138593Ssam break; 469138593Ssam cp = tp; 470138593Ssam } 471138593Ssam set80211(s, IEEE80211_IOC_CHANLIST, 0, 472138593Ssam sizeof(chanlist), (uint8_t *) &chanlist); 473138593Ssam#undef MAXCHAN 474138593Ssam} 475138593Ssam 476138593Ssamstatic void 477138593Ssamset80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 478138593Ssam{ 479138593Ssam 480138593Ssam if (!isanyarg(val)) { 481138593Ssam char *temp; 482138593Ssam struct sockaddr_dl sdl; 483138593Ssam 484155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 485138593Ssam if (temp == NULL) 486138593Ssam errx(1, "malloc failed"); 487138593Ssam temp[0] = ':'; 488138593Ssam strcpy(temp + 1, val); 489138593Ssam sdl.sdl_len = sizeof(sdl); 490138593Ssam link_addr(temp, &sdl); 491138593Ssam free(temp); 492138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 493138593Ssam errx(1, "malformed link-level address"); 494138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 495138593Ssam IEEE80211_ADDR_LEN, LLADDR(&sdl)); 496138593Ssam } else { 497138593Ssam uint8_t zerobssid[IEEE80211_ADDR_LEN]; 498138593Ssam memset(zerobssid, 0, sizeof(zerobssid)); 499138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 500138593Ssam IEEE80211_ADDR_LEN, zerobssid); 501138593Ssam } 502138593Ssam} 503138593Ssam 504138593Ssamstatic int 505138593Ssamgetac(const char *ac) 506138593Ssam{ 507138593Ssam if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 508138593Ssam return WME_AC_BE; 509138593Ssam if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 510138593Ssam return WME_AC_BK; 511138593Ssam if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 512138593Ssam return WME_AC_VI; 513138593Ssam if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 514138593Ssam return WME_AC_VO; 515138593Ssam errx(1, "unknown wme access class %s", ac); 516138593Ssam} 517138593Ssam 518138593Ssamstatic 519138593SsamDECL_CMD_FUNC2(set80211cwmin, ac, val) 520138593Ssam{ 521138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 522138593Ssam} 523138593Ssam 524138593Ssamstatic 525138593SsamDECL_CMD_FUNC2(set80211cwmax, ac, val) 526138593Ssam{ 527138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 528138593Ssam} 529138593Ssam 530138593Ssamstatic 531138593SsamDECL_CMD_FUNC2(set80211aifs, ac, val) 532138593Ssam{ 533138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 534138593Ssam} 535138593Ssam 536138593Ssamstatic 537138593SsamDECL_CMD_FUNC2(set80211txoplimit, ac, val) 538138593Ssam{ 539138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 540138593Ssam} 541138593Ssam 542138593Ssamstatic 543148621SsamDECL_CMD_FUNC(set80211acm, ac, d) 544138593Ssam{ 545148621Ssam set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL); 546138593Ssam} 547148621Ssamstatic 548148621SsamDECL_CMD_FUNC(set80211noacm, ac, d) 549148621Ssam{ 550148621Ssam set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL); 551148621Ssam} 552138593Ssam 553138593Ssamstatic 554148621SsamDECL_CMD_FUNC(set80211ackpolicy, ac, d) 555138593Ssam{ 556148621Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL); 557138593Ssam} 558148621Ssamstatic 559148621SsamDECL_CMD_FUNC(set80211noackpolicy, ac, d) 560148621Ssam{ 561148621Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL); 562148621Ssam} 563138593Ssam 564138593Ssamstatic 565138593SsamDECL_CMD_FUNC2(set80211bsscwmin, ac, val) 566138593Ssam{ 567138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 568138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 569138593Ssam} 570138593Ssam 571138593Ssamstatic 572138593SsamDECL_CMD_FUNC2(set80211bsscwmax, ac, val) 573138593Ssam{ 574138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 575138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 576138593Ssam} 577138593Ssam 578138593Ssamstatic 579138593SsamDECL_CMD_FUNC2(set80211bssaifs, ac, val) 580138593Ssam{ 581138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 582138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 583138593Ssam} 584138593Ssam 585138593Ssamstatic 586138593SsamDECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 587138593Ssam{ 588138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 589138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 590138593Ssam} 591138593Ssam 592138593Ssamstatic 593138593SsamDECL_CMD_FUNC(set80211dtimperiod, val, d) 594138593Ssam{ 595138593Ssam set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 596138593Ssam} 597138593Ssam 598138593Ssamstatic 599138593SsamDECL_CMD_FUNC(set80211bintval, val, d) 600138593Ssam{ 601138593Ssam set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 602138593Ssam} 603138593Ssam 604138593Ssamstatic void 605138593Ssamset80211macmac(int s, int op, const char *val) 606138593Ssam{ 607138593Ssam char *temp; 608138593Ssam struct sockaddr_dl sdl; 609138593Ssam 610155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 611138593Ssam if (temp == NULL) 612138593Ssam errx(1, "malloc failed"); 613138593Ssam temp[0] = ':'; 614138593Ssam strcpy(temp + 1, val); 615138593Ssam sdl.sdl_len = sizeof(sdl); 616138593Ssam link_addr(temp, &sdl); 617138593Ssam free(temp); 618138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 619138593Ssam errx(1, "malformed link-level address"); 620138593Ssam set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 621138593Ssam} 622138593Ssam 623138593Ssamstatic 624138593SsamDECL_CMD_FUNC(set80211addmac, val, d) 625138593Ssam{ 626138593Ssam set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 627138593Ssam} 628138593Ssam 629138593Ssamstatic 630138593SsamDECL_CMD_FUNC(set80211delmac, val, d) 631138593Ssam{ 632138593Ssam set80211macmac(s, IEEE80211_IOC_DELMAC, val); 633138593Ssam} 634138593Ssam 635138593Ssamstatic 636149029SsamDECL_CMD_FUNC(set80211kickmac, val, d) 637149029Ssam{ 638149029Ssam char *temp; 639149029Ssam struct sockaddr_dl sdl; 640149029Ssam struct ieee80211req_mlme mlme; 641149029Ssam 642155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 643149029Ssam if (temp == NULL) 644149029Ssam errx(1, "malloc failed"); 645149029Ssam temp[0] = ':'; 646149029Ssam strcpy(temp + 1, val); 647149029Ssam sdl.sdl_len = sizeof(sdl); 648149029Ssam link_addr(temp, &sdl); 649149029Ssam free(temp); 650149029Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 651149029Ssam errx(1, "malformed link-level address"); 652149029Ssam memset(&mlme, 0, sizeof(mlme)); 653149029Ssam mlme.im_op = IEEE80211_MLME_DEAUTH; 654149029Ssam mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; 655149029Ssam memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN); 656149029Ssam set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme); 657149029Ssam} 658149029Ssam 659149029Ssamstatic 660138593SsamDECL_CMD_FUNC(set80211maccmd, val, d) 661138593Ssam{ 662138593Ssam set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 663138593Ssam} 664138593Ssam 665147795Ssamstatic void 666147795Ssamset80211pureg(const char *val, int d, int s, const struct afswtch *rafp) 667147795Ssam{ 668147795Ssam set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); 669147795Ssam} 670147795Ssam 671153422Ssamstatic void 672153422Ssamset80211burst(const char *val, int d, int s, const struct afswtch *rafp) 673153422Ssam{ 674153422Ssam set80211(s, IEEE80211_IOC_BURST, d, 0, NULL); 675153422Ssam} 676153422Ssam 677148416Ssamstatic 678153354SsamDECL_CMD_FUNC(set80211mcastrate, val, d) 679153354Ssam{ 680153354Ssam set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL); 681153354Ssam} 682153354Ssam 683153354Ssamstatic 684148416SsamDECL_CMD_FUNC(set80211fragthreshold, val, d) 685148416Ssam{ 686148416Ssam set80211(s, IEEE80211_IOC_FRAGTHRESHOLD, 687148416Ssam isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL); 688148416Ssam} 689148416Ssam 690160687Ssamstatic 691160687SsamDECL_CMD_FUNC(set80211bmissthreshold, val, d) 692160687Ssam{ 693160687Ssam set80211(s, IEEE80211_IOC_BMISSTHRESHOLD, 694160687Ssam isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL); 695160687Ssam} 696160687Ssam 697138593Ssamstatic int 698138593Ssamgetmaxrate(uint8_t rates[15], uint8_t nrates) 699138593Ssam{ 700138593Ssam int i, maxrate = -1; 701138593Ssam 702138593Ssam for (i = 0; i < nrates; i++) { 703138593Ssam int rate = rates[i] & IEEE80211_RATE_VAL; 704138593Ssam if (rate > maxrate) 705138593Ssam maxrate = rate; 706138593Ssam } 707138593Ssam return maxrate / 2; 708138593Ssam} 709138593Ssam 710138593Ssamstatic const char * 711138593Ssamgetcaps(int capinfo) 712138593Ssam{ 713138593Ssam static char capstring[32]; 714138593Ssam char *cp = capstring; 715138593Ssam 716138593Ssam if (capinfo & IEEE80211_CAPINFO_ESS) 717138593Ssam *cp++ = 'E'; 718138593Ssam if (capinfo & IEEE80211_CAPINFO_IBSS) 719138593Ssam *cp++ = 'I'; 720138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 721138593Ssam *cp++ = 'c'; 722138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 723138593Ssam *cp++ = 'C'; 724138593Ssam if (capinfo & IEEE80211_CAPINFO_PRIVACY) 725138593Ssam *cp++ = 'P'; 726138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 727138593Ssam *cp++ = 'S'; 728138593Ssam if (capinfo & IEEE80211_CAPINFO_PBCC) 729138593Ssam *cp++ = 'B'; 730138593Ssam if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 731138593Ssam *cp++ = 'A'; 732138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 733138593Ssam *cp++ = 's'; 734138593Ssam if (capinfo & IEEE80211_CAPINFO_RSN) 735138593Ssam *cp++ = 'R'; 736138593Ssam if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 737138593Ssam *cp++ = 'D'; 738138593Ssam *cp = '\0'; 739138593Ssam return capstring; 740138593Ssam} 741138593Ssam 742159885Ssamstatic const char * 743159885Ssamgetflags(int flags) 744159885Ssam{ 745159885Ssam/* XXX need these publicly defined or similar */ 746159885Ssam#define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */ 747159885Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 748159885Ssam#define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */ 749159885Ssam#define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */ 750159885Ssam static char flagstring[32]; 751159885Ssam char *cp = flagstring; 752159885Ssam 753159885Ssam if (flags & IEEE80211_NODE_AUTH) 754159885Ssam *cp++ = 'A'; 755159885Ssam if (flags & IEEE80211_NODE_QOS) 756159885Ssam *cp++ = 'Q'; 757159885Ssam if (flags & IEEE80211_NODE_ERP) 758159885Ssam *cp++ = 'E'; 759159885Ssam if (flags & IEEE80211_NODE_PWR_MGT) 760159885Ssam *cp++ = 'P'; 761159885Ssam *cp = '\0'; 762159885Ssam return flagstring; 763159885Ssam#undef IEEE80211_NODE_AUTH 764159885Ssam#undef IEEE80211_NODE_QOS 765159885Ssam#undef IEEE80211_NODE_ERP 766159885Ssam#undef IEEE80211_NODE_PWR_MGT 767159885Ssam} 768159885Ssam 769138593Ssamstatic void 770138593Ssamprintie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 771138593Ssam{ 772138593Ssam printf("%s", tag); 773138593Ssam if (verbose) { 774138593Ssam maxlen -= strlen(tag)+2; 775138593Ssam if (2*ielen > maxlen) 776138593Ssam maxlen--; 777138593Ssam printf("<"); 778138593Ssam for (; ielen > 0; ie++, ielen--) { 779138593Ssam if (maxlen-- <= 0) 780138593Ssam break; 781138593Ssam printf("%02x", *ie); 782138593Ssam } 783138593Ssam if (ielen != 0) 784138593Ssam printf("-"); 785138593Ssam printf(">"); 786138593Ssam } 787138593Ssam} 788138593Ssam 789138593Ssam/* 790138593Ssam * Copy the ssid string contents into buf, truncating to fit. If the 791138593Ssam * ssid is entirely printable then just copy intact. Otherwise convert 792138593Ssam * to hexadecimal. If the result is truncated then replace the last 793138593Ssam * three characters with "...". 794138593Ssam */ 795146873Sjhbstatic int 796138593Ssamcopy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 797138593Ssam{ 798138593Ssam const u_int8_t *p; 799138593Ssam size_t maxlen; 800138593Ssam int i; 801138593Ssam 802138593Ssam if (essid_len > bufsize) 803138593Ssam maxlen = bufsize; 804138593Ssam else 805138593Ssam maxlen = essid_len; 806138593Ssam /* determine printable or not */ 807138593Ssam for (i = 0, p = essid; i < maxlen; i++, p++) { 808138593Ssam if (*p < ' ' || *p > 0x7e) 809138593Ssam break; 810138593Ssam } 811138593Ssam if (i != maxlen) { /* not printable, print as hex */ 812138593Ssam if (bufsize < 3) 813138593Ssam return 0; 814138593Ssam strlcpy(buf, "0x", bufsize); 815138593Ssam bufsize -= 2; 816138593Ssam p = essid; 817138593Ssam for (i = 0; i < maxlen && bufsize >= 2; i++) { 818147489Savatar sprintf(&buf[2+2*i], "%02x", p[i]); 819138593Ssam bufsize -= 2; 820138593Ssam } 821147489Savatar if (i != essid_len) 822147489Savatar memcpy(&buf[2+2*i-3], "...", 3); 823138593Ssam } else { /* printable, truncate as needed */ 824138593Ssam memcpy(buf, essid, maxlen); 825147489Savatar if (maxlen != essid_len) 826147489Savatar memcpy(&buf[maxlen-3], "...", 3); 827138593Ssam } 828138593Ssam return maxlen; 829138593Ssam} 830138593Ssam 831148686Sstefanf/* unaligned little endian access */ 832138593Ssam#define LE_READ_4(p) \ 833138593Ssam ((u_int32_t) \ 834138593Ssam ((((const u_int8_t *)(p))[0] ) | \ 835138593Ssam (((const u_int8_t *)(p))[1] << 8) | \ 836138593Ssam (((const u_int8_t *)(p))[2] << 16) | \ 837138593Ssam (((const u_int8_t *)(p))[3] << 24))) 838138593Ssam 839138593Ssamstatic int __inline 840138593Ssamiswpaoui(const u_int8_t *frm) 841138593Ssam{ 842138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 843138593Ssam} 844138593Ssam 845138593Ssamstatic int __inline 846138593Ssamiswmeoui(const u_int8_t *frm) 847138593Ssam{ 848138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); 849138593Ssam} 850138593Ssam 851138593Ssamstatic int __inline 852138593Ssamisatherosoui(const u_int8_t *frm) 853138593Ssam{ 854138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 855138593Ssam} 856138593Ssam 857138593Ssamstatic void 858138593Ssamprinties(const u_int8_t *vp, int ielen, int maxcols) 859138593Ssam{ 860138593Ssam while (ielen > 0) { 861138593Ssam switch (vp[0]) { 862138593Ssam case IEEE80211_ELEMID_VENDOR: 863138593Ssam if (iswpaoui(vp)) 864138593Ssam printie(" WPA", vp, 2+vp[1], maxcols); 865138593Ssam else if (iswmeoui(vp)) 866138593Ssam printie(" WME", vp, 2+vp[1], maxcols); 867139492Ssam else if (isatherosoui(vp)) 868139492Ssam printie(" ATH", vp, 2+vp[1], maxcols); 869138593Ssam else 870138593Ssam printie(" VEN", vp, 2+vp[1], maxcols); 871138593Ssam break; 872138593Ssam case IEEE80211_ELEMID_RSN: 873138593Ssam printie(" RSN", vp, 2+vp[1], maxcols); 874138593Ssam break; 875138593Ssam default: 876138593Ssam printie(" ???", vp, 2+vp[1], maxcols); 877138593Ssam break; 878138593Ssam } 879138593Ssam ielen -= 2+vp[1]; 880138593Ssam vp += 2+vp[1]; 881138593Ssam } 882138593Ssam} 883138593Ssam 884138593Ssamstatic void 885138593Ssamlist_scan(int s) 886138593Ssam{ 887138593Ssam uint8_t buf[24*1024]; 888138593Ssam struct ieee80211req ireq; 889153892Srwatson char ssid[IEEE80211_NWID_LEN+1]; 890138593Ssam uint8_t *cp; 891154522Ssam int len, ssidmax; 892138593Ssam 89377218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 89477218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 895138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; 896138593Ssam ireq.i_data = buf; 897138593Ssam ireq.i_len = sizeof(buf); 898138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 899138593Ssam errx(1, "unable to get scan results"); 900138593Ssam len = ireq.i_len; 901138593Ssam if (len < sizeof(struct ieee80211req_scan_result)) 902138593Ssam return; 903138593Ssam 904154522Ssam ssidmax = verbose ? IEEE80211_NWID_LEN : 14; 905154522Ssam printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n" 906154522Ssam , ssidmax, ssidmax, "SSID" 907138593Ssam , "BSSID" 908138593Ssam , "CHAN" 909138593Ssam , "RATE" 910138593Ssam , "S:N" 911138593Ssam , "INT" 912138593Ssam , "CAPS" 913138593Ssam ); 914138593Ssam cp = buf; 915138593Ssam do { 916138593Ssam struct ieee80211req_scan_result *sr; 917138593Ssam uint8_t *vp; 918138593Ssam 919138593Ssam sr = (struct ieee80211req_scan_result *) cp; 920138593Ssam vp = (u_int8_t *)(sr+1); 921154522Ssam printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s" 922154522Ssam , ssidmax 923155461Ssam , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len) 924154522Ssam , ssid 925138593Ssam , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 926165570Ssam , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) 927138593Ssam , getmaxrate(sr->isr_rates, sr->isr_nrates) 928138593Ssam , sr->isr_rssi, sr->isr_noise 929138593Ssam , sr->isr_intval 930138593Ssam , getcaps(sr->isr_capinfo) 931138593Ssam ); 932138593Ssam printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);; 933138593Ssam printf("\n"); 934138593Ssam cp += sr->isr_len, len -= sr->isr_len; 935138593Ssam } while (len >= sizeof(struct ieee80211req_scan_result)); 936138593Ssam} 937138593Ssam 938138593Ssam#include <net80211/ieee80211_freebsd.h> 939138593Ssam 940138593Ssamstatic void 941138593Ssamscan_and_wait(int s) 942138593Ssam{ 943138593Ssam struct ieee80211req ireq; 944138593Ssam int sroute; 945138593Ssam 946138593Ssam sroute = socket(PF_ROUTE, SOCK_RAW, 0); 947138593Ssam if (sroute < 0) { 948138593Ssam perror("socket(PF_ROUTE,SOCK_RAW)"); 949138593Ssam return; 950138593Ssam } 951138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 952138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 953138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_REQ; 954138593Ssam /* NB: only root can trigger a scan so ignore errors */ 955138593Ssam if (ioctl(s, SIOCS80211, &ireq) >= 0) { 956138593Ssam char buf[2048]; 957138593Ssam struct if_announcemsghdr *ifan; 958138593Ssam struct rt_msghdr *rtm; 959138593Ssam 960138593Ssam do { 961138593Ssam if (read(sroute, buf, sizeof(buf)) < 0) { 962138593Ssam perror("read(PF_ROUTE)"); 963138593Ssam break; 964138593Ssam } 965138593Ssam rtm = (struct rt_msghdr *) buf; 966138593Ssam if (rtm->rtm_version != RTM_VERSION) 967138593Ssam break; 968138593Ssam ifan = (struct if_announcemsghdr *) rtm; 969138593Ssam } while (rtm->rtm_type != RTM_IEEE80211 || 970138593Ssam ifan->ifan_what != RTM_IEEE80211_SCAN); 971138593Ssam } 972138593Ssam close(sroute); 973138593Ssam} 974138593Ssam 975138593Ssamstatic 976138593SsamDECL_CMD_FUNC(set80211scan, val, d) 977138593Ssam{ 978138593Ssam scan_and_wait(s); 979138593Ssam list_scan(s); 980138593Ssam} 981138593Ssam 982161147Ssamstatic enum ieee80211_opmode get80211opmode(int s); 983161147Ssam 984138593Ssamstatic void 985138593Ssamlist_stations(int s) 986138593Ssam{ 987161147Ssam union { 988161147Ssam struct ieee80211req_sta_req req; 989161147Ssam uint8_t buf[24*1024]; 990161147Ssam } u; 991161147Ssam enum ieee80211_opmode opmode = get80211opmode(s); 992138593Ssam struct ieee80211req ireq; 993138593Ssam uint8_t *cp; 994138593Ssam int len; 995138593Ssam 996138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 997138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 998161147Ssam /* broadcast address =>'s get all stations */ 999161147Ssam (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); 1000161147Ssam if (opmode == IEEE80211_M_STA) { 1001161147Ssam /* 1002161147Ssam * Get information about the associated AP. 1003161147Ssam */ 1004161147Ssam ireq.i_type = IEEE80211_IOC_BSSID; 1005161147Ssam ireq.i_data = u.req.is_u.macaddr; 1006161147Ssam ireq.i_len = IEEE80211_ADDR_LEN; 1007161147Ssam (void) ioctl(s, SIOCG80211, &ireq); 1008161147Ssam } 1009138593Ssam ireq.i_type = IEEE80211_IOC_STA_INFO; 1010161147Ssam ireq.i_data = &u; 1011161147Ssam ireq.i_len = sizeof(u); 1012138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1013138593Ssam errx(1, "unable to get station information"); 1014138593Ssam len = ireq.i_len; 1015138593Ssam if (len < sizeof(struct ieee80211req_sta_info)) 1016138593Ssam return; 1017138593Ssam 1018159885Ssam printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n" 1019138593Ssam , "ADDR" 1020138593Ssam , "AID" 1021138593Ssam , "CHAN" 1022138593Ssam , "RATE" 1023138593Ssam , "RSSI" 1024138593Ssam , "IDLE" 1025138593Ssam , "TXSEQ" 1026138593Ssam , "RXSEQ" 1027138593Ssam , "CAPS" 1028159885Ssam , "FLAG" 1029138593Ssam ); 1030161147Ssam cp = (uint8_t *) u.req.info; 1031138593Ssam do { 1032138593Ssam struct ieee80211req_sta_info *si; 1033138593Ssam uint8_t *vp; 1034138593Ssam 1035138593Ssam si = (struct ieee80211req_sta_info *) cp; 1036161147Ssam if (si->isi_len < sizeof(*si)) 1037161147Ssam break; 1038138593Ssam vp = (u_int8_t *)(si+1); 1039159885Ssam printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %-4.4s" 1040138593Ssam , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 1041138593Ssam , IEEE80211_AID(si->isi_associd) 1042165570Ssam , ieee80211_mhz2ieee(si->isi_freq, si->isi_freq) 1043138593Ssam , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2 1044138593Ssam , si->isi_rssi 1045138593Ssam , si->isi_inact 1046138593Ssam , si->isi_txseqs[0] 1047138593Ssam , si->isi_rxseqs[0] 1048138593Ssam , getcaps(si->isi_capinfo) 1049159885Ssam , getflags(si->isi_state) 1050138593Ssam ); 1051138593Ssam printies(vp, si->isi_ie_len, 24); 1052138593Ssam printf("\n"); 1053138593Ssam cp += si->isi_len, len -= si->isi_len; 1054138593Ssam } while (len >= sizeof(struct ieee80211req_sta_info)); 1055138593Ssam} 1056138593Ssam 1057138593Ssamstatic void 1058138593Ssamprint_chaninfo(const struct ieee80211_channel *c) 1059138593Ssam{ 1060138593Ssam#define IEEE80211_IS_CHAN_PASSIVE(_c) \ 1061138593Ssam (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE)) 1062138593Ssam char buf[14]; 1063138593Ssam 1064138593Ssam buf[0] = '\0'; 1065138593Ssam if (IEEE80211_IS_CHAN_FHSS(c)) 1066138593Ssam strlcat(buf, " FHSS", sizeof(buf)); 1067165570Ssam if (IEEE80211_IS_CHAN_A(c)) { 1068165570Ssam if (IEEE80211_IS_CHAN_HALF(c)) 1069165570Ssam strlcat(buf, " 11a/10Mhz", sizeof(buf)); 1070165570Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 1071165570Ssam strlcat(buf, " 11a/5Mhz", sizeof(buf)); 1072165570Ssam else 1073165570Ssam strlcat(buf, " 11a", sizeof(buf)); 1074165570Ssam } 1075165570Ssam if (IEEE80211_IS_CHAN_ANYG(c)) 1076138593Ssam strlcat(buf, " 11g", sizeof(buf)); 1077138593Ssam else if (IEEE80211_IS_CHAN_B(c)) 1078138593Ssam strlcat(buf, " 11b", sizeof(buf)); 1079138593Ssam if (IEEE80211_IS_CHAN_T(c)) 1080138593Ssam strlcat(buf, " Turbo", sizeof(buf)); 1081138593Ssam printf("Channel %3u : %u%c Mhz%-14.14s", 1082165570Ssam ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, 1083138593Ssam IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf); 1084138593Ssam#undef IEEE80211_IS_CHAN_PASSIVE 1085138593Ssam} 1086138593Ssam 1087138593Ssamstatic void 1088138593Ssamlist_channels(int s, int allchans) 1089138593Ssam{ 1090138593Ssam struct ieee80211req ireq; 1091138593Ssam struct ieee80211req_chaninfo chans; 1092138593Ssam struct ieee80211req_chaninfo achans; 1093138593Ssam const struct ieee80211_channel *c; 1094165570Ssam int i, half, ieee; 1095138593Ssam 1096138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1097138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1098138593Ssam ireq.i_type = IEEE80211_IOC_CHANINFO; 1099138593Ssam ireq.i_data = &chans; 1100138593Ssam ireq.i_len = sizeof(chans); 1101138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1102138593Ssam errx(1, "unable to get channel information"); 1103138593Ssam if (!allchans) { 1104138593Ssam struct ieee80211req_chanlist active; 1105138593Ssam 1106138593Ssam ireq.i_type = IEEE80211_IOC_CHANLIST; 1107138593Ssam ireq.i_data = &active; 1108138593Ssam ireq.i_len = sizeof(active); 1109138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1110138593Ssam errx(1, "unable to get active channel list"); 1111138593Ssam memset(&achans, 0, sizeof(achans)); 1112138593Ssam for (i = 0; i < chans.ic_nchans; i++) { 1113138593Ssam c = &chans.ic_chans[i]; 1114165570Ssam ieee = ieee80211_mhz2ieee(c->ic_freq, c->ic_flags); 1115165570Ssam if (isset(active.ic_channels, ieee) || allchans) 1116138593Ssam achans.ic_chans[achans.ic_nchans++] = *c; 1117138593Ssam } 1118138593Ssam } else 1119138593Ssam achans = chans; 1120138593Ssam half = achans.ic_nchans / 2; 1121138593Ssam if (achans.ic_nchans % 2) 1122138593Ssam half++; 1123138593Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 1124138593Ssam print_chaninfo(&achans.ic_chans[i]); 1125138593Ssam print_chaninfo(&achans.ic_chans[half+i]); 1126138593Ssam printf("\n"); 1127138593Ssam } 1128138593Ssam if (achans.ic_nchans % 2) { 1129138593Ssam print_chaninfo(&achans.ic_chans[i]); 1130138593Ssam printf("\n"); 1131138593Ssam } 1132138593Ssam} 1133138593Ssam 1134138593Ssamstatic void 1135138593Ssamlist_keys(int s) 1136138593Ssam{ 1137138593Ssam} 1138138593Ssam 1139138593Ssam#define IEEE80211_C_BITS \ 1140138593Ssam"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \ 1141138593Ssam"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \ 1142138593Ssam"\31WPA2\32BURST\33WME" 1143138593Ssam 1144138593Ssamstatic void 1145138593Ssamlist_capabilities(int s) 1146138593Ssam{ 1147138593Ssam struct ieee80211req ireq; 1148138593Ssam u_int32_t caps; 1149138593Ssam 1150138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1151138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1152138593Ssam ireq.i_type = IEEE80211_IOC_DRIVER_CAPS; 1153138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1154138593Ssam errx(1, "unable to get driver capabilities"); 1155138593Ssam caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len); 1156138593Ssam printb(name, caps, IEEE80211_C_BITS); 1157138593Ssam putchar('\n'); 1158138593Ssam} 1159138593Ssam 1160138593Ssamstatic void 1161138593Ssamlist_wme(int s) 1162138593Ssam{ 1163138593Ssam static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 1164138593Ssam struct ieee80211req ireq; 1165138593Ssam int ac; 1166138593Ssam 1167138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1168138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1169138593Ssam ireq.i_len = 0; 1170138593Ssam for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 1171138593Ssamagain: 1172138593Ssam if (ireq.i_len & IEEE80211_WMEPARAM_BSS) 1173138593Ssam printf("\t%s", " "); 1174138593Ssam else 1175138593Ssam printf("\t%s", acnames[ac]); 1176138593Ssam 1177138593Ssam ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac; 1178138593Ssam 1179138593Ssam /* show WME BSS parameters */ 1180138593Ssam ireq.i_type = IEEE80211_IOC_WME_CWMIN; 1181138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1182138593Ssam printf(" cwmin %2u", ireq.i_val); 1183138593Ssam ireq.i_type = IEEE80211_IOC_WME_CWMAX; 1184138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1185138593Ssam printf(" cwmax %2u", ireq.i_val); 1186138593Ssam ireq.i_type = IEEE80211_IOC_WME_AIFS; 1187138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1188138593Ssam printf(" aifs %2u", ireq.i_val); 1189138593Ssam ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT; 1190138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1191138593Ssam printf(" txopLimit %3u", ireq.i_val); 1192138593Ssam ireq.i_type = IEEE80211_IOC_WME_ACM; 1193138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1194138593Ssam if (ireq.i_val) 1195138593Ssam printf(" acm"); 1196138593Ssam else if (verbose) 1197138593Ssam printf(" -acm"); 1198138593Ssam } 1199138593Ssam /* !BSS only */ 1200138593Ssam if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1201138593Ssam ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY; 1202138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1203138593Ssam if (!ireq.i_val) 1204138593Ssam printf(" -ack"); 1205138593Ssam else if (verbose) 1206138593Ssam printf(" ack"); 1207138593Ssam } 1208138593Ssam } 1209138593Ssam printf("\n"); 1210138593Ssam if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { 1211138593Ssam ireq.i_len |= IEEE80211_WMEPARAM_BSS; 1212138593Ssam goto again; 1213138593Ssam } else 1214138593Ssam ireq.i_len &= ~IEEE80211_WMEPARAM_BSS; 1215138593Ssam } 1216138593Ssam} 1217138593Ssam 1218149029Ssamstatic void 1219149029Ssamlist_mac(int s) 1220149029Ssam{ 1221149029Ssam struct ieee80211req ireq; 1222149029Ssam struct ieee80211req_maclist *acllist; 1223149029Ssam int i, nacls, policy; 1224149029Ssam char c; 1225149029Ssam 1226149029Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1227149029Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 1228149029Ssam ireq.i_type = IEEE80211_IOC_MACCMD; 1229149029Ssam ireq.i_val = IEEE80211_MACCMD_POLICY; 1230149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) { 1231149029Ssam if (errno == EINVAL) { 1232149029Ssam printf("No acl policy loaded\n"); 1233149029Ssam return; 1234149029Ssam } 1235149029Ssam err(1, "unable to get mac policy"); 1236149029Ssam } 1237149029Ssam policy = ireq.i_val; 1238149029Ssam 1239149029Ssam ireq.i_val = IEEE80211_MACCMD_LIST; 1240149029Ssam ireq.i_len = 0; 1241149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1242149029Ssam err(1, "unable to get mac acl list size"); 1243149029Ssam if (ireq.i_len == 0) /* NB: no acls */ 1244149029Ssam return; 1245149029Ssam 1246149029Ssam ireq.i_data = malloc(ireq.i_len); 1247149029Ssam if (ireq.i_data == NULL) 1248149029Ssam err(1, "out of memory for acl list"); 1249149029Ssam 1250149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1251149029Ssam err(1, "unable to get mac acl list"); 1252149029Ssam if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 1253149029Ssam if (verbose) 1254149029Ssam printf("policy: open\n"); 1255149029Ssam c = '*'; 1256149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 1257149029Ssam if (verbose) 1258149029Ssam printf("policy: allow\n"); 1259149029Ssam c = '+'; 1260149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 1261149029Ssam if (verbose) 1262149029Ssam printf("policy: deny\n"); 1263149029Ssam c = '-'; 1264149029Ssam } else { 1265149029Ssam printf("policy: unknown (%u)\n", policy); 1266149029Ssam c = '?'; 1267149029Ssam } 1268149029Ssam nacls = ireq.i_len / sizeof(*acllist); 1269149029Ssam acllist = (struct ieee80211req_maclist *) ireq.i_data; 1270149029Ssam for (i = 0; i < nacls; i++) 1271149029Ssam printf("%c%s\n", c, ether_ntoa( 1272149029Ssam (const struct ether_addr *) acllist[i].ml_macaddr)); 1273149029Ssam} 1274149029Ssam 1275138593Ssamstatic 1276138593SsamDECL_CMD_FUNC(set80211list, arg, d) 1277138593Ssam{ 1278138593Ssam#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 1279138593Ssam 1280138593Ssam if (iseq(arg, "sta")) 1281138593Ssam list_stations(s); 1282138593Ssam else if (iseq(arg, "scan") || iseq(arg, "ap")) 1283138593Ssam list_scan(s); 1284138593Ssam else if (iseq(arg, "chan") || iseq(arg, "freq")) 1285138593Ssam list_channels(s, 1); 1286138593Ssam else if (iseq(arg, "active")) 1287138593Ssam list_channels(s, 0); 1288138593Ssam else if (iseq(arg, "keys")) 1289138593Ssam list_keys(s); 1290138593Ssam else if (iseq(arg, "caps")) 1291138593Ssam list_capabilities(s); 1292138593Ssam else if (iseq(arg, "wme")) 1293138593Ssam list_wme(s); 1294149029Ssam else if (iseq(arg, "mac")) 1295149029Ssam list_mac(s); 1296138593Ssam else 1297138593Ssam errx(1, "Don't know how to list %s for %s", arg, name); 1298138593Ssam#undef iseq 1299138593Ssam} 1300138593Ssam 1301138593Ssamstatic enum ieee80211_opmode 1302138593Ssamget80211opmode(int s) 1303138593Ssam{ 1304138593Ssam struct ifmediareq ifmr; 1305138593Ssam 1306138593Ssam (void) memset(&ifmr, 0, sizeof(ifmr)); 1307138593Ssam (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 1308138593Ssam 1309138593Ssam if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 1310138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 1311138593Ssam return IEEE80211_M_IBSS; /* XXX ahdemo */ 1312138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 1313138593Ssam return IEEE80211_M_HOSTAP; 1314138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 1315138593Ssam return IEEE80211_M_MONITOR; 1316138593Ssam } 1317138593Ssam return IEEE80211_M_STA; 1318138593Ssam} 1319138593Ssam 1320138593Ssamstatic const struct ieee80211_channel * 1321138593Ssamgetchaninfo(int s, int chan) 1322138593Ssam{ 1323138593Ssam struct ieee80211req ireq; 1324138593Ssam static struct ieee80211req_chaninfo chans; 1325138593Ssam static struct ieee80211_channel undef; 1326138593Ssam const struct ieee80211_channel *c; 1327138593Ssam int i, freq; 1328138593Ssam 1329138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1330138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1331138593Ssam ireq.i_type = IEEE80211_IOC_CHANINFO; 1332138593Ssam ireq.i_data = &chans; 1333138593Ssam ireq.i_len = sizeof(chans); 1334138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1335138593Ssam errx(1, "unable to get channel information"); 1336138593Ssam freq = ieee80211_ieee2mhz(chan); 1337138593Ssam for (i = 0; i < chans.ic_nchans; i++) { 1338138593Ssam c = &chans.ic_chans[i]; 1339138593Ssam if (c->ic_freq == freq) 1340138593Ssam return c; 1341138593Ssam } 1342138593Ssam return &undef; 1343138593Ssam} 1344138593Ssam 1345138593Ssam#if 0 1346138593Ssamstatic void 1347138593Ssamprintcipher(int s, struct ieee80211req *ireq, int keylenop) 1348138593Ssam{ 1349138593Ssam switch (ireq->i_val) { 1350138593Ssam case IEEE80211_CIPHER_WEP: 1351138593Ssam ireq->i_type = keylenop; 1352138593Ssam if (ioctl(s, SIOCG80211, ireq) != -1) 1353138593Ssam printf("WEP-%s", 1354138593Ssam ireq->i_len <= 5 ? "40" : 1355138593Ssam ireq->i_len <= 13 ? "104" : "128"); 1356138593Ssam else 1357138593Ssam printf("WEP"); 1358138593Ssam break; 1359138593Ssam case IEEE80211_CIPHER_TKIP: 1360138593Ssam printf("TKIP"); 1361138593Ssam break; 1362138593Ssam case IEEE80211_CIPHER_AES_OCB: 1363138593Ssam printf("AES-OCB"); 1364138593Ssam break; 1365138593Ssam case IEEE80211_CIPHER_AES_CCM: 1366138593Ssam printf("AES-CCM"); 1367138593Ssam break; 1368138593Ssam case IEEE80211_CIPHER_CKIP: 1369138593Ssam printf("CKIP"); 1370138593Ssam break; 1371138593Ssam case IEEE80211_CIPHER_NONE: 1372138593Ssam printf("NONE"); 1373138593Ssam break; 1374138593Ssam default: 1375138593Ssam printf("UNKNOWN (0x%x)", ireq->i_val); 1376138593Ssam break; 1377138593Ssam } 1378138593Ssam} 1379138593Ssam#endif 1380138593Ssam 1381138593Ssam#define MAXCOL 78 1382155931Ssamstatic int col; 1383155931Ssamstatic char spacer; 1384138593Ssam 1385155931Ssamstatic void 1386155931SsamLINE_BREAK(void) 1387155931Ssam{ 1388155931Ssam if (spacer != '\t') { 1389155931Ssam printf("\n"); 1390155931Ssam spacer = '\t'; 1391155931Ssam } 1392155931Ssam col = 8; /* 8-col tab */ 1393155931Ssam} 1394138593Ssam 1395138593Ssamstatic void 1396155931SsamLINE_CHECK(const char *fmt, ...) 1397155931Ssam{ 1398155931Ssam char buf[80]; 1399155931Ssam va_list ap; 1400155931Ssam int n; 1401155931Ssam 1402155931Ssam va_start(ap, fmt); 1403155931Ssam n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap); 1404155931Ssam va_end(ap); 1405155931Ssam col += 1+n; 1406155931Ssam if (col > MAXCOL) { 1407155931Ssam LINE_BREAK(); 1408155931Ssam col += n; 1409155931Ssam } 1410155931Ssam buf[0] = spacer; 1411155931Ssam printf("%s", buf); 1412155931Ssam spacer = ' '; 1413155931Ssam} 1414155931Ssam 1415155931Ssamstatic void 1416138593Ssamprintkey(const struct ieee80211req_key *ik) 1417138593Ssam{ 1418138593Ssam static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 1419138593Ssam int keylen = ik->ik_keylen; 1420138593Ssam int printcontents; 1421138593Ssam 1422148001Srwatson printcontents = printkeys && 1423138593Ssam (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 1424138593Ssam if (printcontents) 1425138593Ssam LINE_BREAK(); 1426138593Ssam switch (ik->ik_type) { 1427138593Ssam case IEEE80211_CIPHER_WEP: 1428138593Ssam /* compatibility */ 1429155931Ssam LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1, 1430138593Ssam keylen <= 5 ? "40-bit" : 1431138593Ssam keylen <= 13 ? "104-bit" : "128-bit"); 1432138593Ssam break; 1433138593Ssam case IEEE80211_CIPHER_TKIP: 1434138593Ssam if (keylen > 128/8) 1435138593Ssam keylen -= 128/8; /* ignore MIC for now */ 1436155931Ssam LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1437138593Ssam break; 1438138593Ssam case IEEE80211_CIPHER_AES_OCB: 1439155931Ssam LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1440138593Ssam break; 1441138593Ssam case IEEE80211_CIPHER_AES_CCM: 1442155931Ssam LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1443138593Ssam break; 1444138593Ssam case IEEE80211_CIPHER_CKIP: 1445155931Ssam LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1446138593Ssam break; 1447138593Ssam case IEEE80211_CIPHER_NONE: 1448155931Ssam LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen); 1449138593Ssam break; 1450138593Ssam default: 1451155931Ssam LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit", 1452138593Ssam ik->ik_type, ik->ik_keyix+1, 8*keylen); 1453138593Ssam break; 1454138593Ssam } 1455138593Ssam if (printcontents) { 1456138593Ssam int i; 1457138593Ssam 1458138593Ssam printf(" <"); 1459138593Ssam for (i = 0; i < keylen; i++) 1460138593Ssam printf("%02x", ik->ik_keydata[i]); 1461138593Ssam printf(">"); 1462138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 1463138593Ssam (ik->ik_keyrsc != 0 || verbose)) 1464146873Sjhb printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 1465138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 1466138593Ssam (ik->ik_keytsc != 0 || verbose)) 1467146873Sjhb printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 1468138593Ssam if (ik->ik_flags != 0 && verbose) { 1469138593Ssam const char *sep = " "; 1470138593Ssam 1471138593Ssam if (ik->ik_flags & IEEE80211_KEY_XMIT) 1472138593Ssam printf("%stx", sep), sep = "+"; 1473138593Ssam if (ik->ik_flags & IEEE80211_KEY_RECV) 1474138593Ssam printf("%srx", sep), sep = "+"; 1475138593Ssam if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 1476138593Ssam printf("%sdef", sep), sep = "+"; 1477138593Ssam } 1478138593Ssam LINE_BREAK(); 1479138593Ssam } 1480138593Ssam} 1481138593Ssam 1482138593Ssamstatic void 1483139494Ssamieee80211_status(int s) 1484138593Ssam{ 1485138593Ssam static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 1486138593Ssam enum ieee80211_opmode opmode = get80211opmode(s); 1487138593Ssam int i, num, wpa, wme; 1488138593Ssam struct ieee80211req ireq; 1489138593Ssam u_int8_t data[32]; 1490138593Ssam const struct ieee80211_channel *c; 1491138593Ssam 1492138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1493138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 149477218Sphk ireq.i_data = &data; 149577218Sphk 1496138593Ssam wpa = 0; /* unknown/not set */ 1497138593Ssam 149877218Sphk ireq.i_type = IEEE80211_IOC_SSID; 149977218Sphk ireq.i_val = -1; 150077218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 1501148686Sstefanf /* If we can't get the SSID, this isn't an 802.11 device. */ 150277218Sphk return; 150377218Sphk } 150488748Sambrisko num = 0; 150588748Sambrisko ireq.i_type = IEEE80211_IOC_NUMSSIDS; 1506138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0) 150788748Sambrisko num = ireq.i_val; 1508138593Ssam printf("\tssid "); 1509138593Ssam if (num > 1) { 1510138593Ssam ireq.i_type = IEEE80211_IOC_SSID; 1511138593Ssam for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { 1512138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { 1513138593Ssam printf(" %d:", ireq.i_val + 1); 1514138593Ssam print_string(data, ireq.i_len); 1515138593Ssam } 151688748Sambrisko } 1517138593Ssam } else 1518138593Ssam print_string(data, ireq.i_len); 151977218Sphk 1520138593Ssam ireq.i_type = IEEE80211_IOC_CHANNEL; 1521138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 1522138593Ssam goto end; 1523138593Ssam c = getchaninfo(s, ireq.i_val); 1524138593Ssam if (ireq.i_val != -1) { 1525138593Ssam printf(" channel %d", ireq.i_val); 1526138593Ssam if (verbose) 1527138593Ssam printf(" (%u)", c->ic_freq); 1528138593Ssam } else if (verbose) 1529138593Ssam printf(" channel UNDEF"); 1530138593Ssam 1531138593Ssam ireq.i_type = IEEE80211_IOC_BSSID; 1532138593Ssam ireq.i_len = IEEE80211_ADDR_LEN; 1533138593Ssam if (ioctl(s, SIOCG80211, &ireq) >= 0 && 1534153405Ssam (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) 1535138593Ssam printf(" bssid %s", ether_ntoa(ireq.i_data)); 1536138593Ssam 153777218Sphk ireq.i_type = IEEE80211_IOC_STATIONNAME; 153877218Sphk if (ioctl(s, SIOCG80211, &ireq) != -1) { 1539138593Ssam printf("\n\tstationname "); 154077218Sphk print_string(data, ireq.i_len); 154177218Sphk } 154277218Sphk 1543138593Ssam spacer = ' '; /* force first break */ 1544138593Ssam LINE_BREAK(); 154577218Sphk 154677218Sphk ireq.i_type = IEEE80211_IOC_AUTHMODE; 154777218Sphk if (ioctl(s, SIOCG80211, &ireq) != -1) { 154877218Sphk switch (ireq.i_val) { 154977218Sphk case IEEE80211_AUTH_NONE: 1550155931Ssam LINE_CHECK("authmode NONE"); 155177218Sphk break; 155277218Sphk case IEEE80211_AUTH_OPEN: 1553155931Ssam LINE_CHECK("authmode OPEN"); 155477218Sphk break; 155577218Sphk case IEEE80211_AUTH_SHARED: 1556155931Ssam LINE_CHECK("authmode SHARED"); 155777218Sphk break; 1558138593Ssam case IEEE80211_AUTH_8021X: 1559155931Ssam LINE_CHECK("authmode 802.1x"); 156077218Sphk break; 1561138593Ssam case IEEE80211_AUTH_WPA: 1562138593Ssam ireq.i_type = IEEE80211_IOC_WPA; 1563138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1564138593Ssam wpa = ireq.i_val; 1565138593Ssam if (!wpa) 1566138593Ssam wpa = 1; /* default to WPA1 */ 1567138593Ssam switch (wpa) { 1568138593Ssam case 2: 1569155931Ssam LINE_CHECK("authmode WPA2/802.11i"); 1570138593Ssam break; 1571138593Ssam case 3: 1572155931Ssam LINE_CHECK("authmode WPA1+WPA2/802.11i"); 1573138593Ssam break; 1574138593Ssam default: 1575155931Ssam LINE_CHECK("authmode WPA"); 1576138593Ssam break; 1577138593Ssam } 157877218Sphk break; 1579138593Ssam case IEEE80211_AUTH_AUTO: 1580155931Ssam LINE_CHECK("authmode AUTO"); 158177218Sphk break; 1582127649Ssam default: 1583155931Ssam LINE_CHECK("authmode UNKNOWN (0x%x)", 1584155931Ssam ireq.i_val); 1585127649Ssam break; 1586127649Ssam } 1587127649Ssam } 1588127649Ssam 158977218Sphk ireq.i_type = IEEE80211_IOC_WEP; 159080315Sbrooks if (ioctl(s, SIOCG80211, &ireq) != -1 && 159180315Sbrooks ireq.i_val != IEEE80211_WEP_NOSUP) { 1592138718Ssam int firstkey, wepmode; 1593138593Ssam 1594138718Ssam wepmode = ireq.i_val; 1595138718Ssam switch (wepmode) { 159677218Sphk case IEEE80211_WEP_OFF: 1597155931Ssam LINE_CHECK("privacy OFF"); 159877218Sphk break; 159977218Sphk case IEEE80211_WEP_ON: 1600155931Ssam LINE_CHECK("privacy ON"); 160177218Sphk break; 160277218Sphk case IEEE80211_WEP_MIXED: 1603155931Ssam LINE_CHECK("privacy MIXED"); 160477218Sphk break; 160577218Sphk default: 1606155931Ssam LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); 160777218Sphk break; 160877218Sphk } 160977218Sphk 161077218Sphk /* 161177218Sphk * If we get here then we've got WEP support so we need 161277218Sphk * to print WEP status. 161391454Sbrooks */ 161477218Sphk 161577218Sphk ireq.i_type = IEEE80211_IOC_WEPTXKEY; 161677218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 161777218Sphk warn("WEP support, but no tx key!"); 161877218Sphk goto end; 161977218Sphk } 1620138593Ssam if (ireq.i_val != -1) 1621155931Ssam LINE_CHECK("deftxkey %d", ireq.i_val+1); 1622138718Ssam else if (wepmode != IEEE80211_WEP_OFF || verbose) 1623155931Ssam LINE_CHECK("deftxkey UNDEF"); 162477218Sphk 162577218Sphk ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; 162677218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 162777218Sphk warn("WEP support, but no NUMWEPKEYS support!"); 162877218Sphk goto end; 162977218Sphk } 163077218Sphk num = ireq.i_val; 163177218Sphk 1632138593Ssam firstkey = 1; 1633138593Ssam for (i = 0; i < num; i++) { 1634138593Ssam struct ieee80211req_key ik; 163577218Sphk 1636138593Ssam memset(&ik, 0, sizeof(ik)); 1637138593Ssam ik.ik_keyix = i; 1638138593Ssam ireq.i_type = IEEE80211_IOC_WPAKEY; 1639138593Ssam ireq.i_data = &ik; 1640138593Ssam ireq.i_len = sizeof(ik); 164177218Sphk if (ioctl(s, SIOCG80211, &ireq) < 0) { 164277218Sphk warn("WEP support, but can get keys!"); 164377218Sphk goto end; 164477218Sphk } 1645138593Ssam if (ik.ik_keylen != 0) { 1646138593Ssam if (verbose) 1647138593Ssam LINE_BREAK(); 1648138593Ssam printkey(&ik); 1649138593Ssam firstkey = 0; 1650138593Ssam } 1651138593Ssam } 1652138593Ssam } 1653138593Ssam 1654138593Ssam ireq.i_type = IEEE80211_IOC_POWERSAVE; 1655138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1 && 1656138593Ssam ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { 1657138593Ssam if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) { 1658138593Ssam switch (ireq.i_val) { 1659138593Ssam case IEEE80211_POWERSAVE_OFF: 1660155931Ssam LINE_CHECK("powersavemode OFF"); 1661138593Ssam break; 1662138593Ssam case IEEE80211_POWERSAVE_CAM: 1663155931Ssam LINE_CHECK("powersavemode CAM"); 1664138593Ssam break; 1665138593Ssam case IEEE80211_POWERSAVE_PSP: 1666155931Ssam LINE_CHECK("powersavemode PSP"); 1667138593Ssam break; 1668138593Ssam case IEEE80211_POWERSAVE_PSP_CAM: 1669155931Ssam LINE_CHECK("powersavemode PSP-CAM"); 1670138593Ssam break; 1671138593Ssam } 1672138593Ssam ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; 1673138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1674155931Ssam LINE_CHECK("powersavesleep %d", ireq.i_val); 1675138593Ssam } 1676138593Ssam } 1677138593Ssam 1678138593Ssam ireq.i_type = IEEE80211_IOC_TXPOWMAX; 1679138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1680155931Ssam LINE_CHECK("txpowmax %d", ireq.i_val); 1681138593Ssam 1682138593Ssam if (verbose) { 1683138593Ssam ireq.i_type = IEEE80211_IOC_TXPOWER; 1684138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1685155931Ssam LINE_CHECK("txpower %d", ireq.i_val); 1686138593Ssam } 1687138593Ssam 1688138593Ssam ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; 1689138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1690138593Ssam if (ireq.i_val != IEEE80211_RTS_MAX || verbose) 1691155931Ssam LINE_CHECK("rtsthreshold %d", ireq.i_val); 1692138593Ssam } 1693138593Ssam 1694153354Ssam ireq.i_type = IEEE80211_IOC_MCAST_RATE; 1695153354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1696153354Ssam if (ireq.i_val != 2*1 || verbose) { 1697153354Ssam if (ireq.i_val == 11) 1698155931Ssam LINE_CHECK("mcastrate 5.5"); 1699153354Ssam else 1700155931Ssam LINE_CHECK("mcastrate %d", ireq.i_val/2); 1701153354Ssam } 1702153354Ssam } 1703153354Ssam 1704148416Ssam ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD; 1705148416Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1706148416Ssam if (ireq.i_val != IEEE80211_FRAG_MAX || verbose) 1707155931Ssam LINE_CHECK("fragthreshold %d", ireq.i_val); 1708148416Ssam } 1709148416Ssam 1710160687Ssam ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD; 1711160687Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1712160687Ssam if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose) 1713160687Ssam LINE_CHECK("bmiss %d", ireq.i_val); 1714160687Ssam } 1715160687Ssam 1716165570Ssam if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { 1717147795Ssam ireq.i_type = IEEE80211_IOC_PUREG; 1718147795Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1719147795Ssam if (ireq.i_val) 1720155931Ssam LINE_CHECK("pureg"); 1721147795Ssam else if (verbose) 1722155931Ssam LINE_CHECK("-pureg"); 1723147795Ssam } 1724138593Ssam ireq.i_type = IEEE80211_IOC_PROTMODE; 1725138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1726138593Ssam switch (ireq.i_val) { 1727138593Ssam case IEEE80211_PROTMODE_OFF: 1728155931Ssam LINE_CHECK("protmode OFF"); 1729138593Ssam break; 1730138593Ssam case IEEE80211_PROTMODE_CTS: 1731155931Ssam LINE_CHECK("protmode CTS"); 1732138593Ssam break; 1733138593Ssam case IEEE80211_PROTMODE_RTSCTS: 1734155931Ssam LINE_CHECK("protmode RTSCTS"); 1735138593Ssam break; 1736138593Ssam default: 1737155931Ssam LINE_CHECK("protmode UNKNOWN (0x%x)", 1738155931Ssam ireq.i_val); 1739138593Ssam break; 1740138593Ssam } 1741138593Ssam } 1742138593Ssam } 1743138593Ssam 1744138593Ssam ireq.i_type = IEEE80211_IOC_WME; 1745138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1746138593Ssam wme = ireq.i_val; 1747138593Ssam if (wme) 1748155931Ssam LINE_CHECK("wme"); 1749138593Ssam else if (verbose) 1750155931Ssam LINE_CHECK("-wme"); 1751138593Ssam } else 1752138593Ssam wme = 0; 1753138593Ssam 1754153422Ssam ireq.i_type = IEEE80211_IOC_BURST; 1755153422Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1756153422Ssam if (ireq.i_val) 1757155931Ssam LINE_CHECK("burst"); 1758153422Ssam else if (verbose) 1759155931Ssam LINE_CHECK("-burst"); 1760153422Ssam } 1761153422Ssam 1762138593Ssam if (opmode == IEEE80211_M_HOSTAP) { 1763138593Ssam ireq.i_type = IEEE80211_IOC_HIDESSID; 1764138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1765138593Ssam if (ireq.i_val) 1766155931Ssam LINE_CHECK("ssid HIDE"); 1767138593Ssam else if (verbose) 1768155931Ssam LINE_CHECK("ssid SHOW"); 1769138593Ssam } 1770138593Ssam 1771138593Ssam ireq.i_type = IEEE80211_IOC_APBRIDGE; 1772138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1773138593Ssam if (!ireq.i_val) 1774155931Ssam LINE_CHECK("-apbridge"); 1775138593Ssam else if (verbose) 1776155931Ssam LINE_CHECK("apbridge"); 1777138593Ssam } 1778138593Ssam 1779138593Ssam ireq.i_type = IEEE80211_IOC_DTIM_PERIOD; 1780138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) 1781155931Ssam LINE_CHECK("dtimperiod %u", ireq.i_val); 1782138593Ssam } else { 1783138593Ssam ireq.i_type = IEEE80211_IOC_ROAMING; 1784138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1785138593Ssam if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) { 1786138593Ssam switch (ireq.i_val) { 1787138593Ssam case IEEE80211_ROAMING_DEVICE: 1788155931Ssam LINE_CHECK("roaming DEVICE"); 1789138593Ssam break; 1790138593Ssam case IEEE80211_ROAMING_AUTO: 1791155931Ssam LINE_CHECK("roaming AUTO"); 1792138593Ssam break; 1793138593Ssam case IEEE80211_ROAMING_MANUAL: 1794155931Ssam LINE_CHECK("roaming MANUAL"); 1795138593Ssam break; 1796138593Ssam default: 1797155931Ssam LINE_CHECK("roaming UNKNOWN (0x%x)", 1798155931Ssam ireq.i_val); 1799138593Ssam break; 1800138593Ssam } 1801138593Ssam } 1802138593Ssam } 1803138593Ssam } 1804138593Ssam ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL; 1805138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1806138593Ssam if (ireq.i_val) 1807155931Ssam LINE_CHECK("bintval %u", ireq.i_val); 1808138593Ssam else if (verbose) 1809155931Ssam LINE_CHECK("bintval %u", ireq.i_val); 1810138593Ssam } 1811138593Ssam 1812138593Ssam if (wme && verbose) { 1813138593Ssam LINE_BREAK(); 1814138593Ssam list_wme(s); 1815138593Ssam } 1816138593Ssam 1817138593Ssam if (wpa) { 1818138593Ssam ireq.i_type = IEEE80211_IOC_COUNTERMEASURES; 1819138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1820138593Ssam if (ireq.i_val) 1821155931Ssam LINE_CHECK("countermeasures"); 1822138593Ssam else if (verbose) 1823155931Ssam LINE_CHECK("-countermeasures"); 1824138593Ssam } 1825138593Ssam#if 0 1826138593Ssam /* XXX not interesting with WPA done in user space */ 1827138593Ssam ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 1828138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1829138593Ssam } 1830138593Ssam 1831138593Ssam ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 1832138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1833155931Ssam LINE_CHECK("mcastcipher "); 1834138593Ssam printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 1835138593Ssam spacer = ' '; 1836138593Ssam } 1837138593Ssam 1838138593Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 1839138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1840155931Ssam LINE_CHECK("ucastcipher "); 1841138593Ssam printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 1842138593Ssam } 1843138593Ssam 1844138593Ssam if (wpa & 2) { 1845138593Ssam ireq.i_type = IEEE80211_IOC_RSNCAPS; 1846138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1847155931Ssam LINE_CHECK("RSN caps 0x%x", ireq.i_val); 184877218Sphk spacer = ' '; 1849138593Ssam } 185077218Sphk } 1851138593Ssam 1852138593Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 1853138593Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 1854138593Ssam } 1855138593Ssam#endif 1856138593Ssam LINE_BREAK(); 185777218Sphk } 1858138593Ssam LINE_BREAK(); 185977218Sphk 186077218Sphkend: 186177218Sphk return; 186277218Sphk} 186377218Sphk 186477218Sphkstatic void 186577218Sphkset80211(int s, int type, int val, int len, u_int8_t *data) 186677218Sphk{ 186777218Sphk struct ieee80211req ireq; 186877218Sphk 186977218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 187077218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 187177218Sphk ireq.i_type = type; 187277218Sphk ireq.i_val = val; 187377218Sphk ireq.i_len = len; 187477218Sphk ireq.i_data = data; 187591454Sbrooks if (ioctl(s, SIOCS80211, &ireq) < 0) 187677218Sphk err(1, "SIOCS80211"); 187777218Sphk} 187877218Sphk 187977218Sphkstatic const char * 188077218Sphkget_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 188177218Sphk{ 188277218Sphk int len; 188377218Sphk int hexstr; 188477218Sphk u_int8_t *p; 188577218Sphk 188677218Sphk len = *lenp; 188777218Sphk p = buf; 188877218Sphk hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 188977218Sphk if (hexstr) 189077218Sphk val += 2; 189177218Sphk for (;;) { 189277218Sphk if (*val == '\0') 189377218Sphk break; 189477218Sphk if (sep != NULL && strchr(sep, *val) != NULL) { 189577218Sphk val++; 189677218Sphk break; 189777218Sphk } 189877218Sphk if (hexstr) { 1899127831Sphk if (!isxdigit((u_char)val[0])) { 190077218Sphk warnx("bad hexadecimal digits"); 190177218Sphk return NULL; 190277218Sphk } 1903127831Sphk if (!isxdigit((u_char)val[1])) { 1904127831Sphk warnx("odd count hexadecimal digits"); 1905127831Sphk return NULL; 1906127831Sphk } 190777218Sphk } 1908127831Sphk if (p >= buf + len) { 190977218Sphk if (hexstr) 191077218Sphk warnx("hexadecimal digits too long"); 191177218Sphk else 1912127831Sphk warnx("string too long"); 191377218Sphk return NULL; 191477218Sphk } 191577218Sphk if (hexstr) { 191677218Sphk#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 191777218Sphk *p++ = (tohex((u_char)val[0]) << 4) | 191877218Sphk tohex((u_char)val[1]); 191977218Sphk#undef tohex 192077218Sphk val += 2; 192177218Sphk } else 192277218Sphk *p++ = *val++; 192377218Sphk } 192477218Sphk len = p - buf; 192577218Sphk /* The string "-" is treated as the empty string. */ 1926165045Ssam if (!hexstr && len == 1 && buf[0] == '-') { 192777218Sphk len = 0; 1928165045Ssam memset(buf, 0, *lenp); 1929165045Ssam } else if (len < *lenp) 193077218Sphk memset(p, 0, *lenp - len); 193177218Sphk *lenp = len; 193277218Sphk return val; 193377218Sphk} 193477218Sphk 193577218Sphkstatic void 193677218Sphkprint_string(const u_int8_t *buf, int len) 193777218Sphk{ 193877218Sphk int i; 193977218Sphk int hasspc; 194077218Sphk 194177218Sphk i = 0; 194277218Sphk hasspc = 0; 194391454Sbrooks for (; i < len; i++) { 194477218Sphk if (!isprint(buf[i]) && buf[i] != '\0') 194577218Sphk break; 194677218Sphk if (isspace(buf[i])) 194777218Sphk hasspc++; 194877218Sphk } 194977218Sphk if (i == len) { 195077218Sphk if (hasspc || len == 0 || buf[0] == '\0') 195177218Sphk printf("\"%.*s\"", len, buf); 195277218Sphk else 195377218Sphk printf("%.*s", len, buf); 195477218Sphk } else { 195577218Sphk printf("0x"); 195677218Sphk for (i = 0; i < len; i++) 195777218Sphk printf("%02x", buf[i]); 195877218Sphk } 195977218Sphk} 196077218Sphk 1961138593Ssamstatic struct cmd ieee80211_cmds[] = { 1962138593Ssam DEF_CMD_ARG("ssid", set80211ssid), 1963138593Ssam DEF_CMD_ARG("nwid", set80211ssid), 1964138593Ssam DEF_CMD_ARG("stationname", set80211stationname), 1965138593Ssam DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 1966138593Ssam DEF_CMD_ARG("channel", set80211channel), 1967138593Ssam DEF_CMD_ARG("authmode", set80211authmode), 1968138593Ssam DEF_CMD_ARG("powersavemode", set80211powersavemode), 1969138593Ssam DEF_CMD("powersave", 1, set80211powersave), 1970138593Ssam DEF_CMD("-powersave", 0, set80211powersave), 1971138593Ssam DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 1972138593Ssam DEF_CMD_ARG("wepmode", set80211wepmode), 1973138593Ssam DEF_CMD("wep", 1, set80211wep), 1974138593Ssam DEF_CMD("-wep", 0, set80211wep), 1975139493Ssam DEF_CMD_ARG("deftxkey", set80211weptxkey), 1976138593Ssam DEF_CMD_ARG("weptxkey", set80211weptxkey), 1977138593Ssam DEF_CMD_ARG("wepkey", set80211wepkey), 1978138593Ssam DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 1979138593Ssam DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 1980138593Ssam DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 1981138593Ssam DEF_CMD_ARG("protmode", set80211protmode), 1982138593Ssam DEF_CMD_ARG("txpower", set80211txpower), 1983138593Ssam DEF_CMD_ARG("roaming", set80211roaming), 1984138593Ssam DEF_CMD("wme", 1, set80211wme), 1985138593Ssam DEF_CMD("-wme", 0, set80211wme), 1986138593Ssam DEF_CMD("hidessid", 1, set80211hidessid), 1987138593Ssam DEF_CMD("-hidessid", 0, set80211hidessid), 1988138593Ssam DEF_CMD("apbridge", 1, set80211apbridge), 1989138593Ssam DEF_CMD("-apbridge", 0, set80211apbridge), 1990138593Ssam DEF_CMD_ARG("chanlist", set80211chanlist), 1991138593Ssam DEF_CMD_ARG("bssid", set80211bssid), 1992138593Ssam DEF_CMD_ARG("ap", set80211bssid), 1993138593Ssam DEF_CMD("scan", 0, set80211scan), 1994138593Ssam DEF_CMD_ARG("list", set80211list), 1995138593Ssam DEF_CMD_ARG2("cwmin", set80211cwmin), 1996138593Ssam DEF_CMD_ARG2("cwmax", set80211cwmax), 1997138593Ssam DEF_CMD_ARG2("aifs", set80211aifs), 1998138593Ssam DEF_CMD_ARG2("txoplimit", set80211txoplimit), 1999148621Ssam DEF_CMD_ARG("acm", set80211acm), 2000148621Ssam DEF_CMD_ARG("-acm", set80211noacm), 2001148621Ssam DEF_CMD_ARG("ack", set80211ackpolicy), 2002148621Ssam DEF_CMD_ARG("-ack", set80211noackpolicy), 2003138593Ssam DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 2004138593Ssam DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 2005138593Ssam DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 2006138593Ssam DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 2007138593Ssam DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 2008138593Ssam DEF_CMD_ARG("bintval", set80211bintval), 2009138593Ssam DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 2010138593Ssam DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 2011138593Ssam DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 2012138593Ssam DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 2013138593Ssam DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 2014138593Ssam DEF_CMD_ARG("mac:add", set80211addmac), 2015138593Ssam DEF_CMD_ARG("mac:del", set80211delmac), 2016138593Ssam DEF_CMD_ARG("mac:kick", set80211kickmac), 2017147795Ssam DEF_CMD("pureg", 1, set80211pureg), 2018147795Ssam DEF_CMD("-pureg", 0, set80211pureg), 2019153354Ssam DEF_CMD_ARG("mcastrate", set80211mcastrate), 2020148416Ssam DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 2021153422Ssam DEF_CMD("burst", 1, set80211burst), 2022153422Ssam DEF_CMD("-burst", 0, set80211burst), 2023160687Ssam DEF_CMD_ARG("bmiss", set80211bmissthreshold), 2024160687Ssam DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), 2025138593Ssam}; 2026138593Ssamstatic struct afswtch af_ieee80211 = { 2027138593Ssam .af_name = "af_ieee80211", 2028138593Ssam .af_af = AF_UNSPEC, 2029139494Ssam .af_other_status = ieee80211_status, 2030138593Ssam}; 2031138593Ssam 2032138593Ssamstatic __constructor void 2033138593Ssamieee80211_ctor(void) 2034138593Ssam{ 2035138593Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 2036138593Ssam int i; 2037138593Ssam 2038138593Ssam for (i = 0; i < N(ieee80211_cmds); i++) 2039138593Ssam cmd_register(&ieee80211_cmds[i]); 2040138593Ssam af_register(&af_ieee80211); 2041138593Ssam#undef N 2042138593Ssam} 2043