ifieee80211.c revision 173275
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 173275 2007-11-02 05:24:57Z 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> 94173275Ssam#include <stddef.h> /* NB: for offsetof */ 9577218Sphk 9677218Sphk#include "ifconfig.h" 9777218Sphk 98173275Ssam#define MAXCOL 78 99173275Ssamstatic int col; 100173275Ssamstatic char spacer; 101173275Ssam 102173275Ssamstatic void LINE_INIT(char c); 103173275Ssamstatic void LINE_BREAK(void); 104173275Ssamstatic void LINE_CHECK(const char *fmt, ...); 105173275Ssam 106173275Ssam/* XXX need max array size */ 107173275Ssamstatic const int htrates[16] = { 108173275Ssam 13, /* IFM_IEEE80211_MCS0 */ 109173275Ssam 26, /* IFM_IEEE80211_MCS1 */ 110173275Ssam 39, /* IFM_IEEE80211_MCS2 */ 111173275Ssam 52, /* IFM_IEEE80211_MCS3 */ 112173275Ssam 78, /* IFM_IEEE80211_MCS4 */ 113173275Ssam 104, /* IFM_IEEE80211_MCS5 */ 114173275Ssam 117, /* IFM_IEEE80211_MCS6 */ 115173275Ssam 130, /* IFM_IEEE80211_MCS7 */ 116173275Ssam 26, /* IFM_IEEE80211_MCS8 */ 117173275Ssam 52, /* IFM_IEEE80211_MCS9 */ 118173275Ssam 78, /* IFM_IEEE80211_MCS10 */ 119173275Ssam 104, /* IFM_IEEE80211_MCS11 */ 120173275Ssam 156, /* IFM_IEEE80211_MCS12 */ 121173275Ssam 208, /* IFM_IEEE80211_MCS13 */ 122173275Ssam 234, /* IFM_IEEE80211_MCS14 */ 123173275Ssam 260, /* IFM_IEEE80211_MCS15 */ 124173275Ssam}; 125173275Ssam 126173275Ssamstatic int get80211(int s, int type, void *data, int len); 127173275Ssamstatic int get80211len(int s, int type, void *data, int len, int *plen); 128173275Ssamstatic int get80211val(int s, int type, int *val); 129170531Ssamstatic void set80211(int s, int type, int val, int len, void *data); 13077218Sphkstatic const char *get_string(const char *val, const char *sep, 13177218Sphk u_int8_t *buf, int *lenp); 13277218Sphkstatic void print_string(const u_int8_t *buf, int len); 13377218Sphk 134170531Ssamstatic struct ieee80211req_chaninfo chaninfo; 135170531Ssamstatic struct ifmediareq *ifmr; 136173275Ssamstatic struct ieee80211_channel curchan; 137173275Ssamstatic int gotcurchan = 0; 138173275Ssamstatic int htconf = 0; 139173275Ssamstatic int gothtconf = 0; 140170531Ssam 141173275Ssamstatic void 142173275Ssamgethtconf(int s) 143173275Ssam{ 144173275Ssam if (gothtconf) 145173275Ssam return; 146173275Ssam if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0) 147173275Ssam warn("unable to get HT configuration information"); 148173275Ssam gothtconf = 1; 149173275Ssam} 150173275Ssam 151170531Ssam/* 152170531Ssam * Collect channel info from the kernel. We use this (mostly) 153170531Ssam * to handle mapping between frequency and IEEE channel number. 154170531Ssam */ 155170531Ssamstatic void 156170531Ssamgetchaninfo(int s) 157170531Ssam{ 158170531Ssam if (chaninfo.ic_nchans != 0) 159170531Ssam return; 160173275Ssam if (get80211(s, IEEE80211_IOC_CHANINFO, &chaninfo, sizeof(chaninfo)) < 0) 161170531Ssam errx(1, "unable to get channel information"); 162170531Ssam 163170531Ssam ifmr = ifmedia_getstate(s); 164173275Ssam gethtconf(s); 165170531Ssam} 166170531Ssam 167170531Ssam/* 168170531Ssam * Given the channel at index i with attributes from, 169170531Ssam * check if there is a channel with attributes to in 170170531Ssam * the channel table. With suitable attributes this 171170531Ssam * allows the caller to look for promotion; e.g. from 172170531Ssam * 11b > 11g. 173170531Ssam */ 174138593Ssamstatic int 175170531Ssamcanpromote(int i, int from, int to) 176170531Ssam{ 177170531Ssam const struct ieee80211_channel *fc = &chaninfo.ic_chans[i]; 178170531Ssam int j; 179170531Ssam 180170531Ssam if ((fc->ic_flags & from) != from) 181170531Ssam return i; 182170531Ssam /* NB: quick check exploiting ordering of chans w/ same frequency */ 183170531Ssam if (i+1 < chaninfo.ic_nchans && 184170531Ssam chaninfo.ic_chans[i+1].ic_freq == fc->ic_freq && 185170531Ssam (chaninfo.ic_chans[i+1].ic_flags & to) == to) 186170531Ssam return i+1; 187170531Ssam /* brute force search in case channel list is not ordered */ 188170531Ssam for (j = 0; j < chaninfo.ic_nchans; j++) { 189170531Ssam const struct ieee80211_channel *tc = &chaninfo.ic_chans[j]; 190170531Ssam if (j != i && 191170531Ssam tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to) 192170531Ssam return j; 193170531Ssam } 194170531Ssam return i; 195170531Ssam} 196170531Ssam 197170531Ssam/* 198170531Ssam * Handle channel promotion. When a channel is specified with 199170531Ssam * only a frequency we want to promote it to the ``best'' channel 200170531Ssam * available. The channel list has separate entries for 11b, 11g, 201170531Ssam * 11a, and 11n[ga] channels so specifying a frequency w/o any 202170531Ssam * attributes requires we upgrade, e.g. from 11b -> 11g. This 203170531Ssam * gets complicated when the channel is specified on the same 204170531Ssam * command line with a media request that constrains the available 205170531Ssam * channe list (e.g. mode 11a); we want to honor that to avoid 206170531Ssam * confusing behaviour. 207170531Ssam */ 208170531Ssamstatic int 209170531Ssampromote(int i) 210170531Ssam{ 211170531Ssam /* 212170531Ssam * Query the current mode of the interface in case it's 213170531Ssam * constrained (e.g. to 11a). We must do this carefully 214170531Ssam * as there may be a pending ifmedia request in which case 215170531Ssam * asking the kernel will give us the wrong answer. This 216170531Ssam * is an unfortunate side-effect of the way ifconfig is 217170531Ssam * structure for modularity (yech). 218170531Ssam * 219170531Ssam * NB: ifmr is actually setup in getchaninfo (above); we 220170531Ssam * assume it's called coincident with to this call so 221170531Ssam * we have a ``current setting''; otherwise we must pass 222170531Ssam * the socket descriptor down to here so we can make 223170531Ssam * the ifmedia_getstate call ourselves. 224170531Ssam */ 225170531Ssam int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO; 226170531Ssam 227170531Ssam /* when ambiguous promote to ``best'' */ 228170531Ssam /* NB: we abitrarily pick HT40+ over HT40- */ 229170531Ssam if (chanmode != IFM_IEEE80211_11B) 230170531Ssam i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G); 231173275Ssam if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) { 232170531Ssam i = canpromote(i, IEEE80211_CHAN_G, 233170531Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT20); 234173275Ssam if (htconf & 2) { 235173275Ssam i = canpromote(i, IEEE80211_CHAN_G, 236173275Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D); 237173275Ssam i = canpromote(i, IEEE80211_CHAN_G, 238173275Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U); 239173275Ssam } 240170531Ssam } 241173275Ssam if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) { 242170531Ssam i = canpromote(i, IEEE80211_CHAN_A, 243170531Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT20); 244173275Ssam if (htconf & 2) { 245173275Ssam i = canpromote(i, IEEE80211_CHAN_A, 246173275Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D); 247173275Ssam i = canpromote(i, IEEE80211_CHAN_A, 248173275Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U); 249173275Ssam } 250170531Ssam } 251170531Ssam return i; 252170531Ssam} 253170531Ssam 254170531Ssamstatic void 255170531Ssammapfreq(struct ieee80211_channel *chan, int freq, int flags) 256170531Ssam{ 257170531Ssam int i; 258170531Ssam 259170531Ssam for (i = 0; i < chaninfo.ic_nchans; i++) { 260170531Ssam const struct ieee80211_channel *c = &chaninfo.ic_chans[i]; 261170531Ssam 262170531Ssam if (c->ic_freq == freq && (c->ic_flags & flags) == flags) { 263170531Ssam if (flags == 0) { 264170531Ssam /* when ambiguous promote to ``best'' */ 265170531Ssam c = &chaninfo.ic_chans[promote(i)]; 266170531Ssam } 267170531Ssam *chan = *c; 268170531Ssam return; 269170531Ssam } 270170531Ssam } 271170531Ssam errx(1, "unknown/undefined frequency %u/0x%x", freq, flags); 272170531Ssam} 273170531Ssam 274170531Ssamstatic void 275170531Ssammapchan(struct ieee80211_channel *chan, int ieee, int flags) 276170531Ssam{ 277170531Ssam int i; 278170531Ssam 279170531Ssam for (i = 0; i < chaninfo.ic_nchans; i++) { 280170531Ssam const struct ieee80211_channel *c = &chaninfo.ic_chans[i]; 281170531Ssam 282170531Ssam if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) { 283170531Ssam if (flags == 0) { 284170531Ssam /* when ambiguous promote to ``best'' */ 285170531Ssam c = &chaninfo.ic_chans[promote(i)]; 286170531Ssam } 287170531Ssam *chan = *c; 288170531Ssam return; 289170531Ssam } 290170531Ssam } 291173275Ssam errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags); 292170531Ssam} 293170531Ssam 294173275Ssamstatic const struct ieee80211_channel * 295173275Ssamgetcurchan(int s) 296173275Ssam{ 297173275Ssam if (gotcurchan) 298173275Ssam return &curchan; 299173275Ssam if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) { 300173275Ssam int val; 301173275Ssam /* fall back to legacy ioctl */ 302173275Ssam if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0) 303173275Ssam errx(-1, "cannot figure out current channel"); 304173275Ssam getchaninfo(s); 305173275Ssam mapchan(&curchan, val, 0); 306173275Ssam } 307173275Ssam gotcurchan = 1; 308173275Ssam return &curchan; 309173275Ssam} 310173275Ssam 311170531Ssamstatic int 312170531Ssamieee80211_mhz2ieee(int freq, int flags) 313170531Ssam{ 314170531Ssam struct ieee80211_channel chan; 315170531Ssam mapfreq(&chan, freq, flags); 316170531Ssam return chan.ic_ieee; 317170531Ssam} 318170531Ssam 319170531Ssamstatic int 320138593Ssamisanyarg(const char *arg) 321138593Ssam{ 322173275Ssam return (strncmp(arg, "-", 1) == 0 || 323173275Ssam strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0); 324138593Ssam} 325138593Ssam 326138593Ssamstatic void 32777218Sphkset80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 32877218Sphk{ 32977218Sphk int ssid; 33077218Sphk int len; 331151883Sbrooks u_int8_t data[IEEE80211_NWID_LEN]; 33277218Sphk 33377218Sphk ssid = 0; 334121827Sbrooks len = strlen(val); 33588748Sambrisko if (len > 2 && isdigit(val[0]) && val[1] == ':') { 33688748Sambrisko ssid = atoi(val)-1; 33788748Sambrisko val += 2; 33888748Sambrisko } 33977218Sphk 34077218Sphk bzero(data, sizeof(data)); 34177218Sphk len = sizeof(data); 342151883Sbrooks if (get_string(val, NULL, data, &len) == NULL) 343151883Sbrooks exit(1); 34477218Sphk 34577218Sphk set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 34677218Sphk} 34777218Sphk 348138593Ssamstatic void 34977218Sphkset80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 35077218Sphk{ 35177218Sphk int len; 35277218Sphk u_int8_t data[33]; 35377218Sphk 35477218Sphk bzero(data, sizeof(data)); 35577218Sphk len = sizeof(data); 35677218Sphk get_string(val, NULL, data, &len); 35777218Sphk 35877218Sphk set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 35977218Sphk} 36077218Sphk 361138593Ssam/* 362170531Ssam * Parse a channel specification for attributes/flags. 363170531Ssam * The syntax is: 364170531Ssam * freq/xx channel width (5,10,20,40,40+,40-) 365170531Ssam * freq:mode channel mode (a,b,g,h,n,t,s,d) 366170531Ssam * 367170531Ssam * These can be combined in either order; e.g. 2437:ng/40. 368170531Ssam * Modes are case insensitive. 369170531Ssam * 370170531Ssam * The result is not validated here; it's assumed to be 371170531Ssam * checked against the channel table fetched from the kernel. 372170531Ssam */ 373170531Ssamstatic int 374173275Ssamgetchannelflags(const char *val, int freq) 375138593Ssam{ 376170531Ssam#define _CHAN_HT 0x80000000 377170531Ssam const char *cp; 378170531Ssam int flags; 379138593Ssam 380170531Ssam flags = 0; 381166015Ssam 382170531Ssam cp = strchr(val, ':'); 383170531Ssam if (cp != NULL) { 384170531Ssam for (cp++; isalpha((int) *cp); cp++) { 385170531Ssam /* accept mixed case */ 386170531Ssam int c = *cp; 387170531Ssam if (isupper(c)) 388170531Ssam c = tolower(c); 389170531Ssam switch (c) { 390170531Ssam case 'a': /* 802.11a */ 391170531Ssam flags |= IEEE80211_CHAN_A; 392170531Ssam break; 393170531Ssam case 'b': /* 802.11b */ 394170531Ssam flags |= IEEE80211_CHAN_B; 395170531Ssam break; 396170531Ssam case 'g': /* 802.11g */ 397170531Ssam flags |= IEEE80211_CHAN_G; 398170531Ssam break; 399170531Ssam case 'h': /* ht = 802.11n */ 400170531Ssam case 'n': /* 802.11n */ 401170531Ssam flags |= _CHAN_HT; /* NB: private */ 402170531Ssam break; 403170531Ssam case 'd': /* dt = Atheros Dynamic Turbo */ 404170531Ssam flags |= IEEE80211_CHAN_TURBO; 405170531Ssam break; 406170531Ssam case 't': /* ht, dt, st, t */ 407170531Ssam /* dt and unadorned t specify Dynamic Turbo */ 408170531Ssam if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0) 409170531Ssam flags |= IEEE80211_CHAN_TURBO; 410170531Ssam break; 411170531Ssam case 's': /* st = Atheros Static Turbo */ 412170531Ssam flags |= IEEE80211_CHAN_STURBO; 413170531Ssam break; 414170531Ssam default: 415173275Ssam errx(-1, "%s: Invalid channel attribute %c\n", 416170531Ssam val, *cp); 417170531Ssam } 418170531Ssam } 419170531Ssam } 420170531Ssam cp = strchr(val, '/'); 421170531Ssam if (cp != NULL) { 422170531Ssam char *ep; 423170531Ssam u_long cw = strtoul(cp+1, &ep, 10); 424166015Ssam 425170531Ssam switch (cw) { 426170531Ssam case 5: 427170531Ssam flags |= IEEE80211_CHAN_QUARTER; 428170531Ssam break; 429170531Ssam case 10: 430170531Ssam flags |= IEEE80211_CHAN_HALF; 431170531Ssam break; 432170531Ssam case 20: 433170531Ssam /* NB: this may be removed below */ 434170531Ssam flags |= IEEE80211_CHAN_HT20; 435170531Ssam break; 436170531Ssam case 40: 437170531Ssam if (ep != NULL && *ep == '+') 438170531Ssam flags |= IEEE80211_CHAN_HT40U; 439170531Ssam else if (ep != NULL && *ep == '-') 440170531Ssam flags |= IEEE80211_CHAN_HT40D; 441170531Ssam break; 442170531Ssam default: 443173275Ssam errx(-1, "%s: Invalid channel width\n", val); 444170531Ssam } 445165570Ssam } 446170531Ssam /* 447170531Ssam * Cleanup specifications. 448170531Ssam */ 449170531Ssam if ((flags & _CHAN_HT) == 0) { 450170531Ssam /* 451170531Ssam * If user specified freq/20 or freq/40 quietly remove 452170531Ssam * HT cw attributes depending on channel use. To give 453170531Ssam * an explicit 20/40 width for an HT channel you must 454170531Ssam * indicate it is an HT channel since all HT channels 455170531Ssam * are also usable for legacy operation; e.g. freq:n/40. 456170531Ssam */ 457170531Ssam flags &= ~IEEE80211_CHAN_HT; 458170531Ssam } else { 459170531Ssam /* 460170531Ssam * Remove private indicator that this is an HT channel 461170531Ssam * and if no explicit channel width has been given 462170531Ssam * provide the default settings. 463170531Ssam */ 464170531Ssam flags &= ~_CHAN_HT; 465173275Ssam if ((flags & IEEE80211_CHAN_HT) == 0) { 466173275Ssam struct ieee80211_channel chan; 467173275Ssam /* 468173275Ssam * Consult the channel list to see if we can use 469173275Ssam * HT40+ or HT40- (if both the map routines choose). 470173275Ssam */ 471173275Ssam if (freq > 255) 472173275Ssam mapfreq(&chan, freq, 0); 473173275Ssam else 474173275Ssam mapchan(&chan, freq, 0); 475173275Ssam flags |= (chan.ic_flags & IEEE80211_CHAN_HT); 476173275Ssam } 477170531Ssam } 478170531Ssam return flags; 479170531Ssam#undef _CHAN_HT 480138593Ssam} 481138593Ssam 482138593Ssamstatic void 48377218Sphkset80211channel(const char *val, int d, int s, const struct afswtch *rafp) 48477218Sphk{ 485170531Ssam struct ieee80211_channel chan; 486170531Ssam 487170531Ssam memset(&chan, 0, sizeof(chan)); 488138593Ssam if (!isanyarg(val)) { 489173275Ssam int v, flags; 490170531Ssam 491170531Ssam getchaninfo(s); 492173275Ssam v = atoi(val); 493173275Ssam flags = getchannelflags(val, v); 494170531Ssam if (v > 255) { /* treat as frequency */ 495170531Ssam mapfreq(&chan, v, flags); 496170531Ssam } else { 497170531Ssam mapchan(&chan, v, flags); 498170531Ssam } 499170531Ssam } else { 500170531Ssam chan.ic_freq = IEEE80211_CHAN_ANY; 501170531Ssam } 502170531Ssam set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan); 50377218Sphk} 50477218Sphk 505138593Ssamstatic void 50677218Sphkset80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 50777218Sphk{ 50877218Sphk int mode; 50977218Sphk 51091454Sbrooks if (strcasecmp(val, "none") == 0) { 51177218Sphk mode = IEEE80211_AUTH_NONE; 51291454Sbrooks } else if (strcasecmp(val, "open") == 0) { 51377218Sphk mode = IEEE80211_AUTH_OPEN; 51491454Sbrooks } else if (strcasecmp(val, "shared") == 0) { 51577218Sphk mode = IEEE80211_AUTH_SHARED; 516138593Ssam } else if (strcasecmp(val, "8021x") == 0) { 517138593Ssam mode = IEEE80211_AUTH_8021X; 518138593Ssam } else if (strcasecmp(val, "wpa") == 0) { 519138593Ssam mode = IEEE80211_AUTH_WPA; 52077218Sphk } else { 521150708Sru errx(1, "unknown authmode"); 52277218Sphk } 52377218Sphk 52477218Sphk set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 52577218Sphk} 52677218Sphk 527138593Ssamstatic void 52877218Sphkset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 52977218Sphk{ 53077218Sphk int mode; 53177218Sphk 53291454Sbrooks if (strcasecmp(val, "off") == 0) { 53377218Sphk mode = IEEE80211_POWERSAVE_OFF; 53491454Sbrooks } else if (strcasecmp(val, "on") == 0) { 53577218Sphk mode = IEEE80211_POWERSAVE_ON; 53691454Sbrooks } else if (strcasecmp(val, "cam") == 0) { 53777218Sphk mode = IEEE80211_POWERSAVE_CAM; 53891454Sbrooks } else if (strcasecmp(val, "psp") == 0) { 53977218Sphk mode = IEEE80211_POWERSAVE_PSP; 54091454Sbrooks } else if (strcasecmp(val, "psp-cam") == 0) { 54177218Sphk mode = IEEE80211_POWERSAVE_PSP_CAM; 54277218Sphk } else { 543150708Sru errx(1, "unknown powersavemode"); 54477218Sphk } 54577218Sphk 54677218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 54777218Sphk} 54877218Sphk 549138593Ssamstatic void 55077218Sphkset80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 55177218Sphk{ 55277218Sphk if (d == 0) 55377218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 55477218Sphk 0, NULL); 55577218Sphk else 55677218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 55777218Sphk 0, NULL); 55877218Sphk} 55977218Sphk 560138593Ssamstatic void 56177218Sphkset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 56277218Sphk{ 56377218Sphk set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 56477218Sphk} 56577218Sphk 566138593Ssamstatic void 56777218Sphkset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 56877218Sphk{ 56977218Sphk int mode; 57077218Sphk 57191454Sbrooks if (strcasecmp(val, "off") == 0) { 57277218Sphk mode = IEEE80211_WEP_OFF; 57391454Sbrooks } else if (strcasecmp(val, "on") == 0) { 57477218Sphk mode = IEEE80211_WEP_ON; 57591454Sbrooks } else if (strcasecmp(val, "mixed") == 0) { 57677218Sphk mode = IEEE80211_WEP_MIXED; 57777218Sphk } else { 578150708Sru errx(1, "unknown wep mode"); 57977218Sphk } 58077218Sphk 58177218Sphk set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 58277218Sphk} 58377218Sphk 584138593Ssamstatic void 58577218Sphkset80211wep(const char *val, int d, int s, const struct afswtch *rafp) 58677218Sphk{ 58777218Sphk set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 58877218Sphk} 58977218Sphk 590139493Ssamstatic int 591139493Ssamisundefarg(const char *arg) 592139493Ssam{ 593139493Ssam return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 594139493Ssam} 595139493Ssam 596138593Ssamstatic void 59777218Sphkset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 59877218Sphk{ 599139493Ssam if (isundefarg(val)) 600139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 601139493Ssam else 602139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 60377218Sphk} 60477218Sphk 605138593Ssamstatic void 60677218Sphkset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 60777218Sphk{ 60877218Sphk int key = 0; 60977218Sphk int len; 610120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 61177218Sphk 61291454Sbrooks if (isdigit(val[0]) && val[1] == ':') { 61377218Sphk key = atoi(val)-1; 61477218Sphk val += 2; 61577218Sphk } 61677218Sphk 61777218Sphk bzero(data, sizeof(data)); 61877218Sphk len = sizeof(data); 61977218Sphk get_string(val, NULL, data, &len); 62077218Sphk 62177218Sphk set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 62277218Sphk} 62377218Sphk 62477218Sphk/* 625148686Sstefanf * This function is purely a NetBSD compatability interface. The NetBSD 626148686Sstefanf * interface is too inflexible, but it's there so we'll support it since 62777218Sphk * it's not all that hard. 62877218Sphk */ 629138593Ssamstatic void 63077218Sphkset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 63177218Sphk{ 63277218Sphk int txkey; 63377218Sphk int i, len; 634120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 63577218Sphk 63677218Sphk set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 63777218Sphk 63891454Sbrooks if (isdigit(val[0]) && val[1] == ':') { 63977218Sphk txkey = val[0]-'0'-1; 64077218Sphk val += 2; 64177218Sphk 64291454Sbrooks for (i = 0; i < 4; i++) { 64377218Sphk bzero(data, sizeof(data)); 64477218Sphk len = sizeof(data); 64577218Sphk val = get_string(val, ",", data, &len); 646151827Sbrooks if (val == NULL) 647151827Sbrooks exit(1); 64877218Sphk 64977218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 65077218Sphk } 65177218Sphk } else { 65277218Sphk bzero(data, sizeof(data)); 65377218Sphk len = sizeof(data); 65477218Sphk get_string(val, NULL, data, &len); 65577218Sphk txkey = 0; 65677218Sphk 65777218Sphk set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 65877218Sphk 65977218Sphk bzero(data, sizeof(data)); 66091454Sbrooks for (i = 1; i < 4; i++) 66177218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 66277218Sphk } 66377218Sphk 66477218Sphk set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 66577218Sphk} 66677218Sphk 667138593Ssamstatic void 668127649Ssamset80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 669127649Ssam{ 670148416Ssam set80211(s, IEEE80211_IOC_RTSTHRESHOLD, 671148416Ssam isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL); 672127649Ssam} 673127649Ssam 674138593Ssamstatic void 675127649Ssamset80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 676127649Ssam{ 677127649Ssam int mode; 678127649Ssam 679127649Ssam if (strcasecmp(val, "off") == 0) { 680127649Ssam mode = IEEE80211_PROTMODE_OFF; 681127649Ssam } else if (strcasecmp(val, "cts") == 0) { 682127649Ssam mode = IEEE80211_PROTMODE_CTS; 683173275Ssam } else if (strncasecmp(val, "rtscts", 3) == 0) { 684127649Ssam mode = IEEE80211_PROTMODE_RTSCTS; 685127649Ssam } else { 686150708Sru errx(1, "unknown protection mode"); 687127649Ssam } 688127649Ssam 689127649Ssam set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 690127649Ssam} 691127649Ssam 692138593Ssamstatic void 693173275Ssamset80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp) 694173275Ssam{ 695173275Ssam int mode; 696173275Ssam 697173275Ssam if (strcasecmp(val, "off") == 0) { 698173275Ssam mode = IEEE80211_PROTMODE_OFF; 699173275Ssam } else if (strncasecmp(val, "rts", 3) == 0) { 700173275Ssam mode = IEEE80211_PROTMODE_RTSCTS; 701173275Ssam } else { 702173275Ssam errx(1, "unknown protection mode"); 703173275Ssam } 704173275Ssam 705173275Ssam set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL); 706173275Ssam} 707173275Ssam 708173275Ssamstatic void 709127649Ssamset80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 710127649Ssam{ 711173275Ssam double v = atof(val); 712173275Ssam int txpow; 713173275Ssam 714173275Ssam txpow = (int) (2*v); 715173275Ssam if (txpow != 2*v) 716173275Ssam errx(-1, "invalid tx power (must be .5 dBm units)"); 717173275Ssam set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL); 718127649Ssam} 719127649Ssam 720138593Ssam#define IEEE80211_ROAMING_DEVICE 0 721138593Ssam#define IEEE80211_ROAMING_AUTO 1 722138593Ssam#define IEEE80211_ROAMING_MANUAL 2 723138593Ssam 724138593Ssamstatic void 725138593Ssamset80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 72677218Sphk{ 727138593Ssam int mode; 72877218Sphk 729138593Ssam if (strcasecmp(val, "device") == 0) { 730138593Ssam mode = IEEE80211_ROAMING_DEVICE; 731138593Ssam } else if (strcasecmp(val, "auto") == 0) { 732138593Ssam mode = IEEE80211_ROAMING_AUTO; 733138593Ssam } else if (strcasecmp(val, "manual") == 0) { 734138593Ssam mode = IEEE80211_ROAMING_MANUAL; 735138593Ssam } else { 736150708Sru errx(1, "unknown roaming mode"); 737138593Ssam } 738138593Ssam set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 739138593Ssam} 740138593Ssam 741138593Ssamstatic void 742138593Ssamset80211wme(const char *val, int d, int s, const struct afswtch *rafp) 743138593Ssam{ 744138593Ssam set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 745138593Ssam} 746138593Ssam 747138593Ssamstatic void 748138593Ssamset80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 749138593Ssam{ 750138593Ssam set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 751138593Ssam} 752138593Ssam 753138593Ssamstatic void 754138593Ssamset80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 755138593Ssam{ 756138593Ssam set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 757138593Ssam} 758138593Ssam 759138593Ssamstatic void 760170531Ssamset80211fastframes(const char *val, int d, int s, const struct afswtch *rafp) 761170531Ssam{ 762170531Ssam set80211(s, IEEE80211_IOC_FF, d, 0, NULL); 763170531Ssam} 764170531Ssam 765170531Ssamstatic void 766170531Ssamset80211dturbo(const char *val, int d, int s, const struct afswtch *rafp) 767170531Ssam{ 768170531Ssam set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL); 769170531Ssam} 770170531Ssam 771170531Ssamstatic void 772138593Ssamset80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 773138593Ssam{ 774138593Ssam struct ieee80211req_chanlist chanlist; 775138593Ssam#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) 776138593Ssam char *temp, *cp, *tp; 777138593Ssam 778138593Ssam temp = malloc(strlen(val) + 1); 779138593Ssam if (temp == NULL) 780138593Ssam errx(1, "malloc failed"); 781138593Ssam strcpy(temp, val); 782138593Ssam memset(&chanlist, 0, sizeof(chanlist)); 783138593Ssam cp = temp; 784138593Ssam for (;;) { 785173275Ssam int first, last, f, c; 786138593Ssam 787138593Ssam tp = strchr(cp, ','); 788138593Ssam if (tp != NULL) 789138593Ssam *tp++ = '\0'; 790138593Ssam switch (sscanf(cp, "%u-%u", &first, &last)) { 791138593Ssam case 1: 792138593Ssam if (first > MAXCHAN) 793146873Sjhb errx(-1, "channel %u out of range, max %zu", 794138593Ssam first, MAXCHAN); 795138593Ssam setbit(chanlist.ic_channels, first); 796138593Ssam break; 797138593Ssam case 2: 798138593Ssam if (first > MAXCHAN) 799146873Sjhb errx(-1, "channel %u out of range, max %zu", 800138593Ssam first, MAXCHAN); 801138593Ssam if (last > MAXCHAN) 802146873Sjhb errx(-1, "channel %u out of range, max %zu", 803138593Ssam last, MAXCHAN); 804138593Ssam if (first > last) 805138593Ssam errx(-1, "void channel range, %u > %u", 806138593Ssam first, last); 807138593Ssam for (f = first; f <= last; f++) 808138593Ssam setbit(chanlist.ic_channels, f); 809138593Ssam break; 810138593Ssam } 811138593Ssam if (tp == NULL) 812138593Ssam break; 813173275Ssam c = *tp; 814173275Ssam while (isspace(c)) 815138593Ssam tp++; 816173275Ssam if (!isdigit(c)) 817138593Ssam break; 818138593Ssam cp = tp; 819138593Ssam } 820170531Ssam set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist); 821138593Ssam#undef MAXCHAN 822138593Ssam} 823138593Ssam 824138593Ssamstatic void 825138593Ssamset80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 826138593Ssam{ 827138593Ssam 828138593Ssam if (!isanyarg(val)) { 829138593Ssam char *temp; 830138593Ssam struct sockaddr_dl sdl; 831138593Ssam 832155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 833138593Ssam if (temp == NULL) 834138593Ssam errx(1, "malloc failed"); 835138593Ssam temp[0] = ':'; 836138593Ssam strcpy(temp + 1, val); 837138593Ssam sdl.sdl_len = sizeof(sdl); 838138593Ssam link_addr(temp, &sdl); 839138593Ssam free(temp); 840138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 841138593Ssam errx(1, "malformed link-level address"); 842138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 843138593Ssam IEEE80211_ADDR_LEN, LLADDR(&sdl)); 844138593Ssam } else { 845138593Ssam uint8_t zerobssid[IEEE80211_ADDR_LEN]; 846138593Ssam memset(zerobssid, 0, sizeof(zerobssid)); 847138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 848138593Ssam IEEE80211_ADDR_LEN, zerobssid); 849138593Ssam } 850138593Ssam} 851138593Ssam 852138593Ssamstatic int 853138593Ssamgetac(const char *ac) 854138593Ssam{ 855138593Ssam if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 856138593Ssam return WME_AC_BE; 857138593Ssam if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 858138593Ssam return WME_AC_BK; 859138593Ssam if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 860138593Ssam return WME_AC_VI; 861138593Ssam if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 862138593Ssam return WME_AC_VO; 863138593Ssam errx(1, "unknown wme access class %s", ac); 864138593Ssam} 865138593Ssam 866138593Ssamstatic 867138593SsamDECL_CMD_FUNC2(set80211cwmin, ac, val) 868138593Ssam{ 869138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 870138593Ssam} 871138593Ssam 872138593Ssamstatic 873138593SsamDECL_CMD_FUNC2(set80211cwmax, ac, val) 874138593Ssam{ 875138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 876138593Ssam} 877138593Ssam 878138593Ssamstatic 879138593SsamDECL_CMD_FUNC2(set80211aifs, ac, val) 880138593Ssam{ 881138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 882138593Ssam} 883138593Ssam 884138593Ssamstatic 885138593SsamDECL_CMD_FUNC2(set80211txoplimit, ac, val) 886138593Ssam{ 887138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 888138593Ssam} 889138593Ssam 890138593Ssamstatic 891148621SsamDECL_CMD_FUNC(set80211acm, ac, d) 892138593Ssam{ 893148621Ssam set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL); 894138593Ssam} 895148621Ssamstatic 896148621SsamDECL_CMD_FUNC(set80211noacm, ac, d) 897148621Ssam{ 898148621Ssam set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL); 899148621Ssam} 900138593Ssam 901138593Ssamstatic 902148621SsamDECL_CMD_FUNC(set80211ackpolicy, ac, d) 903138593Ssam{ 904148621Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL); 905138593Ssam} 906148621Ssamstatic 907148621SsamDECL_CMD_FUNC(set80211noackpolicy, ac, d) 908148621Ssam{ 909148621Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL); 910148621Ssam} 911138593Ssam 912138593Ssamstatic 913138593SsamDECL_CMD_FUNC2(set80211bsscwmin, ac, val) 914138593Ssam{ 915138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 916138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 917138593Ssam} 918138593Ssam 919138593Ssamstatic 920138593SsamDECL_CMD_FUNC2(set80211bsscwmax, ac, val) 921138593Ssam{ 922138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 923138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 924138593Ssam} 925138593Ssam 926138593Ssamstatic 927138593SsamDECL_CMD_FUNC2(set80211bssaifs, ac, val) 928138593Ssam{ 929138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 930138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 931138593Ssam} 932138593Ssam 933138593Ssamstatic 934138593SsamDECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 935138593Ssam{ 936138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 937138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 938138593Ssam} 939138593Ssam 940138593Ssamstatic 941138593SsamDECL_CMD_FUNC(set80211dtimperiod, val, d) 942138593Ssam{ 943138593Ssam set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 944138593Ssam} 945138593Ssam 946138593Ssamstatic 947138593SsamDECL_CMD_FUNC(set80211bintval, val, d) 948138593Ssam{ 949138593Ssam set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 950138593Ssam} 951138593Ssam 952138593Ssamstatic void 953138593Ssamset80211macmac(int s, int op, const char *val) 954138593Ssam{ 955138593Ssam char *temp; 956138593Ssam struct sockaddr_dl sdl; 957138593Ssam 958155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 959138593Ssam if (temp == NULL) 960138593Ssam errx(1, "malloc failed"); 961138593Ssam temp[0] = ':'; 962138593Ssam strcpy(temp + 1, val); 963138593Ssam sdl.sdl_len = sizeof(sdl); 964138593Ssam link_addr(temp, &sdl); 965138593Ssam free(temp); 966138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 967138593Ssam errx(1, "malformed link-level address"); 968138593Ssam set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 969138593Ssam} 970138593Ssam 971138593Ssamstatic 972138593SsamDECL_CMD_FUNC(set80211addmac, val, d) 973138593Ssam{ 974138593Ssam set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 975138593Ssam} 976138593Ssam 977138593Ssamstatic 978138593SsamDECL_CMD_FUNC(set80211delmac, val, d) 979138593Ssam{ 980138593Ssam set80211macmac(s, IEEE80211_IOC_DELMAC, val); 981138593Ssam} 982138593Ssam 983138593Ssamstatic 984149029SsamDECL_CMD_FUNC(set80211kickmac, val, d) 985149029Ssam{ 986149029Ssam char *temp; 987149029Ssam struct sockaddr_dl sdl; 988149029Ssam struct ieee80211req_mlme mlme; 989149029Ssam 990155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 991149029Ssam if (temp == NULL) 992149029Ssam errx(1, "malloc failed"); 993149029Ssam temp[0] = ':'; 994149029Ssam strcpy(temp + 1, val); 995149029Ssam sdl.sdl_len = sizeof(sdl); 996149029Ssam link_addr(temp, &sdl); 997149029Ssam free(temp); 998149029Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 999149029Ssam errx(1, "malformed link-level address"); 1000149029Ssam memset(&mlme, 0, sizeof(mlme)); 1001149029Ssam mlme.im_op = IEEE80211_MLME_DEAUTH; 1002149029Ssam mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; 1003149029Ssam memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN); 1004170531Ssam set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme); 1005149029Ssam} 1006149029Ssam 1007149029Ssamstatic 1008138593SsamDECL_CMD_FUNC(set80211maccmd, val, d) 1009138593Ssam{ 1010138593Ssam set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 1011138593Ssam} 1012138593Ssam 1013147795Ssamstatic void 1014147795Ssamset80211pureg(const char *val, int d, int s, const struct afswtch *rafp) 1015147795Ssam{ 1016147795Ssam set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); 1017147795Ssam} 1018147795Ssam 1019153422Ssamstatic void 1020170531Ssamset80211bgscan(const char *val, int d, int s, const struct afswtch *rafp) 1021153422Ssam{ 1022170531Ssam set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL); 1023153422Ssam} 1024153422Ssam 1025148416Ssamstatic 1026170531SsamDECL_CMD_FUNC(set80211bgscanidle, val, d) 1027170531Ssam{ 1028170531Ssam set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL); 1029170531Ssam} 1030170531Ssam 1031170531Ssamstatic 1032170531SsamDECL_CMD_FUNC(set80211bgscanintvl, val, d) 1033170531Ssam{ 1034170531Ssam set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL); 1035170531Ssam} 1036170531Ssam 1037170531Ssamstatic 1038170531SsamDECL_CMD_FUNC(set80211scanvalid, val, d) 1039170531Ssam{ 1040170531Ssam set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL); 1041170531Ssam} 1042170531Ssam 1043170531Ssamstatic 1044170531SsamDECL_CMD_FUNC(set80211roamrssi11a, val, d) 1045170531Ssam{ 1046170531Ssam set80211(s, IEEE80211_IOC_ROAM_RSSI_11A, atoi(val), 0, NULL); 1047170531Ssam} 1048170531Ssam 1049170531Ssamstatic 1050170531SsamDECL_CMD_FUNC(set80211roamrssi11b, val, d) 1051170531Ssam{ 1052170531Ssam set80211(s, IEEE80211_IOC_ROAM_RSSI_11B, atoi(val), 0, NULL); 1053170531Ssam} 1054170531Ssam 1055170531Ssamstatic 1056170531SsamDECL_CMD_FUNC(set80211roamrssi11g, val, d) 1057170531Ssam{ 1058170531Ssam set80211(s, IEEE80211_IOC_ROAM_RSSI_11G, atoi(val), 0, NULL); 1059170531Ssam} 1060170531Ssam 1061170531Ssamstatic 1062170531SsamDECL_CMD_FUNC(set80211roamrate11a, val, d) 1063170531Ssam{ 1064170531Ssam set80211(s, IEEE80211_IOC_ROAM_RATE_11A, 2*atoi(val), 0, NULL); 1065170531Ssam} 1066170531Ssam 1067170531Ssamstatic 1068170531SsamDECL_CMD_FUNC(set80211roamrate11b, val, d) 1069170531Ssam{ 1070170531Ssam set80211(s, IEEE80211_IOC_ROAM_RATE_11B, 2*atoi(val), 0, NULL); 1071170531Ssam} 1072170531Ssam 1073170531Ssamstatic 1074170531SsamDECL_CMD_FUNC(set80211roamrate11g, val, d) 1075170531Ssam{ 1076170531Ssam set80211(s, IEEE80211_IOC_ROAM_RATE_11G, 2*atoi(val), 0, NULL); 1077170531Ssam} 1078170531Ssam 1079170531Ssamstatic 1080153354SsamDECL_CMD_FUNC(set80211mcastrate, val, d) 1081153354Ssam{ 1082170531Ssam set80211(s, IEEE80211_IOC_MCAST_RATE, 2*atoi(val), 0, NULL); 1083153354Ssam} 1084153354Ssam 1085153354Ssamstatic 1086148416SsamDECL_CMD_FUNC(set80211fragthreshold, val, d) 1087148416Ssam{ 1088148416Ssam set80211(s, IEEE80211_IOC_FRAGTHRESHOLD, 1089148416Ssam isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL); 1090148416Ssam} 1091148416Ssam 1092160687Ssamstatic 1093160687SsamDECL_CMD_FUNC(set80211bmissthreshold, val, d) 1094160687Ssam{ 1095160687Ssam set80211(s, IEEE80211_IOC_BMISSTHRESHOLD, 1096160687Ssam isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL); 1097160687Ssam} 1098160687Ssam 1099170531Ssamstatic void 1100170531Ssamset80211burst(const char *val, int d, int s, const struct afswtch *rafp) 1101170531Ssam{ 1102170531Ssam set80211(s, IEEE80211_IOC_BURST, d, 0, NULL); 1103170531Ssam} 1104170531Ssam 1105170531Ssamstatic void 1106170531Ssamset80211doth(const char *val, int d, int s, const struct afswtch *rafp) 1107170531Ssam{ 1108170531Ssam set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL); 1109170531Ssam} 1110170531Ssam 1111173275Ssamstatic void 1112173275Ssamset80211shortgi(const char *val, int d, int s, const struct afswtch *rafp) 1113173275Ssam{ 1114173275Ssam set80211(s, IEEE80211_IOC_SHORTGI, 1115173275Ssam d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0, 1116173275Ssam 0, NULL); 1117173275Ssam} 1118173275Ssam 1119173275Ssamstatic void 1120173275Ssamset80211ampdu(const char *val, int d, int s, const struct afswtch *rafp) 1121173275Ssam{ 1122173275Ssam int ampdu; 1123173275Ssam 1124173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU, &du) < 0) 1125173275Ssam errx(-1, "cannot get AMPDU setting"); 1126173275Ssam if (d < 0) { 1127173275Ssam d = -d; 1128173275Ssam ampdu &= ~d; 1129173275Ssam } else 1130173275Ssam ampdu |= d; 1131173275Ssam set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL); 1132173275Ssam} 1133173275Ssam 1134173275Ssamstatic 1135173275SsamDECL_CMD_FUNC(set80211ampdulimit, val, d) 1136173275Ssam{ 1137173275Ssam int v; 1138173275Ssam 1139173275Ssam switch (atoi(val)) { 1140173275Ssam case 8: 1141173275Ssam case 8*1024: 1142173275Ssam v = IEEE80211_HTCAP_MAXRXAMPDU_8K; 1143173275Ssam break; 1144173275Ssam case 16: 1145173275Ssam case 16*1024: 1146173275Ssam v = IEEE80211_HTCAP_MAXRXAMPDU_16K; 1147173275Ssam break; 1148173275Ssam case 32: 1149173275Ssam case 32*1024: 1150173275Ssam v = IEEE80211_HTCAP_MAXRXAMPDU_32K; 1151173275Ssam break; 1152173275Ssam case 64: 1153173275Ssam case 64*1024: 1154173275Ssam v = IEEE80211_HTCAP_MAXRXAMPDU_64K; 1155173275Ssam break; 1156173275Ssam default: 1157173275Ssam errx(-1, "invalid A-MPDU limit %s", val); 1158173275Ssam } 1159173275Ssam set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL); 1160173275Ssam} 1161173275Ssam 1162173275Ssamstatic 1163173275SsamDECL_CMD_FUNC(set80211ampdudensity, val, d) 1164173275Ssam{ 1165173275Ssam int v; 1166173275Ssam 1167173275Ssam if (isanyarg(val)) 1168173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_NA; 1169173275Ssam else switch ((int)(atof(val)*4)) { 1170173275Ssam case 0: 1171173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_NA; 1172173275Ssam break; 1173173275Ssam case 1: 1174173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_025; 1175173275Ssam break; 1176173275Ssam case 2: 1177173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_05; 1178173275Ssam break; 1179173275Ssam case 4: 1180173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_1; 1181173275Ssam break; 1182173275Ssam case 8: 1183173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_2; 1184173275Ssam break; 1185173275Ssam case 16: 1186173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_4; 1187173275Ssam break; 1188173275Ssam case 32: 1189173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_8; 1190173275Ssam break; 1191173275Ssam case 64: 1192173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_16; 1193173275Ssam break; 1194173275Ssam default: 1195173275Ssam errx(-1, "invalid A-MPDU density %s", val); 1196173275Ssam } 1197173275Ssam set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL); 1198173275Ssam} 1199173275Ssam 1200173275Ssamstatic void 1201173275Ssamset80211amsdu(const char *val, int d, int s, const struct afswtch *rafp) 1202173275Ssam{ 1203173275Ssam int amsdu; 1204173275Ssam 1205173275Ssam if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0) 1206173275Ssam errx(-1, "cannot get AMSDU setting"); 1207173275Ssam if (d < 0) { 1208173275Ssam d = -d; 1209173275Ssam amsdu &= ~d; 1210173275Ssam } else 1211173275Ssam amsdu |= d; 1212173275Ssam set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL); 1213173275Ssam} 1214173275Ssam 1215173275Ssamstatic 1216173275SsamDECL_CMD_FUNC(set80211amsdulimit, val, d) 1217173275Ssam{ 1218173275Ssam set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL); 1219173275Ssam} 1220173275Ssam 1221173275Ssamstatic void 1222173275Ssamset80211puren(const char *val, int d, int s, const struct afswtch *rafp) 1223173275Ssam{ 1224173275Ssam set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL); 1225173275Ssam} 1226173275Ssam 1227173275Ssamstatic void 1228173275Ssamset80211htcompat(const char *val, int d, int s, const struct afswtch *rafp) 1229173275Ssam{ 1230173275Ssam set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL); 1231173275Ssam} 1232173275Ssam 1233173275Ssamstatic void 1234173275Ssamset80211htconf(const char *val, int d, int s, const struct afswtch *rafp) 1235173275Ssam{ 1236173275Ssam set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL); 1237173275Ssam htconf = d; 1238173275Ssam} 1239173275Ssam 1240173275Ssamstatic void 1241173275Ssamset80211inact(const char *val, int d, int s, const struct afswtch *rafp) 1242173275Ssam{ 1243173275Ssam set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL); 1244173275Ssam} 1245173275Ssam 1246173275Ssamstatic void 1247173275SsamLINE_INIT(char c) 1248173275Ssam{ 1249173275Ssam spacer = c; 1250173275Ssam if (c == '\t') 1251173275Ssam col = 8; 1252173275Ssam else 1253173275Ssam col = 1; 1254173275Ssam} 1255173275Ssam 1256173275Ssamstatic void 1257173275SsamLINE_BREAK(void) 1258173275Ssam{ 1259173275Ssam if (spacer != '\t') { 1260173275Ssam printf("\n"); 1261173275Ssam spacer = '\t'; 1262173275Ssam } 1263173275Ssam col = 8; /* 8-col tab */ 1264173275Ssam} 1265173275Ssam 1266173275Ssamstatic void 1267173275SsamLINE_CHECK(const char *fmt, ...) 1268173275Ssam{ 1269173275Ssam char buf[80]; 1270173275Ssam va_list ap; 1271173275Ssam int n; 1272173275Ssam 1273173275Ssam va_start(ap, fmt); 1274173275Ssam n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap); 1275173275Ssam va_end(ap); 1276173275Ssam col += 1+n; 1277173275Ssam if (col > MAXCOL) { 1278173275Ssam LINE_BREAK(); 1279173275Ssam col += n; 1280173275Ssam } 1281173275Ssam buf[0] = spacer; 1282173275Ssam printf("%s", buf); 1283173275Ssam spacer = ' '; 1284173275Ssam} 1285173275Ssam 1286138593Ssamstatic int 1287170531Ssamgetmaxrate(const uint8_t rates[15], uint8_t nrates) 1288138593Ssam{ 1289138593Ssam int i, maxrate = -1; 1290138593Ssam 1291138593Ssam for (i = 0; i < nrates; i++) { 1292138593Ssam int rate = rates[i] & IEEE80211_RATE_VAL; 1293138593Ssam if (rate > maxrate) 1294138593Ssam maxrate = rate; 1295138593Ssam } 1296138593Ssam return maxrate / 2; 1297138593Ssam} 1298138593Ssam 1299138593Ssamstatic const char * 1300138593Ssamgetcaps(int capinfo) 1301138593Ssam{ 1302138593Ssam static char capstring[32]; 1303138593Ssam char *cp = capstring; 1304138593Ssam 1305138593Ssam if (capinfo & IEEE80211_CAPINFO_ESS) 1306138593Ssam *cp++ = 'E'; 1307138593Ssam if (capinfo & IEEE80211_CAPINFO_IBSS) 1308138593Ssam *cp++ = 'I'; 1309138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 1310138593Ssam *cp++ = 'c'; 1311138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 1312138593Ssam *cp++ = 'C'; 1313138593Ssam if (capinfo & IEEE80211_CAPINFO_PRIVACY) 1314138593Ssam *cp++ = 'P'; 1315138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 1316138593Ssam *cp++ = 'S'; 1317138593Ssam if (capinfo & IEEE80211_CAPINFO_PBCC) 1318138593Ssam *cp++ = 'B'; 1319138593Ssam if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 1320138593Ssam *cp++ = 'A'; 1321138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 1322138593Ssam *cp++ = 's'; 1323138593Ssam if (capinfo & IEEE80211_CAPINFO_RSN) 1324138593Ssam *cp++ = 'R'; 1325138593Ssam if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 1326138593Ssam *cp++ = 'D'; 1327138593Ssam *cp = '\0'; 1328138593Ssam return capstring; 1329138593Ssam} 1330138593Ssam 1331159885Ssamstatic const char * 1332159885Ssamgetflags(int flags) 1333159885Ssam{ 1334159885Ssam/* XXX need these publicly defined or similar */ 1335159885Ssam#define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */ 1336159885Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 1337159885Ssam#define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */ 1338159885Ssam#define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */ 1339170531Ssam#define IEEE80211_NODE_HT 0x0040 /* HT enabled */ 1340173275Ssam#define IEEE80211_NODE_HTCOMPAT 0x0080 /* HT setup w/ vendor OUI's */ 1341173275Ssam#define IEEE80211_NODE_WPS 0x0100 /* WPS association */ 1342173275Ssam#define IEEE80211_NODE_TSN 0x0200 /* TSN association */ 1343173275Ssam 1344159885Ssam static char flagstring[32]; 1345159885Ssam char *cp = flagstring; 1346159885Ssam 1347159885Ssam if (flags & IEEE80211_NODE_AUTH) 1348159885Ssam *cp++ = 'A'; 1349159885Ssam if (flags & IEEE80211_NODE_QOS) 1350159885Ssam *cp++ = 'Q'; 1351159885Ssam if (flags & IEEE80211_NODE_ERP) 1352159885Ssam *cp++ = 'E'; 1353159885Ssam if (flags & IEEE80211_NODE_PWR_MGT) 1354159885Ssam *cp++ = 'P'; 1355173275Ssam if (flags & IEEE80211_NODE_HT) { 1356170531Ssam *cp++ = 'H'; 1357173275Ssam if (flags & IEEE80211_NODE_HTCOMPAT) 1358173275Ssam *cp++ = '+'; 1359173275Ssam } 1360173275Ssam if (flags & IEEE80211_NODE_WPS) 1361173275Ssam *cp++ = 'W'; 1362173275Ssam if (flags & IEEE80211_NODE_TSN) 1363173275Ssam *cp++ = 'T'; 1364159885Ssam *cp = '\0'; 1365159885Ssam return flagstring; 1366173275Ssam#undef IEEE80211_NODE_TSN 1367173275Ssam#undef IEEE80211_NODE_WPS 1368173275Ssam#undef IEEE80211_NODE_HTCOMPAT 1369170531Ssam#undef IEEE80211_NODE_HT 1370159885Ssam#undef IEEE80211_NODE_AUTH 1371159885Ssam#undef IEEE80211_NODE_QOS 1372159885Ssam#undef IEEE80211_NODE_ERP 1373159885Ssam#undef IEEE80211_NODE_PWR_MGT 1374159885Ssam} 1375159885Ssam 1376138593Ssamstatic void 1377138593Ssamprintie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 1378138593Ssam{ 1379138593Ssam printf("%s", tag); 1380138593Ssam if (verbose) { 1381138593Ssam maxlen -= strlen(tag)+2; 1382138593Ssam if (2*ielen > maxlen) 1383138593Ssam maxlen--; 1384138593Ssam printf("<"); 1385138593Ssam for (; ielen > 0; ie++, ielen--) { 1386138593Ssam if (maxlen-- <= 0) 1387138593Ssam break; 1388138593Ssam printf("%02x", *ie); 1389138593Ssam } 1390138593Ssam if (ielen != 0) 1391138593Ssam printf("-"); 1392138593Ssam printf(">"); 1393138593Ssam } 1394138593Ssam} 1395138593Ssam 1396170531Ssam#define LE_READ_2(p) \ 1397170531Ssam ((u_int16_t) \ 1398170531Ssam ((((const u_int8_t *)(p))[0] ) | \ 1399170531Ssam (((const u_int8_t *)(p))[1] << 8))) 1400170531Ssam#define LE_READ_4(p) \ 1401170531Ssam ((u_int32_t) \ 1402170531Ssam ((((const u_int8_t *)(p))[0] ) | \ 1403170531Ssam (((const u_int8_t *)(p))[1] << 8) | \ 1404170531Ssam (((const u_int8_t *)(p))[2] << 16) | \ 1405170531Ssam (((const u_int8_t *)(p))[3] << 24))) 1406170531Ssam 1407138593Ssam/* 1408170531Ssam * NB: The decoding routines assume a properly formatted ie 1409170531Ssam * which should be safe as the kernel only retains them 1410170531Ssam * if they parse ok. 1411170531Ssam */ 1412170531Ssam 1413170531Ssamstatic void 1414173275Ssamprintwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1415170531Ssam{ 1416170531Ssam#define MS(_v, _f) (((_v) & _f) >> _f##_S) 1417170531Ssam static const char *acnames[] = { "BE", "BK", "VO", "VI" }; 1418173275Ssam const struct ieee80211_wme_param *wme = 1419173275Ssam (const struct ieee80211_wme_param *) ie; 1420170531Ssam int i; 1421170531Ssam 1422170531Ssam printf("%s", tag); 1423173275Ssam if (!verbose) 1424173275Ssam return; 1425173275Ssam printf("<qosinfo 0x%x", wme->param_qosInfo); 1426173275Ssam ie += offsetof(struct ieee80211_wme_param, params_acParams); 1427173275Ssam for (i = 0; i < WME_NUM_AC; i++) { 1428173275Ssam const struct ieee80211_wme_acparams *ac = 1429173275Ssam &wme->params_acParams[i]; 1430173275Ssam 1431173275Ssam printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]" 1432173275Ssam , acnames[i] 1433173275Ssam , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : "" 1434173275Ssam , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN) 1435173275Ssam , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN) 1436173275Ssam , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX) 1437173275Ssam , LE_READ_2(&ac->acp_txop) 1438173275Ssam ); 1439170531Ssam } 1440173275Ssam printf(">"); 1441170531Ssam#undef MS 1442170531Ssam} 1443170531Ssam 1444170531Ssamstatic void 1445173275Ssamprintwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1446173275Ssam{ 1447173275Ssam printf("%s", tag); 1448173275Ssam if (verbose) { 1449173275Ssam const struct ieee80211_wme_info *wme = 1450173275Ssam (const struct ieee80211_wme_info *) ie; 1451173275Ssam printf("<version 0x%x info 0x%x>", 1452173275Ssam wme->wme_version, wme->wme_info); 1453173275Ssam } 1454173275Ssam} 1455173275Ssam 1456173275Ssamstatic void 1457173275Ssamprinthtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1458173275Ssam{ 1459173275Ssam printf("%s", tag); 1460173275Ssam if (verbose) { 1461173275Ssam const struct ieee80211_ie_htcap *htcap = 1462173275Ssam (const struct ieee80211_ie_htcap *) ie; 1463173275Ssam const char *sep; 1464173275Ssam int i, j; 1465173275Ssam 1466173275Ssam printf("<cap 0x%x param 0x%x", 1467173275Ssam LE_READ_2(&htcap->hc_cap), htcap->hc_param); 1468173275Ssam printf(" mcsset["); 1469173275Ssam sep = ""; 1470173275Ssam for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) 1471173275Ssam if (isset(htcap->hc_mcsset, i)) { 1472173275Ssam for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) 1473173275Ssam if (isclr(htcap->hc_mcsset, j)) 1474173275Ssam break; 1475173275Ssam j--; 1476173275Ssam if (i == j) 1477173275Ssam printf("%s%u", sep, i); 1478173275Ssam else 1479173275Ssam printf("%s%u-%u", sep, i, j); 1480173275Ssam i += j-i; 1481173275Ssam sep = ","; 1482173275Ssam } 1483173275Ssam printf("] extcap 0x%x txbf 0x%x antenna 0x%x>", 1484173275Ssam LE_READ_2(&htcap->hc_extcap), 1485173275Ssam LE_READ_4(&htcap->hc_txbf), 1486173275Ssam htcap->hc_antenna); 1487173275Ssam } 1488173275Ssam} 1489173275Ssam 1490173275Ssamstatic void 1491173275Ssamprinthtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1492173275Ssam{ 1493173275Ssam printf("%s", tag); 1494173275Ssam if (verbose) { 1495173275Ssam const struct ieee80211_ie_htinfo *htinfo = 1496173275Ssam (const struct ieee80211_ie_htinfo *) ie; 1497173275Ssam const char *sep; 1498173275Ssam int i, j; 1499173275Ssam 1500173275Ssam printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel, 1501173275Ssam htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3, 1502173275Ssam LE_READ_2(&htinfo->hi_byte45)); 1503173275Ssam printf(" basicmcs["); 1504173275Ssam sep = ""; 1505173275Ssam for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) 1506173275Ssam if (isset(htinfo->hi_basicmcsset, i)) { 1507173275Ssam for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) 1508173275Ssam if (isclr(htinfo->hi_basicmcsset, j)) 1509173275Ssam break; 1510173275Ssam j--; 1511173275Ssam if (i == j) 1512173275Ssam printf("%s%u", sep, i); 1513173275Ssam else 1514173275Ssam printf("%s%u-%u", sep, i, j); 1515173275Ssam i += j-i; 1516173275Ssam sep = ","; 1517173275Ssam } 1518173275Ssam printf("]>"); 1519173275Ssam } 1520173275Ssam} 1521173275Ssam 1522173275Ssamstatic void 1523170531Ssamprintathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1524170531Ssam{ 1525170531Ssam 1526170531Ssam printf("%s", tag); 1527170531Ssam if (verbose) { 1528170531Ssam const struct ieee80211_ath_ie *ath = 1529170531Ssam (const struct ieee80211_ath_ie *)ie; 1530170531Ssam 1531170531Ssam printf("<"); 1532170531Ssam if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME) 1533170531Ssam printf("DTURBO,"); 1534170531Ssam if (ath->ath_capability & ATHEROS_CAP_COMPRESSION) 1535170531Ssam printf("COMP,"); 1536170531Ssam if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME) 1537170531Ssam printf("FF,"); 1538170531Ssam if (ath->ath_capability & ATHEROS_CAP_XR) 1539170531Ssam printf("XR,"); 1540170531Ssam if (ath->ath_capability & ATHEROS_CAP_AR) 1541170531Ssam printf("AR,"); 1542170531Ssam if (ath->ath_capability & ATHEROS_CAP_BURST) 1543170531Ssam printf("BURST,"); 1544170531Ssam if (ath->ath_capability & ATHEROS_CAP_WME) 1545170531Ssam printf("WME,"); 1546170531Ssam if (ath->ath_capability & ATHEROS_CAP_BOOST) 1547170531Ssam printf("BOOST,"); 1548170531Ssam printf("0x%x>", LE_READ_2(ath->ath_defkeyix)); 1549170531Ssam } 1550170531Ssam} 1551170531Ssam 1552170531Ssamstatic const char * 1553170531Ssamwpa_cipher(const u_int8_t *sel) 1554170531Ssam{ 1555170531Ssam#define WPA_SEL(x) (((x)<<24)|WPA_OUI) 1556170531Ssam u_int32_t w = LE_READ_4(sel); 1557170531Ssam 1558170531Ssam switch (w) { 1559170531Ssam case WPA_SEL(WPA_CSE_NULL): 1560170531Ssam return "NONE"; 1561170531Ssam case WPA_SEL(WPA_CSE_WEP40): 1562170531Ssam return "WEP40"; 1563170531Ssam case WPA_SEL(WPA_CSE_WEP104): 1564170531Ssam return "WEP104"; 1565170531Ssam case WPA_SEL(WPA_CSE_TKIP): 1566170531Ssam return "TKIP"; 1567170531Ssam case WPA_SEL(WPA_CSE_CCMP): 1568170531Ssam return "AES-CCMP"; 1569170531Ssam } 1570170531Ssam return "?"; /* NB: so 1<< is discarded */ 1571170531Ssam#undef WPA_SEL 1572170531Ssam} 1573170531Ssam 1574170531Ssamstatic const char * 1575170531Ssamwpa_keymgmt(const u_int8_t *sel) 1576170531Ssam{ 1577170531Ssam#define WPA_SEL(x) (((x)<<24)|WPA_OUI) 1578170531Ssam u_int32_t w = LE_READ_4(sel); 1579170531Ssam 1580170531Ssam switch (w) { 1581170531Ssam case WPA_SEL(WPA_ASE_8021X_UNSPEC): 1582170531Ssam return "8021X-UNSPEC"; 1583170531Ssam case WPA_SEL(WPA_ASE_8021X_PSK): 1584170531Ssam return "8021X-PSK"; 1585170531Ssam case WPA_SEL(WPA_ASE_NONE): 1586170531Ssam return "NONE"; 1587170531Ssam } 1588170531Ssam return "?"; 1589170531Ssam#undef WPA_SEL 1590170531Ssam} 1591170531Ssam 1592170531Ssamstatic void 1593170531Ssamprintwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1594170531Ssam{ 1595170531Ssam u_int8_t len = ie[1]; 1596170531Ssam 1597170531Ssam printf("%s", tag); 1598170531Ssam if (verbose) { 1599170531Ssam const char *sep; 1600170531Ssam int n; 1601170531Ssam 1602170531Ssam ie += 6, len -= 4; /* NB: len is payload only */ 1603170531Ssam 1604170531Ssam printf("<v%u", LE_READ_2(ie)); 1605170531Ssam ie += 2, len -= 2; 1606170531Ssam 1607170531Ssam printf(" mc:%s", wpa_cipher(ie)); 1608170531Ssam ie += 4, len -= 4; 1609170531Ssam 1610170531Ssam /* unicast ciphers */ 1611170531Ssam n = LE_READ_2(ie); 1612170531Ssam ie += 2, len -= 2; 1613170531Ssam sep = " uc:"; 1614170531Ssam for (; n > 0; n--) { 1615170531Ssam printf("%s%s", sep, wpa_cipher(ie)); 1616170531Ssam ie += 4, len -= 4; 1617170531Ssam sep = "+"; 1618170531Ssam } 1619170531Ssam 1620170531Ssam /* key management algorithms */ 1621170531Ssam n = LE_READ_2(ie); 1622170531Ssam ie += 2, len -= 2; 1623170531Ssam sep = " km:"; 1624170531Ssam for (; n > 0; n--) { 1625170531Ssam printf("%s%s", sep, wpa_keymgmt(ie)); 1626170531Ssam ie += 4, len -= 4; 1627170531Ssam sep = "+"; 1628170531Ssam } 1629170531Ssam 1630170531Ssam if (len > 2) /* optional capabilities */ 1631170531Ssam printf(", caps 0x%x", LE_READ_2(ie)); 1632170531Ssam printf(">"); 1633170531Ssam } 1634170531Ssam} 1635170531Ssam 1636170531Ssamstatic const char * 1637170531Ssamrsn_cipher(const u_int8_t *sel) 1638170531Ssam{ 1639170531Ssam#define RSN_SEL(x) (((x)<<24)|RSN_OUI) 1640170531Ssam u_int32_t w = LE_READ_4(sel); 1641170531Ssam 1642170531Ssam switch (w) { 1643170531Ssam case RSN_SEL(RSN_CSE_NULL): 1644170531Ssam return "NONE"; 1645170531Ssam case RSN_SEL(RSN_CSE_WEP40): 1646170531Ssam return "WEP40"; 1647170531Ssam case RSN_SEL(RSN_CSE_WEP104): 1648170531Ssam return "WEP104"; 1649170531Ssam case RSN_SEL(RSN_CSE_TKIP): 1650170531Ssam return "TKIP"; 1651170531Ssam case RSN_SEL(RSN_CSE_CCMP): 1652170531Ssam return "AES-CCMP"; 1653170531Ssam case RSN_SEL(RSN_CSE_WRAP): 1654170531Ssam return "AES-OCB"; 1655170531Ssam } 1656170531Ssam return "?"; 1657170531Ssam#undef WPA_SEL 1658170531Ssam} 1659170531Ssam 1660170531Ssamstatic const char * 1661170531Ssamrsn_keymgmt(const u_int8_t *sel) 1662170531Ssam{ 1663170531Ssam#define RSN_SEL(x) (((x)<<24)|RSN_OUI) 1664170531Ssam u_int32_t w = LE_READ_4(sel); 1665170531Ssam 1666170531Ssam switch (w) { 1667170531Ssam case RSN_SEL(RSN_ASE_8021X_UNSPEC): 1668170531Ssam return "8021X-UNSPEC"; 1669170531Ssam case RSN_SEL(RSN_ASE_8021X_PSK): 1670170531Ssam return "8021X-PSK"; 1671170531Ssam case RSN_SEL(RSN_ASE_NONE): 1672170531Ssam return "NONE"; 1673170531Ssam } 1674170531Ssam return "?"; 1675170531Ssam#undef RSN_SEL 1676170531Ssam} 1677170531Ssam 1678170531Ssamstatic void 1679170531Ssamprintrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1680170531Ssam{ 1681170531Ssam printf("%s", tag); 1682170531Ssam if (verbose) { 1683170531Ssam const char *sep; 1684170531Ssam int n; 1685170531Ssam 1686173275Ssam ie += 2, ielen -= 2; 1687170531Ssam 1688170531Ssam printf("<v%u", LE_READ_2(ie)); 1689173275Ssam ie += 2, ielen -= 2; 1690170531Ssam 1691170531Ssam printf(" mc:%s", rsn_cipher(ie)); 1692173275Ssam ie += 4, ielen -= 4; 1693170531Ssam 1694170531Ssam /* unicast ciphers */ 1695170531Ssam n = LE_READ_2(ie); 1696173275Ssam ie += 2, ielen -= 2; 1697170531Ssam sep = " uc:"; 1698170531Ssam for (; n > 0; n--) { 1699170531Ssam printf("%s%s", sep, rsn_cipher(ie)); 1700173275Ssam ie += 4, ielen -= 4; 1701170531Ssam sep = "+"; 1702170531Ssam } 1703170531Ssam 1704170531Ssam /* key management algorithms */ 1705170531Ssam n = LE_READ_2(ie); 1706173275Ssam ie += 2, ielen -= 2; 1707170531Ssam sep = " km:"; 1708170531Ssam for (; n > 0; n--) { 1709170531Ssam printf("%s%s", sep, rsn_keymgmt(ie)); 1710173275Ssam ie += 4, ielen -= 4; 1711170531Ssam sep = "+"; 1712170531Ssam } 1713170531Ssam 1714173275Ssam if (ielen > 2) /* optional capabilities */ 1715170531Ssam printf(", caps 0x%x", LE_READ_2(ie)); 1716170531Ssam /* XXXPMKID */ 1717170531Ssam printf(">"); 1718170531Ssam } 1719170531Ssam} 1720170531Ssam 1721170531Ssam/* 1722138593Ssam * Copy the ssid string contents into buf, truncating to fit. If the 1723138593Ssam * ssid is entirely printable then just copy intact. Otherwise convert 1724138593Ssam * to hexadecimal. If the result is truncated then replace the last 1725138593Ssam * three characters with "...". 1726138593Ssam */ 1727146873Sjhbstatic int 1728138593Ssamcopy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 1729138593Ssam{ 1730138593Ssam const u_int8_t *p; 1731138593Ssam size_t maxlen; 1732138593Ssam int i; 1733138593Ssam 1734138593Ssam if (essid_len > bufsize) 1735138593Ssam maxlen = bufsize; 1736138593Ssam else 1737138593Ssam maxlen = essid_len; 1738138593Ssam /* determine printable or not */ 1739138593Ssam for (i = 0, p = essid; i < maxlen; i++, p++) { 1740138593Ssam if (*p < ' ' || *p > 0x7e) 1741138593Ssam break; 1742138593Ssam } 1743138593Ssam if (i != maxlen) { /* not printable, print as hex */ 1744138593Ssam if (bufsize < 3) 1745138593Ssam return 0; 1746138593Ssam strlcpy(buf, "0x", bufsize); 1747138593Ssam bufsize -= 2; 1748138593Ssam p = essid; 1749138593Ssam for (i = 0; i < maxlen && bufsize >= 2; i++) { 1750147489Savatar sprintf(&buf[2+2*i], "%02x", p[i]); 1751138593Ssam bufsize -= 2; 1752138593Ssam } 1753147489Savatar if (i != essid_len) 1754147489Savatar memcpy(&buf[2+2*i-3], "...", 3); 1755138593Ssam } else { /* printable, truncate as needed */ 1756138593Ssam memcpy(buf, essid, maxlen); 1757147489Savatar if (maxlen != essid_len) 1758147489Savatar memcpy(&buf[maxlen-3], "...", 3); 1759138593Ssam } 1760138593Ssam return maxlen; 1761138593Ssam} 1762138593Ssam 1763173275Ssamstatic void 1764173275Ssamprintssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1765173275Ssam{ 1766173275Ssam char ssid[2*IEEE80211_NWID_LEN+1]; 1767173275Ssam 1768173275Ssam printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid); 1769173275Ssam} 1770173275Ssam 1771173275Ssamstatic void 1772173275Ssamprintrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1773173275Ssam{ 1774173275Ssam const char *sep; 1775173275Ssam int i; 1776173275Ssam 1777173275Ssam printf("%s", tag); 1778173275Ssam sep = "<"; 1779173275Ssam for (i = 2; i < ielen; i++) { 1780173275Ssam printf("%s%s%d", sep, 1781173275Ssam ie[i] & IEEE80211_RATE_BASIC ? "B" : "", 1782173275Ssam ie[i] & IEEE80211_RATE_VAL); 1783173275Ssam sep = ","; 1784173275Ssam } 1785173275Ssam printf(">"); 1786173275Ssam} 1787173275Ssam 1788173275Ssamstatic void 1789173275Ssamprintcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 1790173275Ssam{ 1791173275Ssam const struct ieee80211_country_ie *cie = 1792173275Ssam (const struct ieee80211_country_ie *) ie; 1793173275Ssam int i, nbands, schan, nchan; 1794173275Ssam 1795173275Ssam printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]); 1796173275Ssam nbands = (cie->len - 3) / sizeof(cie->band[0]); 1797173275Ssam for (i = 0; i < nbands; i++) { 1798173275Ssam schan = cie->band[i].schan; 1799173275Ssam nchan = cie->band[i].nchan; 1800173275Ssam if (nchan != 1) 1801173275Ssam printf(" %u-%u,%u", schan, schan + nchan-1, 1802173275Ssam cie->band[i].maxtxpwr); 1803173275Ssam else 1804173275Ssam printf(" %u,%u", schan, cie->band[i].maxtxpwr); 1805173275Ssam } 1806173275Ssam printf(">"); 1807173275Ssam} 1808173275Ssam 1809148686Sstefanf/* unaligned little endian access */ 1810138593Ssam#define LE_READ_4(p) \ 1811138593Ssam ((u_int32_t) \ 1812138593Ssam ((((const u_int8_t *)(p))[0] ) | \ 1813138593Ssam (((const u_int8_t *)(p))[1] << 8) | \ 1814138593Ssam (((const u_int8_t *)(p))[2] << 16) | \ 1815138593Ssam (((const u_int8_t *)(p))[3] << 24))) 1816138593Ssam 1817138593Ssamstatic int __inline 1818138593Ssamiswpaoui(const u_int8_t *frm) 1819138593Ssam{ 1820138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 1821138593Ssam} 1822138593Ssam 1823138593Ssamstatic int __inline 1824173275Ssamiswmeinfo(const u_int8_t *frm) 1825138593Ssam{ 1826173275Ssam return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 1827173275Ssam frm[6] == WME_INFO_OUI_SUBTYPE; 1828138593Ssam} 1829138593Ssam 1830138593Ssamstatic int __inline 1831173275Ssamiswmeparam(const u_int8_t *frm) 1832173275Ssam{ 1833173275Ssam return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 1834173275Ssam frm[6] == WME_PARAM_OUI_SUBTYPE; 1835173275Ssam} 1836173275Ssam 1837173275Ssamstatic int __inline 1838138593Ssamisatherosoui(const u_int8_t *frm) 1839138593Ssam{ 1840138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 1841138593Ssam} 1842138593Ssam 1843173275Ssamstatic const char * 1844173275Ssamiename(int elemid) 1845173275Ssam{ 1846173275Ssam switch (elemid) { 1847173275Ssam case IEEE80211_ELEMID_FHPARMS: return " FHPARMS"; 1848173275Ssam case IEEE80211_ELEMID_CFPARMS: return " CFPARMS"; 1849173275Ssam case IEEE80211_ELEMID_TIM: return " TIM"; 1850173275Ssam case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS"; 1851173275Ssam case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE"; 1852173275Ssam case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR"; 1853173275Ssam case IEEE80211_ELEMID_PWRCAP: return " PWRCAP"; 1854173275Ssam case IEEE80211_ELEMID_TPCREQ: return " TPCREQ"; 1855173275Ssam case IEEE80211_ELEMID_TPCREP: return " TPCREP"; 1856173275Ssam case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN"; 1857173275Ssam case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA"; 1858173275Ssam case IEEE80211_ELEMID_MEASREQ: return " MEASREQ"; 1859173275Ssam case IEEE80211_ELEMID_MEASREP: return " MEASREP"; 1860173275Ssam case IEEE80211_ELEMID_QUIET: return " QUIET"; 1861173275Ssam case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS"; 1862173275Ssam case IEEE80211_ELEMID_TPC: return " TPC"; 1863173275Ssam case IEEE80211_ELEMID_CCKM: return " CCKM"; 1864173275Ssam } 1865173275Ssam return " ???"; 1866173275Ssam} 1867173275Ssam 1868138593Ssamstatic void 1869138593Ssamprinties(const u_int8_t *vp, int ielen, int maxcols) 1870138593Ssam{ 1871138593Ssam while (ielen > 0) { 1872138593Ssam switch (vp[0]) { 1873173275Ssam case IEEE80211_ELEMID_SSID: 1874173275Ssam if (verbose) 1875173275Ssam printssid(" SSID", vp, 2+vp[1], maxcols); 1876173275Ssam break; 1877173275Ssam case IEEE80211_ELEMID_RATES: 1878173275Ssam case IEEE80211_ELEMID_XRATES: 1879173275Ssam if (verbose) 1880173275Ssam printrates(vp[0] == IEEE80211_ELEMID_RATES ? 1881173275Ssam " RATES" : " XRATES", vp, 2+vp[1], maxcols); 1882173275Ssam break; 1883173275Ssam case IEEE80211_ELEMID_DSPARMS: 1884173275Ssam if (verbose) 1885173275Ssam printf(" DSPARMS<%u>", vp[2]); 1886173275Ssam break; 1887173275Ssam case IEEE80211_ELEMID_COUNTRY: 1888173275Ssam if (verbose) 1889173275Ssam printcountry(" COUNTRY", vp, 2+vp[1], maxcols); 1890173275Ssam break; 1891173275Ssam case IEEE80211_ELEMID_ERP: 1892173275Ssam if (verbose) 1893173275Ssam printf(" ERP<0x%x>", vp[2]); 1894173275Ssam break; 1895138593Ssam case IEEE80211_ELEMID_VENDOR: 1896138593Ssam if (iswpaoui(vp)) 1897170531Ssam printwpaie(" WPA", vp, 2+vp[1], maxcols); 1898173275Ssam else if (iswmeinfo(vp)) 1899173275Ssam printwmeinfo(" WME", vp, 2+vp[1], maxcols); 1900173275Ssam else if (iswmeparam(vp)) 1901173275Ssam printwmeparam(" WME", vp, 2+vp[1], maxcols); 1902139492Ssam else if (isatherosoui(vp)) 1903170531Ssam printathie(" ATH", vp, 2+vp[1], maxcols); 1904173275Ssam else if (verbose) 1905138593Ssam printie(" VEN", vp, 2+vp[1], maxcols); 1906138593Ssam break; 1907138593Ssam case IEEE80211_ELEMID_RSN: 1908170531Ssam printrsnie(" RSN", vp, 2+vp[1], maxcols); 1909138593Ssam break; 1910173275Ssam case IEEE80211_ELEMID_HTCAP: 1911173275Ssam printhtcap(" HTCAP", vp, 2+vp[1], maxcols); 1912173275Ssam break; 1913173275Ssam case IEEE80211_ELEMID_HTINFO: 1914173275Ssam if (verbose) 1915173275Ssam printhtinfo(" HTINFO", vp, 2+vp[1], maxcols); 1916173275Ssam break; 1917138593Ssam default: 1918173275Ssam if (verbose) 1919173275Ssam printie(iename(vp[0]), vp, 2+vp[1], maxcols); 1920138593Ssam break; 1921138593Ssam } 1922138593Ssam ielen -= 2+vp[1]; 1923138593Ssam vp += 2+vp[1]; 1924138593Ssam } 1925138593Ssam} 1926138593Ssam 1927138593Ssamstatic void 1928138593Ssamlist_scan(int s) 1929138593Ssam{ 1930138593Ssam uint8_t buf[24*1024]; 1931153892Srwatson char ssid[IEEE80211_NWID_LEN+1]; 1932173275Ssam const uint8_t *cp; 1933154522Ssam int len, ssidmax; 1934138593Ssam 1935173275Ssam if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0) 1936138593Ssam errx(1, "unable to get scan results"); 1937138593Ssam if (len < sizeof(struct ieee80211req_scan_result)) 1938138593Ssam return; 1939138593Ssam 1940170531Ssam getchaninfo(s); 1941170531Ssam 1942154522Ssam ssidmax = verbose ? IEEE80211_NWID_LEN : 14; 1943170531Ssam printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n" 1944154522Ssam , ssidmax, ssidmax, "SSID" 1945138593Ssam , "BSSID" 1946138593Ssam , "CHAN" 1947138593Ssam , "RATE" 1948170531Ssam , " S:N" 1949138593Ssam , "INT" 1950138593Ssam , "CAPS" 1951138593Ssam ); 1952138593Ssam cp = buf; 1953138593Ssam do { 1954170531Ssam const struct ieee80211req_scan_result *sr; 1955170531Ssam const uint8_t *vp; 1956138593Ssam 1957170531Ssam sr = (const struct ieee80211req_scan_result *) cp; 1958173275Ssam vp = cp + sr->isr_ie_off; 1959170531Ssam printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s" 1960154522Ssam , ssidmax 1961155461Ssam , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len) 1962154522Ssam , ssid 1963138593Ssam , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 1964165570Ssam , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) 1965138593Ssam , getmaxrate(sr->isr_rates, sr->isr_nrates) 1966170531Ssam , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise 1967138593Ssam , sr->isr_intval 1968138593Ssam , getcaps(sr->isr_capinfo) 1969138593Ssam ); 1970170531Ssam printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24); 1971138593Ssam printf("\n"); 1972138593Ssam cp += sr->isr_len, len -= sr->isr_len; 1973138593Ssam } while (len >= sizeof(struct ieee80211req_scan_result)); 1974138593Ssam} 1975138593Ssam 1976138593Ssam#include <net80211/ieee80211_freebsd.h> 1977138593Ssam 1978138593Ssamstatic void 1979138593Ssamscan_and_wait(int s) 1980138593Ssam{ 1981138593Ssam struct ieee80211req ireq; 1982138593Ssam int sroute; 1983138593Ssam 1984138593Ssam sroute = socket(PF_ROUTE, SOCK_RAW, 0); 1985138593Ssam if (sroute < 0) { 1986138593Ssam perror("socket(PF_ROUTE,SOCK_RAW)"); 1987138593Ssam return; 1988138593Ssam } 1989138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 1990138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 1991138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_REQ; 1992138593Ssam /* NB: only root can trigger a scan so ignore errors */ 1993138593Ssam if (ioctl(s, SIOCS80211, &ireq) >= 0) { 1994138593Ssam char buf[2048]; 1995138593Ssam struct if_announcemsghdr *ifan; 1996138593Ssam struct rt_msghdr *rtm; 1997138593Ssam 1998138593Ssam do { 1999138593Ssam if (read(sroute, buf, sizeof(buf)) < 0) { 2000138593Ssam perror("read(PF_ROUTE)"); 2001138593Ssam break; 2002138593Ssam } 2003138593Ssam rtm = (struct rt_msghdr *) buf; 2004138593Ssam if (rtm->rtm_version != RTM_VERSION) 2005138593Ssam break; 2006138593Ssam ifan = (struct if_announcemsghdr *) rtm; 2007138593Ssam } while (rtm->rtm_type != RTM_IEEE80211 || 2008138593Ssam ifan->ifan_what != RTM_IEEE80211_SCAN); 2009138593Ssam } 2010138593Ssam close(sroute); 2011138593Ssam} 2012138593Ssam 2013138593Ssamstatic 2014138593SsamDECL_CMD_FUNC(set80211scan, val, d) 2015138593Ssam{ 2016138593Ssam scan_and_wait(s); 2017138593Ssam list_scan(s); 2018138593Ssam} 2019138593Ssam 2020161147Ssamstatic enum ieee80211_opmode get80211opmode(int s); 2021161147Ssam 2022173275Ssamstatic int 2023173275Ssamgettxseq(const struct ieee80211req_sta_info *si) 2024173275Ssam{ 2025173275Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 2026173275Ssam 2027173275Ssam int i, txseq; 2028173275Ssam 2029173275Ssam if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 2030173275Ssam return si->isi_txseqs[0]; 2031173275Ssam /* XXX not right but usually what folks want */ 2032173275Ssam txseq = 0; 2033173275Ssam for (i = 0; i < IEEE80211_TID_SIZE; i++) 2034173275Ssam if (si->isi_txseqs[i] > txseq) 2035173275Ssam txseq = si->isi_txseqs[i]; 2036173275Ssam return txseq; 2037173275Ssam#undef IEEE80211_NODE_QOS 2038173275Ssam} 2039173275Ssam 2040173275Ssamstatic int 2041173275Ssamgetrxseq(const struct ieee80211req_sta_info *si) 2042173275Ssam{ 2043173275Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 2044173275Ssam 2045173275Ssam int i, rxseq; 2046173275Ssam 2047173275Ssam if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 2048173275Ssam return si->isi_rxseqs[0]; 2049173275Ssam /* XXX not right but usually what folks want */ 2050173275Ssam rxseq = 0; 2051173275Ssam for (i = 0; i < IEEE80211_TID_SIZE; i++) 2052173275Ssam if (si->isi_rxseqs[i] > rxseq) 2053173275Ssam rxseq = si->isi_rxseqs[i]; 2054173275Ssam return rxseq; 2055173275Ssam#undef IEEE80211_NODE_QOS 2056173275Ssam} 2057173275Ssam 2058173275Ssamstatic int 2059173275Ssamgettxrate(int txrate, int chanflags) 2060173275Ssam{ 2061173275Ssam if (txrate & 0x80) { 2062173275Ssam txrate = htrates[txrate & 0xf]; 2063173275Ssam /* NB: could bump this more based on short gi */ 2064173275Ssam return chanflags & IEEE80211_CHAN_HT40 ? txrate : txrate / 2; 2065173275Ssam } else 2066173275Ssam return (txrate & IEEE80211_RATE_VAL) / 2; 2067173275Ssam} 2068173275Ssam 2069138593Ssamstatic void 2070138593Ssamlist_stations(int s) 2071138593Ssam{ 2072161147Ssam union { 2073161147Ssam struct ieee80211req_sta_req req; 2074161147Ssam uint8_t buf[24*1024]; 2075161147Ssam } u; 2076161147Ssam enum ieee80211_opmode opmode = get80211opmode(s); 2077170531Ssam const uint8_t *cp; 2078138593Ssam int len; 2079138593Ssam 2080161147Ssam /* broadcast address =>'s get all stations */ 2081161147Ssam (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); 2082161147Ssam if (opmode == IEEE80211_M_STA) { 2083161147Ssam /* 2084161147Ssam * Get information about the associated AP. 2085161147Ssam */ 2086173275Ssam (void) get80211(s, IEEE80211_IOC_BSSID, 2087173275Ssam u.req.is_u.macaddr, IEEE80211_ADDR_LEN); 2088161147Ssam } 2089173275Ssam if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0) 2090138593Ssam errx(1, "unable to get station information"); 2091138593Ssam if (len < sizeof(struct ieee80211req_sta_info)) 2092138593Ssam return; 2093138593Ssam 2094170531Ssam getchaninfo(s); 2095170531Ssam 2096159885Ssam printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n" 2097138593Ssam , "ADDR" 2098138593Ssam , "AID" 2099138593Ssam , "CHAN" 2100138593Ssam , "RATE" 2101138593Ssam , "RSSI" 2102138593Ssam , "IDLE" 2103138593Ssam , "TXSEQ" 2104138593Ssam , "RXSEQ" 2105138593Ssam , "CAPS" 2106159885Ssam , "FLAG" 2107138593Ssam ); 2108170531Ssam cp = (const uint8_t *) u.req.info; 2109138593Ssam do { 2110170531Ssam const struct ieee80211req_sta_info *si; 2111138593Ssam 2112170531Ssam si = (const struct ieee80211req_sta_info *) cp; 2113161147Ssam if (si->isi_len < sizeof(*si)) 2114161147Ssam break; 2115170531Ssam printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-4.4s" 2116138593Ssam , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 2117138593Ssam , IEEE80211_AID(si->isi_associd) 2118166015Ssam , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags) 2119173275Ssam , gettxrate(si->isi_txrate, si->isi_flags) 2120170531Ssam , si->isi_rssi/2. 2121138593Ssam , si->isi_inact 2122173275Ssam , gettxseq(si) 2123173275Ssam , getrxseq(si) 2124138593Ssam , getcaps(si->isi_capinfo) 2125159885Ssam , getflags(si->isi_state) 2126138593Ssam ); 2127170531Ssam printies(cp + si->isi_ie_off, si->isi_ie_len, 24); 2128138593Ssam printf("\n"); 2129138593Ssam cp += si->isi_len, len -= si->isi_len; 2130138593Ssam } while (len >= sizeof(struct ieee80211req_sta_info)); 2131138593Ssam} 2132138593Ssam 2133170531Ssamstatic const char * 2134170531Ssamget_chaninfo(const struct ieee80211_channel *c, int precise, 2135170531Ssam char buf[], size_t bsize) 2136138593Ssam{ 2137138593Ssam buf[0] = '\0'; 2138138593Ssam if (IEEE80211_IS_CHAN_FHSS(c)) 2139170531Ssam strlcat(buf, " FHSS", bsize); 2140165570Ssam if (IEEE80211_IS_CHAN_A(c)) { 2141165570Ssam if (IEEE80211_IS_CHAN_HALF(c)) 2142170531Ssam strlcat(buf, " 11a/10Mhz", bsize); 2143165570Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 2144170531Ssam strlcat(buf, " 11a/5Mhz", bsize); 2145165570Ssam else 2146170531Ssam strlcat(buf, " 11a", bsize); 2147165570Ssam } 2148166015Ssam if (IEEE80211_IS_CHAN_ANYG(c)) { 2149166015Ssam if (IEEE80211_IS_CHAN_HALF(c)) 2150170531Ssam strlcat(buf, " 11g/10Mhz", bsize); 2151166015Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 2152170531Ssam strlcat(buf, " 11g/5Mhz", bsize); 2153166015Ssam else 2154170531Ssam strlcat(buf, " 11g", bsize); 2155166015Ssam } else if (IEEE80211_IS_CHAN_B(c)) 2156170531Ssam strlcat(buf, " 11b", bsize); 2157170531Ssam if (IEEE80211_IS_CHAN_TURBO(c)) 2158170531Ssam strlcat(buf, " Turbo", bsize); 2159170531Ssam if (precise) { 2160170531Ssam if (IEEE80211_IS_CHAN_HT20(c)) 2161170531Ssam strlcat(buf, " ht/20", bsize); 2162170531Ssam else if (IEEE80211_IS_CHAN_HT40D(c)) 2163170531Ssam strlcat(buf, " ht/40-", bsize); 2164170531Ssam else if (IEEE80211_IS_CHAN_HT40U(c)) 2165170531Ssam strlcat(buf, " ht/40+", bsize); 2166170531Ssam } else { 2167170531Ssam if (IEEE80211_IS_CHAN_HT(c)) 2168170531Ssam strlcat(buf, " ht", bsize); 2169170531Ssam } 2170170531Ssam return buf; 2171170531Ssam} 2172170531Ssam 2173170531Ssamstatic void 2174173275Ssamprint_chaninfo(const struct ieee80211_channel *c, int verb) 2175170531Ssam{ 2176170531Ssam char buf[14]; 2177170531Ssam 2178138593Ssam printf("Channel %3u : %u%c Mhz%-14.14s", 2179165570Ssam ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, 2180170531Ssam IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', 2181173275Ssam get_chaninfo(c, verb, buf, sizeof(buf))); 2182138593Ssam} 2183138593Ssam 2184138593Ssamstatic void 2185173275Ssamprint_channels(int s, const struct ieee80211req_chaninfo *chans, 2186173275Ssam int allchans, int verb) 2187138593Ssam{ 2188138593Ssam struct ieee80211req_chaninfo achans; 2189170531Ssam uint8_t reported[IEEE80211_CHAN_BYTES]; 2190138593Ssam const struct ieee80211_channel *c; 2191170531Ssam int i, half; 2192138593Ssam 2193170531Ssam memset(&achans, 0, sizeof(achans)); 2194170531Ssam memset(reported, 0, sizeof(reported)); 2195138593Ssam if (!allchans) { 2196138593Ssam struct ieee80211req_chanlist active; 2197138593Ssam 2198173275Ssam if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0) 2199138593Ssam errx(1, "unable to get active channel list"); 2200138593Ssam memset(&achans, 0, sizeof(achans)); 2201173275Ssam for (i = 0; i < chans->ic_nchans; i++) { 2202173275Ssam c = &chans->ic_chans[i]; 2203170531Ssam if (!isset(active.ic_channels, c->ic_ieee)) 2204170531Ssam continue; 2205170531Ssam /* 2206170531Ssam * Suppress compatible duplicates unless 2207170531Ssam * verbose. The kernel gives us it's 2208170531Ssam * complete channel list which has separate 2209170531Ssam * entries for 11g/11b and 11a/turbo. 2210170531Ssam */ 2211173275Ssam if (isset(reported, c->ic_ieee) && !verb) { 2212170531Ssam /* XXX we assume duplicates are adjacent */ 2213170531Ssam achans.ic_chans[achans.ic_nchans-1] = *c; 2214170531Ssam } else { 2215138593Ssam achans.ic_chans[achans.ic_nchans++] = *c; 2216170531Ssam setbit(reported, c->ic_ieee); 2217170531Ssam } 2218138593Ssam } 2219170531Ssam } else { 2220173275Ssam for (i = 0; i < chans->ic_nchans; i++) { 2221173275Ssam c = &chans->ic_chans[i]; 2222170531Ssam /* suppress duplicates as above */ 2223173275Ssam if (isset(reported, c->ic_ieee) && !verb) { 2224170531Ssam /* XXX we assume duplicates are adjacent */ 2225170531Ssam achans.ic_chans[achans.ic_nchans-1] = *c; 2226170531Ssam } else { 2227170531Ssam achans.ic_chans[achans.ic_nchans++] = *c; 2228170531Ssam setbit(reported, c->ic_ieee); 2229170531Ssam } 2230170531Ssam } 2231170531Ssam } 2232138593Ssam half = achans.ic_nchans / 2; 2233138593Ssam if (achans.ic_nchans % 2) 2234138593Ssam half++; 2235170531Ssam 2236138593Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 2237173275Ssam print_chaninfo(&achans.ic_chans[i], verb); 2238173275Ssam print_chaninfo(&achans.ic_chans[half+i], verb); 2239138593Ssam printf("\n"); 2240138593Ssam } 2241138593Ssam if (achans.ic_nchans % 2) { 2242173275Ssam print_chaninfo(&achans.ic_chans[i], verb); 2243138593Ssam printf("\n"); 2244138593Ssam } 2245138593Ssam} 2246138593Ssam 2247138593Ssamstatic void 2248173275Ssamlist_channels(int s, int allchans) 2249173275Ssam{ 2250173275Ssam getchaninfo(s); 2251173275Ssam print_channels(s, &chaninfo, allchans, verbose); 2252173275Ssam} 2253173275Ssam 2254173275Ssamstatic void 2255170531Ssamprint_txpow(const struct ieee80211_channel *c) 2256170531Ssam{ 2257170531Ssam printf("Channel %3u : %u Mhz %3.1f reg %2d ", 2258170531Ssam c->ic_ieee, c->ic_freq, 2259170531Ssam c->ic_maxpower/2., c->ic_maxregpower); 2260170531Ssam} 2261170531Ssam 2262170531Ssamstatic void 2263170531Ssamprint_txpow_verbose(const struct ieee80211_channel *c) 2264170531Ssam{ 2265173275Ssam print_chaninfo(c, 1); 2266170531Ssam printf("min %4.1f dBm max %3.1f dBm reg %2d dBm", 2267170531Ssam c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower); 2268170531Ssam /* indicate where regulatory cap limits power use */ 2269170531Ssam if (c->ic_maxpower > 2*c->ic_maxregpower) 2270170531Ssam printf(" <"); 2271170531Ssam} 2272170531Ssam 2273170531Ssamstatic void 2274170531Ssamlist_txpow(int s) 2275170531Ssam{ 2276170531Ssam struct ieee80211req_chaninfo achans; 2277170531Ssam uint8_t reported[IEEE80211_CHAN_BYTES]; 2278170531Ssam struct ieee80211_channel *c, *prev; 2279170531Ssam int i, half; 2280170531Ssam 2281170531Ssam getchaninfo(s); 2282170531Ssam memset(&achans, 0, sizeof(achans)); 2283170531Ssam memset(reported, 0, sizeof(reported)); 2284170531Ssam for (i = 0; i < chaninfo.ic_nchans; i++) { 2285170531Ssam c = &chaninfo.ic_chans[i]; 2286170531Ssam /* suppress duplicates as above */ 2287170531Ssam if (isset(reported, c->ic_ieee) && !verbose) { 2288170531Ssam /* XXX we assume duplicates are adjacent */ 2289170531Ssam prev = &achans.ic_chans[achans.ic_nchans-1]; 2290170531Ssam /* display highest power on channel */ 2291170531Ssam if (c->ic_maxpower > prev->ic_maxpower) 2292170531Ssam *prev = *c; 2293170531Ssam } else { 2294170531Ssam achans.ic_chans[achans.ic_nchans++] = *c; 2295170531Ssam setbit(reported, c->ic_ieee); 2296170531Ssam } 2297170531Ssam } 2298170531Ssam if (!verbose) { 2299170531Ssam half = achans.ic_nchans / 2; 2300170531Ssam if (achans.ic_nchans % 2) 2301170531Ssam half++; 2302170531Ssam 2303170531Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 2304170531Ssam print_txpow(&achans.ic_chans[i]); 2305170531Ssam print_txpow(&achans.ic_chans[half+i]); 2306170531Ssam printf("\n"); 2307170531Ssam } 2308170531Ssam if (achans.ic_nchans % 2) { 2309170531Ssam print_txpow(&achans.ic_chans[i]); 2310170531Ssam printf("\n"); 2311170531Ssam } 2312170531Ssam } else { 2313170531Ssam for (i = 0; i < achans.ic_nchans; i++) { 2314170531Ssam print_txpow_verbose(&achans.ic_chans[i]); 2315170531Ssam printf("\n"); 2316170531Ssam } 2317170531Ssam } 2318170531Ssam} 2319170531Ssam 2320170531Ssamstatic void 2321138593Ssamlist_keys(int s) 2322138593Ssam{ 2323138593Ssam} 2324138593Ssam 2325138593Ssam#define IEEE80211_C_BITS \ 2326170531Ssam"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\7FF\10TURBOP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \ 2327138593Ssam"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \ 2328170531Ssam"\31WPA2\32BURST\33WME\34WDS\36BGSCAN\37TXFRAG" 2329138593Ssam 2330138593Ssamstatic void 2331138593Ssamlist_capabilities(int s) 2332138593Ssam{ 2333138593Ssam struct ieee80211req ireq; 2334138593Ssam u_int32_t caps; 2335138593Ssam 2336138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 2337138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 2338138593Ssam ireq.i_type = IEEE80211_IOC_DRIVER_CAPS; 2339138593Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 2340138593Ssam errx(1, "unable to get driver capabilities"); 2341138593Ssam caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len); 2342138593Ssam printb(name, caps, IEEE80211_C_BITS); 2343138593Ssam putchar('\n'); 2344138593Ssam} 2345138593Ssam 2346173275Ssamstatic int 2347173275Ssamget80211wme(int s, int param, int ac, int *val) 2348173275Ssam{ 2349173275Ssam struct ieee80211req ireq; 2350173275Ssam 2351173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 2352173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 2353173275Ssam ireq.i_type = param; 2354173275Ssam ireq.i_len = ac; 2355173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) { 2356173275Ssam warn("cannot get WME parameter %d, ac %d%s", 2357173275Ssam param, ac & IEEE80211_WMEPARAM_VAL, 2358173275Ssam ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : ""); 2359173275Ssam return -1; 2360173275Ssam } 2361173275Ssam *val = ireq.i_val; 2362173275Ssam return 0; 2363173275Ssam} 2364173275Ssam 2365138593Ssamstatic void 2366138593Ssamlist_wme(int s) 2367138593Ssam{ 2368138593Ssam static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 2369173275Ssam int ac, val; 2370138593Ssam 2371138593Ssam for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 2372138593Ssamagain: 2373173275Ssam if (ac & IEEE80211_WMEPARAM_BSS) 2374138593Ssam printf("\t%s", " "); 2375138593Ssam else 2376138593Ssam printf("\t%s", acnames[ac]); 2377138593Ssam 2378138593Ssam /* show WME BSS parameters */ 2379173275Ssam if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1) 2380173275Ssam printf(" cwmin %2u", val); 2381173275Ssam if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1) 2382173275Ssam printf(" cwmax %2u", val); 2383173275Ssam if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1) 2384173275Ssam printf(" aifs %2u", val); 2385173275Ssam if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1) 2386173275Ssam printf(" txopLimit %3u", val); 2387173275Ssam if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) { 2388173275Ssam if (val) 2389138593Ssam printf(" acm"); 2390138593Ssam else if (verbose) 2391138593Ssam printf(" -acm"); 2392138593Ssam } 2393138593Ssam /* !BSS only */ 2394173275Ssam if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 2395173275Ssam if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) { 2396173275Ssam if (!val) 2397138593Ssam printf(" -ack"); 2398138593Ssam else if (verbose) 2399138593Ssam printf(" ack"); 2400138593Ssam } 2401138593Ssam } 2402138593Ssam printf("\n"); 2403173275Ssam if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 2404173275Ssam ac |= IEEE80211_WMEPARAM_BSS; 2405138593Ssam goto again; 2406138593Ssam } else 2407173275Ssam ac &= ~IEEE80211_WMEPARAM_BSS; 2408138593Ssam } 2409138593Ssam} 2410138593Ssam 2411149029Ssamstatic void 2412173275Ssamprintpolicy(int policy) 2413173275Ssam{ 2414173275Ssam switch (policy) { 2415173275Ssam case IEEE80211_MACCMD_POLICY_OPEN: 2416173275Ssam printf("policy: open\n"); 2417173275Ssam break; 2418173275Ssam case IEEE80211_MACCMD_POLICY_ALLOW: 2419173275Ssam printf("policy: allow\n"); 2420173275Ssam break; 2421173275Ssam case IEEE80211_MACCMD_POLICY_DENY: 2422173275Ssam printf("policy: deny\n"); 2423173275Ssam break; 2424173275Ssam default: 2425173275Ssam printf("policy: unknown (%u)\n", policy); 2426173275Ssam break; 2427173275Ssam } 2428173275Ssam} 2429173275Ssam 2430173275Ssamstatic void 2431149029Ssamlist_mac(int s) 2432149029Ssam{ 2433149029Ssam struct ieee80211req ireq; 2434149029Ssam struct ieee80211req_maclist *acllist; 2435173275Ssam int i, nacls, policy, len; 2436173275Ssam uint8_t *data; 2437149029Ssam char c; 2438149029Ssam 2439149029Ssam (void) memset(&ireq, 0, sizeof(ireq)); 2440149029Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 2441149029Ssam ireq.i_type = IEEE80211_IOC_MACCMD; 2442149029Ssam ireq.i_val = IEEE80211_MACCMD_POLICY; 2443149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) { 2444149029Ssam if (errno == EINVAL) { 2445149029Ssam printf("No acl policy loaded\n"); 2446149029Ssam return; 2447149029Ssam } 2448149029Ssam err(1, "unable to get mac policy"); 2449149029Ssam } 2450149029Ssam policy = ireq.i_val; 2451149029Ssam if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 2452149029Ssam c = '*'; 2453149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 2454149029Ssam c = '+'; 2455149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 2456149029Ssam c = '-'; 2457149029Ssam } else { 2458149029Ssam printf("policy: unknown (%u)\n", policy); 2459149029Ssam c = '?'; 2460149029Ssam } 2461173275Ssam if (verbose || c == '?') 2462173275Ssam printpolicy(policy); 2463173275Ssam 2464173275Ssam if (get80211len(s, IEEE80211_MACCMD_LIST, NULL, 0, &len) < 0) 2465173275Ssam err(1, "unable to get mac acl list size"); 2466173275Ssam if (len == 0) { /* NB: no acls */ 2467173275Ssam if (!(verbose || c == '?')) 2468173275Ssam printpolicy(policy); 2469173275Ssam return; 2470173275Ssam } 2471173275Ssam 2472173275Ssam data = malloc(len); 2473173275Ssam if (data == NULL) 2474173275Ssam err(1, "out of memory for acl list"); 2475173275Ssam 2476173275Ssam if (get80211(s, IEEE80211_MACCMD_LIST, data, len) < 0) 2477173275Ssam err(1, "unable to get mac acl list"); 2478173275Ssam nacls = len / sizeof(*acllist); 2479173275Ssam acllist = (struct ieee80211req_maclist *) data; 2480149029Ssam for (i = 0; i < nacls; i++) 2481149029Ssam printf("%c%s\n", c, ether_ntoa( 2482149029Ssam (const struct ether_addr *) acllist[i].ml_macaddr)); 2483173275Ssam free(data); 2484149029Ssam} 2485149029Ssam 2486138593Ssamstatic 2487138593SsamDECL_CMD_FUNC(set80211list, arg, d) 2488138593Ssam{ 2489138593Ssam#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 2490138593Ssam 2491173275Ssam LINE_INIT('\t'); 2492173275Ssam 2493138593Ssam if (iseq(arg, "sta")) 2494138593Ssam list_stations(s); 2495138593Ssam else if (iseq(arg, "scan") || iseq(arg, "ap")) 2496138593Ssam list_scan(s); 2497138593Ssam else if (iseq(arg, "chan") || iseq(arg, "freq")) 2498138593Ssam list_channels(s, 1); 2499138593Ssam else if (iseq(arg, "active")) 2500138593Ssam list_channels(s, 0); 2501138593Ssam else if (iseq(arg, "keys")) 2502138593Ssam list_keys(s); 2503138593Ssam else if (iseq(arg, "caps")) 2504138593Ssam list_capabilities(s); 2505138593Ssam else if (iseq(arg, "wme")) 2506138593Ssam list_wme(s); 2507149029Ssam else if (iseq(arg, "mac")) 2508149029Ssam list_mac(s); 2509170531Ssam else if (iseq(arg, "txpow")) 2510170531Ssam list_txpow(s); 2511138593Ssam else 2512138593Ssam errx(1, "Don't know how to list %s for %s", arg, name); 2513138593Ssam#undef iseq 2514138593Ssam} 2515138593Ssam 2516138593Ssamstatic enum ieee80211_opmode 2517138593Ssamget80211opmode(int s) 2518138593Ssam{ 2519138593Ssam struct ifmediareq ifmr; 2520138593Ssam 2521138593Ssam (void) memset(&ifmr, 0, sizeof(ifmr)); 2522138593Ssam (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 2523138593Ssam 2524138593Ssam if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 2525138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 2526138593Ssam return IEEE80211_M_IBSS; /* XXX ahdemo */ 2527138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 2528138593Ssam return IEEE80211_M_HOSTAP; 2529138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 2530138593Ssam return IEEE80211_M_MONITOR; 2531138593Ssam } 2532138593Ssam return IEEE80211_M_STA; 2533138593Ssam} 2534138593Ssam 2535138593Ssam#if 0 2536138593Ssamstatic void 2537138593Ssamprintcipher(int s, struct ieee80211req *ireq, int keylenop) 2538138593Ssam{ 2539138593Ssam switch (ireq->i_val) { 2540138593Ssam case IEEE80211_CIPHER_WEP: 2541138593Ssam ireq->i_type = keylenop; 2542138593Ssam if (ioctl(s, SIOCG80211, ireq) != -1) 2543138593Ssam printf("WEP-%s", 2544138593Ssam ireq->i_len <= 5 ? "40" : 2545138593Ssam ireq->i_len <= 13 ? "104" : "128"); 2546138593Ssam else 2547138593Ssam printf("WEP"); 2548138593Ssam break; 2549138593Ssam case IEEE80211_CIPHER_TKIP: 2550138593Ssam printf("TKIP"); 2551138593Ssam break; 2552138593Ssam case IEEE80211_CIPHER_AES_OCB: 2553138593Ssam printf("AES-OCB"); 2554138593Ssam break; 2555138593Ssam case IEEE80211_CIPHER_AES_CCM: 2556138593Ssam printf("AES-CCM"); 2557138593Ssam break; 2558138593Ssam case IEEE80211_CIPHER_CKIP: 2559138593Ssam printf("CKIP"); 2560138593Ssam break; 2561138593Ssam case IEEE80211_CIPHER_NONE: 2562138593Ssam printf("NONE"); 2563138593Ssam break; 2564138593Ssam default: 2565138593Ssam printf("UNKNOWN (0x%x)", ireq->i_val); 2566138593Ssam break; 2567138593Ssam } 2568138593Ssam} 2569138593Ssam#endif 2570138593Ssam 2571155931Ssamstatic void 2572138593Ssamprintkey(const struct ieee80211req_key *ik) 2573138593Ssam{ 2574138593Ssam static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 2575138593Ssam int keylen = ik->ik_keylen; 2576138593Ssam int printcontents; 2577138593Ssam 2578148001Srwatson printcontents = printkeys && 2579138593Ssam (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 2580138593Ssam if (printcontents) 2581138593Ssam LINE_BREAK(); 2582138593Ssam switch (ik->ik_type) { 2583138593Ssam case IEEE80211_CIPHER_WEP: 2584138593Ssam /* compatibility */ 2585155931Ssam LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1, 2586138593Ssam keylen <= 5 ? "40-bit" : 2587138593Ssam keylen <= 13 ? "104-bit" : "128-bit"); 2588138593Ssam break; 2589138593Ssam case IEEE80211_CIPHER_TKIP: 2590138593Ssam if (keylen > 128/8) 2591138593Ssam keylen -= 128/8; /* ignore MIC for now */ 2592155931Ssam LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 2593138593Ssam break; 2594138593Ssam case IEEE80211_CIPHER_AES_OCB: 2595155931Ssam LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen); 2596138593Ssam break; 2597138593Ssam case IEEE80211_CIPHER_AES_CCM: 2598155931Ssam LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen); 2599138593Ssam break; 2600138593Ssam case IEEE80211_CIPHER_CKIP: 2601155931Ssam LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 2602138593Ssam break; 2603138593Ssam case IEEE80211_CIPHER_NONE: 2604155931Ssam LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen); 2605138593Ssam break; 2606138593Ssam default: 2607155931Ssam LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit", 2608138593Ssam ik->ik_type, ik->ik_keyix+1, 8*keylen); 2609138593Ssam break; 2610138593Ssam } 2611138593Ssam if (printcontents) { 2612138593Ssam int i; 2613138593Ssam 2614138593Ssam printf(" <"); 2615138593Ssam for (i = 0; i < keylen; i++) 2616138593Ssam printf("%02x", ik->ik_keydata[i]); 2617138593Ssam printf(">"); 2618138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 2619138593Ssam (ik->ik_keyrsc != 0 || verbose)) 2620146873Sjhb printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 2621138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 2622138593Ssam (ik->ik_keytsc != 0 || verbose)) 2623146873Sjhb printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 2624138593Ssam if (ik->ik_flags != 0 && verbose) { 2625138593Ssam const char *sep = " "; 2626138593Ssam 2627138593Ssam if (ik->ik_flags & IEEE80211_KEY_XMIT) 2628138593Ssam printf("%stx", sep), sep = "+"; 2629138593Ssam if (ik->ik_flags & IEEE80211_KEY_RECV) 2630138593Ssam printf("%srx", sep), sep = "+"; 2631138593Ssam if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 2632138593Ssam printf("%sdef", sep), sep = "+"; 2633138593Ssam } 2634138593Ssam LINE_BREAK(); 2635138593Ssam } 2636138593Ssam} 2637138593Ssam 2638138593Ssamstatic void 2639173275Ssamprintrate(const char *tag, int v, int defrate, int defmcs) 2640138593Ssam{ 2641173275Ssam if (v == 11) 2642173275Ssam LINE_CHECK("%s 5.5", tag); 2643173275Ssam else if (v & 0x80) { 2644173275Ssam if (v != defmcs) 2645173275Ssam LINE_CHECK("%s %d", tag, v &~ 0x80); 2646173275Ssam } else { 2647173275Ssam if (v != defrate) 2648173275Ssam LINE_CHECK("%s %d", tag, v/2); 2649173275Ssam } 2650173275Ssam} 2651173275Ssam 2652173275Ssamstatic int 2653173275Ssamgetssid(int s, int ix, void *data, size_t len, int *plen) 2654173275Ssam{ 2655138593Ssam struct ieee80211req ireq; 2656138593Ssam 2657138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 2658138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 2659173275Ssam ireq.i_type = IEEE80211_IOC_SSID; 2660173275Ssam ireq.i_val = ix; 2661173275Ssam ireq.i_data = data; 2662173275Ssam ireq.i_len = len; 2663173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 2664173275Ssam return -1; 2665173275Ssam *plen = ireq.i_len; 2666173275Ssam return 0; 2667173275Ssam} 266877218Sphk 2669173275Ssamstatic void 2670173275Ssamprintrssi(const char *tag, int rssi) 2671173275Ssam{ 2672173275Ssam if (rssi & 1) 2673173275Ssam LINE_CHECK("%s %u.5", tag, rssi/2); 2674173275Ssam else 2675173275Ssam LINE_CHECK("%s %u", tag, rssi/2); 2676173275Ssam} 2677138593Ssam 2678173275Ssamstatic void 2679173275Ssamieee80211_status(int s) 2680173275Ssam{ 2681173275Ssam static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 2682173275Ssam enum ieee80211_opmode opmode = get80211opmode(s); 2683173275Ssam int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode; 2684173275Ssam uint8_t data[32]; 2685173275Ssam const struct ieee80211_channel *c; 2686173275Ssam 2687173275Ssam if (getssid(s, -1, data, sizeof(data), &len) < 0) { 2688148686Sstefanf /* If we can't get the SSID, this isn't an 802.11 device. */ 268977218Sphk return; 269077218Sphk } 2691173275Ssam 2692173275Ssam /* 2693173275Ssam * Invalidate cached state so printing status for multiple 2694173275Ssam * if's doesn't reuse the first interfaces' cached state. 2695173275Ssam */ 2696173275Ssam gotcurchan = 0; 2697173275Ssam gothtconf = 0; 2698173275Ssam 2699173275Ssam if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0) 2700173275Ssam num = 0; 2701138593Ssam printf("\tssid "); 2702138593Ssam if (num > 1) { 2703173275Ssam for (i = 0; i < num; i++) { 2704173275Ssam if (getssid(s, i, data, sizeof(data), &len) >= 0 && len > 0) { 2705173275Ssam printf(" %d:", i + 1); 2706173275Ssam print_string(data, len); 2707138593Ssam } 270888748Sambrisko } 2709138593Ssam } else 2710173275Ssam print_string(data, len); 271177218Sphk 2712173275Ssam c = getcurchan(s); 2713170531Ssam if (c->ic_freq != IEEE80211_CHAN_ANY) { 2714170531Ssam char buf[14]; 2715170531Ssam printf(" channel %d (%u Mhz%s)", c->ic_ieee, c->ic_freq, 2716170531Ssam get_chaninfo(c, 1, buf, sizeof(buf))); 2717138593Ssam } else if (verbose) 2718138593Ssam printf(" channel UNDEF"); 2719138593Ssam 2720173275Ssam if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 && 2721173275Ssam (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) 2722173275Ssam printf(" bssid %s", ether_ntoa((struct ether_addr *)data)); 2723138593Ssam 2724173275Ssam if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) { 2725138593Ssam printf("\n\tstationname "); 2726173275Ssam print_string(data, len); 272777218Sphk } 272877218Sphk 2729138593Ssam spacer = ' '; /* force first break */ 2730138593Ssam LINE_BREAK(); 273177218Sphk 2732173275Ssam wpa = 0; 2733173275Ssam if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) { 2734173275Ssam switch (val) { 2735173275Ssam case IEEE80211_AUTH_NONE: 2736173275Ssam LINE_CHECK("authmode NONE"); 2737173275Ssam break; 2738173275Ssam case IEEE80211_AUTH_OPEN: 2739173275Ssam LINE_CHECK("authmode OPEN"); 2740173275Ssam break; 2741173275Ssam case IEEE80211_AUTH_SHARED: 2742173275Ssam LINE_CHECK("authmode SHARED"); 2743173275Ssam break; 2744173275Ssam case IEEE80211_AUTH_8021X: 2745173275Ssam LINE_CHECK("authmode 802.1x"); 2746173275Ssam break; 2747173275Ssam case IEEE80211_AUTH_WPA: 2748173275Ssam if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0) 2749173275Ssam wpa = 1; /* default to WPA1 */ 2750173275Ssam switch (wpa) { 2751173275Ssam case 2: 2752173275Ssam LINE_CHECK("authmode WPA2/802.11i"); 275377218Sphk break; 2754173275Ssam case 3: 2755173275Ssam LINE_CHECK("authmode WPA1+WPA2/802.11i"); 275677218Sphk break; 2757127649Ssam default: 2758173275Ssam LINE_CHECK("authmode WPA"); 2759127649Ssam break; 2760173275Ssam } 2761173275Ssam break; 2762173275Ssam case IEEE80211_AUTH_AUTO: 2763173275Ssam LINE_CHECK("authmode AUTO"); 2764173275Ssam break; 2765173275Ssam default: 2766173275Ssam LINE_CHECK("authmode UNKNOWN (0x%x)", val); 2767173275Ssam break; 2768127649Ssam } 2769127649Ssam } 2770127649Ssam 2771173275Ssam if (wpa || verbose) { 2772173275Ssam if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) { 2773173275Ssam if (val) 2774173275Ssam LINE_CHECK("countermeasures"); 2775173275Ssam else if (verbose) 2776173275Ssam LINE_CHECK("-countermeasures"); 2777173275Ssam } 2778173275Ssam } 2779138593Ssam 2780173275Ssam if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 && 2781173275Ssam wepmode != IEEE80211_WEP_NOSUP) { 2782173275Ssam int firstkey; 2783173275Ssam 2784138718Ssam switch (wepmode) { 2785173275Ssam case IEEE80211_WEP_OFF: 2786173275Ssam LINE_CHECK("privacy OFF"); 2787173275Ssam break; 2788173275Ssam case IEEE80211_WEP_ON: 2789173275Ssam LINE_CHECK("privacy ON"); 2790173275Ssam break; 2791173275Ssam case IEEE80211_WEP_MIXED: 2792173275Ssam LINE_CHECK("privacy MIXED"); 2793173275Ssam break; 2794173275Ssam default: 2795173275Ssam LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); 2796173275Ssam break; 279777218Sphk } 279877218Sphk 279977218Sphk /* 280077218Sphk * If we get here then we've got WEP support so we need 280177218Sphk * to print WEP status. 280291454Sbrooks */ 280377218Sphk 2804173275Ssam if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) { 280577218Sphk warn("WEP support, but no tx key!"); 280677218Sphk goto end; 280777218Sphk } 2808173275Ssam if (val != -1) 2809173275Ssam LINE_CHECK("deftxkey %d", val+1); 2810138718Ssam else if (wepmode != IEEE80211_WEP_OFF || verbose) 2811155931Ssam LINE_CHECK("deftxkey UNDEF"); 281277218Sphk 2813173275Ssam if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) { 281477218Sphk warn("WEP support, but no NUMWEPKEYS support!"); 281577218Sphk goto end; 281677218Sphk } 281777218Sphk 2818138593Ssam firstkey = 1; 2819138593Ssam for (i = 0; i < num; i++) { 2820138593Ssam struct ieee80211req_key ik; 282177218Sphk 2822138593Ssam memset(&ik, 0, sizeof(ik)); 2823138593Ssam ik.ik_keyix = i; 2824173275Ssam if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) { 282577218Sphk warn("WEP support, but can get keys!"); 282677218Sphk goto end; 282777218Sphk } 2828138593Ssam if (ik.ik_keylen != 0) { 2829138593Ssam if (verbose) 2830138593Ssam LINE_BREAK(); 2831138593Ssam printkey(&ik); 2832138593Ssam firstkey = 0; 2833138593Ssam } 2834138593Ssam } 2835173275Ssamend: 2836173275Ssam ; 2837138593Ssam } 2838138593Ssam 2839173275Ssam if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 && 2840173275Ssam val != IEEE80211_POWERSAVE_NOSUP ) { 2841173275Ssam if (val != IEEE80211_POWERSAVE_OFF || verbose) { 2842173275Ssam switch (val) { 2843173275Ssam case IEEE80211_POWERSAVE_OFF: 2844173275Ssam LINE_CHECK("powersavemode OFF"); 2845173275Ssam break; 2846173275Ssam case IEEE80211_POWERSAVE_CAM: 2847173275Ssam LINE_CHECK("powersavemode CAM"); 2848173275Ssam break; 2849173275Ssam case IEEE80211_POWERSAVE_PSP: 2850173275Ssam LINE_CHECK("powersavemode PSP"); 2851173275Ssam break; 2852173275Ssam case IEEE80211_POWERSAVE_PSP_CAM: 2853173275Ssam LINE_CHECK("powersavemode PSP-CAM"); 2854173275Ssam break; 2855138593Ssam } 2856173275Ssam if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1) 2857173275Ssam LINE_CHECK("powersavesleep %d", val); 2858138593Ssam } 2859138593Ssam } 2860138593Ssam 2861173275Ssam if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) { 2862173275Ssam if (val & 1) 2863173275Ssam LINE_CHECK("txpower %d.5", val/2); 2864173275Ssam else 2865173275Ssam LINE_CHECK("txpower %d", val/2); 2866173275Ssam } 2867138593Ssam if (verbose) { 2868173275Ssam if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1) 2869173275Ssam LINE_CHECK("txpowmax %.1f", val/2.); 2870138593Ssam } 2871138593Ssam 2872173275Ssam if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) { 2873173275Ssam if (val != IEEE80211_RTS_MAX || verbose) 2874173275Ssam LINE_CHECK("rtsthreshold %d", val); 2875138593Ssam } 2876138593Ssam 2877173275Ssam if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) { 2878173275Ssam if (val != IEEE80211_FRAG_MAX || verbose) 2879173275Ssam LINE_CHECK("fragthreshold %d", val); 2880170531Ssam } 2881173275Ssam if (opmode == IEEE80211_M_STA || verbose) { 2882173275Ssam if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) { 2883173275Ssam if (val != IEEE80211_HWBMISS_MAX || verbose) 2884173275Ssam LINE_CHECK("bmiss %d", val); 2885153354Ssam } 2886153354Ssam } 2887153354Ssam 2888173275Ssam if (get80211val(s, IEEE80211_IOC_MCAST_RATE, &val) != -1) 2889173275Ssam printrate("mcastrate", val, 2*1, 0/*XXX*/); 2890170531Ssam 2891173275Ssam bgscaninterval = -1; 2892173275Ssam (void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval); 2893173275Ssam 2894173275Ssam if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) { 2895173275Ssam if (val != bgscaninterval || verbose) 2896173275Ssam LINE_CHECK("scanvalid %u", val); 2897148416Ssam } 2898148416Ssam 2899173275Ssam bgscan = 0; 2900173275Ssam if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) { 2901173275Ssam if (bgscan) 2902170531Ssam LINE_CHECK("bgscan"); 2903170531Ssam else if (verbose) 2904170531Ssam LINE_CHECK("-bgscan"); 2905160687Ssam } 2906170531Ssam if (bgscan || verbose) { 2907170531Ssam if (bgscaninterval != -1) 2908170531Ssam LINE_CHECK("bgscanintvl %u", bgscaninterval); 2909173275Ssam if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1) 2910173275Ssam LINE_CHECK("bgscanidle %u", val); 2911170531Ssam if (IEEE80211_IS_CHAN_A(c) || verbose) { 2912173275Ssam if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11A, &val) != -1) 2913173275Ssam printrssi("roam:rssi11a", val); 2914173275Ssam if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11A, &val) != -1) 2915173275Ssam printrate("roam:rate11a", val, -1, -1); 2916170531Ssam } 2917170531Ssam if (IEEE80211_IS_CHAN_B(c) || verbose) { 2918173275Ssam if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11B, &val) != -1) 2919173275Ssam printrssi("roam:rssi11b", val); 2920173275Ssam if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11B, &val) != -1) 2921173275Ssam printrate("roam:rate11b", val, -1, -1); 2922170531Ssam } 2923170531Ssam if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { 2924173275Ssam if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11G, &val) != -1) 2925173275Ssam printrssi("roam:rssi11g", val); 2926173275Ssam if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11G, &val) != -1) 2927173275Ssam printrate("roam:rate11g", val, -1, -1); 2928170531Ssam } 2929170531Ssam } 2930160687Ssam 2931165570Ssam if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { 2932173275Ssam if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) { 2933173275Ssam if (val) 2934155931Ssam LINE_CHECK("pureg"); 2935147795Ssam else if (verbose) 2936155931Ssam LINE_CHECK("-pureg"); 2937147795Ssam } 2938173275Ssam if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) { 2939173275Ssam switch (val) { 2940173275Ssam case IEEE80211_PROTMODE_OFF: 2941173275Ssam LINE_CHECK("protmode OFF"); 2942173275Ssam break; 2943173275Ssam case IEEE80211_PROTMODE_CTS: 2944173275Ssam LINE_CHECK("protmode CTS"); 2945173275Ssam break; 2946173275Ssam case IEEE80211_PROTMODE_RTSCTS: 2947173275Ssam LINE_CHECK("protmode RTSCTS"); 2948173275Ssam break; 2949173275Ssam default: 2950173275Ssam LINE_CHECK("protmode UNKNOWN (0x%x)", val); 2951173275Ssam break; 2952138593Ssam } 2953138593Ssam } 2954138593Ssam } 2955138593Ssam 2956173275Ssam if (IEEE80211_IS_CHAN_HT(c) || verbose) { 2957173275Ssam gethtconf(s); 2958173275Ssam switch (htconf & 3) { 2959173275Ssam case 0: 2960173275Ssam case 2: 2961173275Ssam LINE_CHECK("-ht"); 2962173275Ssam break; 2963173275Ssam case 1: 2964173275Ssam LINE_CHECK("ht20"); 2965173275Ssam break; 2966173275Ssam case 3: 2967173275Ssam if (verbose) 2968173275Ssam LINE_CHECK("ht"); 2969173275Ssam break; 2970173275Ssam } 2971173275Ssam if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) { 2972173275Ssam if (!val) 2973173275Ssam LINE_CHECK("-htcompat"); 2974173275Ssam else if (verbose) 2975173275Ssam LINE_CHECK("htcompat"); 2976173275Ssam } 2977173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) { 2978173275Ssam switch (val) { 2979173275Ssam case 0: 2980173275Ssam LINE_CHECK("-ampdu"); 2981173275Ssam break; 2982173275Ssam case 1: 2983173275Ssam LINE_CHECK("ampdutx -ampdurx"); 2984173275Ssam break; 2985173275Ssam case 2: 2986173275Ssam LINE_CHECK("-ampdutx ampdurx"); 2987173275Ssam break; 2988173275Ssam case 3: 2989173275Ssam if (verbose) 2990173275Ssam LINE_CHECK("ampdu"); 2991173275Ssam break; 2992173275Ssam } 2993173275Ssam } 2994173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) { 2995173275Ssam switch (val) { 2996173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_8K: 2997173275Ssam LINE_CHECK("ampdulimit 8k"); 2998173275Ssam break; 2999173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_16K: 3000173275Ssam LINE_CHECK("ampdulimit 16k"); 3001173275Ssam break; 3002173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_32K: 3003173275Ssam LINE_CHECK("ampdulimit 32k"); 3004173275Ssam break; 3005173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_64K: 3006173275Ssam LINE_CHECK("ampdulimit 64k"); 3007173275Ssam break; 3008173275Ssam } 3009173275Ssam } 3010173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) { 3011173275Ssam switch (val) { 3012173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_NA: 3013173275Ssam if (verbose) 3014173275Ssam LINE_CHECK("ampdudensity -"); 3015173275Ssam break; 3016173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_025: 3017173275Ssam LINE_CHECK("ampdudensity .25"); 3018173275Ssam break; 3019173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_05: 3020173275Ssam LINE_CHECK("ampdudensity .5"); 3021173275Ssam break; 3022173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_1: 3023173275Ssam LINE_CHECK("ampdudensity 1"); 3024173275Ssam break; 3025173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_2: 3026173275Ssam LINE_CHECK("ampdudensity 2"); 3027173275Ssam break; 3028173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_4: 3029173275Ssam LINE_CHECK("ampdudensity 4"); 3030173275Ssam break; 3031173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_8: 3032173275Ssam LINE_CHECK("ampdudensity 8"); 3033173275Ssam break; 3034173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_16: 3035173275Ssam LINE_CHECK("ampdudensity 16"); 3036173275Ssam break; 3037173275Ssam } 3038173275Ssam } 3039173275Ssam if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) { 3040173275Ssam switch (val) { 3041173275Ssam case 0: 3042173275Ssam LINE_CHECK("-amsdu"); 3043173275Ssam break; 3044173275Ssam case 1: 3045173275Ssam LINE_CHECK("amsdutx -amsdurx"); 3046173275Ssam break; 3047173275Ssam case 2: 3048173275Ssam LINE_CHECK("-amsdutx amsdurx"); 3049173275Ssam break; 3050173275Ssam case 3: 3051173275Ssam if (verbose) 3052173275Ssam LINE_CHECK("amsdu"); 3053173275Ssam break; 3054173275Ssam } 3055173275Ssam } 3056173275Ssam /* XXX amsdu limit */ 3057173275Ssam /* XXX 20/40 */ 3058173275Ssam if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) { 3059173275Ssam if (val) 3060173275Ssam LINE_CHECK("shortgi"); 3061173275Ssam else if (verbose) 3062173275Ssam LINE_CHECK("-shortgi"); 3063173275Ssam } 3064173275Ssam if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) { 3065173275Ssam if (val == IEEE80211_PROTMODE_OFF) 3066173275Ssam LINE_CHECK("htprotmode OFF"); 3067173275Ssam else if (val != IEEE80211_PROTMODE_RTSCTS) 3068173275Ssam LINE_CHECK("htprotmode UNKNOWN (0x%x)", val); 3069173275Ssam else if (verbose) 3070173275Ssam LINE_CHECK("htprotmode RTSCTS"); 3071173275Ssam } 3072173275Ssam if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) { 3073173275Ssam if (val) 3074173275Ssam LINE_CHECK("puren"); 3075173275Ssam else if (verbose) 3076173275Ssam LINE_CHECK("-puren"); 3077173275Ssam } 3078173275Ssam } 3079173275Ssam 3080173275Ssam if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) { 3081138593Ssam if (wme) 3082155931Ssam LINE_CHECK("wme"); 3083138593Ssam else if (verbose) 3084155931Ssam LINE_CHECK("-wme"); 3085138593Ssam } else 3086138593Ssam wme = 0; 3087138593Ssam 3088173275Ssam if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) { 3089173275Ssam if (val) 3090155931Ssam LINE_CHECK("burst"); 3091153422Ssam else if (verbose) 3092155931Ssam LINE_CHECK("-burst"); 3093153422Ssam } 3094153422Ssam 3095173275Ssam if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) { 3096173275Ssam if (val) 3097170531Ssam LINE_CHECK("ff"); 3098170531Ssam else if (verbose) 3099170531Ssam LINE_CHECK("-ff"); 3100170531Ssam } 3101173275Ssam if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) { 3102173275Ssam if (val) 3103170531Ssam LINE_CHECK("dturbo"); 3104170531Ssam else if (verbose) 3105170531Ssam LINE_CHECK("-dturbo"); 3106170531Ssam } 3107170531Ssam 3108138593Ssam if (opmode == IEEE80211_M_HOSTAP) { 3109173275Ssam if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) { 3110173275Ssam if (val) 3111168075Ssam LINE_CHECK("hidessid"); 3112138593Ssam else if (verbose) 3113168075Ssam LINE_CHECK("-hidessid"); 3114138593Ssam } 3115173275Ssam if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) { 3116173275Ssam if (!val) 3117155931Ssam LINE_CHECK("-apbridge"); 3118138593Ssam else if (verbose) 3119155931Ssam LINE_CHECK("apbridge"); 3120138593Ssam } 3121173275Ssam if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1) 3122173275Ssam LINE_CHECK("dtimperiod %u", val); 3123138593Ssam 3124173275Ssam if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) { 3125173275Ssam if (!val) 3126170531Ssam LINE_CHECK("-doth"); 3127170531Ssam else if (verbose) 3128170531Ssam LINE_CHECK("doth"); 3129170531Ssam } 3130173275Ssam if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) { 3131173275Ssam if (!val) 3132173275Ssam LINE_CHECK("-inact"); 3133173275Ssam else if (verbose) 3134173275Ssam LINE_CHECK("inact"); 3135173275Ssam } 3136138593Ssam } else { 3137173275Ssam if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) { 3138173275Ssam if (val != IEEE80211_ROAMING_AUTO || verbose) { 3139173275Ssam switch (val) { 3140138593Ssam case IEEE80211_ROAMING_DEVICE: 3141155931Ssam LINE_CHECK("roaming DEVICE"); 3142138593Ssam break; 3143138593Ssam case IEEE80211_ROAMING_AUTO: 3144155931Ssam LINE_CHECK("roaming AUTO"); 3145138593Ssam break; 3146138593Ssam case IEEE80211_ROAMING_MANUAL: 3147155931Ssam LINE_CHECK("roaming MANUAL"); 3148138593Ssam break; 3149138593Ssam default: 3150155931Ssam LINE_CHECK("roaming UNKNOWN (0x%x)", 3151173275Ssam val); 3152138593Ssam break; 3153138593Ssam } 3154138593Ssam } 3155138593Ssam } 3156138593Ssam } 3157173275Ssam if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) { 3158173275Ssam /* XXX default define not visible */ 3159173275Ssam if (val != 100 || verbose) 3160173275Ssam LINE_CHECK("bintval %u", val); 3161138593Ssam } 3162138593Ssam 3163138593Ssam if (wme && verbose) { 3164138593Ssam LINE_BREAK(); 3165138593Ssam list_wme(s); 3166138593Ssam } 3167173275Ssam LINE_BREAK(); 3168173275Ssam} 3169138593Ssam 3170173275Ssamstatic int 3171173275Ssamget80211(int s, int type, void *data, int len) 3172173275Ssam{ 3173173275Ssam struct ieee80211req ireq; 3174138593Ssam 3175173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3176173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3177173275Ssam ireq.i_type = type; 3178173275Ssam ireq.i_data = data; 3179173275Ssam ireq.i_len = len; 3180173275Ssam return ioctl(s, SIOCG80211, &ireq); 3181173275Ssam} 3182138593Ssam 3183173275Ssamstatic int 3184173275Ssamget80211len(int s, int type, void *data, int len, int *plen) 3185173275Ssam{ 3186173275Ssam struct ieee80211req ireq; 3187138593Ssam 3188173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3189173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3190173275Ssam ireq.i_type = type; 3191173275Ssam ireq.i_len = len; 3192173275Ssam ireq.i_data = data; 3193173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 3194173275Ssam return -1; 3195173275Ssam *plen = ireq.i_len; 3196173275Ssam return 0; 3197173275Ssam} 3198138593Ssam 3199173275Ssamstatic int 3200173275Ssamget80211val(int s, int type, int *val) 3201173275Ssam{ 3202173275Ssam struct ieee80211req ireq; 320377218Sphk 3204173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3205173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3206173275Ssam ireq.i_type = type; 3207173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 3208173275Ssam return -1; 3209173275Ssam *val = ireq.i_val; 3210173275Ssam return 0; 321177218Sphk} 321277218Sphk 321377218Sphkstatic void 3214170531Ssamset80211(int s, int type, int val, int len, void *data) 321577218Sphk{ 321677218Sphk struct ieee80211req ireq; 321777218Sphk 321877218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 321977218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 322077218Sphk ireq.i_type = type; 322177218Sphk ireq.i_val = val; 322277218Sphk ireq.i_len = len; 322377218Sphk ireq.i_data = data; 322491454Sbrooks if (ioctl(s, SIOCS80211, &ireq) < 0) 322577218Sphk err(1, "SIOCS80211"); 322677218Sphk} 322777218Sphk 322877218Sphkstatic const char * 322977218Sphkget_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 323077218Sphk{ 323177218Sphk int len; 323277218Sphk int hexstr; 323377218Sphk u_int8_t *p; 323477218Sphk 323577218Sphk len = *lenp; 323677218Sphk p = buf; 323777218Sphk hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 323877218Sphk if (hexstr) 323977218Sphk val += 2; 324077218Sphk for (;;) { 324177218Sphk if (*val == '\0') 324277218Sphk break; 324377218Sphk if (sep != NULL && strchr(sep, *val) != NULL) { 324477218Sphk val++; 324577218Sphk break; 324677218Sphk } 324777218Sphk if (hexstr) { 3248127831Sphk if (!isxdigit((u_char)val[0])) { 324977218Sphk warnx("bad hexadecimal digits"); 325077218Sphk return NULL; 325177218Sphk } 3252127831Sphk if (!isxdigit((u_char)val[1])) { 3253127831Sphk warnx("odd count hexadecimal digits"); 3254127831Sphk return NULL; 3255127831Sphk } 325677218Sphk } 3257127831Sphk if (p >= buf + len) { 325877218Sphk if (hexstr) 325977218Sphk warnx("hexadecimal digits too long"); 326077218Sphk else 3261127831Sphk warnx("string too long"); 326277218Sphk return NULL; 326377218Sphk } 326477218Sphk if (hexstr) { 326577218Sphk#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 326677218Sphk *p++ = (tohex((u_char)val[0]) << 4) | 326777218Sphk tohex((u_char)val[1]); 326877218Sphk#undef tohex 326977218Sphk val += 2; 327077218Sphk } else 327177218Sphk *p++ = *val++; 327277218Sphk } 327377218Sphk len = p - buf; 327477218Sphk /* The string "-" is treated as the empty string. */ 3275165045Ssam if (!hexstr && len == 1 && buf[0] == '-') { 327677218Sphk len = 0; 3277165045Ssam memset(buf, 0, *lenp); 3278165045Ssam } else if (len < *lenp) 327977218Sphk memset(p, 0, *lenp - len); 328077218Sphk *lenp = len; 328177218Sphk return val; 328277218Sphk} 328377218Sphk 328477218Sphkstatic void 328577218Sphkprint_string(const u_int8_t *buf, int len) 328677218Sphk{ 328777218Sphk int i; 328877218Sphk int hasspc; 328977218Sphk 329077218Sphk i = 0; 329177218Sphk hasspc = 0; 329291454Sbrooks for (; i < len; i++) { 329377218Sphk if (!isprint(buf[i]) && buf[i] != '\0') 329477218Sphk break; 329577218Sphk if (isspace(buf[i])) 329677218Sphk hasspc++; 329777218Sphk } 329877218Sphk if (i == len) { 329977218Sphk if (hasspc || len == 0 || buf[0] == '\0') 330077218Sphk printf("\"%.*s\"", len, buf); 330177218Sphk else 330277218Sphk printf("%.*s", len, buf); 330377218Sphk } else { 330477218Sphk printf("0x"); 330577218Sphk for (i = 0; i < len; i++) 330677218Sphk printf("%02x", buf[i]); 330777218Sphk } 330877218Sphk} 330977218Sphk 3310138593Ssamstatic struct cmd ieee80211_cmds[] = { 3311138593Ssam DEF_CMD_ARG("ssid", set80211ssid), 3312138593Ssam DEF_CMD_ARG("nwid", set80211ssid), 3313138593Ssam DEF_CMD_ARG("stationname", set80211stationname), 3314138593Ssam DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 3315138593Ssam DEF_CMD_ARG("channel", set80211channel), 3316138593Ssam DEF_CMD_ARG("authmode", set80211authmode), 3317138593Ssam DEF_CMD_ARG("powersavemode", set80211powersavemode), 3318138593Ssam DEF_CMD("powersave", 1, set80211powersave), 3319138593Ssam DEF_CMD("-powersave", 0, set80211powersave), 3320138593Ssam DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 3321138593Ssam DEF_CMD_ARG("wepmode", set80211wepmode), 3322138593Ssam DEF_CMD("wep", 1, set80211wep), 3323138593Ssam DEF_CMD("-wep", 0, set80211wep), 3324139493Ssam DEF_CMD_ARG("deftxkey", set80211weptxkey), 3325138593Ssam DEF_CMD_ARG("weptxkey", set80211weptxkey), 3326138593Ssam DEF_CMD_ARG("wepkey", set80211wepkey), 3327138593Ssam DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 3328138593Ssam DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 3329138593Ssam DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 3330138593Ssam DEF_CMD_ARG("protmode", set80211protmode), 3331138593Ssam DEF_CMD_ARG("txpower", set80211txpower), 3332138593Ssam DEF_CMD_ARG("roaming", set80211roaming), 3333138593Ssam DEF_CMD("wme", 1, set80211wme), 3334138593Ssam DEF_CMD("-wme", 0, set80211wme), 3335138593Ssam DEF_CMD("hidessid", 1, set80211hidessid), 3336138593Ssam DEF_CMD("-hidessid", 0, set80211hidessid), 3337138593Ssam DEF_CMD("apbridge", 1, set80211apbridge), 3338138593Ssam DEF_CMD("-apbridge", 0, set80211apbridge), 3339138593Ssam DEF_CMD_ARG("chanlist", set80211chanlist), 3340138593Ssam DEF_CMD_ARG("bssid", set80211bssid), 3341138593Ssam DEF_CMD_ARG("ap", set80211bssid), 3342138593Ssam DEF_CMD("scan", 0, set80211scan), 3343138593Ssam DEF_CMD_ARG("list", set80211list), 3344138593Ssam DEF_CMD_ARG2("cwmin", set80211cwmin), 3345138593Ssam DEF_CMD_ARG2("cwmax", set80211cwmax), 3346138593Ssam DEF_CMD_ARG2("aifs", set80211aifs), 3347138593Ssam DEF_CMD_ARG2("txoplimit", set80211txoplimit), 3348148621Ssam DEF_CMD_ARG("acm", set80211acm), 3349148621Ssam DEF_CMD_ARG("-acm", set80211noacm), 3350148621Ssam DEF_CMD_ARG("ack", set80211ackpolicy), 3351148621Ssam DEF_CMD_ARG("-ack", set80211noackpolicy), 3352138593Ssam DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 3353138593Ssam DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 3354138593Ssam DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 3355138593Ssam DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 3356138593Ssam DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 3357138593Ssam DEF_CMD_ARG("bintval", set80211bintval), 3358138593Ssam DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 3359138593Ssam DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 3360138593Ssam DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 3361138593Ssam DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 3362138593Ssam DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 3363138593Ssam DEF_CMD_ARG("mac:add", set80211addmac), 3364138593Ssam DEF_CMD_ARG("mac:del", set80211delmac), 3365138593Ssam DEF_CMD_ARG("mac:kick", set80211kickmac), 3366147795Ssam DEF_CMD("pureg", 1, set80211pureg), 3367147795Ssam DEF_CMD("-pureg", 0, set80211pureg), 3368170531Ssam DEF_CMD("ff", 1, set80211fastframes), 3369170531Ssam DEF_CMD("-ff", 0, set80211fastframes), 3370170531Ssam DEF_CMD("dturbo", 1, set80211dturbo), 3371170531Ssam DEF_CMD("-dturbo", 0, set80211dturbo), 3372170531Ssam DEF_CMD("bgscan", 1, set80211bgscan), 3373170531Ssam DEF_CMD("-bgscan", 0, set80211bgscan), 3374170531Ssam DEF_CMD_ARG("bgscanidle", set80211bgscanidle), 3375170531Ssam DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl), 3376170531Ssam DEF_CMD_ARG("scanvalid", set80211scanvalid), 3377170531Ssam DEF_CMD_ARG("roam:rssi11a", set80211roamrssi11a), 3378170531Ssam DEF_CMD_ARG("roam:rssi11b", set80211roamrssi11b), 3379170531Ssam DEF_CMD_ARG("roam:rssi11g", set80211roamrssi11g), 3380170531Ssam DEF_CMD_ARG("roam:rate11a", set80211roamrate11a), 3381170531Ssam DEF_CMD_ARG("roam:rate11b", set80211roamrate11b), 3382170531Ssam DEF_CMD_ARG("roam:rate11g", set80211roamrate11g), 3383153354Ssam DEF_CMD_ARG("mcastrate", set80211mcastrate), 3384148416Ssam DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 3385153422Ssam DEF_CMD("burst", 1, set80211burst), 3386153422Ssam DEF_CMD("-burst", 0, set80211burst), 3387160687Ssam DEF_CMD_ARG("bmiss", set80211bmissthreshold), 3388160687Ssam DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), 3389173275Ssam DEF_CMD("shortgi", 1, set80211shortgi), 3390173275Ssam DEF_CMD("-shortgi", 0, set80211shortgi), 3391173275Ssam DEF_CMD("ampdurx", 2, set80211ampdu), 3392173275Ssam DEF_CMD("-ampdurx", -2, set80211ampdu), 3393173275Ssam DEF_CMD("ampdutx", 1, set80211ampdu), 3394173275Ssam DEF_CMD("-ampdutx", -1, set80211ampdu), 3395173275Ssam DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */ 3396173275Ssam DEF_CMD("-ampdu", -3, set80211ampdu), 3397173275Ssam DEF_CMD_ARG("ampdulimit", set80211ampdulimit), 3398173275Ssam DEF_CMD_ARG("ampdudensity", set80211ampdudensity), 3399173275Ssam DEF_CMD("amsdurx", 2, set80211amsdu), 3400173275Ssam DEF_CMD("-amsdurx", -2, set80211amsdu), 3401173275Ssam DEF_CMD("amsdutx", 1, set80211amsdu), 3402173275Ssam DEF_CMD("-amsdutx", -1, set80211amsdu), 3403173275Ssam DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */ 3404173275Ssam DEF_CMD("-amsdu", -3, set80211amsdu), 3405173275Ssam DEF_CMD_ARG("amsdulimit", set80211amsdulimit), 3406173275Ssam DEF_CMD("puren", 1, set80211puren), 3407173275Ssam DEF_CMD("-puren", 0, set80211puren), 3408170531Ssam DEF_CMD("doth", 1, set80211doth), 3409170531Ssam DEF_CMD("-doth", 0, set80211doth), 3410173275Ssam DEF_CMD("htcompat", 1, set80211htcompat), 3411173275Ssam DEF_CMD("-htcompat", 0, set80211htcompat), 3412173275Ssam DEF_CMD("inact", 1, set80211inact), 3413173275Ssam DEF_CMD("-inact", 0, set80211inact), 3414173275Ssam DEF_CMD_ARG("htprotmode", set80211htprotmode), 3415173275Ssam DEF_CMD("ht20", 1, set80211htconf), 3416173275Ssam DEF_CMD("-ht20", 0, set80211htconf), 3417173275Ssam DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */ 3418173275Ssam DEF_CMD("-ht40", 0, set80211htconf), 3419173275Ssam DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */ 3420173275Ssam DEF_CMD("-ht", 0, set80211htconf), 3421138593Ssam}; 3422138593Ssamstatic struct afswtch af_ieee80211 = { 3423138593Ssam .af_name = "af_ieee80211", 3424138593Ssam .af_af = AF_UNSPEC, 3425139494Ssam .af_other_status = ieee80211_status, 3426138593Ssam}; 3427138593Ssam 3428138593Ssamstatic __constructor void 3429138593Ssamieee80211_ctor(void) 3430138593Ssam{ 3431138593Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 3432138593Ssam int i; 3433138593Ssam 3434138593Ssam for (i = 0; i < N(ieee80211_cmds); i++) 3435138593Ssam cmd_register(&ieee80211_cmds[i]); 3436138593Ssam af_register(&af_ieee80211); 3437138593Ssam#undef N 3438138593Ssam} 3439