ifieee80211.c revision 181454
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 181454 2008-08-09 05:37:22Z 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_ioctl.h> 8177218Sphk 8277218Sphk#include <ctype.h> 8377218Sphk#include <err.h> 8477218Sphk#include <errno.h> 8577218Sphk#include <fcntl.h> 86146873Sjhb#include <inttypes.h> 8777218Sphk#include <stdio.h> 8877218Sphk#include <stdlib.h> 8977218Sphk#include <string.h> 9077218Sphk#include <unistd.h> 91155931Ssam#include <stdarg.h> 92173275Ssam#include <stddef.h> /* NB: for offsetof */ 9377218Sphk 9477218Sphk#include "ifconfig.h" 95178354Ssam#include "regdomain.h" 9677218Sphk 97178354Ssam#ifndef IEEE80211_FIXED_RATE_NONE 98178354Ssam#define IEEE80211_FIXED_RATE_NONE 0xff 99178354Ssam#endif 100178354Ssam 101178354Ssam#define REQ_ECM 0x01000000 /* enable if ECM set */ 102178354Ssam#define REQ_OUTDOOR 0x02000000 /* enable for outdoor operation */ 103178354Ssam#define REQ_FLAGS 0xff000000 /* private flags, don't pass to os */ 104178354Ssam 105178354Ssam/* XXX need these publicly defined or similar */ 106178354Ssam#ifndef IEEE80211_NODE_AUTH 107178354Ssam#define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */ 108178354Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 109178354Ssam#define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */ 110178354Ssam#define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */ 111178354Ssam#define IEEE80211_NODE_HT 0x0040 /* HT enabled */ 112178354Ssam#define IEEE80211_NODE_HTCOMPAT 0x0080 /* HT setup w/ vendor OUI's */ 113178354Ssam#define IEEE80211_NODE_WPS 0x0100 /* WPS association */ 114178354Ssam#define IEEE80211_NODE_TSN 0x0200 /* TSN association */ 115178354Ssam#endif 116178354Ssam 117173275Ssam#define MAXCOL 78 118173275Ssamstatic int col; 119173275Ssamstatic char spacer; 120173275Ssam 121173275Ssamstatic void LINE_INIT(char c); 122173275Ssamstatic void LINE_BREAK(void); 123173275Ssamstatic void LINE_CHECK(const char *fmt, ...); 124173275Ssam 125178354Ssamstatic const char *modename[] = { 126178354Ssam "auto", "11a", "11b", "11g", "fh", "turboA", "turboG", 127178354Ssam "sturbo", "11na", "11ng" 128173275Ssam}; 129173275Ssam 130178354Ssamstatic void set80211(int s, int type, int val, int len, void *data); 131173275Ssamstatic int get80211(int s, int type, void *data, int len); 132173275Ssamstatic int get80211len(int s, int type, void *data, int len, int *plen); 133173275Ssamstatic int get80211val(int s, int type, int *val); 13477218Sphkstatic const char *get_string(const char *val, const char *sep, 13577218Sphk u_int8_t *buf, int *lenp); 13677218Sphkstatic void print_string(const u_int8_t *buf, int len); 137178354Ssamstatic void print_regdomain(const struct ieee80211_regdomain *, int); 138178354Ssamstatic void print_channels(int, const struct ieee80211req_chaninfo *, 139178354Ssam int allchans, int verbose); 140178354Ssamstatic void regdomain_makechannels(struct ieee80211_regdomain_req *, 141178354Ssam const struct ieee80211_devcaps_req *); 14277218Sphk 143170531Ssamstatic struct ieee80211req_chaninfo chaninfo; 144178354Ssamstatic struct ieee80211_regdomain regdomain; 145178354Ssamstatic int gotregdomain = 0; 146178354Ssamstatic struct ieee80211_roamparams_req roamparams; 147178354Ssamstatic int gotroam = 0; 148178354Ssamstatic struct ieee80211_txparams_req txparams; 149178354Ssamstatic int gottxparams = 0; 150173275Ssamstatic struct ieee80211_channel curchan; 151173275Ssamstatic int gotcurchan = 0; 152178354Ssamstatic struct ifmediareq *ifmr; 153173275Ssamstatic int htconf = 0; 154173275Ssamstatic int gothtconf = 0; 155170531Ssam 156173275Ssamstatic void 157173275Ssamgethtconf(int s) 158173275Ssam{ 159173275Ssam if (gothtconf) 160173275Ssam return; 161173275Ssam if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0) 162173275Ssam warn("unable to get HT configuration information"); 163173275Ssam gothtconf = 1; 164173275Ssam} 165173275Ssam 166170531Ssam/* 167170531Ssam * Collect channel info from the kernel. We use this (mostly) 168170531Ssam * to handle mapping between frequency and IEEE channel number. 169170531Ssam */ 170170531Ssamstatic void 171170531Ssamgetchaninfo(int s) 172170531Ssam{ 173170531Ssam if (chaninfo.ic_nchans != 0) 174170531Ssam return; 175173275Ssam if (get80211(s, IEEE80211_IOC_CHANINFO, &chaninfo, sizeof(chaninfo)) < 0) 176170531Ssam errx(1, "unable to get channel information"); 177170531Ssam ifmr = ifmedia_getstate(s); 178173275Ssam gethtconf(s); 179170531Ssam} 180170531Ssam 181178354Ssamstatic struct regdata * 182178354Ssamgetregdata(void) 183178354Ssam{ 184178354Ssam static struct regdata *rdp = NULL; 185178354Ssam if (rdp == NULL) { 186178354Ssam rdp = lib80211_alloc_regdata(); 187178354Ssam if (rdp == NULL) 188181198Ssam errx(-1, "missing or corrupted regdomain database"); 189178354Ssam } 190178354Ssam return rdp; 191178354Ssam} 192178354Ssam 193170531Ssam/* 194170531Ssam * Given the channel at index i with attributes from, 195170531Ssam * check if there is a channel with attributes to in 196170531Ssam * the channel table. With suitable attributes this 197170531Ssam * allows the caller to look for promotion; e.g. from 198170531Ssam * 11b > 11g. 199170531Ssam */ 200138593Ssamstatic int 201170531Ssamcanpromote(int i, int from, int to) 202170531Ssam{ 203170531Ssam const struct ieee80211_channel *fc = &chaninfo.ic_chans[i]; 204170531Ssam int j; 205170531Ssam 206170531Ssam if ((fc->ic_flags & from) != from) 207170531Ssam return i; 208170531Ssam /* NB: quick check exploiting ordering of chans w/ same frequency */ 209170531Ssam if (i+1 < chaninfo.ic_nchans && 210170531Ssam chaninfo.ic_chans[i+1].ic_freq == fc->ic_freq && 211170531Ssam (chaninfo.ic_chans[i+1].ic_flags & to) == to) 212170531Ssam return i+1; 213170531Ssam /* brute force search in case channel list is not ordered */ 214170531Ssam for (j = 0; j < chaninfo.ic_nchans; j++) { 215170531Ssam const struct ieee80211_channel *tc = &chaninfo.ic_chans[j]; 216170531Ssam if (j != i && 217170531Ssam tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to) 218170531Ssam return j; 219170531Ssam } 220170531Ssam return i; 221170531Ssam} 222170531Ssam 223170531Ssam/* 224170531Ssam * Handle channel promotion. When a channel is specified with 225170531Ssam * only a frequency we want to promote it to the ``best'' channel 226170531Ssam * available. The channel list has separate entries for 11b, 11g, 227170531Ssam * 11a, and 11n[ga] channels so specifying a frequency w/o any 228170531Ssam * attributes requires we upgrade, e.g. from 11b -> 11g. This 229170531Ssam * gets complicated when the channel is specified on the same 230170531Ssam * command line with a media request that constrains the available 231170531Ssam * channe list (e.g. mode 11a); we want to honor that to avoid 232170531Ssam * confusing behaviour. 233170531Ssam */ 234170531Ssamstatic int 235170531Ssampromote(int i) 236170531Ssam{ 237170531Ssam /* 238170531Ssam * Query the current mode of the interface in case it's 239170531Ssam * constrained (e.g. to 11a). We must do this carefully 240170531Ssam * as there may be a pending ifmedia request in which case 241170531Ssam * asking the kernel will give us the wrong answer. This 242170531Ssam * is an unfortunate side-effect of the way ifconfig is 243170531Ssam * structure for modularity (yech). 244170531Ssam * 245170531Ssam * NB: ifmr is actually setup in getchaninfo (above); we 246170531Ssam * assume it's called coincident with to this call so 247170531Ssam * we have a ``current setting''; otherwise we must pass 248170531Ssam * the socket descriptor down to here so we can make 249170531Ssam * the ifmedia_getstate call ourselves. 250170531Ssam */ 251170531Ssam int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO; 252170531Ssam 253170531Ssam /* when ambiguous promote to ``best'' */ 254170531Ssam /* NB: we abitrarily pick HT40+ over HT40- */ 255170531Ssam if (chanmode != IFM_IEEE80211_11B) 256170531Ssam i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G); 257173275Ssam if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) { 258170531Ssam i = canpromote(i, IEEE80211_CHAN_G, 259170531Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT20); 260173275Ssam if (htconf & 2) { 261173275Ssam i = canpromote(i, IEEE80211_CHAN_G, 262173275Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D); 263173275Ssam i = canpromote(i, IEEE80211_CHAN_G, 264173275Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U); 265173275Ssam } 266170531Ssam } 267173275Ssam if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) { 268170531Ssam i = canpromote(i, IEEE80211_CHAN_A, 269170531Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT20); 270173275Ssam if (htconf & 2) { 271173275Ssam i = canpromote(i, IEEE80211_CHAN_A, 272173275Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D); 273173275Ssam i = canpromote(i, IEEE80211_CHAN_A, 274173275Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U); 275173275Ssam } 276170531Ssam } 277170531Ssam return i; 278170531Ssam} 279170531Ssam 280170531Ssamstatic void 281170531Ssammapfreq(struct ieee80211_channel *chan, int freq, int flags) 282170531Ssam{ 283170531Ssam int i; 284170531Ssam 285170531Ssam for (i = 0; i < chaninfo.ic_nchans; i++) { 286170531Ssam const struct ieee80211_channel *c = &chaninfo.ic_chans[i]; 287170531Ssam 288170531Ssam if (c->ic_freq == freq && (c->ic_flags & flags) == flags) { 289170531Ssam if (flags == 0) { 290170531Ssam /* when ambiguous promote to ``best'' */ 291170531Ssam c = &chaninfo.ic_chans[promote(i)]; 292170531Ssam } 293170531Ssam *chan = *c; 294170531Ssam return; 295170531Ssam } 296170531Ssam } 297170531Ssam errx(1, "unknown/undefined frequency %u/0x%x", freq, flags); 298170531Ssam} 299170531Ssam 300170531Ssamstatic void 301170531Ssammapchan(struct ieee80211_channel *chan, int ieee, int flags) 302170531Ssam{ 303170531Ssam int i; 304170531Ssam 305170531Ssam for (i = 0; i < chaninfo.ic_nchans; i++) { 306170531Ssam const struct ieee80211_channel *c = &chaninfo.ic_chans[i]; 307170531Ssam 308170531Ssam if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) { 309170531Ssam if (flags == 0) { 310170531Ssam /* when ambiguous promote to ``best'' */ 311170531Ssam c = &chaninfo.ic_chans[promote(i)]; 312170531Ssam } 313170531Ssam *chan = *c; 314170531Ssam return; 315170531Ssam } 316170531Ssam } 317173275Ssam errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags); 318170531Ssam} 319170531Ssam 320173275Ssamstatic const struct ieee80211_channel * 321173275Ssamgetcurchan(int s) 322173275Ssam{ 323173275Ssam if (gotcurchan) 324173275Ssam return &curchan; 325173275Ssam if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) { 326173275Ssam int val; 327173275Ssam /* fall back to legacy ioctl */ 328173275Ssam if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0) 329173275Ssam errx(-1, "cannot figure out current channel"); 330173275Ssam getchaninfo(s); 331173275Ssam mapchan(&curchan, val, 0); 332173275Ssam } 333173275Ssam gotcurchan = 1; 334173275Ssam return &curchan; 335173275Ssam} 336173275Ssam 337178354Ssamstatic enum ieee80211_phymode 338178354Ssamchan2mode(const struct ieee80211_channel *c) 339178354Ssam{ 340178354Ssam if (IEEE80211_IS_CHAN_HTA(c)) 341178354Ssam return IEEE80211_MODE_11NA; 342178354Ssam if (IEEE80211_IS_CHAN_HTG(c)) 343178354Ssam return IEEE80211_MODE_11NG; 344178354Ssam if (IEEE80211_IS_CHAN_108A(c)) 345178354Ssam return IEEE80211_MODE_TURBO_A; 346178354Ssam if (IEEE80211_IS_CHAN_108G(c)) 347178354Ssam return IEEE80211_MODE_TURBO_G; 348178354Ssam if (IEEE80211_IS_CHAN_ST(c)) 349178354Ssam return IEEE80211_MODE_STURBO_A; 350178354Ssam if (IEEE80211_IS_CHAN_FHSS(c)) 351178354Ssam return IEEE80211_MODE_FH; 352178354Ssam if (IEEE80211_IS_CHAN_A(c)) 353178354Ssam return IEEE80211_MODE_11A; 354178354Ssam if (IEEE80211_IS_CHAN_ANYG(c)) 355178354Ssam return IEEE80211_MODE_11G; 356178354Ssam if (IEEE80211_IS_CHAN_B(c)) 357178354Ssam return IEEE80211_MODE_11B; 358178354Ssam return IEEE80211_MODE_AUTO; 359178354Ssam} 360178354Ssam 361178354Ssamstatic void 362178354Ssamgetroam(int s) 363178354Ssam{ 364178354Ssam if (gotroam) 365178354Ssam return; 366178354Ssam if (get80211(s, IEEE80211_IOC_ROAM, 367178354Ssam &roamparams, sizeof(roamparams)) < 0) 368178354Ssam errx(1, "unable to get roaming parameters"); 369178354Ssam gotroam = 1; 370178354Ssam} 371178354Ssam 372178354Ssamstatic void 373178354Ssamsetroam_cb(int s, void *arg) 374178354Ssam{ 375178354Ssam struct ieee80211_roamparams_req *roam = arg; 376178354Ssam set80211(s, IEEE80211_IOC_ROAM, 0, sizeof(*roam), roam); 377178354Ssam} 378178354Ssam 379178354Ssamstatic void 380178354Ssamgettxparams(int s) 381178354Ssam{ 382178354Ssam if (gottxparams) 383178354Ssam return; 384178354Ssam if (get80211(s, IEEE80211_IOC_TXPARAMS, 385178354Ssam &txparams, sizeof(txparams)) < 0) 386178354Ssam errx(1, "unable to get transmit parameters"); 387178354Ssam gottxparams = 1; 388178354Ssam} 389178354Ssam 390178354Ssamstatic void 391178354Ssamsettxparams_cb(int s, void *arg) 392178354Ssam{ 393178354Ssam struct ieee80211_txparams_req *txp = arg; 394178354Ssam set80211(s, IEEE80211_IOC_TXPARAMS, 0, sizeof(*txp), txp); 395178354Ssam} 396178354Ssam 397178354Ssamstatic void 398178354Ssamgetregdomain(int s) 399178354Ssam{ 400178354Ssam if (gotregdomain) 401178354Ssam return; 402178354Ssam if (get80211(s, IEEE80211_IOC_REGDOMAIN, 403178354Ssam ®domain, sizeof(regdomain)) < 0) 404178354Ssam errx(1, "unable to get regulatory domain info"); 405178354Ssam gotregdomain = 1; 406178354Ssam} 407178354Ssam 408178354Ssamstatic void 409178354Ssamgetdevcaps(int s, struct ieee80211_devcaps_req *dc) 410178354Ssam{ 411178354Ssam if (get80211(s, IEEE80211_IOC_DEVCAPS, dc, sizeof(*dc)) < 0) 412178354Ssam errx(1, "unable to get device capabilities"); 413178354Ssam} 414178354Ssam 415178354Ssamstatic void 416178354Ssamsetregdomain_cb(int s, void *arg) 417178354Ssam{ 418178354Ssam struct ieee80211_regdomain_req req; 419178354Ssam struct ieee80211_regdomain *rd = arg; 420178354Ssam struct ieee80211_devcaps_req dc; 421178354Ssam struct regdata *rdp = getregdata(); 422178354Ssam 423178354Ssam if (rd->country != 0) { 424178354Ssam const struct country *cc; 425178354Ssam /* 426178354Ssam * Check current country seting to make sure it's 427178354Ssam * compatible with the new regdomain. If not, then 428178354Ssam * override it with any default country for this 429178354Ssam * SKU. If we cannot arrange a match, then abort. 430178354Ssam */ 431178354Ssam cc = lib80211_country_findbycc(rdp, rd->country); 432178354Ssam if (cc == NULL) 433178354Ssam errx(1, "unknown ISO country code %d", rd->country); 434178354Ssam if (cc->rd->sku != rd->regdomain) { 435178354Ssam const struct regdomain *rp; 436178354Ssam /* 437178354Ssam * Check if country is incompatible with regdomain. 438178354Ssam * To enable multiple regdomains for a country code 439178354Ssam * we permit a mismatch between the regdomain and 440178354Ssam * the country's associated regdomain when the 441178354Ssam * regdomain is setup w/o a default country. For 442178354Ssam * example, US is bound to the FCC regdomain but 443178354Ssam * we allow US to be combined with FCC3 because FCC3 444178354Ssam * has not default country. This allows bogus 445178354Ssam * combinations like FCC3+DK which are resolved when 446178354Ssam * constructing the channel list by deferring to the 447178354Ssam * regdomain to construct the channel list. 448178354Ssam */ 449178354Ssam rp = lib80211_regdomain_findbysku(rdp, rd->regdomain); 450178354Ssam if (rp == NULL) 451178354Ssam errx(1, "country %s (%s) is not usable with " 452178354Ssam "regdomain %d", cc->isoname, cc->name, 453178354Ssam rd->regdomain); 454178354Ssam else if (rp->cc != 0 && rp->cc != cc) 455178354Ssam errx(1, "country %s (%s) is not usable with " 456178354Ssam "regdomain %s", cc->isoname, cc->name, 457178354Ssam rp->name); 458178354Ssam } 459178354Ssam } 460178354Ssam req.rd = *rd; 461178354Ssam /* 462178354Ssam * Fetch the device capabilities and calculate the 463178354Ssam * full set of netbands for which we request a new 464178354Ssam * channel list be constructed. Once that's done we 465178354Ssam * push the regdomain info + channel list to the kernel. 466178354Ssam */ 467178354Ssam getdevcaps(s, &dc); 468178354Ssam#if 0 469178354Ssam if (verbose) { 470178354Ssam printf("drivercaps: 0x%x\n", dc.dc_drivercaps); 471178354Ssam printf("cryptocaps: 0x%x\n", dc.dc_cryptocaps); 472178354Ssam printf("htcaps : 0x%x\n", dc.dc_htcaps); 473178354Ssam memcpy(&chaninfo, &dc.dc_chaninfo, sizeof(chaninfo)); 474178354Ssam print_channels(s, &dc.dc_chaninfo, 1/*allchans*/, 1/*verbose*/); 475178354Ssam } 476178354Ssam#endif 477178354Ssam regdomain_makechannels(&req, &dc); 478178354Ssam if (verbose) { 479178354Ssam LINE_INIT(':'); 480178354Ssam print_regdomain(rd, 1/*verbose*/); 481178354Ssam LINE_BREAK(); 482178354Ssam memcpy(&chaninfo, &req.chaninfo, sizeof(chaninfo)); 483178354Ssam print_channels(s, &req.chaninfo, 1/*allchans*/, 1/*verbose*/); 484178354Ssam } 485178354Ssam if (req.chaninfo.ic_nchans == 0) 486178354Ssam errx(1, "no channels calculated"); 487178354Ssam set80211(s, IEEE80211_IOC_REGDOMAIN, 0, sizeof(req), &req); 488178354Ssam} 489178354Ssam 490170531Ssamstatic int 491170531Ssamieee80211_mhz2ieee(int freq, int flags) 492170531Ssam{ 493170531Ssam struct ieee80211_channel chan; 494170531Ssam mapfreq(&chan, freq, flags); 495170531Ssam return chan.ic_ieee; 496170531Ssam} 497170531Ssam 498170531Ssamstatic int 499138593Ssamisanyarg(const char *arg) 500138593Ssam{ 501173275Ssam return (strncmp(arg, "-", 1) == 0 || 502173275Ssam strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0); 503138593Ssam} 504138593Ssam 505138593Ssamstatic void 50677218Sphkset80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 50777218Sphk{ 50877218Sphk int ssid; 50977218Sphk int len; 510151883Sbrooks u_int8_t data[IEEE80211_NWID_LEN]; 51177218Sphk 51277218Sphk ssid = 0; 513121827Sbrooks len = strlen(val); 514178354Ssam if (len > 2 && isdigit((int)val[0]) && val[1] == ':') { 51588748Sambrisko ssid = atoi(val)-1; 51688748Sambrisko val += 2; 51788748Sambrisko } 51877218Sphk 51977218Sphk bzero(data, sizeof(data)); 52077218Sphk len = sizeof(data); 521151883Sbrooks if (get_string(val, NULL, data, &len) == NULL) 522151883Sbrooks exit(1); 52377218Sphk 52477218Sphk set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 52577218Sphk} 52677218Sphk 527138593Ssamstatic void 52877218Sphkset80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 52977218Sphk{ 53077218Sphk int len; 53177218Sphk u_int8_t data[33]; 53277218Sphk 53377218Sphk bzero(data, sizeof(data)); 53477218Sphk len = sizeof(data); 53577218Sphk get_string(val, NULL, data, &len); 53677218Sphk 53777218Sphk set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 53877218Sphk} 53977218Sphk 540138593Ssam/* 541170531Ssam * Parse a channel specification for attributes/flags. 542170531Ssam * The syntax is: 543170531Ssam * freq/xx channel width (5,10,20,40,40+,40-) 544170531Ssam * freq:mode channel mode (a,b,g,h,n,t,s,d) 545170531Ssam * 546170531Ssam * These can be combined in either order; e.g. 2437:ng/40. 547170531Ssam * Modes are case insensitive. 548170531Ssam * 549170531Ssam * The result is not validated here; it's assumed to be 550170531Ssam * checked against the channel table fetched from the kernel. 551170531Ssam */ 552170531Ssamstatic int 553173275Ssamgetchannelflags(const char *val, int freq) 554138593Ssam{ 555170531Ssam#define _CHAN_HT 0x80000000 556170531Ssam const char *cp; 557170531Ssam int flags; 558138593Ssam 559170531Ssam flags = 0; 560166015Ssam 561170531Ssam cp = strchr(val, ':'); 562170531Ssam if (cp != NULL) { 563170531Ssam for (cp++; isalpha((int) *cp); cp++) { 564170531Ssam /* accept mixed case */ 565170531Ssam int c = *cp; 566170531Ssam if (isupper(c)) 567170531Ssam c = tolower(c); 568170531Ssam switch (c) { 569170531Ssam case 'a': /* 802.11a */ 570170531Ssam flags |= IEEE80211_CHAN_A; 571170531Ssam break; 572170531Ssam case 'b': /* 802.11b */ 573170531Ssam flags |= IEEE80211_CHAN_B; 574170531Ssam break; 575170531Ssam case 'g': /* 802.11g */ 576170531Ssam flags |= IEEE80211_CHAN_G; 577170531Ssam break; 578170531Ssam case 'h': /* ht = 802.11n */ 579170531Ssam case 'n': /* 802.11n */ 580170531Ssam flags |= _CHAN_HT; /* NB: private */ 581170531Ssam break; 582170531Ssam case 'd': /* dt = Atheros Dynamic Turbo */ 583170531Ssam flags |= IEEE80211_CHAN_TURBO; 584170531Ssam break; 585170531Ssam case 't': /* ht, dt, st, t */ 586170531Ssam /* dt and unadorned t specify Dynamic Turbo */ 587170531Ssam if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0) 588170531Ssam flags |= IEEE80211_CHAN_TURBO; 589170531Ssam break; 590170531Ssam case 's': /* st = Atheros Static Turbo */ 591170531Ssam flags |= IEEE80211_CHAN_STURBO; 592170531Ssam break; 593170531Ssam default: 594173275Ssam errx(-1, "%s: Invalid channel attribute %c\n", 595170531Ssam val, *cp); 596170531Ssam } 597170531Ssam } 598170531Ssam } 599170531Ssam cp = strchr(val, '/'); 600170531Ssam if (cp != NULL) { 601170531Ssam char *ep; 602170531Ssam u_long cw = strtoul(cp+1, &ep, 10); 603166015Ssam 604170531Ssam switch (cw) { 605170531Ssam case 5: 606170531Ssam flags |= IEEE80211_CHAN_QUARTER; 607170531Ssam break; 608170531Ssam case 10: 609170531Ssam flags |= IEEE80211_CHAN_HALF; 610170531Ssam break; 611170531Ssam case 20: 612170531Ssam /* NB: this may be removed below */ 613170531Ssam flags |= IEEE80211_CHAN_HT20; 614170531Ssam break; 615170531Ssam case 40: 616170531Ssam if (ep != NULL && *ep == '+') 617170531Ssam flags |= IEEE80211_CHAN_HT40U; 618170531Ssam else if (ep != NULL && *ep == '-') 619170531Ssam flags |= IEEE80211_CHAN_HT40D; 620170531Ssam break; 621170531Ssam default: 622173275Ssam errx(-1, "%s: Invalid channel width\n", val); 623170531Ssam } 624165570Ssam } 625170531Ssam /* 626170531Ssam * Cleanup specifications. 627170531Ssam */ 628170531Ssam if ((flags & _CHAN_HT) == 0) { 629170531Ssam /* 630170531Ssam * If user specified freq/20 or freq/40 quietly remove 631170531Ssam * HT cw attributes depending on channel use. To give 632170531Ssam * an explicit 20/40 width for an HT channel you must 633170531Ssam * indicate it is an HT channel since all HT channels 634170531Ssam * are also usable for legacy operation; e.g. freq:n/40. 635170531Ssam */ 636170531Ssam flags &= ~IEEE80211_CHAN_HT; 637170531Ssam } else { 638170531Ssam /* 639170531Ssam * Remove private indicator that this is an HT channel 640170531Ssam * and if no explicit channel width has been given 641170531Ssam * provide the default settings. 642170531Ssam */ 643170531Ssam flags &= ~_CHAN_HT; 644173275Ssam if ((flags & IEEE80211_CHAN_HT) == 0) { 645173275Ssam struct ieee80211_channel chan; 646173275Ssam /* 647173275Ssam * Consult the channel list to see if we can use 648173275Ssam * HT40+ or HT40- (if both the map routines choose). 649173275Ssam */ 650173275Ssam if (freq > 255) 651173275Ssam mapfreq(&chan, freq, 0); 652173275Ssam else 653173275Ssam mapchan(&chan, freq, 0); 654173275Ssam flags |= (chan.ic_flags & IEEE80211_CHAN_HT); 655173275Ssam } 656170531Ssam } 657170531Ssam return flags; 658170531Ssam#undef _CHAN_HT 659138593Ssam} 660138593Ssam 661138593Ssamstatic void 66277218Sphkset80211channel(const char *val, int d, int s, const struct afswtch *rafp) 66377218Sphk{ 664170531Ssam struct ieee80211_channel chan; 665170531Ssam 666170531Ssam memset(&chan, 0, sizeof(chan)); 667138593Ssam if (!isanyarg(val)) { 668173275Ssam int v, flags; 669179958Sthompsa char *ep; 670170531Ssam 671170531Ssam getchaninfo(s); 672179958Sthompsa v = strtol(val, &ep, 10); 673179958Sthompsa if (val[0] == '\0' || ep[0] != '\0' || errno == ERANGE) 674179958Sthompsa errx(1, "invalid channel number"); 675173275Ssam flags = getchannelflags(val, v); 676170531Ssam if (v > 255) { /* treat as frequency */ 677170531Ssam mapfreq(&chan, v, flags); 678170531Ssam } else { 679170531Ssam mapchan(&chan, v, flags); 680170531Ssam } 681170531Ssam } else { 682170531Ssam chan.ic_freq = IEEE80211_CHAN_ANY; 683170531Ssam } 684170531Ssam set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan); 68577218Sphk} 68677218Sphk 687138593Ssamstatic void 688178354Ssamset80211chanswitch(const char *val, int d, int s, const struct afswtch *rafp) 689178354Ssam{ 690178354Ssam struct ieee80211_chanswitch_req csr; 691178354Ssam int v, flags; 692178354Ssam 693178354Ssam memset(&csr, 0, sizeof(csr)); 694178354Ssam getchaninfo(s); 695178354Ssam v = atoi(val); 696178354Ssam flags = getchannelflags(val, v); 697178354Ssam if (v > 255) { /* treat as frequency */ 698178354Ssam mapfreq(&csr.csa_chan, v, flags); 699178354Ssam } else { 700178354Ssam mapchan(&csr.csa_chan, v, flags); 701178354Ssam } 702178354Ssam csr.csa_mode = 1; 703178354Ssam csr.csa_count = 5; 704178354Ssam set80211(s, IEEE80211_IOC_CHANSWITCH, 0, sizeof(csr), &csr); 705178354Ssam} 706178354Ssam 707178354Ssamstatic void 70877218Sphkset80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 70977218Sphk{ 71077218Sphk int mode; 71177218Sphk 71291454Sbrooks if (strcasecmp(val, "none") == 0) { 71377218Sphk mode = IEEE80211_AUTH_NONE; 71491454Sbrooks } else if (strcasecmp(val, "open") == 0) { 71577218Sphk mode = IEEE80211_AUTH_OPEN; 71691454Sbrooks } else if (strcasecmp(val, "shared") == 0) { 71777218Sphk mode = IEEE80211_AUTH_SHARED; 718138593Ssam } else if (strcasecmp(val, "8021x") == 0) { 719138593Ssam mode = IEEE80211_AUTH_8021X; 720138593Ssam } else if (strcasecmp(val, "wpa") == 0) { 721138593Ssam mode = IEEE80211_AUTH_WPA; 72277218Sphk } else { 723150708Sru errx(1, "unknown authmode"); 72477218Sphk } 72577218Sphk 72677218Sphk set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 72777218Sphk} 72877218Sphk 729138593Ssamstatic void 73077218Sphkset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 73177218Sphk{ 73277218Sphk int mode; 73377218Sphk 73491454Sbrooks if (strcasecmp(val, "off") == 0) { 73577218Sphk mode = IEEE80211_POWERSAVE_OFF; 73691454Sbrooks } else if (strcasecmp(val, "on") == 0) { 73777218Sphk mode = IEEE80211_POWERSAVE_ON; 73891454Sbrooks } else if (strcasecmp(val, "cam") == 0) { 73977218Sphk mode = IEEE80211_POWERSAVE_CAM; 74091454Sbrooks } else if (strcasecmp(val, "psp") == 0) { 74177218Sphk mode = IEEE80211_POWERSAVE_PSP; 74291454Sbrooks } else if (strcasecmp(val, "psp-cam") == 0) { 74377218Sphk mode = IEEE80211_POWERSAVE_PSP_CAM; 74477218Sphk } else { 745150708Sru errx(1, "unknown powersavemode"); 74677218Sphk } 74777218Sphk 74877218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 74977218Sphk} 75077218Sphk 751138593Ssamstatic void 75277218Sphkset80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 75377218Sphk{ 75477218Sphk if (d == 0) 75577218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 75677218Sphk 0, NULL); 75777218Sphk else 75877218Sphk set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 75977218Sphk 0, NULL); 76077218Sphk} 76177218Sphk 762138593Ssamstatic void 76377218Sphkset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 76477218Sphk{ 76577218Sphk set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 76677218Sphk} 76777218Sphk 768138593Ssamstatic void 76977218Sphkset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 77077218Sphk{ 77177218Sphk int mode; 77277218Sphk 77391454Sbrooks if (strcasecmp(val, "off") == 0) { 77477218Sphk mode = IEEE80211_WEP_OFF; 77591454Sbrooks } else if (strcasecmp(val, "on") == 0) { 77677218Sphk mode = IEEE80211_WEP_ON; 77791454Sbrooks } else if (strcasecmp(val, "mixed") == 0) { 77877218Sphk mode = IEEE80211_WEP_MIXED; 77977218Sphk } else { 780150708Sru errx(1, "unknown wep mode"); 78177218Sphk } 78277218Sphk 78377218Sphk set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 78477218Sphk} 78577218Sphk 786138593Ssamstatic void 78777218Sphkset80211wep(const char *val, int d, int s, const struct afswtch *rafp) 78877218Sphk{ 78977218Sphk set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 79077218Sphk} 79177218Sphk 792139493Ssamstatic int 793139493Ssamisundefarg(const char *arg) 794139493Ssam{ 795139493Ssam return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 796139493Ssam} 797139493Ssam 798138593Ssamstatic void 79977218Sphkset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 80077218Sphk{ 801139493Ssam if (isundefarg(val)) 802139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 803139493Ssam else 804139493Ssam set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 80577218Sphk} 80677218Sphk 807138593Ssamstatic void 80877218Sphkset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 80977218Sphk{ 81077218Sphk int key = 0; 81177218Sphk int len; 812120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 81377218Sphk 814178354Ssam if (isdigit((int)val[0]) && val[1] == ':') { 81577218Sphk key = atoi(val)-1; 81677218Sphk val += 2; 81777218Sphk } 81877218Sphk 81977218Sphk bzero(data, sizeof(data)); 82077218Sphk len = sizeof(data); 82177218Sphk get_string(val, NULL, data, &len); 82277218Sphk 82377218Sphk set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 82477218Sphk} 82577218Sphk 82677218Sphk/* 827148686Sstefanf * This function is purely a NetBSD compatability interface. The NetBSD 828148686Sstefanf * interface is too inflexible, but it's there so we'll support it since 82977218Sphk * it's not all that hard. 83077218Sphk */ 831138593Ssamstatic void 83277218Sphkset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 83377218Sphk{ 83477218Sphk int txkey; 83577218Sphk int i, len; 836120178Ssam u_int8_t data[IEEE80211_KEYBUF_SIZE]; 83777218Sphk 83877218Sphk set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 83977218Sphk 840178354Ssam if (isdigit((int)val[0]) && val[1] == ':') { 84177218Sphk txkey = val[0]-'0'-1; 84277218Sphk val += 2; 84377218Sphk 84491454Sbrooks for (i = 0; i < 4; i++) { 84577218Sphk bzero(data, sizeof(data)); 84677218Sphk len = sizeof(data); 84777218Sphk val = get_string(val, ",", data, &len); 848151827Sbrooks if (val == NULL) 849151827Sbrooks exit(1); 85077218Sphk 85177218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 85277218Sphk } 85377218Sphk } else { 85477218Sphk bzero(data, sizeof(data)); 85577218Sphk len = sizeof(data); 85677218Sphk get_string(val, NULL, data, &len); 85777218Sphk txkey = 0; 85877218Sphk 85977218Sphk set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 86077218Sphk 86177218Sphk bzero(data, sizeof(data)); 86291454Sbrooks for (i = 1; i < 4; i++) 86377218Sphk set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 86477218Sphk } 86577218Sphk 86677218Sphk set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 86777218Sphk} 86877218Sphk 869138593Ssamstatic void 870127649Ssamset80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 871127649Ssam{ 872148416Ssam set80211(s, IEEE80211_IOC_RTSTHRESHOLD, 873148416Ssam isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL); 874127649Ssam} 875127649Ssam 876138593Ssamstatic void 877127649Ssamset80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 878127649Ssam{ 879127649Ssam int mode; 880127649Ssam 881127649Ssam if (strcasecmp(val, "off") == 0) { 882127649Ssam mode = IEEE80211_PROTMODE_OFF; 883127649Ssam } else if (strcasecmp(val, "cts") == 0) { 884127649Ssam mode = IEEE80211_PROTMODE_CTS; 885173275Ssam } else if (strncasecmp(val, "rtscts", 3) == 0) { 886127649Ssam mode = IEEE80211_PROTMODE_RTSCTS; 887127649Ssam } else { 888150708Sru errx(1, "unknown protection mode"); 889127649Ssam } 890127649Ssam 891127649Ssam set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 892127649Ssam} 893127649Ssam 894138593Ssamstatic void 895173275Ssamset80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp) 896173275Ssam{ 897173275Ssam int mode; 898173275Ssam 899173275Ssam if (strcasecmp(val, "off") == 0) { 900173275Ssam mode = IEEE80211_PROTMODE_OFF; 901173275Ssam } else if (strncasecmp(val, "rts", 3) == 0) { 902173275Ssam mode = IEEE80211_PROTMODE_RTSCTS; 903173275Ssam } else { 904173275Ssam errx(1, "unknown protection mode"); 905173275Ssam } 906173275Ssam 907173275Ssam set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL); 908173275Ssam} 909173275Ssam 910173275Ssamstatic void 911127649Ssamset80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 912127649Ssam{ 913173275Ssam double v = atof(val); 914173275Ssam int txpow; 915173275Ssam 916173275Ssam txpow = (int) (2*v); 917173275Ssam if (txpow != 2*v) 918173275Ssam errx(-1, "invalid tx power (must be .5 dBm units)"); 919173275Ssam set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL); 920127649Ssam} 921127649Ssam 922138593Ssam#define IEEE80211_ROAMING_DEVICE 0 923138593Ssam#define IEEE80211_ROAMING_AUTO 1 924138593Ssam#define IEEE80211_ROAMING_MANUAL 2 925138593Ssam 926138593Ssamstatic void 927138593Ssamset80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 92877218Sphk{ 929138593Ssam int mode; 93077218Sphk 931138593Ssam if (strcasecmp(val, "device") == 0) { 932138593Ssam mode = IEEE80211_ROAMING_DEVICE; 933138593Ssam } else if (strcasecmp(val, "auto") == 0) { 934138593Ssam mode = IEEE80211_ROAMING_AUTO; 935138593Ssam } else if (strcasecmp(val, "manual") == 0) { 936138593Ssam mode = IEEE80211_ROAMING_MANUAL; 937138593Ssam } else { 938150708Sru errx(1, "unknown roaming mode"); 939138593Ssam } 940138593Ssam set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 941138593Ssam} 942138593Ssam 943138593Ssamstatic void 944138593Ssamset80211wme(const char *val, int d, int s, const struct afswtch *rafp) 945138593Ssam{ 946138593Ssam set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 947138593Ssam} 948138593Ssam 949138593Ssamstatic void 950138593Ssamset80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 951138593Ssam{ 952138593Ssam set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 953138593Ssam} 954138593Ssam 955138593Ssamstatic void 956138593Ssamset80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 957138593Ssam{ 958138593Ssam set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 959138593Ssam} 960138593Ssam 961138593Ssamstatic void 962170531Ssamset80211fastframes(const char *val, int d, int s, const struct afswtch *rafp) 963170531Ssam{ 964170531Ssam set80211(s, IEEE80211_IOC_FF, d, 0, NULL); 965170531Ssam} 966170531Ssam 967170531Ssamstatic void 968170531Ssamset80211dturbo(const char *val, int d, int s, const struct afswtch *rafp) 969170531Ssam{ 970170531Ssam set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL); 971170531Ssam} 972170531Ssam 973170531Ssamstatic void 974138593Ssamset80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 975138593Ssam{ 976138593Ssam struct ieee80211req_chanlist chanlist; 977138593Ssam#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY) 978138593Ssam char *temp, *cp, *tp; 979138593Ssam 980138593Ssam temp = malloc(strlen(val) + 1); 981138593Ssam if (temp == NULL) 982138593Ssam errx(1, "malloc failed"); 983138593Ssam strcpy(temp, val); 984138593Ssam memset(&chanlist, 0, sizeof(chanlist)); 985138593Ssam cp = temp; 986138593Ssam for (;;) { 987173275Ssam int first, last, f, c; 988138593Ssam 989138593Ssam tp = strchr(cp, ','); 990138593Ssam if (tp != NULL) 991138593Ssam *tp++ = '\0'; 992138593Ssam switch (sscanf(cp, "%u-%u", &first, &last)) { 993138593Ssam case 1: 994138593Ssam if (first > MAXCHAN) 995146873Sjhb errx(-1, "channel %u out of range, max %zu", 996138593Ssam first, MAXCHAN); 997138593Ssam setbit(chanlist.ic_channels, first); 998138593Ssam break; 999138593Ssam case 2: 1000138593Ssam if (first > MAXCHAN) 1001146873Sjhb errx(-1, "channel %u out of range, max %zu", 1002138593Ssam first, MAXCHAN); 1003138593Ssam if (last > MAXCHAN) 1004146873Sjhb errx(-1, "channel %u out of range, max %zu", 1005138593Ssam last, MAXCHAN); 1006138593Ssam if (first > last) 1007138593Ssam errx(-1, "void channel range, %u > %u", 1008138593Ssam first, last); 1009138593Ssam for (f = first; f <= last; f++) 1010138593Ssam setbit(chanlist.ic_channels, f); 1011138593Ssam break; 1012138593Ssam } 1013138593Ssam if (tp == NULL) 1014138593Ssam break; 1015173275Ssam c = *tp; 1016173275Ssam while (isspace(c)) 1017138593Ssam tp++; 1018173275Ssam if (!isdigit(c)) 1019138593Ssam break; 1020138593Ssam cp = tp; 1021138593Ssam } 1022170531Ssam set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist); 1023138593Ssam#undef MAXCHAN 1024138593Ssam} 1025138593Ssam 1026138593Ssamstatic void 1027138593Ssamset80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 1028138593Ssam{ 1029138593Ssam 1030138593Ssam if (!isanyarg(val)) { 1031138593Ssam char *temp; 1032138593Ssam struct sockaddr_dl sdl; 1033138593Ssam 1034155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 1035138593Ssam if (temp == NULL) 1036138593Ssam errx(1, "malloc failed"); 1037138593Ssam temp[0] = ':'; 1038138593Ssam strcpy(temp + 1, val); 1039138593Ssam sdl.sdl_len = sizeof(sdl); 1040138593Ssam link_addr(temp, &sdl); 1041138593Ssam free(temp); 1042138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 1043138593Ssam errx(1, "malformed link-level address"); 1044138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 1045138593Ssam IEEE80211_ADDR_LEN, LLADDR(&sdl)); 1046138593Ssam } else { 1047138593Ssam uint8_t zerobssid[IEEE80211_ADDR_LEN]; 1048138593Ssam memset(zerobssid, 0, sizeof(zerobssid)); 1049138593Ssam set80211(s, IEEE80211_IOC_BSSID, 0, 1050138593Ssam IEEE80211_ADDR_LEN, zerobssid); 1051138593Ssam } 1052138593Ssam} 1053138593Ssam 1054138593Ssamstatic int 1055138593Ssamgetac(const char *ac) 1056138593Ssam{ 1057138593Ssam if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 1058138593Ssam return WME_AC_BE; 1059138593Ssam if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 1060138593Ssam return WME_AC_BK; 1061138593Ssam if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 1062138593Ssam return WME_AC_VI; 1063138593Ssam if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 1064138593Ssam return WME_AC_VO; 1065138593Ssam errx(1, "unknown wme access class %s", ac); 1066138593Ssam} 1067138593Ssam 1068138593Ssamstatic 1069138593SsamDECL_CMD_FUNC2(set80211cwmin, ac, val) 1070138593Ssam{ 1071138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 1072138593Ssam} 1073138593Ssam 1074138593Ssamstatic 1075138593SsamDECL_CMD_FUNC2(set80211cwmax, ac, val) 1076138593Ssam{ 1077138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 1078138593Ssam} 1079138593Ssam 1080138593Ssamstatic 1081138593SsamDECL_CMD_FUNC2(set80211aifs, ac, val) 1082138593Ssam{ 1083138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 1084138593Ssam} 1085138593Ssam 1086138593Ssamstatic 1087138593SsamDECL_CMD_FUNC2(set80211txoplimit, ac, val) 1088138593Ssam{ 1089138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 1090138593Ssam} 1091138593Ssam 1092138593Ssamstatic 1093148621SsamDECL_CMD_FUNC(set80211acm, ac, d) 1094138593Ssam{ 1095148621Ssam set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL); 1096138593Ssam} 1097148621Ssamstatic 1098148621SsamDECL_CMD_FUNC(set80211noacm, ac, d) 1099148621Ssam{ 1100148621Ssam set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL); 1101148621Ssam} 1102138593Ssam 1103138593Ssamstatic 1104148621SsamDECL_CMD_FUNC(set80211ackpolicy, ac, d) 1105138593Ssam{ 1106148621Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL); 1107138593Ssam} 1108148621Ssamstatic 1109148621SsamDECL_CMD_FUNC(set80211noackpolicy, ac, d) 1110148621Ssam{ 1111148621Ssam set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL); 1112148621Ssam} 1113138593Ssam 1114138593Ssamstatic 1115138593SsamDECL_CMD_FUNC2(set80211bsscwmin, ac, val) 1116138593Ssam{ 1117138593Ssam set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 1118138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 1119138593Ssam} 1120138593Ssam 1121138593Ssamstatic 1122138593SsamDECL_CMD_FUNC2(set80211bsscwmax, ac, val) 1123138593Ssam{ 1124138593Ssam set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 1125138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 1126138593Ssam} 1127138593Ssam 1128138593Ssamstatic 1129138593SsamDECL_CMD_FUNC2(set80211bssaifs, ac, val) 1130138593Ssam{ 1131138593Ssam set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 1132138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 1133138593Ssam} 1134138593Ssam 1135138593Ssamstatic 1136138593SsamDECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 1137138593Ssam{ 1138138593Ssam set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 1139138593Ssam getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 1140138593Ssam} 1141138593Ssam 1142138593Ssamstatic 1143138593SsamDECL_CMD_FUNC(set80211dtimperiod, val, d) 1144138593Ssam{ 1145138593Ssam set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 1146138593Ssam} 1147138593Ssam 1148138593Ssamstatic 1149138593SsamDECL_CMD_FUNC(set80211bintval, val, d) 1150138593Ssam{ 1151138593Ssam set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 1152138593Ssam} 1153138593Ssam 1154138593Ssamstatic void 1155138593Ssamset80211macmac(int s, int op, const char *val) 1156138593Ssam{ 1157138593Ssam char *temp; 1158138593Ssam struct sockaddr_dl sdl; 1159138593Ssam 1160155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 1161138593Ssam if (temp == NULL) 1162138593Ssam errx(1, "malloc failed"); 1163138593Ssam temp[0] = ':'; 1164138593Ssam strcpy(temp + 1, val); 1165138593Ssam sdl.sdl_len = sizeof(sdl); 1166138593Ssam link_addr(temp, &sdl); 1167138593Ssam free(temp); 1168138593Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 1169138593Ssam errx(1, "malformed link-level address"); 1170138593Ssam set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 1171138593Ssam} 1172138593Ssam 1173138593Ssamstatic 1174138593SsamDECL_CMD_FUNC(set80211addmac, val, d) 1175138593Ssam{ 1176138593Ssam set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 1177138593Ssam} 1178138593Ssam 1179138593Ssamstatic 1180138593SsamDECL_CMD_FUNC(set80211delmac, val, d) 1181138593Ssam{ 1182138593Ssam set80211macmac(s, IEEE80211_IOC_DELMAC, val); 1183138593Ssam} 1184138593Ssam 1185138593Ssamstatic 1186149029SsamDECL_CMD_FUNC(set80211kickmac, val, d) 1187149029Ssam{ 1188149029Ssam char *temp; 1189149029Ssam struct sockaddr_dl sdl; 1190149029Ssam struct ieee80211req_mlme mlme; 1191149029Ssam 1192155702Ssam temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 1193149029Ssam if (temp == NULL) 1194149029Ssam errx(1, "malloc failed"); 1195149029Ssam temp[0] = ':'; 1196149029Ssam strcpy(temp + 1, val); 1197149029Ssam sdl.sdl_len = sizeof(sdl); 1198149029Ssam link_addr(temp, &sdl); 1199149029Ssam free(temp); 1200149029Ssam if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 1201149029Ssam errx(1, "malformed link-level address"); 1202149029Ssam memset(&mlme, 0, sizeof(mlme)); 1203149029Ssam mlme.im_op = IEEE80211_MLME_DEAUTH; 1204149029Ssam mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; 1205149029Ssam memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN); 1206170531Ssam set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme); 1207149029Ssam} 1208149029Ssam 1209149029Ssamstatic 1210138593SsamDECL_CMD_FUNC(set80211maccmd, val, d) 1211138593Ssam{ 1212138593Ssam set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 1213138593Ssam} 1214138593Ssam 1215147795Ssamstatic void 1216147795Ssamset80211pureg(const char *val, int d, int s, const struct afswtch *rafp) 1217147795Ssam{ 1218147795Ssam set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); 1219147795Ssam} 1220147795Ssam 1221153422Ssamstatic void 1222170531Ssamset80211bgscan(const char *val, int d, int s, const struct afswtch *rafp) 1223153422Ssam{ 1224170531Ssam set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL); 1225153422Ssam} 1226153422Ssam 1227148416Ssamstatic 1228170531SsamDECL_CMD_FUNC(set80211bgscanidle, val, d) 1229170531Ssam{ 1230170531Ssam set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL); 1231170531Ssam} 1232170531Ssam 1233170531Ssamstatic 1234170531SsamDECL_CMD_FUNC(set80211bgscanintvl, val, d) 1235170531Ssam{ 1236170531Ssam set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL); 1237170531Ssam} 1238170531Ssam 1239170531Ssamstatic 1240170531SsamDECL_CMD_FUNC(set80211scanvalid, val, d) 1241170531Ssam{ 1242170531Ssam set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL); 1243170531Ssam} 1244170531Ssam 1245178354Ssam/* 1246178354Ssam * Parse an optional trailing specification of which netbands 1247178354Ssam * to apply a parameter to. This is basically the same syntax 1248178354Ssam * as used for channels but you can concatenate to specify 1249178354Ssam * multiple. For example: 1250178354Ssam * 14:abg apply to 11a, 11b, and 11g 1251178354Ssam * 6:ht apply to 11na and 11ng 1252178354Ssam * We don't make a big effort to catch silly things; this is 1253178354Ssam * really a convenience mechanism. 1254178354Ssam */ 1255178354Ssamstatic int 1256178354Ssamgetmodeflags(const char *val) 1257170531Ssam{ 1258178354Ssam const char *cp; 1259178354Ssam int flags; 1260178354Ssam 1261178354Ssam flags = 0; 1262178354Ssam 1263178354Ssam cp = strchr(val, ':'); 1264178354Ssam if (cp != NULL) { 1265178354Ssam for (cp++; isalpha((int) *cp); cp++) { 1266178354Ssam /* accept mixed case */ 1267178354Ssam int c = *cp; 1268178354Ssam if (isupper(c)) 1269178354Ssam c = tolower(c); 1270178354Ssam switch (c) { 1271178354Ssam case 'a': /* 802.11a */ 1272178354Ssam flags |= IEEE80211_CHAN_A; 1273178354Ssam break; 1274178354Ssam case 'b': /* 802.11b */ 1275178354Ssam flags |= IEEE80211_CHAN_B; 1276178354Ssam break; 1277178354Ssam case 'g': /* 802.11g */ 1278178354Ssam flags |= IEEE80211_CHAN_G; 1279178354Ssam break; 1280178354Ssam case 'h': /* ht = 802.11n */ 1281178354Ssam case 'n': /* 802.11n */ 1282178354Ssam flags |= IEEE80211_CHAN_HT; 1283178354Ssam break; 1284178354Ssam case 'd': /* dt = Atheros Dynamic Turbo */ 1285178354Ssam flags |= IEEE80211_CHAN_TURBO; 1286178354Ssam break; 1287178354Ssam case 't': /* ht, dt, st, t */ 1288178354Ssam /* dt and unadorned t specify Dynamic Turbo */ 1289178354Ssam if ((flags & (IEEE80211_CHAN_STURBO|IEEE80211_CHAN_HT)) == 0) 1290178354Ssam flags |= IEEE80211_CHAN_TURBO; 1291178354Ssam break; 1292178354Ssam case 's': /* st = Atheros Static Turbo */ 1293178354Ssam flags |= IEEE80211_CHAN_STURBO; 1294178354Ssam break; 1295178354Ssam default: 1296178354Ssam errx(-1, "%s: Invalid mode attribute %c\n", 1297178354Ssam val, *cp); 1298178354Ssam } 1299178354Ssam } 1300178354Ssam } 1301178354Ssam return flags; 1302170531Ssam} 1303170531Ssam 1304178354Ssam#define IEEE80211_CHAN_HTA (IEEE80211_CHAN_HT|IEEE80211_CHAN_5GHZ) 1305178354Ssam#define IEEE80211_CHAN_HTG (IEEE80211_CHAN_HT|IEEE80211_CHAN_2GHZ) 1306178354Ssam 1307178354Ssam#define _APPLY(_flags, _base, _param, _v) do { \ 1308178354Ssam if (_flags & IEEE80211_CHAN_HT) { \ 1309178354Ssam if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\ 1310178354Ssam _base.params[IEEE80211_MODE_11NA]._param = _v; \ 1311178354Ssam _base.params[IEEE80211_MODE_11NG]._param = _v; \ 1312178354Ssam } else if (_flags & IEEE80211_CHAN_5GHZ) \ 1313178354Ssam _base.params[IEEE80211_MODE_11NA]._param = _v; \ 1314178354Ssam else \ 1315178354Ssam _base.params[IEEE80211_MODE_11NG]._param = _v; \ 1316178354Ssam } \ 1317178354Ssam if (_flags & IEEE80211_CHAN_TURBO) { \ 1318178354Ssam if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\ 1319178354Ssam _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ 1320178354Ssam _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ 1321178354Ssam } else if (_flags & IEEE80211_CHAN_5GHZ) \ 1322178354Ssam _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ 1323178354Ssam else \ 1324178354Ssam _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ 1325178354Ssam } \ 1326178354Ssam if (_flags & IEEE80211_CHAN_STURBO) \ 1327178354Ssam _base.params[IEEE80211_MODE_STURBO_A]._param = _v; \ 1328178354Ssam if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \ 1329178354Ssam _base.params[IEEE80211_MODE_11A]._param = _v; \ 1330178354Ssam if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \ 1331178354Ssam _base.params[IEEE80211_MODE_11G]._param = _v; \ 1332178354Ssam if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \ 1333178354Ssam _base.params[IEEE80211_MODE_11B]._param = _v; \ 1334178354Ssam} while (0) 1335178354Ssam#define _APPLY1(_flags, _base, _param, _v) do { \ 1336178354Ssam if (_flags & IEEE80211_CHAN_HT) { \ 1337178354Ssam if (_flags & IEEE80211_CHAN_5GHZ) \ 1338178354Ssam _base.params[IEEE80211_MODE_11NA]._param = _v; \ 1339178354Ssam else \ 1340178354Ssam _base.params[IEEE80211_MODE_11NG]._param = _v; \ 1341178354Ssam } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) \ 1342178354Ssam _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ 1343178354Ssam else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) \ 1344178354Ssam _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ 1345178354Ssam else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) \ 1346178354Ssam _base.params[IEEE80211_MODE_STURBO_A]._param = _v; \ 1347178354Ssam else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \ 1348178354Ssam _base.params[IEEE80211_MODE_11A]._param = _v; \ 1349178354Ssam else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \ 1350178354Ssam _base.params[IEEE80211_MODE_11G]._param = _v; \ 1351178354Ssam else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \ 1352178354Ssam _base.params[IEEE80211_MODE_11B]._param = _v; \ 1353178354Ssam} while (0) 1354178354Ssam#define _APPLY_RATE(_flags, _base, _param, _v) do { \ 1355178354Ssam if (_flags & IEEE80211_CHAN_HT) { \ 1356178354Ssam if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\ 1357178354Ssam _base.params[IEEE80211_MODE_11NA]._param = _v|0x80; \ 1358178354Ssam _base.params[IEEE80211_MODE_11NG]._param = _v|0x80; \ 1359178354Ssam } else if (_flags & IEEE80211_CHAN_5GHZ) \ 1360178354Ssam _base.params[IEEE80211_MODE_11NA]._param = _v|0x80; \ 1361178354Ssam else \ 1362178354Ssam _base.params[IEEE80211_MODE_11NG]._param = _v|0x80; \ 1363178354Ssam } \ 1364178354Ssam if (_flags & IEEE80211_CHAN_TURBO) { \ 1365178354Ssam if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\ 1366178354Ssam _base.params[IEEE80211_MODE_TURBO_A]._param = 2*_v; \ 1367178354Ssam _base.params[IEEE80211_MODE_TURBO_G]._param = 2*_v; \ 1368178354Ssam } else if (_flags & IEEE80211_CHAN_5GHZ) \ 1369178354Ssam _base.params[IEEE80211_MODE_TURBO_A]._param = 2*_v; \ 1370178354Ssam else \ 1371178354Ssam _base.params[IEEE80211_MODE_TURBO_G]._param = 2*_v; \ 1372178354Ssam } \ 1373178354Ssam if (_flags & IEEE80211_CHAN_STURBO) \ 1374178354Ssam _base.params[IEEE80211_MODE_STURBO_A]._param = 2*_v; \ 1375178354Ssam if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \ 1376178354Ssam _base.params[IEEE80211_MODE_11A]._param = 2*_v; \ 1377178354Ssam if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \ 1378178354Ssam _base.params[IEEE80211_MODE_11G]._param = (_v == 5 ? 11 : 2*_v);\ 1379178354Ssam if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \ 1380178354Ssam _base.params[IEEE80211_MODE_11B]._param = (_v == 5 ? 11 : 2*_v);\ 1381178354Ssam} while (0) 1382178354Ssam#define _APPLY_RATE1(_flags, _base, _param, _v) do { \ 1383178354Ssam if (_flags & IEEE80211_CHAN_HT) { \ 1384178354Ssam if (_flags & IEEE80211_CHAN_5GHZ) \ 1385178354Ssam _base.params[IEEE80211_MODE_11NA]._param = _v|0x80; \ 1386178354Ssam else \ 1387178354Ssam _base.params[IEEE80211_MODE_11NG]._param = _v|0x80; \ 1388178354Ssam } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) \ 1389178354Ssam _base.params[IEEE80211_MODE_TURBO_A]._param = 2*_v; \ 1390178354Ssam else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) \ 1391178354Ssam _base.params[IEEE80211_MODE_TURBO_G]._param = 2*_v; \ 1392178354Ssam else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) \ 1393178354Ssam _base.params[IEEE80211_MODE_STURBO_A]._param = 2*_v; \ 1394178354Ssam else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \ 1395178354Ssam _base.params[IEEE80211_MODE_11A]._param = 2*_v; \ 1396178354Ssam else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \ 1397178354Ssam _base.params[IEEE80211_MODE_11G]._param = (_v == 5 ? 11 : 2*_v);\ 1398178354Ssam else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \ 1399178354Ssam _base.params[IEEE80211_MODE_11B]._param = (_v == 5 ? 11 : 2*_v);\ 1400178354Ssam} while (0) 1401178354Ssam 1402170531Ssamstatic 1403178354SsamDECL_CMD_FUNC(set80211roamrssi, val, d) 1404170531Ssam{ 1405178354Ssam double v = atof(val); 1406178354Ssam int rssi, flags; 1407178354Ssam 1408178354Ssam rssi = (int) (2*v); 1409178354Ssam if (rssi != 2*v) 1410178354Ssam errx(-1, "invalid rssi (must be .5 dBm units)"); 1411178354Ssam flags = getmodeflags(val); 1412178354Ssam getroam(s); 1413178354Ssam if (flags == 0) { /* NB: no flags => current channel */ 1414178354Ssam flags = getcurchan(s)->ic_flags; 1415178354Ssam _APPLY1(flags, roamparams, rssi, rssi); 1416178354Ssam } else 1417178354Ssam _APPLY(flags, roamparams, rssi, rssi); 1418178354Ssam callback_register(setroam_cb, &roamparams); 1419170531Ssam} 1420170531Ssam 1421170531Ssamstatic 1422178354SsamDECL_CMD_FUNC(set80211roamrate, val, d) 1423170531Ssam{ 1424178354Ssam int v = atoi(val), flags; 1425178354Ssam 1426178354Ssam flags = getmodeflags(val); 1427178354Ssam getroam(s); 1428178354Ssam if (flags == 0) { /* NB: no flags => current channel */ 1429178354Ssam flags = getcurchan(s)->ic_flags; 1430178354Ssam _APPLY_RATE1(flags, roamparams, rate, v); 1431178354Ssam } else 1432178354Ssam _APPLY_RATE(flags, roamparams, rate, v); 1433178354Ssam callback_register(setroam_cb, &roamparams); 1434170531Ssam} 1435170531Ssam 1436170531Ssamstatic 1437178354SsamDECL_CMD_FUNC(set80211mcastrate, val, d) 1438170531Ssam{ 1439178354Ssam int v = atoi(val), flags; 1440178354Ssam 1441178354Ssam flags = getmodeflags(val); 1442178354Ssam gettxparams(s); 1443178354Ssam if (flags == 0) { /* NB: no flags => current channel */ 1444178354Ssam flags = getcurchan(s)->ic_flags; 1445178354Ssam _APPLY_RATE1(flags, txparams, mcastrate, v); 1446178354Ssam } else 1447178354Ssam _APPLY_RATE(flags, txparams, mcastrate, v); 1448178354Ssam callback_register(settxparams_cb, &txparams); 1449170531Ssam} 1450170531Ssam 1451170531Ssamstatic 1452178354SsamDECL_CMD_FUNC(set80211mgtrate, val, d) 1453170531Ssam{ 1454178354Ssam int v = atoi(val), flags; 1455178354Ssam 1456178354Ssam flags = getmodeflags(val); 1457178354Ssam gettxparams(s); 1458178354Ssam if (flags == 0) { /* NB: no flags => current channel */ 1459178354Ssam flags = getcurchan(s)->ic_flags; 1460178354Ssam _APPLY_RATE1(flags, txparams, mgmtrate, v); 1461178354Ssam } else 1462178354Ssam _APPLY_RATE(flags, txparams, mgmtrate, v); 1463178354Ssam callback_register(settxparams_cb, &txparams); 1464170531Ssam} 1465170531Ssam 1466170531Ssamstatic 1467178354SsamDECL_CMD_FUNC(set80211ucastrate, val, d) 1468170531Ssam{ 1469178354Ssam int v, flags; 1470178354Ssam 1471178354Ssam gettxparams(s); 1472178354Ssam flags = getmodeflags(val); 1473178354Ssam if (isanyarg(val)) { 1474178354Ssam if (flags == 0) { /* NB: no flags => current channel */ 1475178354Ssam flags = getcurchan(s)->ic_flags; 1476178354Ssam _APPLY1(flags, txparams, ucastrate, 1477178354Ssam IEEE80211_FIXED_RATE_NONE); 1478178354Ssam } else 1479178354Ssam _APPLY(flags, txparams, ucastrate, 1480178354Ssam IEEE80211_FIXED_RATE_NONE); 1481178354Ssam } else { 1482178354Ssam v = atoi(val); 1483178354Ssam if (flags == 0) { /* NB: no flags => current channel */ 1484178354Ssam flags = getcurchan(s)->ic_flags; 1485178354Ssam _APPLY_RATE1(flags, txparams, ucastrate, v); 1486178354Ssam } else 1487178354Ssam _APPLY_RATE(flags, txparams, ucastrate, v); 1488178354Ssam } 1489178354Ssam callback_register(settxparams_cb, &txparams); 1490170531Ssam} 1491170531Ssam 1492170531Ssamstatic 1493178354SsamDECL_CMD_FUNC(set80211maxretry, val, d) 1494153354Ssam{ 1495178354Ssam int v = atoi(val), flags; 1496178354Ssam 1497178354Ssam flags = getmodeflags(val); 1498178354Ssam gettxparams(s); 1499178354Ssam if (flags == 0) { /* NB: no flags => current channel */ 1500178354Ssam flags = getcurchan(s)->ic_flags; 1501178354Ssam _APPLY1(flags, txparams, maxretry, v); 1502178354Ssam } else 1503178354Ssam _APPLY(flags, txparams, maxretry, v); 1504178354Ssam callback_register(settxparams_cb, &txparams); 1505153354Ssam} 1506178354Ssam#undef _APPLY_RATE 1507178354Ssam#undef _APPLY 1508178354Ssam#undef IEEE80211_CHAN_HTA 1509178354Ssam#undef IEEE80211_CHAN_HTG 1510153354Ssam 1511153354Ssamstatic 1512148416SsamDECL_CMD_FUNC(set80211fragthreshold, val, d) 1513148416Ssam{ 1514148416Ssam set80211(s, IEEE80211_IOC_FRAGTHRESHOLD, 1515148416Ssam isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL); 1516148416Ssam} 1517148416Ssam 1518160687Ssamstatic 1519160687SsamDECL_CMD_FUNC(set80211bmissthreshold, val, d) 1520160687Ssam{ 1521160687Ssam set80211(s, IEEE80211_IOC_BMISSTHRESHOLD, 1522160687Ssam isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL); 1523160687Ssam} 1524160687Ssam 1525170531Ssamstatic void 1526170531Ssamset80211burst(const char *val, int d, int s, const struct afswtch *rafp) 1527170531Ssam{ 1528170531Ssam set80211(s, IEEE80211_IOC_BURST, d, 0, NULL); 1529170531Ssam} 1530170531Ssam 1531170531Ssamstatic void 1532170531Ssamset80211doth(const char *val, int d, int s, const struct afswtch *rafp) 1533170531Ssam{ 1534170531Ssam set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL); 1535170531Ssam} 1536170531Ssam 1537173275Ssamstatic void 1538178354Ssamset80211dfs(const char *val, int d, int s, const struct afswtch *rafp) 1539178354Ssam{ 1540178354Ssam set80211(s, IEEE80211_IOC_DFS, d, 0, NULL); 1541178354Ssam} 1542178354Ssam 1543178354Ssamstatic void 1544173275Ssamset80211shortgi(const char *val, int d, int s, const struct afswtch *rafp) 1545173275Ssam{ 1546173275Ssam set80211(s, IEEE80211_IOC_SHORTGI, 1547173275Ssam d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0, 1548173275Ssam 0, NULL); 1549173275Ssam} 1550173275Ssam 1551173275Ssamstatic void 1552173275Ssamset80211ampdu(const char *val, int d, int s, const struct afswtch *rafp) 1553173275Ssam{ 1554173275Ssam int ampdu; 1555173275Ssam 1556173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU, &du) < 0) 1557173275Ssam errx(-1, "cannot get AMPDU setting"); 1558173275Ssam if (d < 0) { 1559173275Ssam d = -d; 1560173275Ssam ampdu &= ~d; 1561173275Ssam } else 1562173275Ssam ampdu |= d; 1563173275Ssam set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL); 1564173275Ssam} 1565173275Ssam 1566173275Ssamstatic 1567173275SsamDECL_CMD_FUNC(set80211ampdulimit, val, d) 1568173275Ssam{ 1569173275Ssam int v; 1570173275Ssam 1571173275Ssam switch (atoi(val)) { 1572173275Ssam case 8: 1573173275Ssam case 8*1024: 1574173275Ssam v = IEEE80211_HTCAP_MAXRXAMPDU_8K; 1575173275Ssam break; 1576173275Ssam case 16: 1577173275Ssam case 16*1024: 1578173275Ssam v = IEEE80211_HTCAP_MAXRXAMPDU_16K; 1579173275Ssam break; 1580173275Ssam case 32: 1581173275Ssam case 32*1024: 1582173275Ssam v = IEEE80211_HTCAP_MAXRXAMPDU_32K; 1583173275Ssam break; 1584173275Ssam case 64: 1585173275Ssam case 64*1024: 1586173275Ssam v = IEEE80211_HTCAP_MAXRXAMPDU_64K; 1587173275Ssam break; 1588173275Ssam default: 1589173275Ssam errx(-1, "invalid A-MPDU limit %s", val); 1590173275Ssam } 1591173275Ssam set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL); 1592173275Ssam} 1593173275Ssam 1594173275Ssamstatic 1595173275SsamDECL_CMD_FUNC(set80211ampdudensity, val, d) 1596173275Ssam{ 1597173275Ssam int v; 1598173275Ssam 1599173275Ssam if (isanyarg(val)) 1600173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_NA; 1601173275Ssam else switch ((int)(atof(val)*4)) { 1602173275Ssam case 0: 1603173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_NA; 1604173275Ssam break; 1605173275Ssam case 1: 1606173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_025; 1607173275Ssam break; 1608173275Ssam case 2: 1609173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_05; 1610173275Ssam break; 1611173275Ssam case 4: 1612173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_1; 1613173275Ssam break; 1614173275Ssam case 8: 1615173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_2; 1616173275Ssam break; 1617173275Ssam case 16: 1618173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_4; 1619173275Ssam break; 1620173275Ssam case 32: 1621173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_8; 1622173275Ssam break; 1623173275Ssam case 64: 1624173275Ssam v = IEEE80211_HTCAP_MPDUDENSITY_16; 1625173275Ssam break; 1626173275Ssam default: 1627173275Ssam errx(-1, "invalid A-MPDU density %s", val); 1628173275Ssam } 1629173275Ssam set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL); 1630173275Ssam} 1631173275Ssam 1632173275Ssamstatic void 1633173275Ssamset80211amsdu(const char *val, int d, int s, const struct afswtch *rafp) 1634173275Ssam{ 1635173275Ssam int amsdu; 1636173275Ssam 1637173275Ssam if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0) 1638173275Ssam errx(-1, "cannot get AMSDU setting"); 1639173275Ssam if (d < 0) { 1640173275Ssam d = -d; 1641173275Ssam amsdu &= ~d; 1642173275Ssam } else 1643173275Ssam amsdu |= d; 1644173275Ssam set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL); 1645173275Ssam} 1646173275Ssam 1647173275Ssamstatic 1648173275SsamDECL_CMD_FUNC(set80211amsdulimit, val, d) 1649173275Ssam{ 1650173275Ssam set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL); 1651173275Ssam} 1652173275Ssam 1653173275Ssamstatic void 1654173275Ssamset80211puren(const char *val, int d, int s, const struct afswtch *rafp) 1655173275Ssam{ 1656173275Ssam set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL); 1657173275Ssam} 1658173275Ssam 1659173275Ssamstatic void 1660173275Ssamset80211htcompat(const char *val, int d, int s, const struct afswtch *rafp) 1661173275Ssam{ 1662173275Ssam set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL); 1663173275Ssam} 1664173275Ssam 1665173275Ssamstatic void 1666173275Ssamset80211htconf(const char *val, int d, int s, const struct afswtch *rafp) 1667173275Ssam{ 1668173275Ssam set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL); 1669173275Ssam htconf = d; 1670173275Ssam} 1671173275Ssam 1672173275Ssamstatic void 1673178354Ssamset80211dwds(const char *val, int d, int s, const struct afswtch *rafp) 1674178354Ssam{ 1675178354Ssam set80211(s, IEEE80211_IOC_DWDS, d, 0, NULL); 1676178354Ssam} 1677178354Ssam 1678178354Ssamstatic void 1679173275Ssamset80211inact(const char *val, int d, int s, const struct afswtch *rafp) 1680173275Ssam{ 1681173275Ssam set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL); 1682173275Ssam} 1683173275Ssam 1684173275Ssamstatic void 1685178354Ssamset80211tsn(const char *val, int d, int s, const struct afswtch *rafp) 1686178354Ssam{ 1687178354Ssam set80211(s, IEEE80211_IOC_TSN, d, 0, NULL); 1688178354Ssam} 1689178354Ssam 1690178354Ssamstatic void 1691178354Ssamset80211dotd(const char *val, int d, int s, const struct afswtch *rafp) 1692178354Ssam{ 1693178354Ssam set80211(s, IEEE80211_IOC_DOTD, d, 0, NULL); 1694178354Ssam} 1695178354Ssam 1696178354Ssamstatic int 1697178354Ssamregdomain_sort(const void *a, const void *b) 1698178354Ssam{ 1699178354Ssam#define CHAN_ALL \ 1700178354Ssam (IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER) 1701178354Ssam const struct ieee80211_channel *ca = a; 1702178354Ssam const struct ieee80211_channel *cb = b; 1703178354Ssam 1704178354Ssam return ca->ic_freq == cb->ic_freq ? 1705178354Ssam (ca->ic_flags & CHAN_ALL) - (cb->ic_flags & CHAN_ALL) : 1706178354Ssam ca->ic_freq - cb->ic_freq; 1707178354Ssam#undef CHAN_ALL 1708178354Ssam} 1709178354Ssam 1710178354Ssamstatic const struct ieee80211_channel * 1711178354Ssamchanlookup(const struct ieee80211_channel chans[], int nchans, 1712178354Ssam int freq, int flags) 1713178354Ssam{ 1714178354Ssam int i; 1715178354Ssam 1716178354Ssam flags &= IEEE80211_CHAN_ALLTURBO; 1717178354Ssam for (i = 0; i < nchans; i++) { 1718178354Ssam const struct ieee80211_channel *c = &chans[i]; 1719178354Ssam if (c->ic_freq == freq && 1720178354Ssam (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) 1721178354Ssam return c; 1722178354Ssam } 1723178354Ssam return NULL; 1724178354Ssam} 1725178354Ssam 1726178354Ssamstatic void 1727178354Ssamregdomain_addchans(struct ieee80211req_chaninfo *ci, 1728178354Ssam const netband_head *bands, 1729178354Ssam const struct ieee80211_regdomain *reg, 1730178354Ssam uint32_t chanFlags, 1731178354Ssam const struct ieee80211req_chaninfo *avail) 1732178354Ssam{ 1733178354Ssam const struct netband *nb; 1734178354Ssam const struct freqband *b; 1735178354Ssam struct ieee80211_channel *c, *prev; 1736178354Ssam int freq, channelSep; 1737178354Ssam 1738178354Ssam channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40; 1739178354Ssam LIST_FOREACH(nb, bands, next) { 1740178354Ssam b = nb->band; 1741178354Ssam if (verbose) 1742178354Ssam printf("%s: chanFlags 0x%x b %p\n", 1743178354Ssam __func__, chanFlags, b); 1744178354Ssam prev = NULL; 1745178354Ssam for (freq = b->freqStart; freq <= b->freqEnd; freq += b->chanSep) { 1746178354Ssam uint32_t flags = nb->flags | b->flags; 1747178354Ssam 1748178354Ssam /* check if device can operate on this frequency */ 1749178354Ssam if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, chanFlags) == NULL) { 1750178354Ssam if (verbose) 1751178354Ssam printf("%u: skip, flags 0x%x not available\n", freq, chanFlags); 1752178354Ssam continue; 1753178354Ssam } 1754178354Ssam if ((flags & IEEE80211_CHAN_HALF) && 1755178354Ssam (chanFlags & IEEE80211_CHAN_HALF) == 0) { 1756178354Ssam if (verbose) 1757178354Ssam printf("%u: skip, device does not support half-rate channels\n", freq); 1758178354Ssam continue; 1759178354Ssam } 1760178354Ssam if ((flags & IEEE80211_CHAN_QUARTER) && 1761178354Ssam (chanFlags & IEEE80211_CHAN_QUARTER) == 0) { 1762178354Ssam if (verbose) 1763178354Ssam printf("%u: skip, device does not support quarter-rate channels\n", freq); 1764178354Ssam continue; 1765178354Ssam } 1766178354Ssam if ((flags & IEEE80211_CHAN_HT20) && 1767178354Ssam (chanFlags & IEEE80211_CHAN_HT20) == 0) { 1768178354Ssam if (verbose) 1769178354Ssam printf("%u: skip, device does not support HT20 operation\n", freq); 1770178354Ssam continue; 1771178354Ssam } 1772178354Ssam if ((flags & IEEE80211_CHAN_HT40) && 1773178354Ssam (chanFlags & IEEE80211_CHAN_HT40) == 0) { 1774178354Ssam if (verbose) 1775178354Ssam printf("%u: skip, device does not support HT40 operation\n", freq); 1776178354Ssam continue; 1777178354Ssam } 1778178354Ssam if ((flags & REQ_ECM) && !reg->ecm) { 1779178354Ssam if (verbose) 1780178354Ssam printf("%u: skip, ECM channel\n", freq); 1781178354Ssam continue; 1782178354Ssam } 1783178354Ssam if ((flags & REQ_OUTDOOR) && reg->location == 'I') { 1784178354Ssam if (verbose) 1785178354Ssam printf("%u: skip, outdoor channel\n", freq); 1786178354Ssam continue; 1787178354Ssam } 1788178354Ssam if ((flags & IEEE80211_CHAN_HT40) && 1789178354Ssam prev != NULL && (freq - prev->ic_freq) < channelSep) { 1790178354Ssam if (verbose) 1791178354Ssam printf("%u: skip, only %u channel " 1792178354Ssam "separation, need %d\n", freq, 1793178354Ssam freq - prev->ic_freq, channelSep); 1794178354Ssam continue; 1795178354Ssam } 1796178354Ssam if (ci->ic_nchans == IEEE80211_CHAN_MAX) { 1797178354Ssam if (verbose) 1798178354Ssam printf("%u: skip, channel table full\n", freq); 1799178354Ssam break; 1800178354Ssam } 1801178354Ssam c = &ci->ic_chans[ci->ic_nchans++]; 1802178354Ssam c->ic_freq = freq; 1803178354Ssam c->ic_flags = chanFlags | 1804178354Ssam (flags &~ (REQ_FLAGS | IEEE80211_CHAN_HT40)); 1805178354Ssam if (c->ic_flags & IEEE80211_CHAN_DFS) 1806178354Ssam c->ic_maxregpower = nb->maxPowerDFS; 1807178354Ssam else 1808178354Ssam c->ic_maxregpower = nb->maxPower; 1809178354Ssam if (verbose) 1810178354Ssam printf("[%3d] add freq %u flags 0x%x power %u\n", 1811178354Ssam ci->ic_nchans-1, c->ic_freq, c->ic_flags, 1812178354Ssam c->ic_maxregpower); 1813178354Ssam /* NB: kernel fills in other fields */ 1814178354Ssam prev = c; 1815178354Ssam } 1816178354Ssam } 1817178354Ssam} 1818178354Ssam 1819178354Ssamstatic void 1820178354Ssamregdomain_makechannels( 1821178354Ssam struct ieee80211_regdomain_req *req, 1822178354Ssam const struct ieee80211_devcaps_req *dc) 1823178354Ssam{ 1824178354Ssam struct regdata *rdp = getregdata(); 1825178354Ssam const struct country *cc; 1826178354Ssam const struct ieee80211_regdomain *reg = &req->rd; 1827178354Ssam struct ieee80211req_chaninfo *ci = &req->chaninfo; 1828178354Ssam const struct regdomain *rd; 1829178354Ssam 1830178354Ssam /* 1831178354Ssam * Locate construction table for new channel list. We treat 1832178354Ssam * the regdomain/SKU as definitive so a country can be in 1833178354Ssam * multiple with different properties (e.g. US in FCC+FCC3). 1834178354Ssam * If no regdomain is specified then we fallback on the country 1835178354Ssam * code to find the associated regdomain since countries always 1836178354Ssam * belong to at least one regdomain. 1837178354Ssam */ 1838178354Ssam if (reg->regdomain == 0) { 1839178354Ssam cc = lib80211_country_findbycc(rdp, reg->country); 1840178354Ssam if (cc == NULL) 1841178354Ssam errx(1, "internal error, country %d not found", 1842178354Ssam reg->country); 1843178354Ssam rd = cc->rd; 1844178354Ssam } else 1845178354Ssam rd = lib80211_regdomain_findbysku(rdp, reg->regdomain); 1846178354Ssam if (rd == NULL) 1847178354Ssam errx(1, "internal error, regdomain %d not found", 1848178354Ssam reg->regdomain); 1849178354Ssam if (rd->sku != SKU_DEBUG) { 1850178354Ssam memset(ci, 0, sizeof(*ci)); 1851178354Ssam if (!LIST_EMPTY(&rd->bands_11b)) 1852178354Ssam regdomain_addchans(ci, &rd->bands_11b, reg, 1853178354Ssam IEEE80211_CHAN_B, &dc->dc_chaninfo); 1854178354Ssam if (!LIST_EMPTY(&rd->bands_11g)) 1855178354Ssam regdomain_addchans(ci, &rd->bands_11g, reg, 1856178354Ssam IEEE80211_CHAN_G, &dc->dc_chaninfo); 1857178354Ssam if (!LIST_EMPTY(&rd->bands_11a)) 1858178354Ssam regdomain_addchans(ci, &rd->bands_11a, reg, 1859178354Ssam IEEE80211_CHAN_A, &dc->dc_chaninfo); 1860178354Ssam if (!LIST_EMPTY(&rd->bands_11na)) { 1861178354Ssam regdomain_addchans(ci, &rd->bands_11na, reg, 1862178354Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT20, 1863178354Ssam &dc->dc_chaninfo); 1864178354Ssam regdomain_addchans(ci, &rd->bands_11na, reg, 1865178354Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U, 1866178354Ssam &dc->dc_chaninfo); 1867178354Ssam regdomain_addchans(ci, &rd->bands_11na, reg, 1868178354Ssam IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D, 1869178354Ssam &dc->dc_chaninfo); 1870178354Ssam } 1871178354Ssam if (!LIST_EMPTY(&rd->bands_11ng)) { 1872178354Ssam regdomain_addchans(ci, &rd->bands_11ng, reg, 1873178354Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT20, 1874178354Ssam &dc->dc_chaninfo); 1875178354Ssam regdomain_addchans(ci, &rd->bands_11ng, reg, 1876178354Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U, 1877178354Ssam &dc->dc_chaninfo); 1878178354Ssam regdomain_addchans(ci, &rd->bands_11ng, reg, 1879178354Ssam IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D, 1880178354Ssam &dc->dc_chaninfo); 1881178354Ssam } 1882178354Ssam qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]), 1883178354Ssam regdomain_sort); 1884178354Ssam } else 1885178354Ssam *ci = dc->dc_chaninfo; 1886178354Ssam} 1887178354Ssam 1888178354Ssamstatic void 1889178354Ssamlist_countries(void) 1890178354Ssam{ 1891178354Ssam struct regdata *rdp = getregdata(); 1892178354Ssam const struct country *cp; 1893178354Ssam const struct regdomain *dp; 1894178354Ssam int i; 1895178354Ssam 1896178354Ssam i = 0; 1897178354Ssam printf("\nCountry codes:\n"); 1898178354Ssam LIST_FOREACH(cp, &rdp->countries, next) { 1899178354Ssam printf("%2s %-15.15s%s", cp->isoname, 1900178354Ssam cp->name, ((i+1)%4) == 0 ? "\n" : " "); 1901178354Ssam i++; 1902178354Ssam } 1903178354Ssam i = 0; 1904178354Ssam printf("\nRegulatory domains:\n"); 1905178354Ssam LIST_FOREACH(dp, &rdp->domains, next) { 1906178354Ssam printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " "); 1907178354Ssam i++; 1908178354Ssam } 1909178354Ssam printf("\n"); 1910178354Ssam} 1911178354Ssam 1912178354Ssamstatic void 1913178354Ssamdefaultcountry(const struct regdomain *rd) 1914178354Ssam{ 1915178354Ssam struct regdata *rdp = getregdata(); 1916178354Ssam const struct country *cc; 1917178354Ssam 1918178354Ssam cc = lib80211_country_findbycc(rdp, rd->cc->code); 1919178354Ssam if (cc == NULL) 1920178354Ssam errx(1, "internal error, ISO country code %d not " 1921178354Ssam "defined for regdomain %s", rd->cc->code, rd->name); 1922178354Ssam regdomain.country = cc->code; 1923178354Ssam regdomain.isocc[0] = cc->isoname[0]; 1924178354Ssam regdomain.isocc[1] = cc->isoname[1]; 1925178354Ssam} 1926178354Ssam 1927178354Ssamstatic 1928178354SsamDECL_CMD_FUNC(set80211regdomain, val, d) 1929178354Ssam{ 1930178354Ssam struct regdata *rdp = getregdata(); 1931178354Ssam const struct regdomain *rd; 1932178354Ssam 1933178354Ssam rd = lib80211_regdomain_findbyname(rdp, val); 1934178354Ssam if (rd == NULL) { 1935178354Ssam rd = lib80211_regdomain_findbysku(rdp, atoi(val)); 1936178354Ssam if (rd == NULL) 1937178354Ssam errx(1, "unknown regdomain %s", val); 1938178354Ssam } 1939178354Ssam getregdomain(s); 1940178354Ssam regdomain.regdomain = rd->sku; 1941178354Ssam if (regdomain.country == 0 && rd->cc != NULL) { 1942178354Ssam /* 1943178354Ssam * No country code setup and there's a default 1944178354Ssam * one for this regdomain fill it in. 1945178354Ssam */ 1946178354Ssam defaultcountry(rd); 1947178354Ssam } 1948178354Ssam callback_register(setregdomain_cb, ®domain); 1949178354Ssam} 1950178354Ssam 1951178354Ssamstatic 1952178354SsamDECL_CMD_FUNC(set80211country, val, d) 1953178354Ssam{ 1954178354Ssam struct regdata *rdp = getregdata(); 1955178354Ssam const struct country *cc; 1956178354Ssam 1957178354Ssam cc = lib80211_country_findbyname(rdp, val); 1958178354Ssam if (cc == NULL) { 1959178354Ssam cc = lib80211_country_findbycc(rdp, atoi(val)); 1960178354Ssam if (cc == NULL) 1961178354Ssam errx(1, "unknown ISO country code %s", val); 1962178354Ssam } 1963178354Ssam getregdomain(s); 1964178354Ssam regdomain.regdomain = cc->rd->sku; 1965178354Ssam regdomain.country = cc->code; 1966178354Ssam regdomain.isocc[0] = cc->isoname[0]; 1967178354Ssam regdomain.isocc[1] = cc->isoname[1]; 1968178354Ssam callback_register(setregdomain_cb, ®domain); 1969178354Ssam} 1970178354Ssam 1971178354Ssamstatic void 1972178354Ssamset80211location(const char *val, int d, int s, const struct afswtch *rafp) 1973178354Ssam{ 1974178354Ssam getregdomain(s); 1975178354Ssam regdomain.location = d; 1976178354Ssam callback_register(setregdomain_cb, ®domain); 1977178354Ssam} 1978178354Ssam 1979178354Ssamstatic void 1980178354Ssamset80211ecm(const char *val, int d, int s, const struct afswtch *rafp) 1981178354Ssam{ 1982178354Ssam getregdomain(s); 1983178354Ssam regdomain.ecm = d; 1984178354Ssam callback_register(setregdomain_cb, ®domain); 1985178354Ssam} 1986178354Ssam 1987178354Ssamstatic void 1988173275SsamLINE_INIT(char c) 1989173275Ssam{ 1990173275Ssam spacer = c; 1991173275Ssam if (c == '\t') 1992173275Ssam col = 8; 1993173275Ssam else 1994173275Ssam col = 1; 1995173275Ssam} 1996173275Ssam 1997173275Ssamstatic void 1998173275SsamLINE_BREAK(void) 1999173275Ssam{ 2000173275Ssam if (spacer != '\t') { 2001173275Ssam printf("\n"); 2002173275Ssam spacer = '\t'; 2003173275Ssam } 2004173275Ssam col = 8; /* 8-col tab */ 2005173275Ssam} 2006173275Ssam 2007173275Ssamstatic void 2008173275SsamLINE_CHECK(const char *fmt, ...) 2009173275Ssam{ 2010173275Ssam char buf[80]; 2011173275Ssam va_list ap; 2012173275Ssam int n; 2013173275Ssam 2014173275Ssam va_start(ap, fmt); 2015173275Ssam n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap); 2016173275Ssam va_end(ap); 2017173275Ssam col += 1+n; 2018173275Ssam if (col > MAXCOL) { 2019173275Ssam LINE_BREAK(); 2020173275Ssam col += n; 2021173275Ssam } 2022173275Ssam buf[0] = spacer; 2023173275Ssam printf("%s", buf); 2024173275Ssam spacer = ' '; 2025173275Ssam} 2026173275Ssam 2027138593Ssamstatic int 2028170531Ssamgetmaxrate(const uint8_t rates[15], uint8_t nrates) 2029138593Ssam{ 2030138593Ssam int i, maxrate = -1; 2031138593Ssam 2032138593Ssam for (i = 0; i < nrates; i++) { 2033138593Ssam int rate = rates[i] & IEEE80211_RATE_VAL; 2034138593Ssam if (rate > maxrate) 2035138593Ssam maxrate = rate; 2036138593Ssam } 2037138593Ssam return maxrate / 2; 2038138593Ssam} 2039138593Ssam 2040138593Ssamstatic const char * 2041138593Ssamgetcaps(int capinfo) 2042138593Ssam{ 2043138593Ssam static char capstring[32]; 2044138593Ssam char *cp = capstring; 2045138593Ssam 2046138593Ssam if (capinfo & IEEE80211_CAPINFO_ESS) 2047138593Ssam *cp++ = 'E'; 2048138593Ssam if (capinfo & IEEE80211_CAPINFO_IBSS) 2049138593Ssam *cp++ = 'I'; 2050138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 2051138593Ssam *cp++ = 'c'; 2052138593Ssam if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 2053138593Ssam *cp++ = 'C'; 2054138593Ssam if (capinfo & IEEE80211_CAPINFO_PRIVACY) 2055138593Ssam *cp++ = 'P'; 2056138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 2057138593Ssam *cp++ = 'S'; 2058138593Ssam if (capinfo & IEEE80211_CAPINFO_PBCC) 2059138593Ssam *cp++ = 'B'; 2060138593Ssam if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 2061138593Ssam *cp++ = 'A'; 2062138593Ssam if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 2063138593Ssam *cp++ = 's'; 2064138593Ssam if (capinfo & IEEE80211_CAPINFO_RSN) 2065138593Ssam *cp++ = 'R'; 2066138593Ssam if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 2067138593Ssam *cp++ = 'D'; 2068138593Ssam *cp = '\0'; 2069138593Ssam return capstring; 2070138593Ssam} 2071138593Ssam 2072159885Ssamstatic const char * 2073159885Ssamgetflags(int flags) 2074159885Ssam{ 2075159885Ssam static char flagstring[32]; 2076159885Ssam char *cp = flagstring; 2077159885Ssam 2078159885Ssam if (flags & IEEE80211_NODE_AUTH) 2079159885Ssam *cp++ = 'A'; 2080159885Ssam if (flags & IEEE80211_NODE_QOS) 2081159885Ssam *cp++ = 'Q'; 2082159885Ssam if (flags & IEEE80211_NODE_ERP) 2083159885Ssam *cp++ = 'E'; 2084159885Ssam if (flags & IEEE80211_NODE_PWR_MGT) 2085159885Ssam *cp++ = 'P'; 2086173275Ssam if (flags & IEEE80211_NODE_HT) { 2087170531Ssam *cp++ = 'H'; 2088173275Ssam if (flags & IEEE80211_NODE_HTCOMPAT) 2089173275Ssam *cp++ = '+'; 2090173275Ssam } 2091173275Ssam if (flags & IEEE80211_NODE_WPS) 2092173275Ssam *cp++ = 'W'; 2093173275Ssam if (flags & IEEE80211_NODE_TSN) 2094173275Ssam *cp++ = 'T'; 2095159885Ssam *cp = '\0'; 2096159885Ssam return flagstring; 2097159885Ssam} 2098159885Ssam 2099138593Ssamstatic void 2100138593Ssamprintie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 2101138593Ssam{ 2102138593Ssam printf("%s", tag); 2103138593Ssam if (verbose) { 2104138593Ssam maxlen -= strlen(tag)+2; 2105138593Ssam if (2*ielen > maxlen) 2106138593Ssam maxlen--; 2107138593Ssam printf("<"); 2108138593Ssam for (; ielen > 0; ie++, ielen--) { 2109138593Ssam if (maxlen-- <= 0) 2110138593Ssam break; 2111138593Ssam printf("%02x", *ie); 2112138593Ssam } 2113138593Ssam if (ielen != 0) 2114138593Ssam printf("-"); 2115138593Ssam printf(">"); 2116138593Ssam } 2117138593Ssam} 2118138593Ssam 2119170531Ssam#define LE_READ_2(p) \ 2120170531Ssam ((u_int16_t) \ 2121170531Ssam ((((const u_int8_t *)(p))[0] ) | \ 2122170531Ssam (((const u_int8_t *)(p))[1] << 8))) 2123170531Ssam#define LE_READ_4(p) \ 2124170531Ssam ((u_int32_t) \ 2125170531Ssam ((((const u_int8_t *)(p))[0] ) | \ 2126170531Ssam (((const u_int8_t *)(p))[1] << 8) | \ 2127170531Ssam (((const u_int8_t *)(p))[2] << 16) | \ 2128170531Ssam (((const u_int8_t *)(p))[3] << 24))) 2129170531Ssam 2130138593Ssam/* 2131170531Ssam * NB: The decoding routines assume a properly formatted ie 2132170531Ssam * which should be safe as the kernel only retains them 2133170531Ssam * if they parse ok. 2134170531Ssam */ 2135170531Ssam 2136170531Ssamstatic void 2137173275Ssamprintwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2138170531Ssam{ 2139170531Ssam#define MS(_v, _f) (((_v) & _f) >> _f##_S) 2140170531Ssam static const char *acnames[] = { "BE", "BK", "VO", "VI" }; 2141173275Ssam const struct ieee80211_wme_param *wme = 2142173275Ssam (const struct ieee80211_wme_param *) ie; 2143170531Ssam int i; 2144170531Ssam 2145170531Ssam printf("%s", tag); 2146173275Ssam if (!verbose) 2147173275Ssam return; 2148173275Ssam printf("<qosinfo 0x%x", wme->param_qosInfo); 2149173275Ssam ie += offsetof(struct ieee80211_wme_param, params_acParams); 2150173275Ssam for (i = 0; i < WME_NUM_AC; i++) { 2151173275Ssam const struct ieee80211_wme_acparams *ac = 2152173275Ssam &wme->params_acParams[i]; 2153173275Ssam 2154173275Ssam printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]" 2155173275Ssam , acnames[i] 2156173275Ssam , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : "" 2157173275Ssam , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN) 2158173275Ssam , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN) 2159173275Ssam , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX) 2160173275Ssam , LE_READ_2(&ac->acp_txop) 2161173275Ssam ); 2162170531Ssam } 2163173275Ssam printf(">"); 2164170531Ssam#undef MS 2165170531Ssam} 2166170531Ssam 2167170531Ssamstatic void 2168173275Ssamprintwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2169173275Ssam{ 2170173275Ssam printf("%s", tag); 2171173275Ssam if (verbose) { 2172173275Ssam const struct ieee80211_wme_info *wme = 2173173275Ssam (const struct ieee80211_wme_info *) ie; 2174173275Ssam printf("<version 0x%x info 0x%x>", 2175173275Ssam wme->wme_version, wme->wme_info); 2176173275Ssam } 2177173275Ssam} 2178173275Ssam 2179173275Ssamstatic void 2180173275Ssamprinthtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2181173275Ssam{ 2182173275Ssam printf("%s", tag); 2183173275Ssam if (verbose) { 2184173275Ssam const struct ieee80211_ie_htcap *htcap = 2185173275Ssam (const struct ieee80211_ie_htcap *) ie; 2186173275Ssam const char *sep; 2187173275Ssam int i, j; 2188173275Ssam 2189173275Ssam printf("<cap 0x%x param 0x%x", 2190173275Ssam LE_READ_2(&htcap->hc_cap), htcap->hc_param); 2191173275Ssam printf(" mcsset["); 2192173275Ssam sep = ""; 2193173275Ssam for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) 2194173275Ssam if (isset(htcap->hc_mcsset, i)) { 2195173275Ssam for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) 2196173275Ssam if (isclr(htcap->hc_mcsset, j)) 2197173275Ssam break; 2198173275Ssam j--; 2199173275Ssam if (i == j) 2200173275Ssam printf("%s%u", sep, i); 2201173275Ssam else 2202173275Ssam printf("%s%u-%u", sep, i, j); 2203173275Ssam i += j-i; 2204173275Ssam sep = ","; 2205173275Ssam } 2206173275Ssam printf("] extcap 0x%x txbf 0x%x antenna 0x%x>", 2207173275Ssam LE_READ_2(&htcap->hc_extcap), 2208173275Ssam LE_READ_4(&htcap->hc_txbf), 2209173275Ssam htcap->hc_antenna); 2210173275Ssam } 2211173275Ssam} 2212173275Ssam 2213173275Ssamstatic void 2214173275Ssamprinthtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2215173275Ssam{ 2216173275Ssam printf("%s", tag); 2217173275Ssam if (verbose) { 2218173275Ssam const struct ieee80211_ie_htinfo *htinfo = 2219173275Ssam (const struct ieee80211_ie_htinfo *) ie; 2220173275Ssam const char *sep; 2221173275Ssam int i, j; 2222173275Ssam 2223173275Ssam printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel, 2224173275Ssam htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3, 2225173275Ssam LE_READ_2(&htinfo->hi_byte45)); 2226173275Ssam printf(" basicmcs["); 2227173275Ssam sep = ""; 2228173275Ssam for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) 2229173275Ssam if (isset(htinfo->hi_basicmcsset, i)) { 2230173275Ssam for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) 2231173275Ssam if (isclr(htinfo->hi_basicmcsset, j)) 2232173275Ssam break; 2233173275Ssam j--; 2234173275Ssam if (i == j) 2235173275Ssam printf("%s%u", sep, i); 2236173275Ssam else 2237173275Ssam printf("%s%u-%u", sep, i, j); 2238173275Ssam i += j-i; 2239173275Ssam sep = ","; 2240173275Ssam } 2241173275Ssam printf("]>"); 2242173275Ssam } 2243173275Ssam} 2244173275Ssam 2245173275Ssamstatic void 2246170531Ssamprintathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2247170531Ssam{ 2248170531Ssam 2249170531Ssam printf("%s", tag); 2250170531Ssam if (verbose) { 2251170531Ssam const struct ieee80211_ath_ie *ath = 2252170531Ssam (const struct ieee80211_ath_ie *)ie; 2253170531Ssam 2254170531Ssam printf("<"); 2255170531Ssam if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME) 2256170531Ssam printf("DTURBO,"); 2257170531Ssam if (ath->ath_capability & ATHEROS_CAP_COMPRESSION) 2258170531Ssam printf("COMP,"); 2259170531Ssam if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME) 2260170531Ssam printf("FF,"); 2261170531Ssam if (ath->ath_capability & ATHEROS_CAP_XR) 2262170531Ssam printf("XR,"); 2263170531Ssam if (ath->ath_capability & ATHEROS_CAP_AR) 2264170531Ssam printf("AR,"); 2265170531Ssam if (ath->ath_capability & ATHEROS_CAP_BURST) 2266170531Ssam printf("BURST,"); 2267170531Ssam if (ath->ath_capability & ATHEROS_CAP_WME) 2268170531Ssam printf("WME,"); 2269170531Ssam if (ath->ath_capability & ATHEROS_CAP_BOOST) 2270170531Ssam printf("BOOST,"); 2271170531Ssam printf("0x%x>", LE_READ_2(ath->ath_defkeyix)); 2272170531Ssam } 2273170531Ssam} 2274170531Ssam 2275170531Ssamstatic const char * 2276170531Ssamwpa_cipher(const u_int8_t *sel) 2277170531Ssam{ 2278170531Ssam#define WPA_SEL(x) (((x)<<24)|WPA_OUI) 2279170531Ssam u_int32_t w = LE_READ_4(sel); 2280170531Ssam 2281170531Ssam switch (w) { 2282170531Ssam case WPA_SEL(WPA_CSE_NULL): 2283170531Ssam return "NONE"; 2284170531Ssam case WPA_SEL(WPA_CSE_WEP40): 2285170531Ssam return "WEP40"; 2286170531Ssam case WPA_SEL(WPA_CSE_WEP104): 2287170531Ssam return "WEP104"; 2288170531Ssam case WPA_SEL(WPA_CSE_TKIP): 2289170531Ssam return "TKIP"; 2290170531Ssam case WPA_SEL(WPA_CSE_CCMP): 2291170531Ssam return "AES-CCMP"; 2292170531Ssam } 2293170531Ssam return "?"; /* NB: so 1<< is discarded */ 2294170531Ssam#undef WPA_SEL 2295170531Ssam} 2296170531Ssam 2297170531Ssamstatic const char * 2298170531Ssamwpa_keymgmt(const u_int8_t *sel) 2299170531Ssam{ 2300170531Ssam#define WPA_SEL(x) (((x)<<24)|WPA_OUI) 2301170531Ssam u_int32_t w = LE_READ_4(sel); 2302170531Ssam 2303170531Ssam switch (w) { 2304170531Ssam case WPA_SEL(WPA_ASE_8021X_UNSPEC): 2305170531Ssam return "8021X-UNSPEC"; 2306170531Ssam case WPA_SEL(WPA_ASE_8021X_PSK): 2307170531Ssam return "8021X-PSK"; 2308170531Ssam case WPA_SEL(WPA_ASE_NONE): 2309170531Ssam return "NONE"; 2310170531Ssam } 2311170531Ssam return "?"; 2312170531Ssam#undef WPA_SEL 2313170531Ssam} 2314170531Ssam 2315170531Ssamstatic void 2316170531Ssamprintwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2317170531Ssam{ 2318170531Ssam u_int8_t len = ie[1]; 2319170531Ssam 2320170531Ssam printf("%s", tag); 2321170531Ssam if (verbose) { 2322170531Ssam const char *sep; 2323170531Ssam int n; 2324170531Ssam 2325170531Ssam ie += 6, len -= 4; /* NB: len is payload only */ 2326170531Ssam 2327170531Ssam printf("<v%u", LE_READ_2(ie)); 2328170531Ssam ie += 2, len -= 2; 2329170531Ssam 2330170531Ssam printf(" mc:%s", wpa_cipher(ie)); 2331170531Ssam ie += 4, len -= 4; 2332170531Ssam 2333170531Ssam /* unicast ciphers */ 2334170531Ssam n = LE_READ_2(ie); 2335170531Ssam ie += 2, len -= 2; 2336170531Ssam sep = " uc:"; 2337170531Ssam for (; n > 0; n--) { 2338170531Ssam printf("%s%s", sep, wpa_cipher(ie)); 2339170531Ssam ie += 4, len -= 4; 2340170531Ssam sep = "+"; 2341170531Ssam } 2342170531Ssam 2343170531Ssam /* key management algorithms */ 2344170531Ssam n = LE_READ_2(ie); 2345170531Ssam ie += 2, len -= 2; 2346170531Ssam sep = " km:"; 2347170531Ssam for (; n > 0; n--) { 2348170531Ssam printf("%s%s", sep, wpa_keymgmt(ie)); 2349170531Ssam ie += 4, len -= 4; 2350170531Ssam sep = "+"; 2351170531Ssam } 2352170531Ssam 2353170531Ssam if (len > 2) /* optional capabilities */ 2354170531Ssam printf(", caps 0x%x", LE_READ_2(ie)); 2355170531Ssam printf(">"); 2356170531Ssam } 2357170531Ssam} 2358170531Ssam 2359170531Ssamstatic const char * 2360170531Ssamrsn_cipher(const u_int8_t *sel) 2361170531Ssam{ 2362170531Ssam#define RSN_SEL(x) (((x)<<24)|RSN_OUI) 2363170531Ssam u_int32_t w = LE_READ_4(sel); 2364170531Ssam 2365170531Ssam switch (w) { 2366170531Ssam case RSN_SEL(RSN_CSE_NULL): 2367170531Ssam return "NONE"; 2368170531Ssam case RSN_SEL(RSN_CSE_WEP40): 2369170531Ssam return "WEP40"; 2370170531Ssam case RSN_SEL(RSN_CSE_WEP104): 2371170531Ssam return "WEP104"; 2372170531Ssam case RSN_SEL(RSN_CSE_TKIP): 2373170531Ssam return "TKIP"; 2374170531Ssam case RSN_SEL(RSN_CSE_CCMP): 2375170531Ssam return "AES-CCMP"; 2376170531Ssam case RSN_SEL(RSN_CSE_WRAP): 2377170531Ssam return "AES-OCB"; 2378170531Ssam } 2379170531Ssam return "?"; 2380170531Ssam#undef WPA_SEL 2381170531Ssam} 2382170531Ssam 2383170531Ssamstatic const char * 2384170531Ssamrsn_keymgmt(const u_int8_t *sel) 2385170531Ssam{ 2386170531Ssam#define RSN_SEL(x) (((x)<<24)|RSN_OUI) 2387170531Ssam u_int32_t w = LE_READ_4(sel); 2388170531Ssam 2389170531Ssam switch (w) { 2390170531Ssam case RSN_SEL(RSN_ASE_8021X_UNSPEC): 2391170531Ssam return "8021X-UNSPEC"; 2392170531Ssam case RSN_SEL(RSN_ASE_8021X_PSK): 2393170531Ssam return "8021X-PSK"; 2394170531Ssam case RSN_SEL(RSN_ASE_NONE): 2395170531Ssam return "NONE"; 2396170531Ssam } 2397170531Ssam return "?"; 2398170531Ssam#undef RSN_SEL 2399170531Ssam} 2400170531Ssam 2401170531Ssamstatic void 2402170531Ssamprintrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2403170531Ssam{ 2404170531Ssam printf("%s", tag); 2405170531Ssam if (verbose) { 2406170531Ssam const char *sep; 2407170531Ssam int n; 2408170531Ssam 2409173275Ssam ie += 2, ielen -= 2; 2410170531Ssam 2411170531Ssam printf("<v%u", LE_READ_2(ie)); 2412173275Ssam ie += 2, ielen -= 2; 2413170531Ssam 2414170531Ssam printf(" mc:%s", rsn_cipher(ie)); 2415173275Ssam ie += 4, ielen -= 4; 2416170531Ssam 2417170531Ssam /* unicast ciphers */ 2418170531Ssam n = LE_READ_2(ie); 2419173275Ssam ie += 2, ielen -= 2; 2420170531Ssam sep = " uc:"; 2421170531Ssam for (; n > 0; n--) { 2422170531Ssam printf("%s%s", sep, rsn_cipher(ie)); 2423173275Ssam ie += 4, ielen -= 4; 2424170531Ssam sep = "+"; 2425170531Ssam } 2426170531Ssam 2427170531Ssam /* key management algorithms */ 2428170531Ssam n = LE_READ_2(ie); 2429173275Ssam ie += 2, ielen -= 2; 2430170531Ssam sep = " km:"; 2431170531Ssam for (; n > 0; n--) { 2432170531Ssam printf("%s%s", sep, rsn_keymgmt(ie)); 2433173275Ssam ie += 4, ielen -= 4; 2434170531Ssam sep = "+"; 2435170531Ssam } 2436170531Ssam 2437173275Ssam if (ielen > 2) /* optional capabilities */ 2438170531Ssam printf(", caps 0x%x", LE_READ_2(ie)); 2439170531Ssam /* XXXPMKID */ 2440170531Ssam printf(">"); 2441170531Ssam } 2442170531Ssam} 2443170531Ssam 2444181454Ssam/* XXX move to a public include file */ 2445181454Ssam#define IEEE80211_WPS_DEV_PASS_ID 0x1012 2446181454Ssam#define IEEE80211_WPS_SELECTED_REG 0x1041 2447181454Ssam#define IEEE80211_WPS_SETUP_STATE 0x1044 2448181454Ssam#define IEEE80211_WPS_UUID_E 0x1047 2449181454Ssam#define IEEE80211_WPS_VERSION 0x104a 2450181454Ssam 2451181454Ssam#define BE_READ_2(p) \ 2452181454Ssam ((u_int16_t) \ 2453181454Ssam ((((const u_int8_t *)(p))[1] ) | \ 2454181454Ssam (((const u_int8_t *)(p))[0] << 8))) 2455181454Ssam 2456181454Ssamstatic void 2457181454Ssamprintwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2458181454Ssam{ 2459181454Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 2460181454Ssam u_int8_t len = ie[1]; 2461181454Ssam 2462181454Ssam printf("%s", tag); 2463181454Ssam if (verbose) { 2464181454Ssam static const char *dev_pass_id[] = { 2465181454Ssam "D", /* Default (PIN) */ 2466181454Ssam "U", /* User-specified */ 2467181454Ssam "M", /* Machine-specified */ 2468181454Ssam "K", /* Rekey */ 2469181454Ssam "P", /* PushButton */ 2470181454Ssam "R" /* Registrar-specified */ 2471181454Ssam }; 2472181454Ssam int n; 2473181454Ssam 2474181454Ssam ie +=6, len -= 4; /* NB: len is payload only */ 2475181454Ssam 2476181454Ssam /* WPS IE in Beacon and Probe Resp frames have different fields */ 2477181454Ssam printf("<"); 2478181454Ssam while (len) { 2479181454Ssam uint16_t tlv_type = BE_READ_2(ie); 2480181454Ssam uint16_t tlv_len = BE_READ_2(ie + 2); 2481181454Ssam 2482181454Ssam ie += 4, len -= 4; 2483181454Ssam 2484181454Ssam switch (tlv_type) { 2485181454Ssam case IEEE80211_WPS_VERSION: 2486181454Ssam printf("v:%d.%d", *ie >> 4, *ie & 0xf); 2487181454Ssam break; 2488181454Ssam case IEEE80211_WPS_SETUP_STATE: 2489181454Ssam /* Only 1 and 2 are valid */ 2490181454Ssam if (*ie == 0 || *ie >= 3) 2491181454Ssam printf(" state:B"); 2492181454Ssam else 2493181454Ssam printf(" st:%s", *ie == 1 ? "N" : "C"); 2494181454Ssam break; 2495181454Ssam case IEEE80211_WPS_SELECTED_REG: 2496181454Ssam printf(" sel:%s", *ie ? "T" : "F"); 2497181454Ssam break; 2498181454Ssam case IEEE80211_WPS_DEV_PASS_ID: 2499181454Ssam n = LE_READ_2(ie); 2500181454Ssam if (n < N(dev_pass_id)) 2501181454Ssam printf(" dpi:%s", dev_pass_id[n]); 2502181454Ssam break; 2503181454Ssam case IEEE80211_WPS_UUID_E: 2504181454Ssam printf(" uuid-e:"); 2505181454Ssam for (n = 0; n < (tlv_len - 1); n++) 2506181454Ssam printf("%02x-", ie[n]); 2507181454Ssam printf("%02x", ie[n]); 2508181454Ssam break; 2509181454Ssam } 2510181454Ssam ie += tlv_len, len -= tlv_len; 2511181454Ssam } 2512181454Ssam printf(">"); 2513181454Ssam } 2514181454Ssam#undef N 2515181454Ssam} 2516181454Ssam 2517170531Ssam/* 2518138593Ssam * Copy the ssid string contents into buf, truncating to fit. If the 2519138593Ssam * ssid is entirely printable then just copy intact. Otherwise convert 2520138593Ssam * to hexadecimal. If the result is truncated then replace the last 2521138593Ssam * three characters with "...". 2522138593Ssam */ 2523146873Sjhbstatic int 2524138593Ssamcopy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 2525138593Ssam{ 2526138593Ssam const u_int8_t *p; 2527138593Ssam size_t maxlen; 2528138593Ssam int i; 2529138593Ssam 2530138593Ssam if (essid_len > bufsize) 2531138593Ssam maxlen = bufsize; 2532138593Ssam else 2533138593Ssam maxlen = essid_len; 2534138593Ssam /* determine printable or not */ 2535138593Ssam for (i = 0, p = essid; i < maxlen; i++, p++) { 2536138593Ssam if (*p < ' ' || *p > 0x7e) 2537138593Ssam break; 2538138593Ssam } 2539138593Ssam if (i != maxlen) { /* not printable, print as hex */ 2540138593Ssam if (bufsize < 3) 2541138593Ssam return 0; 2542138593Ssam strlcpy(buf, "0x", bufsize); 2543138593Ssam bufsize -= 2; 2544138593Ssam p = essid; 2545138593Ssam for (i = 0; i < maxlen && bufsize >= 2; i++) { 2546147489Savatar sprintf(&buf[2+2*i], "%02x", p[i]); 2547138593Ssam bufsize -= 2; 2548138593Ssam } 2549147489Savatar if (i != essid_len) 2550147489Savatar memcpy(&buf[2+2*i-3], "...", 3); 2551138593Ssam } else { /* printable, truncate as needed */ 2552138593Ssam memcpy(buf, essid, maxlen); 2553147489Savatar if (maxlen != essid_len) 2554147489Savatar memcpy(&buf[maxlen-3], "...", 3); 2555138593Ssam } 2556138593Ssam return maxlen; 2557138593Ssam} 2558138593Ssam 2559173275Ssamstatic void 2560173275Ssamprintssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2561173275Ssam{ 2562173275Ssam char ssid[2*IEEE80211_NWID_LEN+1]; 2563173275Ssam 2564173275Ssam printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid); 2565173275Ssam} 2566173275Ssam 2567173275Ssamstatic void 2568173275Ssamprintrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2569173275Ssam{ 2570173275Ssam const char *sep; 2571173275Ssam int i; 2572173275Ssam 2573173275Ssam printf("%s", tag); 2574173275Ssam sep = "<"; 2575173275Ssam for (i = 2; i < ielen; i++) { 2576173275Ssam printf("%s%s%d", sep, 2577173275Ssam ie[i] & IEEE80211_RATE_BASIC ? "B" : "", 2578173275Ssam ie[i] & IEEE80211_RATE_VAL); 2579173275Ssam sep = ","; 2580173275Ssam } 2581173275Ssam printf(">"); 2582173275Ssam} 2583173275Ssam 2584173275Ssamstatic void 2585173275Ssamprintcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2586173275Ssam{ 2587173275Ssam const struct ieee80211_country_ie *cie = 2588173275Ssam (const struct ieee80211_country_ie *) ie; 2589173275Ssam int i, nbands, schan, nchan; 2590173275Ssam 2591173275Ssam printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]); 2592173275Ssam nbands = (cie->len - 3) / sizeof(cie->band[0]); 2593173275Ssam for (i = 0; i < nbands; i++) { 2594173275Ssam schan = cie->band[i].schan; 2595173275Ssam nchan = cie->band[i].nchan; 2596173275Ssam if (nchan != 1) 2597173275Ssam printf(" %u-%u,%u", schan, schan + nchan-1, 2598173275Ssam cie->band[i].maxtxpwr); 2599173275Ssam else 2600173275Ssam printf(" %u,%u", schan, cie->band[i].maxtxpwr); 2601173275Ssam } 2602173275Ssam printf(">"); 2603173275Ssam} 2604173275Ssam 2605148686Sstefanf/* unaligned little endian access */ 2606138593Ssam#define LE_READ_4(p) \ 2607138593Ssam ((u_int32_t) \ 2608138593Ssam ((((const u_int8_t *)(p))[0] ) | \ 2609138593Ssam (((const u_int8_t *)(p))[1] << 8) | \ 2610138593Ssam (((const u_int8_t *)(p))[2] << 16) | \ 2611138593Ssam (((const u_int8_t *)(p))[3] << 24))) 2612138593Ssam 2613178354Ssamstatic __inline int 2614138593Ssamiswpaoui(const u_int8_t *frm) 2615138593Ssam{ 2616138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 2617138593Ssam} 2618138593Ssam 2619178354Ssamstatic __inline int 2620173275Ssamiswmeinfo(const u_int8_t *frm) 2621138593Ssam{ 2622173275Ssam return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 2623173275Ssam frm[6] == WME_INFO_OUI_SUBTYPE; 2624138593Ssam} 2625138593Ssam 2626178354Ssamstatic __inline int 2627173275Ssamiswmeparam(const u_int8_t *frm) 2628173275Ssam{ 2629173275Ssam return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 2630173275Ssam frm[6] == WME_PARAM_OUI_SUBTYPE; 2631173275Ssam} 2632173275Ssam 2633178354Ssamstatic __inline int 2634138593Ssamisatherosoui(const u_int8_t *frm) 2635138593Ssam{ 2636138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 2637138593Ssam} 2638138593Ssam 2639181454Ssamstatic __inline int 2640181454Ssamiswpsoui(const uint8_t *frm) 2641181454Ssam{ 2642181454Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI); 2643181454Ssam} 2644181454Ssam 2645173275Ssamstatic const char * 2646173275Ssamiename(int elemid) 2647173275Ssam{ 2648173275Ssam switch (elemid) { 2649173275Ssam case IEEE80211_ELEMID_FHPARMS: return " FHPARMS"; 2650173275Ssam case IEEE80211_ELEMID_CFPARMS: return " CFPARMS"; 2651173275Ssam case IEEE80211_ELEMID_TIM: return " TIM"; 2652173275Ssam case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS"; 2653173275Ssam case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE"; 2654173275Ssam case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR"; 2655173275Ssam case IEEE80211_ELEMID_PWRCAP: return " PWRCAP"; 2656173275Ssam case IEEE80211_ELEMID_TPCREQ: return " TPCREQ"; 2657173275Ssam case IEEE80211_ELEMID_TPCREP: return " TPCREP"; 2658173275Ssam case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN"; 2659173275Ssam case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA"; 2660173275Ssam case IEEE80211_ELEMID_MEASREQ: return " MEASREQ"; 2661173275Ssam case IEEE80211_ELEMID_MEASREP: return " MEASREP"; 2662173275Ssam case IEEE80211_ELEMID_QUIET: return " QUIET"; 2663173275Ssam case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS"; 2664173275Ssam case IEEE80211_ELEMID_TPC: return " TPC"; 2665173275Ssam case IEEE80211_ELEMID_CCKM: return " CCKM"; 2666173275Ssam } 2667173275Ssam return " ???"; 2668173275Ssam} 2669173275Ssam 2670138593Ssamstatic void 2671138593Ssamprinties(const u_int8_t *vp, int ielen, int maxcols) 2672138593Ssam{ 2673138593Ssam while (ielen > 0) { 2674138593Ssam switch (vp[0]) { 2675173275Ssam case IEEE80211_ELEMID_SSID: 2676173275Ssam if (verbose) 2677173275Ssam printssid(" SSID", vp, 2+vp[1], maxcols); 2678173275Ssam break; 2679173275Ssam case IEEE80211_ELEMID_RATES: 2680173275Ssam case IEEE80211_ELEMID_XRATES: 2681173275Ssam if (verbose) 2682173275Ssam printrates(vp[0] == IEEE80211_ELEMID_RATES ? 2683173275Ssam " RATES" : " XRATES", vp, 2+vp[1], maxcols); 2684173275Ssam break; 2685173275Ssam case IEEE80211_ELEMID_DSPARMS: 2686173275Ssam if (verbose) 2687173275Ssam printf(" DSPARMS<%u>", vp[2]); 2688173275Ssam break; 2689173275Ssam case IEEE80211_ELEMID_COUNTRY: 2690173275Ssam if (verbose) 2691173275Ssam printcountry(" COUNTRY", vp, 2+vp[1], maxcols); 2692173275Ssam break; 2693173275Ssam case IEEE80211_ELEMID_ERP: 2694173275Ssam if (verbose) 2695173275Ssam printf(" ERP<0x%x>", vp[2]); 2696173275Ssam break; 2697138593Ssam case IEEE80211_ELEMID_VENDOR: 2698138593Ssam if (iswpaoui(vp)) 2699170531Ssam printwpaie(" WPA", vp, 2+vp[1], maxcols); 2700173275Ssam else if (iswmeinfo(vp)) 2701173275Ssam printwmeinfo(" WME", vp, 2+vp[1], maxcols); 2702173275Ssam else if (iswmeparam(vp)) 2703173275Ssam printwmeparam(" WME", vp, 2+vp[1], maxcols); 2704139492Ssam else if (isatherosoui(vp)) 2705170531Ssam printathie(" ATH", vp, 2+vp[1], maxcols); 2706181454Ssam else if (iswpsoui(vp)) 2707181454Ssam printwpsie(" WPS", vp, 2+vp[1], maxcols); 2708173275Ssam else if (verbose) 2709138593Ssam printie(" VEN", vp, 2+vp[1], maxcols); 2710138593Ssam break; 2711138593Ssam case IEEE80211_ELEMID_RSN: 2712170531Ssam printrsnie(" RSN", vp, 2+vp[1], maxcols); 2713138593Ssam break; 2714173275Ssam case IEEE80211_ELEMID_HTCAP: 2715173275Ssam printhtcap(" HTCAP", vp, 2+vp[1], maxcols); 2716173275Ssam break; 2717173275Ssam case IEEE80211_ELEMID_HTINFO: 2718173275Ssam if (verbose) 2719173275Ssam printhtinfo(" HTINFO", vp, 2+vp[1], maxcols); 2720173275Ssam break; 2721138593Ssam default: 2722173275Ssam if (verbose) 2723173275Ssam printie(iename(vp[0]), vp, 2+vp[1], maxcols); 2724138593Ssam break; 2725138593Ssam } 2726138593Ssam ielen -= 2+vp[1]; 2727138593Ssam vp += 2+vp[1]; 2728138593Ssam } 2729138593Ssam} 2730138593Ssam 2731138593Ssamstatic void 2732178354Ssamprintmimo(const struct ieee80211_mimo_info *mi) 2733178354Ssam{ 2734178354Ssam /* NB: don't muddy display unless there's something to show */ 2735178354Ssam if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) { 2736178354Ssam /* XXX ignore EVM for now */ 2737178354Ssam printf(" (rssi %d:%d:%d nf %d:%d:%d)", 2738178354Ssam mi->rssi[0], mi->rssi[1], mi->rssi[2], 2739178354Ssam mi->noise[0], mi->noise[1], mi->noise[2]); 2740178354Ssam } 2741178354Ssam} 2742178354Ssam 2743178354Ssamstatic void 2744138593Ssamlist_scan(int s) 2745138593Ssam{ 2746138593Ssam uint8_t buf[24*1024]; 2747153892Srwatson char ssid[IEEE80211_NWID_LEN+1]; 2748173275Ssam const uint8_t *cp; 2749154522Ssam int len, ssidmax; 2750138593Ssam 2751173275Ssam if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0) 2752138593Ssam errx(1, "unable to get scan results"); 2753138593Ssam if (len < sizeof(struct ieee80211req_scan_result)) 2754138593Ssam return; 2755138593Ssam 2756170531Ssam getchaninfo(s); 2757170531Ssam 2758154522Ssam ssidmax = verbose ? IEEE80211_NWID_LEN : 14; 2759170531Ssam printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n" 2760154522Ssam , ssidmax, ssidmax, "SSID" 2761138593Ssam , "BSSID" 2762138593Ssam , "CHAN" 2763138593Ssam , "RATE" 2764170531Ssam , " S:N" 2765138593Ssam , "INT" 2766138593Ssam , "CAPS" 2767138593Ssam ); 2768138593Ssam cp = buf; 2769138593Ssam do { 2770170531Ssam const struct ieee80211req_scan_result *sr; 2771170531Ssam const uint8_t *vp; 2772138593Ssam 2773170531Ssam sr = (const struct ieee80211req_scan_result *) cp; 2774173275Ssam vp = cp + sr->isr_ie_off; 2775170531Ssam printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s" 2776154522Ssam , ssidmax 2777155461Ssam , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len) 2778154522Ssam , ssid 2779138593Ssam , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 2780165570Ssam , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) 2781138593Ssam , getmaxrate(sr->isr_rates, sr->isr_nrates) 2782170531Ssam , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise 2783138593Ssam , sr->isr_intval 2784138593Ssam , getcaps(sr->isr_capinfo) 2785138593Ssam ); 2786170531Ssam printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24); 2787138593Ssam printf("\n"); 2788138593Ssam cp += sr->isr_len, len -= sr->isr_len; 2789138593Ssam } while (len >= sizeof(struct ieee80211req_scan_result)); 2790138593Ssam} 2791138593Ssam 2792178354Ssam#ifdef __FreeBSD__ 2793138593Ssam#include <net80211/ieee80211_freebsd.h> 2794178354Ssam#endif 2795178354Ssam#ifdef __NetBSD__ 2796178354Ssam#include <net80211/ieee80211_netbsd.h> 2797178354Ssam#endif 2798138593Ssam 2799138593Ssamstatic void 2800138593Ssamscan_and_wait(int s) 2801138593Ssam{ 2802178354Ssam struct ieee80211_scan_req sr; 2803138593Ssam struct ieee80211req ireq; 2804138593Ssam int sroute; 2805138593Ssam 2806138593Ssam sroute = socket(PF_ROUTE, SOCK_RAW, 0); 2807138593Ssam if (sroute < 0) { 2808138593Ssam perror("socket(PF_ROUTE,SOCK_RAW)"); 2809138593Ssam return; 2810138593Ssam } 2811138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 2812138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 2813138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_REQ; 2814178354Ssam 2815178354Ssam memset(&sr, 0, sizeof(sr)); 2816178354Ssam sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE 2817178354Ssam | IEEE80211_IOC_SCAN_NOPICK 2818178354Ssam | IEEE80211_IOC_SCAN_ONCE; 2819178354Ssam sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; 2820178354Ssam sr.sr_nssid = 0; 2821178354Ssam 2822178354Ssam ireq.i_data = &sr; 2823178354Ssam ireq.i_len = sizeof(sr); 2824138593Ssam /* NB: only root can trigger a scan so ignore errors */ 2825138593Ssam if (ioctl(s, SIOCS80211, &ireq) >= 0) { 2826138593Ssam char buf[2048]; 2827138593Ssam struct if_announcemsghdr *ifan; 2828138593Ssam struct rt_msghdr *rtm; 2829138593Ssam 2830138593Ssam do { 2831138593Ssam if (read(sroute, buf, sizeof(buf)) < 0) { 2832138593Ssam perror("read(PF_ROUTE)"); 2833138593Ssam break; 2834138593Ssam } 2835138593Ssam rtm = (struct rt_msghdr *) buf; 2836138593Ssam if (rtm->rtm_version != RTM_VERSION) 2837138593Ssam break; 2838138593Ssam ifan = (struct if_announcemsghdr *) rtm; 2839138593Ssam } while (rtm->rtm_type != RTM_IEEE80211 || 2840138593Ssam ifan->ifan_what != RTM_IEEE80211_SCAN); 2841138593Ssam } 2842138593Ssam close(sroute); 2843138593Ssam} 2844138593Ssam 2845138593Ssamstatic 2846138593SsamDECL_CMD_FUNC(set80211scan, val, d) 2847138593Ssam{ 2848138593Ssam scan_and_wait(s); 2849138593Ssam list_scan(s); 2850138593Ssam} 2851138593Ssam 2852161147Ssamstatic enum ieee80211_opmode get80211opmode(int s); 2853161147Ssam 2854173275Ssamstatic int 2855173275Ssamgettxseq(const struct ieee80211req_sta_info *si) 2856173275Ssam{ 2857173275Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 2858173275Ssam 2859173275Ssam int i, txseq; 2860173275Ssam 2861173275Ssam if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 2862173275Ssam return si->isi_txseqs[0]; 2863173275Ssam /* XXX not right but usually what folks want */ 2864173275Ssam txseq = 0; 2865173275Ssam for (i = 0; i < IEEE80211_TID_SIZE; i++) 2866173275Ssam if (si->isi_txseqs[i] > txseq) 2867173275Ssam txseq = si->isi_txseqs[i]; 2868173275Ssam return txseq; 2869173275Ssam#undef IEEE80211_NODE_QOS 2870173275Ssam} 2871173275Ssam 2872173275Ssamstatic int 2873173275Ssamgetrxseq(const struct ieee80211req_sta_info *si) 2874173275Ssam{ 2875173275Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 2876173275Ssam 2877173275Ssam int i, rxseq; 2878173275Ssam 2879173275Ssam if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 2880173275Ssam return si->isi_rxseqs[0]; 2881173275Ssam /* XXX not right but usually what folks want */ 2882173275Ssam rxseq = 0; 2883173275Ssam for (i = 0; i < IEEE80211_TID_SIZE; i++) 2884173275Ssam if (si->isi_rxseqs[i] > rxseq) 2885173275Ssam rxseq = si->isi_rxseqs[i]; 2886173275Ssam return rxseq; 2887173275Ssam#undef IEEE80211_NODE_QOS 2888173275Ssam} 2889173275Ssam 2890138593Ssamstatic void 2891138593Ssamlist_stations(int s) 2892138593Ssam{ 2893161147Ssam union { 2894161147Ssam struct ieee80211req_sta_req req; 2895161147Ssam uint8_t buf[24*1024]; 2896161147Ssam } u; 2897161147Ssam enum ieee80211_opmode opmode = get80211opmode(s); 2898170531Ssam const uint8_t *cp; 2899138593Ssam int len; 2900138593Ssam 2901161147Ssam /* broadcast address =>'s get all stations */ 2902161147Ssam (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); 2903161147Ssam if (opmode == IEEE80211_M_STA) { 2904161147Ssam /* 2905161147Ssam * Get information about the associated AP. 2906161147Ssam */ 2907173275Ssam (void) get80211(s, IEEE80211_IOC_BSSID, 2908173275Ssam u.req.is_u.macaddr, IEEE80211_ADDR_LEN); 2909161147Ssam } 2910173275Ssam if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0) 2911138593Ssam errx(1, "unable to get station information"); 2912138593Ssam if (len < sizeof(struct ieee80211req_sta_info)) 2913138593Ssam return; 2914138593Ssam 2915170531Ssam getchaninfo(s); 2916170531Ssam 2917159885Ssam printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n" 2918138593Ssam , "ADDR" 2919138593Ssam , "AID" 2920138593Ssam , "CHAN" 2921138593Ssam , "RATE" 2922138593Ssam , "RSSI" 2923138593Ssam , "IDLE" 2924138593Ssam , "TXSEQ" 2925138593Ssam , "RXSEQ" 2926138593Ssam , "CAPS" 2927159885Ssam , "FLAG" 2928138593Ssam ); 2929170531Ssam cp = (const uint8_t *) u.req.info; 2930138593Ssam do { 2931170531Ssam const struct ieee80211req_sta_info *si; 2932138593Ssam 2933170531Ssam si = (const struct ieee80211req_sta_info *) cp; 2934161147Ssam if (si->isi_len < sizeof(*si)) 2935161147Ssam break; 2936170531Ssam printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-4.4s" 2937138593Ssam , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 2938138593Ssam , IEEE80211_AID(si->isi_associd) 2939166015Ssam , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags) 2940178354Ssam , si->isi_txmbps/2 2941170531Ssam , si->isi_rssi/2. 2942138593Ssam , si->isi_inact 2943173275Ssam , gettxseq(si) 2944173275Ssam , getrxseq(si) 2945138593Ssam , getcaps(si->isi_capinfo) 2946159885Ssam , getflags(si->isi_state) 2947138593Ssam ); 2948170531Ssam printies(cp + si->isi_ie_off, si->isi_ie_len, 24); 2949178354Ssam printmimo(&si->isi_mimo); 2950138593Ssam printf("\n"); 2951138593Ssam cp += si->isi_len, len -= si->isi_len; 2952138593Ssam } while (len >= sizeof(struct ieee80211req_sta_info)); 2953138593Ssam} 2954138593Ssam 2955170531Ssamstatic const char * 2956170531Ssamget_chaninfo(const struct ieee80211_channel *c, int precise, 2957170531Ssam char buf[], size_t bsize) 2958138593Ssam{ 2959138593Ssam buf[0] = '\0'; 2960138593Ssam if (IEEE80211_IS_CHAN_FHSS(c)) 2961170531Ssam strlcat(buf, " FHSS", bsize); 2962165570Ssam if (IEEE80211_IS_CHAN_A(c)) { 2963165570Ssam if (IEEE80211_IS_CHAN_HALF(c)) 2964170531Ssam strlcat(buf, " 11a/10Mhz", bsize); 2965165570Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 2966170531Ssam strlcat(buf, " 11a/5Mhz", bsize); 2967165570Ssam else 2968170531Ssam strlcat(buf, " 11a", bsize); 2969165570Ssam } 2970166015Ssam if (IEEE80211_IS_CHAN_ANYG(c)) { 2971166015Ssam if (IEEE80211_IS_CHAN_HALF(c)) 2972170531Ssam strlcat(buf, " 11g/10Mhz", bsize); 2973166015Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 2974170531Ssam strlcat(buf, " 11g/5Mhz", bsize); 2975166015Ssam else 2976170531Ssam strlcat(buf, " 11g", bsize); 2977166015Ssam } else if (IEEE80211_IS_CHAN_B(c)) 2978170531Ssam strlcat(buf, " 11b", bsize); 2979170531Ssam if (IEEE80211_IS_CHAN_TURBO(c)) 2980170531Ssam strlcat(buf, " Turbo", bsize); 2981170531Ssam if (precise) { 2982170531Ssam if (IEEE80211_IS_CHAN_HT20(c)) 2983170531Ssam strlcat(buf, " ht/20", bsize); 2984170531Ssam else if (IEEE80211_IS_CHAN_HT40D(c)) 2985170531Ssam strlcat(buf, " ht/40-", bsize); 2986170531Ssam else if (IEEE80211_IS_CHAN_HT40U(c)) 2987170531Ssam strlcat(buf, " ht/40+", bsize); 2988170531Ssam } else { 2989170531Ssam if (IEEE80211_IS_CHAN_HT(c)) 2990170531Ssam strlcat(buf, " ht", bsize); 2991170531Ssam } 2992170531Ssam return buf; 2993170531Ssam} 2994170531Ssam 2995170531Ssamstatic void 2996173275Ssamprint_chaninfo(const struct ieee80211_channel *c, int verb) 2997170531Ssam{ 2998170531Ssam char buf[14]; 2999170531Ssam 3000138593Ssam printf("Channel %3u : %u%c Mhz%-14.14s", 3001165570Ssam ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, 3002170531Ssam IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', 3003173275Ssam get_chaninfo(c, verb, buf, sizeof(buf))); 3004138593Ssam} 3005138593Ssam 3006138593Ssamstatic void 3007173275Ssamprint_channels(int s, const struct ieee80211req_chaninfo *chans, 3008173275Ssam int allchans, int verb) 3009138593Ssam{ 3010138593Ssam struct ieee80211req_chaninfo achans; 3011170531Ssam uint8_t reported[IEEE80211_CHAN_BYTES]; 3012138593Ssam const struct ieee80211_channel *c; 3013170531Ssam int i, half; 3014138593Ssam 3015170531Ssam memset(&achans, 0, sizeof(achans)); 3016170531Ssam memset(reported, 0, sizeof(reported)); 3017138593Ssam if (!allchans) { 3018138593Ssam struct ieee80211req_chanlist active; 3019138593Ssam 3020173275Ssam if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0) 3021138593Ssam errx(1, "unable to get active channel list"); 3022138593Ssam memset(&achans, 0, sizeof(achans)); 3023173275Ssam for (i = 0; i < chans->ic_nchans; i++) { 3024173275Ssam c = &chans->ic_chans[i]; 3025170531Ssam if (!isset(active.ic_channels, c->ic_ieee)) 3026170531Ssam continue; 3027170531Ssam /* 3028170531Ssam * Suppress compatible duplicates unless 3029170531Ssam * verbose. The kernel gives us it's 3030170531Ssam * complete channel list which has separate 3031170531Ssam * entries for 11g/11b and 11a/turbo. 3032170531Ssam */ 3033173275Ssam if (isset(reported, c->ic_ieee) && !verb) { 3034170531Ssam /* XXX we assume duplicates are adjacent */ 3035170531Ssam achans.ic_chans[achans.ic_nchans-1] = *c; 3036170531Ssam } else { 3037138593Ssam achans.ic_chans[achans.ic_nchans++] = *c; 3038170531Ssam setbit(reported, c->ic_ieee); 3039170531Ssam } 3040138593Ssam } 3041170531Ssam } else { 3042173275Ssam for (i = 0; i < chans->ic_nchans; i++) { 3043173275Ssam c = &chans->ic_chans[i]; 3044170531Ssam /* suppress duplicates as above */ 3045173275Ssam if (isset(reported, c->ic_ieee) && !verb) { 3046170531Ssam /* XXX we assume duplicates are adjacent */ 3047170531Ssam achans.ic_chans[achans.ic_nchans-1] = *c; 3048170531Ssam } else { 3049170531Ssam achans.ic_chans[achans.ic_nchans++] = *c; 3050170531Ssam setbit(reported, c->ic_ieee); 3051170531Ssam } 3052170531Ssam } 3053170531Ssam } 3054138593Ssam half = achans.ic_nchans / 2; 3055138593Ssam if (achans.ic_nchans % 2) 3056138593Ssam half++; 3057170531Ssam 3058138593Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 3059173275Ssam print_chaninfo(&achans.ic_chans[i], verb); 3060173275Ssam print_chaninfo(&achans.ic_chans[half+i], verb); 3061138593Ssam printf("\n"); 3062138593Ssam } 3063138593Ssam if (achans.ic_nchans % 2) { 3064173275Ssam print_chaninfo(&achans.ic_chans[i], verb); 3065138593Ssam printf("\n"); 3066138593Ssam } 3067138593Ssam} 3068138593Ssam 3069138593Ssamstatic void 3070173275Ssamlist_channels(int s, int allchans) 3071173275Ssam{ 3072173275Ssam getchaninfo(s); 3073173275Ssam print_channels(s, &chaninfo, allchans, verbose); 3074173275Ssam} 3075173275Ssam 3076173275Ssamstatic void 3077170531Ssamprint_txpow(const struct ieee80211_channel *c) 3078170531Ssam{ 3079170531Ssam printf("Channel %3u : %u Mhz %3.1f reg %2d ", 3080170531Ssam c->ic_ieee, c->ic_freq, 3081170531Ssam c->ic_maxpower/2., c->ic_maxregpower); 3082170531Ssam} 3083170531Ssam 3084170531Ssamstatic void 3085170531Ssamprint_txpow_verbose(const struct ieee80211_channel *c) 3086170531Ssam{ 3087173275Ssam print_chaninfo(c, 1); 3088170531Ssam printf("min %4.1f dBm max %3.1f dBm reg %2d dBm", 3089170531Ssam c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower); 3090170531Ssam /* indicate where regulatory cap limits power use */ 3091170531Ssam if (c->ic_maxpower > 2*c->ic_maxregpower) 3092170531Ssam printf(" <"); 3093170531Ssam} 3094170531Ssam 3095170531Ssamstatic void 3096170531Ssamlist_txpow(int s) 3097170531Ssam{ 3098170531Ssam struct ieee80211req_chaninfo achans; 3099170531Ssam uint8_t reported[IEEE80211_CHAN_BYTES]; 3100170531Ssam struct ieee80211_channel *c, *prev; 3101170531Ssam int i, half; 3102170531Ssam 3103170531Ssam getchaninfo(s); 3104170531Ssam memset(&achans, 0, sizeof(achans)); 3105170531Ssam memset(reported, 0, sizeof(reported)); 3106170531Ssam for (i = 0; i < chaninfo.ic_nchans; i++) { 3107170531Ssam c = &chaninfo.ic_chans[i]; 3108170531Ssam /* suppress duplicates as above */ 3109170531Ssam if (isset(reported, c->ic_ieee) && !verbose) { 3110170531Ssam /* XXX we assume duplicates are adjacent */ 3111170531Ssam prev = &achans.ic_chans[achans.ic_nchans-1]; 3112170531Ssam /* display highest power on channel */ 3113170531Ssam if (c->ic_maxpower > prev->ic_maxpower) 3114170531Ssam *prev = *c; 3115170531Ssam } else { 3116170531Ssam achans.ic_chans[achans.ic_nchans++] = *c; 3117170531Ssam setbit(reported, c->ic_ieee); 3118170531Ssam } 3119170531Ssam } 3120170531Ssam if (!verbose) { 3121170531Ssam half = achans.ic_nchans / 2; 3122170531Ssam if (achans.ic_nchans % 2) 3123170531Ssam half++; 3124170531Ssam 3125170531Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 3126170531Ssam print_txpow(&achans.ic_chans[i]); 3127170531Ssam print_txpow(&achans.ic_chans[half+i]); 3128170531Ssam printf("\n"); 3129170531Ssam } 3130170531Ssam if (achans.ic_nchans % 2) { 3131170531Ssam print_txpow(&achans.ic_chans[i]); 3132170531Ssam printf("\n"); 3133170531Ssam } 3134170531Ssam } else { 3135170531Ssam for (i = 0; i < achans.ic_nchans; i++) { 3136170531Ssam print_txpow_verbose(&achans.ic_chans[i]); 3137170531Ssam printf("\n"); 3138170531Ssam } 3139170531Ssam } 3140170531Ssam} 3141170531Ssam 3142170531Ssamstatic void 3143138593Ssamlist_keys(int s) 3144138593Ssam{ 3145138593Ssam} 3146138593Ssam 3147138593Ssam#define IEEE80211_C_BITS \ 3148181102Ssam "\20\1STA\7FF\10TURBOP\11IBSS\12PMGT" \ 3149178354Ssam "\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \ 3150181102Ssam "\21MONITOR\22DFS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \ 3151178354Ssam "\37TXFRAG" 3152138593Ssam 3153178354Ssam#define IEEE80211_CRYPTO_BITS \ 3154178354Ssam "\20\1WEP\2TKIP\3AES\4AES_CCM\5TKIPMIC\6CKIP\12PMGT" 3155178354Ssam 3156178354Ssam#define IEEE80211_HTCAP_BITS \ 3157178354Ssam "\20\1LDPC\2CHWIDTH40\5GREENFIELD\6SHORTGI20\7SHORTGI40\10TXSTBC" \ 3158178354Ssam "\21AMPDU\22AMSDU\23HT" 3159178354Ssam 3160138593Ssamstatic void 3161138593Ssamlist_capabilities(int s) 3162138593Ssam{ 3163178354Ssam struct ieee80211_devcaps_req dc; 3164138593Ssam 3165178354Ssam getdevcaps(s, &dc); 3166178354Ssam printb("drivercaps", dc.dc_drivercaps, IEEE80211_C_BITS); 3167178354Ssam if (dc.dc_cryptocaps != 0 || verbose) { 3168178354Ssam putchar('\n'); 3169178354Ssam printb("cryptocaps", dc.dc_cryptocaps, IEEE80211_CRYPTO_BITS); 3170178354Ssam } 3171178354Ssam if (dc.dc_htcaps != 0 || verbose) { 3172178354Ssam putchar('\n'); 3173178354Ssam printb("htcaps", dc.dc_htcaps, IEEE80211_HTCAP_BITS); 3174178354Ssam } 3175138593Ssam putchar('\n'); 3176138593Ssam} 3177138593Ssam 3178173275Ssamstatic int 3179173275Ssamget80211wme(int s, int param, int ac, int *val) 3180173275Ssam{ 3181173275Ssam struct ieee80211req ireq; 3182173275Ssam 3183173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3184173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3185173275Ssam ireq.i_type = param; 3186173275Ssam ireq.i_len = ac; 3187173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) { 3188173275Ssam warn("cannot get WME parameter %d, ac %d%s", 3189173275Ssam param, ac & IEEE80211_WMEPARAM_VAL, 3190173275Ssam ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : ""); 3191173275Ssam return -1; 3192173275Ssam } 3193173275Ssam *val = ireq.i_val; 3194173275Ssam return 0; 3195173275Ssam} 3196173275Ssam 3197138593Ssamstatic void 3198181199Ssamlist_wme_aci(int s, const char *tag, int ac) 3199138593Ssam{ 3200181199Ssam int val; 3201138593Ssam 3202181199Ssam printf("\t%s", tag); 3203138593Ssam 3204181199Ssam /* show WME BSS parameters */ 3205181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1) 3206181199Ssam printf(" cwmin %2u", val); 3207181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1) 3208181199Ssam printf(" cwmax %2u", val); 3209181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1) 3210181199Ssam printf(" aifs %2u", val); 3211181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1) 3212181199Ssam printf(" txopLimit %3u", val); 3213181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) { 3214181199Ssam if (val) 3215181199Ssam printf(" acm"); 3216181199Ssam else if (verbose) 3217181199Ssam printf(" -acm"); 3218181199Ssam } 3219181199Ssam /* !BSS only */ 3220181199Ssam if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 3221181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) { 3222181199Ssam if (!val) 3223181199Ssam printf(" -ack"); 3224138593Ssam else if (verbose) 3225181199Ssam printf(" ack"); 3226138593Ssam } 3227181199Ssam } 3228181199Ssam printf("\n"); 3229181199Ssam} 3230181199Ssam 3231181199Ssamstatic void 3232181199Ssamlist_wme(int s) 3233181199Ssam{ 3234181199Ssam static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 3235181199Ssam int ac; 3236181199Ssam 3237181199Ssam if (verbose) { 3238181199Ssam /* display both BSS and local settings */ 3239181199Ssam for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 3240181199Ssam again: 3241181199Ssam if (ac & IEEE80211_WMEPARAM_BSS) 3242181199Ssam list_wme_aci(s, " ", ac); 3243181199Ssam else 3244181199Ssam list_wme_aci(s, acnames[ac], ac); 3245181199Ssam if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 3246181199Ssam ac |= IEEE80211_WMEPARAM_BSS; 3247181199Ssam goto again; 3248181199Ssam } else 3249181199Ssam ac &= ~IEEE80211_WMEPARAM_BSS; 3250138593Ssam } 3251181199Ssam } else { 3252181199Ssam /* display only channel settings */ 3253181199Ssam for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) 3254181199Ssam list_wme_aci(s, acnames[ac], ac); 3255138593Ssam } 3256138593Ssam} 3257138593Ssam 3258149029Ssamstatic void 3259178354Ssamlist_roam(int s) 3260178354Ssam{ 3261178354Ssam const struct ieee80211_roamparam *rp; 3262178354Ssam int mode; 3263178354Ssam 3264178354Ssam getroam(s); 3265178354Ssam for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_11NA; mode++) { 3266178354Ssam rp = &roamparams.params[mode]; 3267178354Ssam if (rp->rssi == 0 && rp->rate == 0) 3268178354Ssam continue; 3269178354Ssam if (rp->rssi & 1) 3270178354Ssam LINE_CHECK("roam:%-6.6s rssi %2u.5dBm rate %2u Mb/s", 3271178354Ssam modename[mode], rp->rssi/2, rp->rate/2); 3272178354Ssam else 3273178354Ssam LINE_CHECK("roam:%-6.6s rssi %4udBm rate %2u Mb/s", 3274178354Ssam modename[mode], rp->rssi/2, rp->rate/2); 3275178354Ssam } 3276178354Ssam for (; mode < IEEE80211_MODE_MAX; mode++) { 3277178354Ssam rp = &roamparams.params[mode]; 3278178354Ssam if (rp->rssi == 0 && rp->rate == 0) 3279178354Ssam continue; 3280178354Ssam if (rp->rssi & 1) 3281178354Ssam LINE_CHECK("roam:%-6.6s rssi %2u.5dBm MCS %2u ", 3282178354Ssam modename[mode], rp->rssi/2, rp->rate &~ 0x80); 3283178354Ssam else 3284178354Ssam LINE_CHECK("roam:%-6.6s rssi %4udBm MCS %2u ", 3285178354Ssam modename[mode], rp->rssi/2, rp->rate &~ 0x80); 3286178354Ssam } 3287178354Ssam} 3288178354Ssam 3289178354Ssamstatic void 3290178354Ssamlist_txparams(int s) 3291178354Ssam{ 3292178354Ssam const struct ieee80211_txparam *tp; 3293178354Ssam int mode; 3294178354Ssam 3295178354Ssam gettxparams(s); 3296178354Ssam for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_11NA; mode++) { 3297178354Ssam tp = &txparams.params[mode]; 3298178354Ssam if (tp->mgmtrate == 0 && tp->mcastrate == 0) 3299178354Ssam continue; 3300178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 3301178354Ssam LINE_CHECK("%-6.6s ucast NONE mgmt %2u Mb/s " 3302178354Ssam "mcast %2u Mb/s maxretry %u", 3303178354Ssam modename[mode], tp->mgmtrate/2, 3304178354Ssam tp->mcastrate/2, tp->maxretry); 3305178354Ssam else 3306178354Ssam LINE_CHECK("%-6.6s ucast %2u Mb/s mgmt %2u Mb/s " 3307178354Ssam "mcast %2u Mb/s maxretry %u", 3308178354Ssam modename[mode], tp->ucastrate/2, tp->mgmtrate/2, 3309178354Ssam tp->mcastrate/2, tp->maxretry); 3310178354Ssam } 3311178354Ssam for (; mode < IEEE80211_MODE_MAX; mode++) { 3312178354Ssam tp = &txparams.params[mode]; 3313178354Ssam if (tp->mgmtrate == 0 && tp->mcastrate == 0) 3314178354Ssam continue; 3315178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 3316178354Ssam LINE_CHECK("%-6.6s ucast NONE mgmt %2u MCS " 3317178354Ssam "mcast %2u MCS maxretry %u", 3318178354Ssam modename[mode], tp->mgmtrate &~ 0x80, 3319178354Ssam tp->mcastrate &~ 0x80, tp->maxretry); 3320178354Ssam else 3321178354Ssam LINE_CHECK("%-6.6s ucast %2u MCS mgmt %2u MCS " 3322178354Ssam "mcast %2u MCS maxretry %u", 3323178354Ssam modename[mode], tp->ucastrate &~ 0x80, 3324178354Ssam tp->mgmtrate &~ 0x80, 3325178354Ssam tp->mcastrate &~ 0x80, tp->maxretry); 3326178354Ssam } 3327178354Ssam} 3328178354Ssam 3329178354Ssamstatic void 3330173275Ssamprintpolicy(int policy) 3331173275Ssam{ 3332173275Ssam switch (policy) { 3333173275Ssam case IEEE80211_MACCMD_POLICY_OPEN: 3334173275Ssam printf("policy: open\n"); 3335173275Ssam break; 3336173275Ssam case IEEE80211_MACCMD_POLICY_ALLOW: 3337173275Ssam printf("policy: allow\n"); 3338173275Ssam break; 3339173275Ssam case IEEE80211_MACCMD_POLICY_DENY: 3340173275Ssam printf("policy: deny\n"); 3341173275Ssam break; 3342178354Ssam case IEEE80211_MACCMD_POLICY_RADIUS: 3343178354Ssam printf("policy: radius\n"); 3344178354Ssam break; 3345173275Ssam default: 3346173275Ssam printf("policy: unknown (%u)\n", policy); 3347173275Ssam break; 3348173275Ssam } 3349173275Ssam} 3350173275Ssam 3351173275Ssamstatic void 3352149029Ssamlist_mac(int s) 3353149029Ssam{ 3354149029Ssam struct ieee80211req ireq; 3355149029Ssam struct ieee80211req_maclist *acllist; 3356173275Ssam int i, nacls, policy, len; 3357173275Ssam uint8_t *data; 3358149029Ssam char c; 3359149029Ssam 3360149029Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3361149029Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 3362149029Ssam ireq.i_type = IEEE80211_IOC_MACCMD; 3363149029Ssam ireq.i_val = IEEE80211_MACCMD_POLICY; 3364149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) { 3365149029Ssam if (errno == EINVAL) { 3366149029Ssam printf("No acl policy loaded\n"); 3367149029Ssam return; 3368149029Ssam } 3369149029Ssam err(1, "unable to get mac policy"); 3370149029Ssam } 3371149029Ssam policy = ireq.i_val; 3372149029Ssam if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 3373149029Ssam c = '*'; 3374149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 3375149029Ssam c = '+'; 3376149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 3377149029Ssam c = '-'; 3378178354Ssam } else if (policy == IEEE80211_MACCMD_POLICY_RADIUS) { 3379178354Ssam c = 'r'; /* NB: should never have entries */ 3380149029Ssam } else { 3381149029Ssam printf("policy: unknown (%u)\n", policy); 3382149029Ssam c = '?'; 3383149029Ssam } 3384173275Ssam if (verbose || c == '?') 3385173275Ssam printpolicy(policy); 3386173275Ssam 3387175952Ssam ireq.i_val = IEEE80211_MACCMD_LIST; 3388175952Ssam ireq.i_len = 0; 3389175952Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 3390173275Ssam err(1, "unable to get mac acl list size"); 3391175952Ssam if (ireq.i_len == 0) { /* NB: no acls */ 3392173275Ssam if (!(verbose || c == '?')) 3393173275Ssam printpolicy(policy); 3394173275Ssam return; 3395173275Ssam } 3396175952Ssam len = ireq.i_len; 3397173275Ssam 3398173275Ssam data = malloc(len); 3399173275Ssam if (data == NULL) 3400173275Ssam err(1, "out of memory for acl list"); 3401173275Ssam 3402175952Ssam ireq.i_data = data; 3403175952Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 3404173275Ssam err(1, "unable to get mac acl list"); 3405173275Ssam nacls = len / sizeof(*acllist); 3406173275Ssam acllist = (struct ieee80211req_maclist *) data; 3407149029Ssam for (i = 0; i < nacls; i++) 3408149029Ssam printf("%c%s\n", c, ether_ntoa( 3409149029Ssam (const struct ether_addr *) acllist[i].ml_macaddr)); 3410173275Ssam free(data); 3411149029Ssam} 3412149029Ssam 3413178354Ssamstatic void 3414178354Ssamprint_regdomain(const struct ieee80211_regdomain *reg, int verb) 3415178354Ssam{ 3416178354Ssam if ((reg->regdomain != 0 && 3417178354Ssam reg->regdomain != reg->country) || verb) { 3418178354Ssam const struct regdomain *rd = 3419178354Ssam lib80211_regdomain_findbysku(getregdata(), reg->regdomain); 3420178354Ssam if (rd == NULL) 3421178354Ssam LINE_CHECK("regdomain %d", reg->regdomain); 3422178354Ssam else 3423178354Ssam LINE_CHECK("regdomain %s", rd->name); 3424178354Ssam } 3425178354Ssam if (reg->country != 0 || verb) { 3426178354Ssam const struct country *cc = 3427178354Ssam lib80211_country_findbycc(getregdata(), reg->country); 3428178354Ssam if (cc == NULL) 3429178354Ssam LINE_CHECK("country %d", reg->country); 3430178354Ssam else 3431178354Ssam LINE_CHECK("country %s", cc->isoname); 3432178354Ssam } 3433178354Ssam if (reg->location == 'I') 3434178354Ssam LINE_CHECK("indoor"); 3435178354Ssam else if (reg->location == 'O') 3436178354Ssam LINE_CHECK("outdoor"); 3437178354Ssam else if (verb) 3438178354Ssam LINE_CHECK("anywhere"); 3439178354Ssam if (reg->ecm) 3440178354Ssam LINE_CHECK("ecm"); 3441178354Ssam else if (verb) 3442178354Ssam LINE_CHECK("-ecm"); 3443178354Ssam} 3444178354Ssam 3445178354Ssamstatic void 3446178354Ssamlist_regdomain(int s, int channelsalso) 3447178354Ssam{ 3448178354Ssam getregdomain(s); 3449178354Ssam if (channelsalso) { 3450178354Ssam getchaninfo(s); 3451178354Ssam spacer = ':'; 3452178354Ssam print_regdomain(®domain, 1); 3453178354Ssam LINE_BREAK(); 3454178354Ssam print_channels(s, &chaninfo, 1/*allchans*/, 1/*verbose*/); 3455178354Ssam } else 3456178354Ssam print_regdomain(®domain, verbose); 3457178354Ssam} 3458178354Ssam 3459138593Ssamstatic 3460138593SsamDECL_CMD_FUNC(set80211list, arg, d) 3461138593Ssam{ 3462138593Ssam#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 3463138593Ssam 3464173275Ssam LINE_INIT('\t'); 3465173275Ssam 3466138593Ssam if (iseq(arg, "sta")) 3467138593Ssam list_stations(s); 3468138593Ssam else if (iseq(arg, "scan") || iseq(arg, "ap")) 3469138593Ssam list_scan(s); 3470138593Ssam else if (iseq(arg, "chan") || iseq(arg, "freq")) 3471138593Ssam list_channels(s, 1); 3472138593Ssam else if (iseq(arg, "active")) 3473138593Ssam list_channels(s, 0); 3474138593Ssam else if (iseq(arg, "keys")) 3475138593Ssam list_keys(s); 3476138593Ssam else if (iseq(arg, "caps")) 3477138593Ssam list_capabilities(s); 3478178354Ssam else if (iseq(arg, "wme") || iseq(arg, "wmm")) 3479138593Ssam list_wme(s); 3480149029Ssam else if (iseq(arg, "mac")) 3481149029Ssam list_mac(s); 3482170531Ssam else if (iseq(arg, "txpow")) 3483170531Ssam list_txpow(s); 3484178354Ssam else if (iseq(arg, "roam")) 3485178354Ssam list_roam(s); 3486178354Ssam else if (iseq(arg, "txparam") || iseq(arg, "txparm")) 3487178354Ssam list_txparams(s); 3488178354Ssam else if (iseq(arg, "regdomain")) 3489178354Ssam list_regdomain(s, 1); 3490178354Ssam else if (iseq(arg, "countries")) 3491178354Ssam list_countries(); 3492138593Ssam else 3493138593Ssam errx(1, "Don't know how to list %s for %s", arg, name); 3494178354Ssam LINE_BREAK(); 3495138593Ssam#undef iseq 3496138593Ssam} 3497138593Ssam 3498138593Ssamstatic enum ieee80211_opmode 3499138593Ssamget80211opmode(int s) 3500138593Ssam{ 3501138593Ssam struct ifmediareq ifmr; 3502138593Ssam 3503138593Ssam (void) memset(&ifmr, 0, sizeof(ifmr)); 3504138593Ssam (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 3505138593Ssam 3506138593Ssam if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 3507138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 3508138593Ssam return IEEE80211_M_IBSS; /* XXX ahdemo */ 3509138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 3510138593Ssam return IEEE80211_M_HOSTAP; 3511138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 3512138593Ssam return IEEE80211_M_MONITOR; 3513138593Ssam } 3514138593Ssam return IEEE80211_M_STA; 3515138593Ssam} 3516138593Ssam 3517138593Ssam#if 0 3518138593Ssamstatic void 3519138593Ssamprintcipher(int s, struct ieee80211req *ireq, int keylenop) 3520138593Ssam{ 3521138593Ssam switch (ireq->i_val) { 3522138593Ssam case IEEE80211_CIPHER_WEP: 3523138593Ssam ireq->i_type = keylenop; 3524138593Ssam if (ioctl(s, SIOCG80211, ireq) != -1) 3525138593Ssam printf("WEP-%s", 3526138593Ssam ireq->i_len <= 5 ? "40" : 3527138593Ssam ireq->i_len <= 13 ? "104" : "128"); 3528138593Ssam else 3529138593Ssam printf("WEP"); 3530138593Ssam break; 3531138593Ssam case IEEE80211_CIPHER_TKIP: 3532138593Ssam printf("TKIP"); 3533138593Ssam break; 3534138593Ssam case IEEE80211_CIPHER_AES_OCB: 3535138593Ssam printf("AES-OCB"); 3536138593Ssam break; 3537138593Ssam case IEEE80211_CIPHER_AES_CCM: 3538138593Ssam printf("AES-CCM"); 3539138593Ssam break; 3540138593Ssam case IEEE80211_CIPHER_CKIP: 3541138593Ssam printf("CKIP"); 3542138593Ssam break; 3543138593Ssam case IEEE80211_CIPHER_NONE: 3544138593Ssam printf("NONE"); 3545138593Ssam break; 3546138593Ssam default: 3547138593Ssam printf("UNKNOWN (0x%x)", ireq->i_val); 3548138593Ssam break; 3549138593Ssam } 3550138593Ssam} 3551138593Ssam#endif 3552138593Ssam 3553155931Ssamstatic void 3554138593Ssamprintkey(const struct ieee80211req_key *ik) 3555138593Ssam{ 3556138593Ssam static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 3557138593Ssam int keylen = ik->ik_keylen; 3558138593Ssam int printcontents; 3559138593Ssam 3560148001Srwatson printcontents = printkeys && 3561138593Ssam (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 3562138593Ssam if (printcontents) 3563138593Ssam LINE_BREAK(); 3564138593Ssam switch (ik->ik_type) { 3565138593Ssam case IEEE80211_CIPHER_WEP: 3566138593Ssam /* compatibility */ 3567155931Ssam LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1, 3568138593Ssam keylen <= 5 ? "40-bit" : 3569138593Ssam keylen <= 13 ? "104-bit" : "128-bit"); 3570138593Ssam break; 3571138593Ssam case IEEE80211_CIPHER_TKIP: 3572138593Ssam if (keylen > 128/8) 3573138593Ssam keylen -= 128/8; /* ignore MIC for now */ 3574155931Ssam LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3575138593Ssam break; 3576138593Ssam case IEEE80211_CIPHER_AES_OCB: 3577155931Ssam LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3578138593Ssam break; 3579138593Ssam case IEEE80211_CIPHER_AES_CCM: 3580155931Ssam LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3581138593Ssam break; 3582138593Ssam case IEEE80211_CIPHER_CKIP: 3583155931Ssam LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3584138593Ssam break; 3585138593Ssam case IEEE80211_CIPHER_NONE: 3586155931Ssam LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3587138593Ssam break; 3588138593Ssam default: 3589155931Ssam LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit", 3590138593Ssam ik->ik_type, ik->ik_keyix+1, 8*keylen); 3591138593Ssam break; 3592138593Ssam } 3593138593Ssam if (printcontents) { 3594138593Ssam int i; 3595138593Ssam 3596138593Ssam printf(" <"); 3597138593Ssam for (i = 0; i < keylen; i++) 3598138593Ssam printf("%02x", ik->ik_keydata[i]); 3599138593Ssam printf(">"); 3600138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 3601138593Ssam (ik->ik_keyrsc != 0 || verbose)) 3602146873Sjhb printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 3603138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 3604138593Ssam (ik->ik_keytsc != 0 || verbose)) 3605146873Sjhb printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 3606138593Ssam if (ik->ik_flags != 0 && verbose) { 3607138593Ssam const char *sep = " "; 3608138593Ssam 3609138593Ssam if (ik->ik_flags & IEEE80211_KEY_XMIT) 3610138593Ssam printf("%stx", sep), sep = "+"; 3611138593Ssam if (ik->ik_flags & IEEE80211_KEY_RECV) 3612138593Ssam printf("%srx", sep), sep = "+"; 3613138593Ssam if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 3614138593Ssam printf("%sdef", sep), sep = "+"; 3615138593Ssam } 3616138593Ssam LINE_BREAK(); 3617138593Ssam } 3618138593Ssam} 3619138593Ssam 3620138593Ssamstatic void 3621173275Ssamprintrate(const char *tag, int v, int defrate, int defmcs) 3622138593Ssam{ 3623173275Ssam if (v == 11) 3624173275Ssam LINE_CHECK("%s 5.5", tag); 3625173275Ssam else if (v & 0x80) { 3626173275Ssam if (v != defmcs) 3627173275Ssam LINE_CHECK("%s %d", tag, v &~ 0x80); 3628173275Ssam } else { 3629173275Ssam if (v != defrate) 3630173275Ssam LINE_CHECK("%s %d", tag, v/2); 3631173275Ssam } 3632173275Ssam} 3633173275Ssam 3634173275Ssamstatic int 3635173275Ssamgetssid(int s, int ix, void *data, size_t len, int *plen) 3636173275Ssam{ 3637138593Ssam struct ieee80211req ireq; 3638138593Ssam 3639138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3640138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3641173275Ssam ireq.i_type = IEEE80211_IOC_SSID; 3642173275Ssam ireq.i_val = ix; 3643173275Ssam ireq.i_data = data; 3644173275Ssam ireq.i_len = len; 3645173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 3646173275Ssam return -1; 3647173275Ssam *plen = ireq.i_len; 3648173275Ssam return 0; 3649173275Ssam} 365077218Sphk 3651173275Ssamstatic void 3652173275Ssamieee80211_status(int s) 3653173275Ssam{ 3654173275Ssam static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 3655173275Ssam enum ieee80211_opmode opmode = get80211opmode(s); 3656173275Ssam int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode; 3657173275Ssam uint8_t data[32]; 3658173275Ssam const struct ieee80211_channel *c; 3659178354Ssam const struct ieee80211_roamparam *rp; 3660178354Ssam const struct ieee80211_txparam *tp; 3661173275Ssam 3662173275Ssam if (getssid(s, -1, data, sizeof(data), &len) < 0) { 3663148686Sstefanf /* If we can't get the SSID, this isn't an 802.11 device. */ 366477218Sphk return; 366577218Sphk } 3666173275Ssam 3667173275Ssam /* 3668173275Ssam * Invalidate cached state so printing status for multiple 3669173275Ssam * if's doesn't reuse the first interfaces' cached state. 3670173275Ssam */ 3671173275Ssam gotcurchan = 0; 3672178354Ssam gotroam = 0; 3673178354Ssam gottxparams = 0; 3674173275Ssam gothtconf = 0; 3675178354Ssam gotregdomain = 0; 3676173275Ssam 3677173275Ssam if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0) 3678173275Ssam num = 0; 3679138593Ssam printf("\tssid "); 3680138593Ssam if (num > 1) { 3681173275Ssam for (i = 0; i < num; i++) { 3682173275Ssam if (getssid(s, i, data, sizeof(data), &len) >= 0 && len > 0) { 3683173275Ssam printf(" %d:", i + 1); 3684173275Ssam print_string(data, len); 3685138593Ssam } 368688748Sambrisko } 3687138593Ssam } else 3688173275Ssam print_string(data, len); 368977218Sphk 3690173275Ssam c = getcurchan(s); 3691170531Ssam if (c->ic_freq != IEEE80211_CHAN_ANY) { 3692170531Ssam char buf[14]; 3693170531Ssam printf(" channel %d (%u Mhz%s)", c->ic_ieee, c->ic_freq, 3694170531Ssam get_chaninfo(c, 1, buf, sizeof(buf))); 3695138593Ssam } else if (verbose) 3696138593Ssam printf(" channel UNDEF"); 3697138593Ssam 3698173275Ssam if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 && 3699173275Ssam (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) 3700173275Ssam printf(" bssid %s", ether_ntoa((struct ether_addr *)data)); 3701138593Ssam 3702173275Ssam if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) { 3703138593Ssam printf("\n\tstationname "); 3704173275Ssam print_string(data, len); 370577218Sphk } 370677218Sphk 3707138593Ssam spacer = ' '; /* force first break */ 3708138593Ssam LINE_BREAK(); 370977218Sphk 3710178354Ssam list_regdomain(s, 0); 3711178354Ssam 3712173275Ssam wpa = 0; 3713173275Ssam if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) { 3714173275Ssam switch (val) { 3715173275Ssam case IEEE80211_AUTH_NONE: 3716173275Ssam LINE_CHECK("authmode NONE"); 3717173275Ssam break; 3718173275Ssam case IEEE80211_AUTH_OPEN: 3719173275Ssam LINE_CHECK("authmode OPEN"); 3720173275Ssam break; 3721173275Ssam case IEEE80211_AUTH_SHARED: 3722173275Ssam LINE_CHECK("authmode SHARED"); 3723173275Ssam break; 3724173275Ssam case IEEE80211_AUTH_8021X: 3725173275Ssam LINE_CHECK("authmode 802.1x"); 3726173275Ssam break; 3727173275Ssam case IEEE80211_AUTH_WPA: 3728173275Ssam if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0) 3729173275Ssam wpa = 1; /* default to WPA1 */ 3730173275Ssam switch (wpa) { 3731173275Ssam case 2: 3732173275Ssam LINE_CHECK("authmode WPA2/802.11i"); 373377218Sphk break; 3734173275Ssam case 3: 3735173275Ssam LINE_CHECK("authmode WPA1+WPA2/802.11i"); 373677218Sphk break; 3737127649Ssam default: 3738173275Ssam LINE_CHECK("authmode WPA"); 3739127649Ssam break; 3740173275Ssam } 3741173275Ssam break; 3742173275Ssam case IEEE80211_AUTH_AUTO: 3743173275Ssam LINE_CHECK("authmode AUTO"); 3744173275Ssam break; 3745173275Ssam default: 3746173275Ssam LINE_CHECK("authmode UNKNOWN (0x%x)", val); 3747173275Ssam break; 3748127649Ssam } 3749127649Ssam } 3750127649Ssam 3751173275Ssam if (wpa || verbose) { 3752178354Ssam if (get80211val(s, IEEE80211_IOC_WPS, &val) != -1) { 3753178354Ssam if (val) 3754178354Ssam LINE_CHECK("wps"); 3755178354Ssam else if (verbose) 3756178354Ssam LINE_CHECK("-wps"); 3757178354Ssam } 3758178354Ssam if (get80211val(s, IEEE80211_IOC_TSN, &val) != -1) { 3759178354Ssam if (val) 3760178354Ssam LINE_CHECK("tsn"); 3761178354Ssam else if (verbose) 3762178354Ssam LINE_CHECK("-tsn"); 3763178354Ssam } 3764173275Ssam if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) { 3765173275Ssam if (val) 3766173275Ssam LINE_CHECK("countermeasures"); 3767173275Ssam else if (verbose) 3768173275Ssam LINE_CHECK("-countermeasures"); 3769173275Ssam } 3770178354Ssam#if 0 3771178354Ssam /* XXX not interesting with WPA done in user space */ 3772178354Ssam ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 3773178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3774178354Ssam } 3775178354Ssam 3776178354Ssam ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 3777178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3778178354Ssam LINE_CHECK("mcastcipher "); 3779178354Ssam printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 3780178354Ssam spacer = ' '; 3781178354Ssam } 3782178354Ssam 3783178354Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 3784178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3785178354Ssam LINE_CHECK("ucastcipher "); 3786178354Ssam printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 3787178354Ssam } 3788178354Ssam 3789178354Ssam if (wpa & 2) { 3790178354Ssam ireq.i_type = IEEE80211_IOC_RSNCAPS; 3791178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3792178354Ssam LINE_CHECK("RSN caps 0x%x", ireq.i_val); 3793178354Ssam spacer = ' '; 3794178354Ssam } 3795178354Ssam } 3796178354Ssam 3797178354Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 3798178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3799178354Ssam } 3800178354Ssam#endif 3801173275Ssam } 3802138593Ssam 3803173275Ssam if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 && 3804173275Ssam wepmode != IEEE80211_WEP_NOSUP) { 3805173275Ssam int firstkey; 3806173275Ssam 3807138718Ssam switch (wepmode) { 3808173275Ssam case IEEE80211_WEP_OFF: 3809173275Ssam LINE_CHECK("privacy OFF"); 3810173275Ssam break; 3811173275Ssam case IEEE80211_WEP_ON: 3812173275Ssam LINE_CHECK("privacy ON"); 3813173275Ssam break; 3814173275Ssam case IEEE80211_WEP_MIXED: 3815173275Ssam LINE_CHECK("privacy MIXED"); 3816173275Ssam break; 3817173275Ssam default: 3818173275Ssam LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); 3819173275Ssam break; 382077218Sphk } 382177218Sphk 382277218Sphk /* 382377218Sphk * If we get here then we've got WEP support so we need 382477218Sphk * to print WEP status. 382591454Sbrooks */ 382677218Sphk 3827173275Ssam if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) { 382877218Sphk warn("WEP support, but no tx key!"); 382977218Sphk goto end; 383077218Sphk } 3831173275Ssam if (val != -1) 3832173275Ssam LINE_CHECK("deftxkey %d", val+1); 3833138718Ssam else if (wepmode != IEEE80211_WEP_OFF || verbose) 3834155931Ssam LINE_CHECK("deftxkey UNDEF"); 383577218Sphk 3836173275Ssam if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) { 383777218Sphk warn("WEP support, but no NUMWEPKEYS support!"); 383877218Sphk goto end; 383977218Sphk } 384077218Sphk 3841138593Ssam firstkey = 1; 3842138593Ssam for (i = 0; i < num; i++) { 3843138593Ssam struct ieee80211req_key ik; 384477218Sphk 3845138593Ssam memset(&ik, 0, sizeof(ik)); 3846138593Ssam ik.ik_keyix = i; 3847173275Ssam if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) { 384877218Sphk warn("WEP support, but can get keys!"); 384977218Sphk goto end; 385077218Sphk } 3851138593Ssam if (ik.ik_keylen != 0) { 3852138593Ssam if (verbose) 3853138593Ssam LINE_BREAK(); 3854138593Ssam printkey(&ik); 3855138593Ssam firstkey = 0; 3856138593Ssam } 3857138593Ssam } 3858173275Ssamend: 3859173275Ssam ; 3860138593Ssam } 3861138593Ssam 3862173275Ssam if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 && 3863173275Ssam val != IEEE80211_POWERSAVE_NOSUP ) { 3864173275Ssam if (val != IEEE80211_POWERSAVE_OFF || verbose) { 3865173275Ssam switch (val) { 3866173275Ssam case IEEE80211_POWERSAVE_OFF: 3867173275Ssam LINE_CHECK("powersavemode OFF"); 3868173275Ssam break; 3869173275Ssam case IEEE80211_POWERSAVE_CAM: 3870173275Ssam LINE_CHECK("powersavemode CAM"); 3871173275Ssam break; 3872173275Ssam case IEEE80211_POWERSAVE_PSP: 3873173275Ssam LINE_CHECK("powersavemode PSP"); 3874173275Ssam break; 3875173275Ssam case IEEE80211_POWERSAVE_PSP_CAM: 3876173275Ssam LINE_CHECK("powersavemode PSP-CAM"); 3877173275Ssam break; 3878138593Ssam } 3879173275Ssam if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1) 3880173275Ssam LINE_CHECK("powersavesleep %d", val); 3881138593Ssam } 3882138593Ssam } 3883138593Ssam 3884173275Ssam if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) { 3885173275Ssam if (val & 1) 3886173275Ssam LINE_CHECK("txpower %d.5", val/2); 3887173275Ssam else 3888173275Ssam LINE_CHECK("txpower %d", val/2); 3889173275Ssam } 3890138593Ssam if (verbose) { 3891173275Ssam if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1) 3892173275Ssam LINE_CHECK("txpowmax %.1f", val/2.); 3893138593Ssam } 3894138593Ssam 3895178354Ssam if (get80211val(s, IEEE80211_IOC_DOTD, &val) != -1) { 3896178354Ssam if (val) 3897178354Ssam LINE_CHECK("dotd"); 3898178354Ssam else if (verbose) 3899178354Ssam LINE_CHECK("-dotd"); 3900178354Ssam } 3901178354Ssam 3902173275Ssam if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) { 3903173275Ssam if (val != IEEE80211_RTS_MAX || verbose) 3904173275Ssam LINE_CHECK("rtsthreshold %d", val); 3905138593Ssam } 3906138593Ssam 3907173275Ssam if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) { 3908173275Ssam if (val != IEEE80211_FRAG_MAX || verbose) 3909173275Ssam LINE_CHECK("fragthreshold %d", val); 3910170531Ssam } 3911173275Ssam if (opmode == IEEE80211_M_STA || verbose) { 3912173275Ssam if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) { 3913173275Ssam if (val != IEEE80211_HWBMISS_MAX || verbose) 3914173275Ssam LINE_CHECK("bmiss %d", val); 3915153354Ssam } 3916153354Ssam } 3917153354Ssam 3918178354Ssam if (!verbose) { 3919178354Ssam gettxparams(s); 3920178354Ssam tp = &txparams.params[chan2mode(c)]; 3921178354Ssam printrate("ucastrate", tp->ucastrate, 3922178354Ssam IEEE80211_FIXED_RATE_NONE, IEEE80211_FIXED_RATE_NONE); 3923178354Ssam printrate("mcastrate", tp->mcastrate, 2*1, 0x80|0); 3924178354Ssam printrate("mgmtrate", tp->mgmtrate, 2*1, 0x80|0); 3925178354Ssam if (tp->maxretry != 6) /* XXX */ 3926178354Ssam LINE_CHECK("maxretry %d", tp->maxretry); 3927178354Ssam } else { 3928178354Ssam LINE_BREAK(); 3929178354Ssam list_txparams(s); 3930178354Ssam } 3931170531Ssam 3932173275Ssam bgscaninterval = -1; 3933173275Ssam (void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval); 3934173275Ssam 3935173275Ssam if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) { 3936173275Ssam if (val != bgscaninterval || verbose) 3937173275Ssam LINE_CHECK("scanvalid %u", val); 3938148416Ssam } 3939148416Ssam 3940173275Ssam bgscan = 0; 3941173275Ssam if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) { 3942173275Ssam if (bgscan) 3943170531Ssam LINE_CHECK("bgscan"); 3944170531Ssam else if (verbose) 3945170531Ssam LINE_CHECK("-bgscan"); 3946160687Ssam } 3947170531Ssam if (bgscan || verbose) { 3948170531Ssam if (bgscaninterval != -1) 3949170531Ssam LINE_CHECK("bgscanintvl %u", bgscaninterval); 3950173275Ssam if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1) 3951173275Ssam LINE_CHECK("bgscanidle %u", val); 3952178354Ssam if (!verbose) { 3953178354Ssam getroam(s); 3954178354Ssam rp = &roamparams.params[chan2mode(c)]; 3955178354Ssam if (rp->rssi & 1) 3956178354Ssam LINE_CHECK("roam:rssi %u.5", rp->rssi/2); 3957178354Ssam else 3958178354Ssam LINE_CHECK("roam:rssi %u", rp->rssi/2); 3959178354Ssam LINE_CHECK("roam:rate %u", rp->rate/2); 3960178354Ssam } else { 3961178354Ssam LINE_BREAK(); 3962178354Ssam list_roam(s); 3963170531Ssam } 3964170531Ssam } 3965160687Ssam 3966165570Ssam if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { 3967173275Ssam if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) { 3968173275Ssam if (val) 3969155931Ssam LINE_CHECK("pureg"); 3970147795Ssam else if (verbose) 3971155931Ssam LINE_CHECK("-pureg"); 3972147795Ssam } 3973173275Ssam if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) { 3974173275Ssam switch (val) { 3975173275Ssam case IEEE80211_PROTMODE_OFF: 3976173275Ssam LINE_CHECK("protmode OFF"); 3977173275Ssam break; 3978173275Ssam case IEEE80211_PROTMODE_CTS: 3979173275Ssam LINE_CHECK("protmode CTS"); 3980173275Ssam break; 3981173275Ssam case IEEE80211_PROTMODE_RTSCTS: 3982173275Ssam LINE_CHECK("protmode RTSCTS"); 3983173275Ssam break; 3984173275Ssam default: 3985173275Ssam LINE_CHECK("protmode UNKNOWN (0x%x)", val); 3986173275Ssam break; 3987138593Ssam } 3988138593Ssam } 3989138593Ssam } 3990138593Ssam 3991173275Ssam if (IEEE80211_IS_CHAN_HT(c) || verbose) { 3992173275Ssam gethtconf(s); 3993173275Ssam switch (htconf & 3) { 3994173275Ssam case 0: 3995173275Ssam case 2: 3996173275Ssam LINE_CHECK("-ht"); 3997173275Ssam break; 3998173275Ssam case 1: 3999173275Ssam LINE_CHECK("ht20"); 4000173275Ssam break; 4001173275Ssam case 3: 4002173275Ssam if (verbose) 4003173275Ssam LINE_CHECK("ht"); 4004173275Ssam break; 4005173275Ssam } 4006173275Ssam if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) { 4007173275Ssam if (!val) 4008173275Ssam LINE_CHECK("-htcompat"); 4009173275Ssam else if (verbose) 4010173275Ssam LINE_CHECK("htcompat"); 4011173275Ssam } 4012173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) { 4013173275Ssam switch (val) { 4014173275Ssam case 0: 4015173275Ssam LINE_CHECK("-ampdu"); 4016173275Ssam break; 4017173275Ssam case 1: 4018173275Ssam LINE_CHECK("ampdutx -ampdurx"); 4019173275Ssam break; 4020173275Ssam case 2: 4021173275Ssam LINE_CHECK("-ampdutx ampdurx"); 4022173275Ssam break; 4023173275Ssam case 3: 4024173275Ssam if (verbose) 4025173275Ssam LINE_CHECK("ampdu"); 4026173275Ssam break; 4027173275Ssam } 4028173275Ssam } 4029173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) { 4030173275Ssam switch (val) { 4031173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_8K: 4032173275Ssam LINE_CHECK("ampdulimit 8k"); 4033173275Ssam break; 4034173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_16K: 4035173275Ssam LINE_CHECK("ampdulimit 16k"); 4036173275Ssam break; 4037173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_32K: 4038173275Ssam LINE_CHECK("ampdulimit 32k"); 4039173275Ssam break; 4040173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_64K: 4041173275Ssam LINE_CHECK("ampdulimit 64k"); 4042173275Ssam break; 4043173275Ssam } 4044173275Ssam } 4045173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) { 4046173275Ssam switch (val) { 4047173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_NA: 4048173275Ssam if (verbose) 4049173275Ssam LINE_CHECK("ampdudensity -"); 4050173275Ssam break; 4051173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_025: 4052173275Ssam LINE_CHECK("ampdudensity .25"); 4053173275Ssam break; 4054173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_05: 4055173275Ssam LINE_CHECK("ampdudensity .5"); 4056173275Ssam break; 4057173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_1: 4058173275Ssam LINE_CHECK("ampdudensity 1"); 4059173275Ssam break; 4060173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_2: 4061173275Ssam LINE_CHECK("ampdudensity 2"); 4062173275Ssam break; 4063173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_4: 4064173275Ssam LINE_CHECK("ampdudensity 4"); 4065173275Ssam break; 4066173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_8: 4067173275Ssam LINE_CHECK("ampdudensity 8"); 4068173275Ssam break; 4069173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_16: 4070173275Ssam LINE_CHECK("ampdudensity 16"); 4071173275Ssam break; 4072173275Ssam } 4073173275Ssam } 4074173275Ssam if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) { 4075173275Ssam switch (val) { 4076173275Ssam case 0: 4077173275Ssam LINE_CHECK("-amsdu"); 4078173275Ssam break; 4079173275Ssam case 1: 4080173275Ssam LINE_CHECK("amsdutx -amsdurx"); 4081173275Ssam break; 4082173275Ssam case 2: 4083173275Ssam LINE_CHECK("-amsdutx amsdurx"); 4084173275Ssam break; 4085173275Ssam case 3: 4086173275Ssam if (verbose) 4087173275Ssam LINE_CHECK("amsdu"); 4088173275Ssam break; 4089173275Ssam } 4090173275Ssam } 4091173275Ssam /* XXX amsdu limit */ 4092173275Ssam if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) { 4093173275Ssam if (val) 4094173275Ssam LINE_CHECK("shortgi"); 4095173275Ssam else if (verbose) 4096173275Ssam LINE_CHECK("-shortgi"); 4097173275Ssam } 4098173275Ssam if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) { 4099173275Ssam if (val == IEEE80211_PROTMODE_OFF) 4100173275Ssam LINE_CHECK("htprotmode OFF"); 4101173275Ssam else if (val != IEEE80211_PROTMODE_RTSCTS) 4102173275Ssam LINE_CHECK("htprotmode UNKNOWN (0x%x)", val); 4103173275Ssam else if (verbose) 4104173275Ssam LINE_CHECK("htprotmode RTSCTS"); 4105173275Ssam } 4106173275Ssam if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) { 4107173275Ssam if (val) 4108173275Ssam LINE_CHECK("puren"); 4109173275Ssam else if (verbose) 4110173275Ssam LINE_CHECK("-puren"); 4111173275Ssam } 4112173275Ssam } 4113173275Ssam 4114173275Ssam if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) { 4115138593Ssam if (wme) 4116155931Ssam LINE_CHECK("wme"); 4117138593Ssam else if (verbose) 4118155931Ssam LINE_CHECK("-wme"); 4119138593Ssam } else 4120138593Ssam wme = 0; 4121138593Ssam 4122173275Ssam if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) { 4123173275Ssam if (val) 4124155931Ssam LINE_CHECK("burst"); 4125153422Ssam else if (verbose) 4126155931Ssam LINE_CHECK("-burst"); 4127153422Ssam } 4128153422Ssam 4129173275Ssam if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) { 4130173275Ssam if (val) 4131170531Ssam LINE_CHECK("ff"); 4132170531Ssam else if (verbose) 4133170531Ssam LINE_CHECK("-ff"); 4134170531Ssam } 4135173275Ssam if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) { 4136173275Ssam if (val) 4137170531Ssam LINE_CHECK("dturbo"); 4138170531Ssam else if (verbose) 4139170531Ssam LINE_CHECK("-dturbo"); 4140170531Ssam } 4141178354Ssam if (get80211val(s, IEEE80211_IOC_DWDS, &val) != -1) { 4142178354Ssam if (val) 4143178354Ssam LINE_CHECK("dwds"); 4144178354Ssam else if (verbose) 4145178354Ssam LINE_CHECK("-dwds"); 4146178354Ssam } 4147170531Ssam 4148138593Ssam if (opmode == IEEE80211_M_HOSTAP) { 4149173275Ssam if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) { 4150173275Ssam if (val) 4151168075Ssam LINE_CHECK("hidessid"); 4152138593Ssam else if (verbose) 4153168075Ssam LINE_CHECK("-hidessid"); 4154138593Ssam } 4155173275Ssam if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) { 4156173275Ssam if (!val) 4157155931Ssam LINE_CHECK("-apbridge"); 4158138593Ssam else if (verbose) 4159155931Ssam LINE_CHECK("apbridge"); 4160138593Ssam } 4161173275Ssam if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1) 4162173275Ssam LINE_CHECK("dtimperiod %u", val); 4163138593Ssam 4164173275Ssam if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) { 4165173275Ssam if (!val) 4166170531Ssam LINE_CHECK("-doth"); 4167170531Ssam else if (verbose) 4168170531Ssam LINE_CHECK("doth"); 4169170531Ssam } 4170178354Ssam if (get80211val(s, IEEE80211_IOC_DFS, &val) != -1) { 4171178354Ssam if (!val) 4172178354Ssam LINE_CHECK("-dfs"); 4173178354Ssam else if (verbose) 4174178354Ssam LINE_CHECK("dfs"); 4175178354Ssam } 4176173275Ssam if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) { 4177173275Ssam if (!val) 4178173275Ssam LINE_CHECK("-inact"); 4179173275Ssam else if (verbose) 4180173275Ssam LINE_CHECK("inact"); 4181173275Ssam } 4182138593Ssam } else { 4183173275Ssam if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) { 4184173275Ssam if (val != IEEE80211_ROAMING_AUTO || verbose) { 4185173275Ssam switch (val) { 4186138593Ssam case IEEE80211_ROAMING_DEVICE: 4187155931Ssam LINE_CHECK("roaming DEVICE"); 4188138593Ssam break; 4189138593Ssam case IEEE80211_ROAMING_AUTO: 4190155931Ssam LINE_CHECK("roaming AUTO"); 4191138593Ssam break; 4192138593Ssam case IEEE80211_ROAMING_MANUAL: 4193155931Ssam LINE_CHECK("roaming MANUAL"); 4194138593Ssam break; 4195138593Ssam default: 4196155931Ssam LINE_CHECK("roaming UNKNOWN (0x%x)", 4197173275Ssam val); 4198138593Ssam break; 4199138593Ssam } 4200138593Ssam } 4201138593Ssam } 4202138593Ssam } 4203173275Ssam if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) { 4204173275Ssam /* XXX default define not visible */ 4205173275Ssam if (val != 100 || verbose) 4206173275Ssam LINE_CHECK("bintval %u", val); 4207138593Ssam } 4208138593Ssam 4209138593Ssam if (wme && verbose) { 4210138593Ssam LINE_BREAK(); 4211138593Ssam list_wme(s); 4212138593Ssam } 4213173275Ssam LINE_BREAK(); 4214173275Ssam} 4215138593Ssam 4216173275Ssamstatic int 4217173275Ssamget80211(int s, int type, void *data, int len) 4218173275Ssam{ 4219173275Ssam struct ieee80211req ireq; 4220138593Ssam 4221173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 4222173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4223173275Ssam ireq.i_type = type; 4224173275Ssam ireq.i_data = data; 4225173275Ssam ireq.i_len = len; 4226173275Ssam return ioctl(s, SIOCG80211, &ireq); 4227173275Ssam} 4228138593Ssam 4229173275Ssamstatic int 4230173275Ssamget80211len(int s, int type, void *data, int len, int *plen) 4231173275Ssam{ 4232173275Ssam struct ieee80211req ireq; 4233138593Ssam 4234173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 4235173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4236173275Ssam ireq.i_type = type; 4237173275Ssam ireq.i_len = len; 4238173275Ssam ireq.i_data = data; 4239173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 4240173275Ssam return -1; 4241173275Ssam *plen = ireq.i_len; 4242173275Ssam return 0; 4243173275Ssam} 4244138593Ssam 4245173275Ssamstatic int 4246173275Ssamget80211val(int s, int type, int *val) 4247173275Ssam{ 4248173275Ssam struct ieee80211req ireq; 424977218Sphk 4250173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 4251173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4252173275Ssam ireq.i_type = type; 4253173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 4254173275Ssam return -1; 4255173275Ssam *val = ireq.i_val; 4256173275Ssam return 0; 425777218Sphk} 425877218Sphk 425977218Sphkstatic void 4260170531Ssamset80211(int s, int type, int val, int len, void *data) 426177218Sphk{ 426277218Sphk struct ieee80211req ireq; 426377218Sphk 426477218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 426577218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 426677218Sphk ireq.i_type = type; 426777218Sphk ireq.i_val = val; 426877218Sphk ireq.i_len = len; 426977218Sphk ireq.i_data = data; 427091454Sbrooks if (ioctl(s, SIOCS80211, &ireq) < 0) 427177218Sphk err(1, "SIOCS80211"); 427277218Sphk} 427377218Sphk 427477218Sphkstatic const char * 427577218Sphkget_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 427677218Sphk{ 427777218Sphk int len; 427877218Sphk int hexstr; 427977218Sphk u_int8_t *p; 428077218Sphk 428177218Sphk len = *lenp; 428277218Sphk p = buf; 428377218Sphk hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 428477218Sphk if (hexstr) 428577218Sphk val += 2; 428677218Sphk for (;;) { 428777218Sphk if (*val == '\0') 428877218Sphk break; 428977218Sphk if (sep != NULL && strchr(sep, *val) != NULL) { 429077218Sphk val++; 429177218Sphk break; 429277218Sphk } 429377218Sphk if (hexstr) { 4294127831Sphk if (!isxdigit((u_char)val[0])) { 429577218Sphk warnx("bad hexadecimal digits"); 429677218Sphk return NULL; 429777218Sphk } 4298127831Sphk if (!isxdigit((u_char)val[1])) { 4299127831Sphk warnx("odd count hexadecimal digits"); 4300127831Sphk return NULL; 4301127831Sphk } 430277218Sphk } 4303127831Sphk if (p >= buf + len) { 430477218Sphk if (hexstr) 430577218Sphk warnx("hexadecimal digits too long"); 430677218Sphk else 4307127831Sphk warnx("string too long"); 430877218Sphk return NULL; 430977218Sphk } 431077218Sphk if (hexstr) { 431177218Sphk#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 431277218Sphk *p++ = (tohex((u_char)val[0]) << 4) | 431377218Sphk tohex((u_char)val[1]); 431477218Sphk#undef tohex 431577218Sphk val += 2; 431677218Sphk } else 431777218Sphk *p++ = *val++; 431877218Sphk } 431977218Sphk len = p - buf; 432077218Sphk /* The string "-" is treated as the empty string. */ 4321165045Ssam if (!hexstr && len == 1 && buf[0] == '-') { 432277218Sphk len = 0; 4323165045Ssam memset(buf, 0, *lenp); 4324165045Ssam } else if (len < *lenp) 432577218Sphk memset(p, 0, *lenp - len); 432677218Sphk *lenp = len; 432777218Sphk return val; 432877218Sphk} 432977218Sphk 433077218Sphkstatic void 433177218Sphkprint_string(const u_int8_t *buf, int len) 433277218Sphk{ 433377218Sphk int i; 433477218Sphk int hasspc; 433577218Sphk 433677218Sphk i = 0; 433777218Sphk hasspc = 0; 433891454Sbrooks for (; i < len; i++) { 433977218Sphk if (!isprint(buf[i]) && buf[i] != '\0') 434077218Sphk break; 434177218Sphk if (isspace(buf[i])) 434277218Sphk hasspc++; 434377218Sphk } 434477218Sphk if (i == len) { 434577218Sphk if (hasspc || len == 0 || buf[0] == '\0') 434677218Sphk printf("\"%.*s\"", len, buf); 434777218Sphk else 434877218Sphk printf("%.*s", len, buf); 434977218Sphk } else { 435077218Sphk printf("0x"); 435177218Sphk for (i = 0; i < len; i++) 435277218Sphk printf("%02x", buf[i]); 435377218Sphk } 435477218Sphk} 435577218Sphk 4356178354Ssam/* 4357178354Ssam * Virtual AP cloning support. 4358178354Ssam */ 4359178354Ssamstatic struct ieee80211_clone_params params = { 4360178354Ssam .icp_opmode = IEEE80211_M_STA, /* default to station mode */ 4361178354Ssam}; 4362178354Ssam 4363178354Ssamstatic void 4364178354Ssamwlan_create(int s, struct ifreq *ifr) 4365178354Ssam{ 4366178354Ssam static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 4367178354Ssam 4368178354Ssam if (params.icp_parent[0] == '\0') 4369178354Ssam errx(1, "must specify a parent when creating a wlan device"); 4370178354Ssam if (params.icp_opmode == IEEE80211_M_WDS && 4371178354Ssam memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0) 4372178354Ssam errx(1, "no bssid specified for WDS (use wlanbssid)"); 4373178354Ssam ifr->ifr_data = (caddr_t) ¶ms; 4374178354Ssam if (ioctl(s, SIOCIFCREATE2, ifr) < 0) 4375178354Ssam err(1, "SIOCIFCREATE2"); 4376178354Ssam} 4377178354Ssam 4378178354Ssamstatic 4379178354SsamDECL_CMD_FUNC(set80211clone_wlandev, arg, d) 4380178354Ssam{ 4381178354Ssam strlcpy(params.icp_parent, arg, IFNAMSIZ); 4382178354Ssam clone_setcallback(wlan_create); 4383178354Ssam} 4384178354Ssam 4385178354Ssamstatic 4386178354SsamDECL_CMD_FUNC(set80211clone_wlanbssid, arg, d) 4387178354Ssam{ 4388178354Ssam const struct ether_addr *ea; 4389178354Ssam 4390178354Ssam ea = ether_aton(arg); 4391178354Ssam if (ea == NULL) 4392178354Ssam errx(1, "%s: cannot parse bssid", arg); 4393178354Ssam memcpy(params.icp_bssid, ea->octet, IEEE80211_ADDR_LEN); 4394178354Ssam clone_setcallback(wlan_create); 4395178354Ssam} 4396178354Ssam 4397178354Ssamstatic 4398178354SsamDECL_CMD_FUNC(set80211clone_wlanaddr, arg, d) 4399178354Ssam{ 4400178354Ssam const struct ether_addr *ea; 4401178354Ssam 4402178354Ssam ea = ether_aton(arg); 4403178354Ssam if (ea == NULL) 4404178354Ssam errx(1, "%s: cannot parse addres", arg); 4405178354Ssam memcpy(params.icp_macaddr, ea->octet, IEEE80211_ADDR_LEN); 4406178354Ssam params.icp_flags |= IEEE80211_CLONE_MACADDR; 4407178354Ssam clone_setcallback(wlan_create); 4408178354Ssam} 4409178354Ssam 4410178354Ssamstatic 4411178354SsamDECL_CMD_FUNC(set80211clone_wlanmode, arg, d) 4412178354Ssam{ 4413178354Ssam#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 4414178354Ssam if (iseq(arg, "sta")) 4415178354Ssam params.icp_opmode = IEEE80211_M_STA; 4416178354Ssam else if (iseq(arg, "ahdemo") || iseq(arg, "adhoc-demo")) 4417178354Ssam params.icp_opmode = IEEE80211_M_AHDEMO; 4418178354Ssam else if (iseq(arg, "ibss") || iseq(arg, "adhoc")) 4419178354Ssam params.icp_opmode = IEEE80211_M_IBSS; 4420178354Ssam else if (iseq(arg, "ap") || iseq(arg, "host")) 4421178354Ssam params.icp_opmode = IEEE80211_M_HOSTAP; 4422178354Ssam else if (iseq(arg, "wds")) 4423178354Ssam params.icp_opmode = IEEE80211_M_WDS; 4424178354Ssam else if (iseq(arg, "monitor")) 4425178354Ssam params.icp_opmode = IEEE80211_M_MONITOR; 4426178354Ssam else 4427178354Ssam errx(1, "Don't know to create %s for %s", arg, name); 4428178354Ssam clone_setcallback(wlan_create); 4429178354Ssam#undef iseq 4430178354Ssam} 4431178354Ssam 4432178354Ssamstatic void 4433178354Ssamset80211clone_beacons(const char *val, int d, int s, const struct afswtch *rafp) 4434178354Ssam{ 4435178354Ssam /* NB: inverted sense */ 4436178354Ssam if (d) 4437178354Ssam params.icp_flags &= ~IEEE80211_CLONE_NOBEACONS; 4438178354Ssam else 4439178354Ssam params.icp_flags |= IEEE80211_CLONE_NOBEACONS; 4440178354Ssam clone_setcallback(wlan_create); 4441178354Ssam} 4442178354Ssam 4443178354Ssamstatic void 4444178354Ssamset80211clone_bssid(const char *val, int d, int s, const struct afswtch *rafp) 4445178354Ssam{ 4446178354Ssam if (d) 4447178354Ssam params.icp_flags |= IEEE80211_CLONE_BSSID; 4448178354Ssam else 4449178354Ssam params.icp_flags &= ~IEEE80211_CLONE_BSSID; 4450178354Ssam clone_setcallback(wlan_create); 4451178354Ssam} 4452178354Ssam 4453178354Ssamstatic void 4454178354Ssamset80211clone_wdslegacy(const char *val, int d, int s, const struct afswtch *rafp) 4455178354Ssam{ 4456178354Ssam if (d) 4457178354Ssam params.icp_flags |= IEEE80211_CLONE_WDSLEGACY; 4458178354Ssam else 4459178354Ssam params.icp_flags &= ~IEEE80211_CLONE_WDSLEGACY; 4460178354Ssam clone_setcallback(wlan_create); 4461178354Ssam} 4462178354Ssam 4463138593Ssamstatic struct cmd ieee80211_cmds[] = { 4464138593Ssam DEF_CMD_ARG("ssid", set80211ssid), 4465138593Ssam DEF_CMD_ARG("nwid", set80211ssid), 4466138593Ssam DEF_CMD_ARG("stationname", set80211stationname), 4467138593Ssam DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 4468138593Ssam DEF_CMD_ARG("channel", set80211channel), 4469138593Ssam DEF_CMD_ARG("authmode", set80211authmode), 4470138593Ssam DEF_CMD_ARG("powersavemode", set80211powersavemode), 4471138593Ssam DEF_CMD("powersave", 1, set80211powersave), 4472138593Ssam DEF_CMD("-powersave", 0, set80211powersave), 4473138593Ssam DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 4474138593Ssam DEF_CMD_ARG("wepmode", set80211wepmode), 4475138593Ssam DEF_CMD("wep", 1, set80211wep), 4476138593Ssam DEF_CMD("-wep", 0, set80211wep), 4477139493Ssam DEF_CMD_ARG("deftxkey", set80211weptxkey), 4478138593Ssam DEF_CMD_ARG("weptxkey", set80211weptxkey), 4479138593Ssam DEF_CMD_ARG("wepkey", set80211wepkey), 4480138593Ssam DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 4481138593Ssam DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 4482138593Ssam DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 4483138593Ssam DEF_CMD_ARG("protmode", set80211protmode), 4484138593Ssam DEF_CMD_ARG("txpower", set80211txpower), 4485138593Ssam DEF_CMD_ARG("roaming", set80211roaming), 4486138593Ssam DEF_CMD("wme", 1, set80211wme), 4487138593Ssam DEF_CMD("-wme", 0, set80211wme), 4488178354Ssam DEF_CMD("wmm", 1, set80211wme), 4489178354Ssam DEF_CMD("-wmm", 0, set80211wme), 4490138593Ssam DEF_CMD("hidessid", 1, set80211hidessid), 4491138593Ssam DEF_CMD("-hidessid", 0, set80211hidessid), 4492138593Ssam DEF_CMD("apbridge", 1, set80211apbridge), 4493138593Ssam DEF_CMD("-apbridge", 0, set80211apbridge), 4494138593Ssam DEF_CMD_ARG("chanlist", set80211chanlist), 4495138593Ssam DEF_CMD_ARG("bssid", set80211bssid), 4496138593Ssam DEF_CMD_ARG("ap", set80211bssid), 4497138593Ssam DEF_CMD("scan", 0, set80211scan), 4498138593Ssam DEF_CMD_ARG("list", set80211list), 4499138593Ssam DEF_CMD_ARG2("cwmin", set80211cwmin), 4500138593Ssam DEF_CMD_ARG2("cwmax", set80211cwmax), 4501138593Ssam DEF_CMD_ARG2("aifs", set80211aifs), 4502138593Ssam DEF_CMD_ARG2("txoplimit", set80211txoplimit), 4503148621Ssam DEF_CMD_ARG("acm", set80211acm), 4504148621Ssam DEF_CMD_ARG("-acm", set80211noacm), 4505148621Ssam DEF_CMD_ARG("ack", set80211ackpolicy), 4506148621Ssam DEF_CMD_ARG("-ack", set80211noackpolicy), 4507138593Ssam DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 4508138593Ssam DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 4509138593Ssam DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 4510138593Ssam DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 4511138593Ssam DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 4512138593Ssam DEF_CMD_ARG("bintval", set80211bintval), 4513138593Ssam DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 4514138593Ssam DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 4515138593Ssam DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 4516178354Ssam DEF_CMD("mac:radius", IEEE80211_MACCMD_POLICY_RADIUS, set80211maccmd), 4517138593Ssam DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 4518138593Ssam DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 4519138593Ssam DEF_CMD_ARG("mac:add", set80211addmac), 4520138593Ssam DEF_CMD_ARG("mac:del", set80211delmac), 4521138593Ssam DEF_CMD_ARG("mac:kick", set80211kickmac), 4522147795Ssam DEF_CMD("pureg", 1, set80211pureg), 4523147795Ssam DEF_CMD("-pureg", 0, set80211pureg), 4524170531Ssam DEF_CMD("ff", 1, set80211fastframes), 4525170531Ssam DEF_CMD("-ff", 0, set80211fastframes), 4526170531Ssam DEF_CMD("dturbo", 1, set80211dturbo), 4527170531Ssam DEF_CMD("-dturbo", 0, set80211dturbo), 4528170531Ssam DEF_CMD("bgscan", 1, set80211bgscan), 4529170531Ssam DEF_CMD("-bgscan", 0, set80211bgscan), 4530170531Ssam DEF_CMD_ARG("bgscanidle", set80211bgscanidle), 4531170531Ssam DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl), 4532170531Ssam DEF_CMD_ARG("scanvalid", set80211scanvalid), 4533178354Ssam DEF_CMD_ARG("roam:rssi", set80211roamrssi), 4534178354Ssam DEF_CMD_ARG("roam:rate", set80211roamrate), 4535153354Ssam DEF_CMD_ARG("mcastrate", set80211mcastrate), 4536178354Ssam DEF_CMD_ARG("ucastrate", set80211ucastrate), 4537178354Ssam DEF_CMD_ARG("mgtrate", set80211mgtrate), 4538178354Ssam DEF_CMD_ARG("mgmtrate", set80211mgtrate), 4539178354Ssam DEF_CMD_ARG("maxretry", set80211maxretry), 4540148416Ssam DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 4541153422Ssam DEF_CMD("burst", 1, set80211burst), 4542153422Ssam DEF_CMD("-burst", 0, set80211burst), 4543160687Ssam DEF_CMD_ARG("bmiss", set80211bmissthreshold), 4544160687Ssam DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), 4545173275Ssam DEF_CMD("shortgi", 1, set80211shortgi), 4546173275Ssam DEF_CMD("-shortgi", 0, set80211shortgi), 4547173275Ssam DEF_CMD("ampdurx", 2, set80211ampdu), 4548173275Ssam DEF_CMD("-ampdurx", -2, set80211ampdu), 4549173275Ssam DEF_CMD("ampdutx", 1, set80211ampdu), 4550173275Ssam DEF_CMD("-ampdutx", -1, set80211ampdu), 4551173275Ssam DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */ 4552173275Ssam DEF_CMD("-ampdu", -3, set80211ampdu), 4553173275Ssam DEF_CMD_ARG("ampdulimit", set80211ampdulimit), 4554173275Ssam DEF_CMD_ARG("ampdudensity", set80211ampdudensity), 4555173275Ssam DEF_CMD("amsdurx", 2, set80211amsdu), 4556173275Ssam DEF_CMD("-amsdurx", -2, set80211amsdu), 4557173275Ssam DEF_CMD("amsdutx", 1, set80211amsdu), 4558173275Ssam DEF_CMD("-amsdutx", -1, set80211amsdu), 4559173275Ssam DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */ 4560173275Ssam DEF_CMD("-amsdu", -3, set80211amsdu), 4561173275Ssam DEF_CMD_ARG("amsdulimit", set80211amsdulimit), 4562173275Ssam DEF_CMD("puren", 1, set80211puren), 4563173275Ssam DEF_CMD("-puren", 0, set80211puren), 4564170531Ssam DEF_CMD("doth", 1, set80211doth), 4565170531Ssam DEF_CMD("-doth", 0, set80211doth), 4566178354Ssam DEF_CMD("dfs", 1, set80211dfs), 4567178354Ssam DEF_CMD("-dfs", 0, set80211dfs), 4568173275Ssam DEF_CMD("htcompat", 1, set80211htcompat), 4569173275Ssam DEF_CMD("-htcompat", 0, set80211htcompat), 4570178354Ssam DEF_CMD("dwds", 1, set80211dwds), 4571178354Ssam DEF_CMD("-dwds", 0, set80211dwds), 4572173275Ssam DEF_CMD("inact", 1, set80211inact), 4573173275Ssam DEF_CMD("-inact", 0, set80211inact), 4574178354Ssam DEF_CMD("tsn", 1, set80211tsn), 4575178354Ssam DEF_CMD("-tsn", 0, set80211tsn), 4576178354Ssam DEF_CMD_ARG("regdomain", set80211regdomain), 4577178354Ssam DEF_CMD_ARG("country", set80211country), 4578178354Ssam DEF_CMD("indoor", 'I', set80211location), 4579178354Ssam DEF_CMD("-indoor", 'O', set80211location), 4580178354Ssam DEF_CMD("outdoor", 'O', set80211location), 4581178354Ssam DEF_CMD("-outdoor", 'I', set80211location), 4582178354Ssam DEF_CMD("anywhere", ' ', set80211location), 4583178354Ssam DEF_CMD("ecm", 1, set80211ecm), 4584178354Ssam DEF_CMD("-ecm", 0, set80211ecm), 4585178354Ssam DEF_CMD("dotd", 1, set80211dotd), 4586178354Ssam DEF_CMD("-dotd", 0, set80211dotd), 4587173275Ssam DEF_CMD_ARG("htprotmode", set80211htprotmode), 4588173275Ssam DEF_CMD("ht20", 1, set80211htconf), 4589173275Ssam DEF_CMD("-ht20", 0, set80211htconf), 4590173275Ssam DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */ 4591173275Ssam DEF_CMD("-ht40", 0, set80211htconf), 4592173275Ssam DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */ 4593173275Ssam DEF_CMD("-ht", 0, set80211htconf), 4594178354Ssam /* XXX for testing */ 4595178354Ssam DEF_CMD_ARG("chanswitch", set80211chanswitch), 4596178354Ssam 4597178354Ssam /* vap cloning support */ 4598178354Ssam DEF_CLONE_CMD_ARG("wlanaddr", set80211clone_wlanaddr), 4599178354Ssam DEF_CLONE_CMD_ARG("wlanbssid", set80211clone_wlanbssid), 4600178354Ssam DEF_CLONE_CMD_ARG("wlandev", set80211clone_wlandev), 4601178354Ssam DEF_CLONE_CMD_ARG("wlanmode", set80211clone_wlanmode), 4602178354Ssam DEF_CLONE_CMD("beacons", 1, set80211clone_beacons), 4603178354Ssam DEF_CLONE_CMD("-beacons", 0, set80211clone_beacons), 4604178354Ssam DEF_CLONE_CMD("bssid", 1, set80211clone_bssid), 4605178354Ssam DEF_CLONE_CMD("-bssid", 0, set80211clone_bssid), 4606178354Ssam DEF_CLONE_CMD("wdslegacy", 1, set80211clone_wdslegacy), 4607178354Ssam DEF_CLONE_CMD("-wdslegacy", 0, set80211clone_wdslegacy), 4608138593Ssam}; 4609138593Ssamstatic struct afswtch af_ieee80211 = { 4610138593Ssam .af_name = "af_ieee80211", 4611138593Ssam .af_af = AF_UNSPEC, 4612139494Ssam .af_other_status = ieee80211_status, 4613138593Ssam}; 4614138593Ssam 4615138593Ssamstatic __constructor void 4616138593Ssamieee80211_ctor(void) 4617138593Ssam{ 4618138593Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 4619138593Ssam int i; 4620138593Ssam 4621138593Ssam for (i = 0; i < N(ieee80211_cmds); i++) 4622138593Ssam cmd_register(&ieee80211_cmds[i]); 4623138593Ssam af_register(&af_ieee80211); 4624138593Ssam#undef N 4625138593Ssam} 4626