ifieee80211.c revision 181199
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 181199 2008-08-02 18:10:14Z 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 2444170531Ssam/* 2445138593Ssam * Copy the ssid string contents into buf, truncating to fit. If the 2446138593Ssam * ssid is entirely printable then just copy intact. Otherwise convert 2447138593Ssam * to hexadecimal. If the result is truncated then replace the last 2448138593Ssam * three characters with "...". 2449138593Ssam */ 2450146873Sjhbstatic int 2451138593Ssamcopy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 2452138593Ssam{ 2453138593Ssam const u_int8_t *p; 2454138593Ssam size_t maxlen; 2455138593Ssam int i; 2456138593Ssam 2457138593Ssam if (essid_len > bufsize) 2458138593Ssam maxlen = bufsize; 2459138593Ssam else 2460138593Ssam maxlen = essid_len; 2461138593Ssam /* determine printable or not */ 2462138593Ssam for (i = 0, p = essid; i < maxlen; i++, p++) { 2463138593Ssam if (*p < ' ' || *p > 0x7e) 2464138593Ssam break; 2465138593Ssam } 2466138593Ssam if (i != maxlen) { /* not printable, print as hex */ 2467138593Ssam if (bufsize < 3) 2468138593Ssam return 0; 2469138593Ssam strlcpy(buf, "0x", bufsize); 2470138593Ssam bufsize -= 2; 2471138593Ssam p = essid; 2472138593Ssam for (i = 0; i < maxlen && bufsize >= 2; i++) { 2473147489Savatar sprintf(&buf[2+2*i], "%02x", p[i]); 2474138593Ssam bufsize -= 2; 2475138593Ssam } 2476147489Savatar if (i != essid_len) 2477147489Savatar memcpy(&buf[2+2*i-3], "...", 3); 2478138593Ssam } else { /* printable, truncate as needed */ 2479138593Ssam memcpy(buf, essid, maxlen); 2480147489Savatar if (maxlen != essid_len) 2481147489Savatar memcpy(&buf[maxlen-3], "...", 3); 2482138593Ssam } 2483138593Ssam return maxlen; 2484138593Ssam} 2485138593Ssam 2486173275Ssamstatic void 2487173275Ssamprintssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2488173275Ssam{ 2489173275Ssam char ssid[2*IEEE80211_NWID_LEN+1]; 2490173275Ssam 2491173275Ssam printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid); 2492173275Ssam} 2493173275Ssam 2494173275Ssamstatic void 2495173275Ssamprintrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2496173275Ssam{ 2497173275Ssam const char *sep; 2498173275Ssam int i; 2499173275Ssam 2500173275Ssam printf("%s", tag); 2501173275Ssam sep = "<"; 2502173275Ssam for (i = 2; i < ielen; i++) { 2503173275Ssam printf("%s%s%d", sep, 2504173275Ssam ie[i] & IEEE80211_RATE_BASIC ? "B" : "", 2505173275Ssam ie[i] & IEEE80211_RATE_VAL); 2506173275Ssam sep = ","; 2507173275Ssam } 2508173275Ssam printf(">"); 2509173275Ssam} 2510173275Ssam 2511173275Ssamstatic void 2512173275Ssamprintcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2513173275Ssam{ 2514173275Ssam const struct ieee80211_country_ie *cie = 2515173275Ssam (const struct ieee80211_country_ie *) ie; 2516173275Ssam int i, nbands, schan, nchan; 2517173275Ssam 2518173275Ssam printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]); 2519173275Ssam nbands = (cie->len - 3) / sizeof(cie->band[0]); 2520173275Ssam for (i = 0; i < nbands; i++) { 2521173275Ssam schan = cie->band[i].schan; 2522173275Ssam nchan = cie->band[i].nchan; 2523173275Ssam if (nchan != 1) 2524173275Ssam printf(" %u-%u,%u", schan, schan + nchan-1, 2525173275Ssam cie->band[i].maxtxpwr); 2526173275Ssam else 2527173275Ssam printf(" %u,%u", schan, cie->band[i].maxtxpwr); 2528173275Ssam } 2529173275Ssam printf(">"); 2530173275Ssam} 2531173275Ssam 2532148686Sstefanf/* unaligned little endian access */ 2533138593Ssam#define LE_READ_4(p) \ 2534138593Ssam ((u_int32_t) \ 2535138593Ssam ((((const u_int8_t *)(p))[0] ) | \ 2536138593Ssam (((const u_int8_t *)(p))[1] << 8) | \ 2537138593Ssam (((const u_int8_t *)(p))[2] << 16) | \ 2538138593Ssam (((const u_int8_t *)(p))[3] << 24))) 2539138593Ssam 2540178354Ssamstatic __inline int 2541138593Ssamiswpaoui(const u_int8_t *frm) 2542138593Ssam{ 2543138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 2544138593Ssam} 2545138593Ssam 2546178354Ssamstatic __inline int 2547173275Ssamiswmeinfo(const u_int8_t *frm) 2548138593Ssam{ 2549173275Ssam return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 2550173275Ssam frm[6] == WME_INFO_OUI_SUBTYPE; 2551138593Ssam} 2552138593Ssam 2553178354Ssamstatic __inline int 2554173275Ssamiswmeparam(const u_int8_t *frm) 2555173275Ssam{ 2556173275Ssam return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 2557173275Ssam frm[6] == WME_PARAM_OUI_SUBTYPE; 2558173275Ssam} 2559173275Ssam 2560178354Ssamstatic __inline int 2561138593Ssamisatherosoui(const u_int8_t *frm) 2562138593Ssam{ 2563138593Ssam return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 2564138593Ssam} 2565138593Ssam 2566173275Ssamstatic const char * 2567173275Ssamiename(int elemid) 2568173275Ssam{ 2569173275Ssam switch (elemid) { 2570173275Ssam case IEEE80211_ELEMID_FHPARMS: return " FHPARMS"; 2571173275Ssam case IEEE80211_ELEMID_CFPARMS: return " CFPARMS"; 2572173275Ssam case IEEE80211_ELEMID_TIM: return " TIM"; 2573173275Ssam case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS"; 2574173275Ssam case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE"; 2575173275Ssam case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR"; 2576173275Ssam case IEEE80211_ELEMID_PWRCAP: return " PWRCAP"; 2577173275Ssam case IEEE80211_ELEMID_TPCREQ: return " TPCREQ"; 2578173275Ssam case IEEE80211_ELEMID_TPCREP: return " TPCREP"; 2579173275Ssam case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN"; 2580173275Ssam case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA"; 2581173275Ssam case IEEE80211_ELEMID_MEASREQ: return " MEASREQ"; 2582173275Ssam case IEEE80211_ELEMID_MEASREP: return " MEASREP"; 2583173275Ssam case IEEE80211_ELEMID_QUIET: return " QUIET"; 2584173275Ssam case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS"; 2585173275Ssam case IEEE80211_ELEMID_TPC: return " TPC"; 2586173275Ssam case IEEE80211_ELEMID_CCKM: return " CCKM"; 2587173275Ssam } 2588173275Ssam return " ???"; 2589173275Ssam} 2590173275Ssam 2591138593Ssamstatic void 2592138593Ssamprinties(const u_int8_t *vp, int ielen, int maxcols) 2593138593Ssam{ 2594138593Ssam while (ielen > 0) { 2595138593Ssam switch (vp[0]) { 2596173275Ssam case IEEE80211_ELEMID_SSID: 2597173275Ssam if (verbose) 2598173275Ssam printssid(" SSID", vp, 2+vp[1], maxcols); 2599173275Ssam break; 2600173275Ssam case IEEE80211_ELEMID_RATES: 2601173275Ssam case IEEE80211_ELEMID_XRATES: 2602173275Ssam if (verbose) 2603173275Ssam printrates(vp[0] == IEEE80211_ELEMID_RATES ? 2604173275Ssam " RATES" : " XRATES", vp, 2+vp[1], maxcols); 2605173275Ssam break; 2606173275Ssam case IEEE80211_ELEMID_DSPARMS: 2607173275Ssam if (verbose) 2608173275Ssam printf(" DSPARMS<%u>", vp[2]); 2609173275Ssam break; 2610173275Ssam case IEEE80211_ELEMID_COUNTRY: 2611173275Ssam if (verbose) 2612173275Ssam printcountry(" COUNTRY", vp, 2+vp[1], maxcols); 2613173275Ssam break; 2614173275Ssam case IEEE80211_ELEMID_ERP: 2615173275Ssam if (verbose) 2616173275Ssam printf(" ERP<0x%x>", vp[2]); 2617173275Ssam break; 2618138593Ssam case IEEE80211_ELEMID_VENDOR: 2619138593Ssam if (iswpaoui(vp)) 2620170531Ssam printwpaie(" WPA", vp, 2+vp[1], maxcols); 2621173275Ssam else if (iswmeinfo(vp)) 2622173275Ssam printwmeinfo(" WME", vp, 2+vp[1], maxcols); 2623173275Ssam else if (iswmeparam(vp)) 2624173275Ssam printwmeparam(" WME", vp, 2+vp[1], maxcols); 2625139492Ssam else if (isatherosoui(vp)) 2626170531Ssam printathie(" ATH", vp, 2+vp[1], maxcols); 2627173275Ssam else if (verbose) 2628138593Ssam printie(" VEN", vp, 2+vp[1], maxcols); 2629138593Ssam break; 2630138593Ssam case IEEE80211_ELEMID_RSN: 2631170531Ssam printrsnie(" RSN", vp, 2+vp[1], maxcols); 2632138593Ssam break; 2633173275Ssam case IEEE80211_ELEMID_HTCAP: 2634173275Ssam printhtcap(" HTCAP", vp, 2+vp[1], maxcols); 2635173275Ssam break; 2636173275Ssam case IEEE80211_ELEMID_HTINFO: 2637173275Ssam if (verbose) 2638173275Ssam printhtinfo(" HTINFO", vp, 2+vp[1], maxcols); 2639173275Ssam break; 2640138593Ssam default: 2641173275Ssam if (verbose) 2642173275Ssam printie(iename(vp[0]), vp, 2+vp[1], maxcols); 2643138593Ssam break; 2644138593Ssam } 2645138593Ssam ielen -= 2+vp[1]; 2646138593Ssam vp += 2+vp[1]; 2647138593Ssam } 2648138593Ssam} 2649138593Ssam 2650138593Ssamstatic void 2651178354Ssamprintmimo(const struct ieee80211_mimo_info *mi) 2652178354Ssam{ 2653178354Ssam /* NB: don't muddy display unless there's something to show */ 2654178354Ssam if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) { 2655178354Ssam /* XXX ignore EVM for now */ 2656178354Ssam printf(" (rssi %d:%d:%d nf %d:%d:%d)", 2657178354Ssam mi->rssi[0], mi->rssi[1], mi->rssi[2], 2658178354Ssam mi->noise[0], mi->noise[1], mi->noise[2]); 2659178354Ssam } 2660178354Ssam} 2661178354Ssam 2662178354Ssamstatic void 2663138593Ssamlist_scan(int s) 2664138593Ssam{ 2665138593Ssam uint8_t buf[24*1024]; 2666153892Srwatson char ssid[IEEE80211_NWID_LEN+1]; 2667173275Ssam const uint8_t *cp; 2668154522Ssam int len, ssidmax; 2669138593Ssam 2670173275Ssam if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0) 2671138593Ssam errx(1, "unable to get scan results"); 2672138593Ssam if (len < sizeof(struct ieee80211req_scan_result)) 2673138593Ssam return; 2674138593Ssam 2675170531Ssam getchaninfo(s); 2676170531Ssam 2677154522Ssam ssidmax = verbose ? IEEE80211_NWID_LEN : 14; 2678170531Ssam printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n" 2679154522Ssam , ssidmax, ssidmax, "SSID" 2680138593Ssam , "BSSID" 2681138593Ssam , "CHAN" 2682138593Ssam , "RATE" 2683170531Ssam , " S:N" 2684138593Ssam , "INT" 2685138593Ssam , "CAPS" 2686138593Ssam ); 2687138593Ssam cp = buf; 2688138593Ssam do { 2689170531Ssam const struct ieee80211req_scan_result *sr; 2690170531Ssam const uint8_t *vp; 2691138593Ssam 2692170531Ssam sr = (const struct ieee80211req_scan_result *) cp; 2693173275Ssam vp = cp + sr->isr_ie_off; 2694170531Ssam printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s" 2695154522Ssam , ssidmax 2696155461Ssam , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len) 2697154522Ssam , ssid 2698138593Ssam , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 2699165570Ssam , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) 2700138593Ssam , getmaxrate(sr->isr_rates, sr->isr_nrates) 2701170531Ssam , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise 2702138593Ssam , sr->isr_intval 2703138593Ssam , getcaps(sr->isr_capinfo) 2704138593Ssam ); 2705170531Ssam printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24); 2706138593Ssam printf("\n"); 2707138593Ssam cp += sr->isr_len, len -= sr->isr_len; 2708138593Ssam } while (len >= sizeof(struct ieee80211req_scan_result)); 2709138593Ssam} 2710138593Ssam 2711178354Ssam#ifdef __FreeBSD__ 2712138593Ssam#include <net80211/ieee80211_freebsd.h> 2713178354Ssam#endif 2714178354Ssam#ifdef __NetBSD__ 2715178354Ssam#include <net80211/ieee80211_netbsd.h> 2716178354Ssam#endif 2717138593Ssam 2718138593Ssamstatic void 2719138593Ssamscan_and_wait(int s) 2720138593Ssam{ 2721178354Ssam struct ieee80211_scan_req sr; 2722138593Ssam struct ieee80211req ireq; 2723138593Ssam int sroute; 2724138593Ssam 2725138593Ssam sroute = socket(PF_ROUTE, SOCK_RAW, 0); 2726138593Ssam if (sroute < 0) { 2727138593Ssam perror("socket(PF_ROUTE,SOCK_RAW)"); 2728138593Ssam return; 2729138593Ssam } 2730138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 2731138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 2732138593Ssam ireq.i_type = IEEE80211_IOC_SCAN_REQ; 2733178354Ssam 2734178354Ssam memset(&sr, 0, sizeof(sr)); 2735178354Ssam sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE 2736178354Ssam | IEEE80211_IOC_SCAN_NOPICK 2737178354Ssam | IEEE80211_IOC_SCAN_ONCE; 2738178354Ssam sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; 2739178354Ssam sr.sr_nssid = 0; 2740178354Ssam 2741178354Ssam ireq.i_data = &sr; 2742178354Ssam ireq.i_len = sizeof(sr); 2743138593Ssam /* NB: only root can trigger a scan so ignore errors */ 2744138593Ssam if (ioctl(s, SIOCS80211, &ireq) >= 0) { 2745138593Ssam char buf[2048]; 2746138593Ssam struct if_announcemsghdr *ifan; 2747138593Ssam struct rt_msghdr *rtm; 2748138593Ssam 2749138593Ssam do { 2750138593Ssam if (read(sroute, buf, sizeof(buf)) < 0) { 2751138593Ssam perror("read(PF_ROUTE)"); 2752138593Ssam break; 2753138593Ssam } 2754138593Ssam rtm = (struct rt_msghdr *) buf; 2755138593Ssam if (rtm->rtm_version != RTM_VERSION) 2756138593Ssam break; 2757138593Ssam ifan = (struct if_announcemsghdr *) rtm; 2758138593Ssam } while (rtm->rtm_type != RTM_IEEE80211 || 2759138593Ssam ifan->ifan_what != RTM_IEEE80211_SCAN); 2760138593Ssam } 2761138593Ssam close(sroute); 2762138593Ssam} 2763138593Ssam 2764138593Ssamstatic 2765138593SsamDECL_CMD_FUNC(set80211scan, val, d) 2766138593Ssam{ 2767138593Ssam scan_and_wait(s); 2768138593Ssam list_scan(s); 2769138593Ssam} 2770138593Ssam 2771161147Ssamstatic enum ieee80211_opmode get80211opmode(int s); 2772161147Ssam 2773173275Ssamstatic int 2774173275Ssamgettxseq(const struct ieee80211req_sta_info *si) 2775173275Ssam{ 2776173275Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 2777173275Ssam 2778173275Ssam int i, txseq; 2779173275Ssam 2780173275Ssam if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 2781173275Ssam return si->isi_txseqs[0]; 2782173275Ssam /* XXX not right but usually what folks want */ 2783173275Ssam txseq = 0; 2784173275Ssam for (i = 0; i < IEEE80211_TID_SIZE; i++) 2785173275Ssam if (si->isi_txseqs[i] > txseq) 2786173275Ssam txseq = si->isi_txseqs[i]; 2787173275Ssam return txseq; 2788173275Ssam#undef IEEE80211_NODE_QOS 2789173275Ssam} 2790173275Ssam 2791173275Ssamstatic int 2792173275Ssamgetrxseq(const struct ieee80211req_sta_info *si) 2793173275Ssam{ 2794173275Ssam#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ 2795173275Ssam 2796173275Ssam int i, rxseq; 2797173275Ssam 2798173275Ssam if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 2799173275Ssam return si->isi_rxseqs[0]; 2800173275Ssam /* XXX not right but usually what folks want */ 2801173275Ssam rxseq = 0; 2802173275Ssam for (i = 0; i < IEEE80211_TID_SIZE; i++) 2803173275Ssam if (si->isi_rxseqs[i] > rxseq) 2804173275Ssam rxseq = si->isi_rxseqs[i]; 2805173275Ssam return rxseq; 2806173275Ssam#undef IEEE80211_NODE_QOS 2807173275Ssam} 2808173275Ssam 2809138593Ssamstatic void 2810138593Ssamlist_stations(int s) 2811138593Ssam{ 2812161147Ssam union { 2813161147Ssam struct ieee80211req_sta_req req; 2814161147Ssam uint8_t buf[24*1024]; 2815161147Ssam } u; 2816161147Ssam enum ieee80211_opmode opmode = get80211opmode(s); 2817170531Ssam const uint8_t *cp; 2818138593Ssam int len; 2819138593Ssam 2820161147Ssam /* broadcast address =>'s get all stations */ 2821161147Ssam (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); 2822161147Ssam if (opmode == IEEE80211_M_STA) { 2823161147Ssam /* 2824161147Ssam * Get information about the associated AP. 2825161147Ssam */ 2826173275Ssam (void) get80211(s, IEEE80211_IOC_BSSID, 2827173275Ssam u.req.is_u.macaddr, IEEE80211_ADDR_LEN); 2828161147Ssam } 2829173275Ssam if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0) 2830138593Ssam errx(1, "unable to get station information"); 2831138593Ssam if (len < sizeof(struct ieee80211req_sta_info)) 2832138593Ssam return; 2833138593Ssam 2834170531Ssam getchaninfo(s); 2835170531Ssam 2836159885Ssam printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n" 2837138593Ssam , "ADDR" 2838138593Ssam , "AID" 2839138593Ssam , "CHAN" 2840138593Ssam , "RATE" 2841138593Ssam , "RSSI" 2842138593Ssam , "IDLE" 2843138593Ssam , "TXSEQ" 2844138593Ssam , "RXSEQ" 2845138593Ssam , "CAPS" 2846159885Ssam , "FLAG" 2847138593Ssam ); 2848170531Ssam cp = (const uint8_t *) u.req.info; 2849138593Ssam do { 2850170531Ssam const struct ieee80211req_sta_info *si; 2851138593Ssam 2852170531Ssam si = (const struct ieee80211req_sta_info *) cp; 2853161147Ssam if (si->isi_len < sizeof(*si)) 2854161147Ssam break; 2855170531Ssam printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-4.4s" 2856138593Ssam , ether_ntoa((const struct ether_addr*) si->isi_macaddr) 2857138593Ssam , IEEE80211_AID(si->isi_associd) 2858166015Ssam , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags) 2859178354Ssam , si->isi_txmbps/2 2860170531Ssam , si->isi_rssi/2. 2861138593Ssam , si->isi_inact 2862173275Ssam , gettxseq(si) 2863173275Ssam , getrxseq(si) 2864138593Ssam , getcaps(si->isi_capinfo) 2865159885Ssam , getflags(si->isi_state) 2866138593Ssam ); 2867170531Ssam printies(cp + si->isi_ie_off, si->isi_ie_len, 24); 2868178354Ssam printmimo(&si->isi_mimo); 2869138593Ssam printf("\n"); 2870138593Ssam cp += si->isi_len, len -= si->isi_len; 2871138593Ssam } while (len >= sizeof(struct ieee80211req_sta_info)); 2872138593Ssam} 2873138593Ssam 2874170531Ssamstatic const char * 2875170531Ssamget_chaninfo(const struct ieee80211_channel *c, int precise, 2876170531Ssam char buf[], size_t bsize) 2877138593Ssam{ 2878138593Ssam buf[0] = '\0'; 2879138593Ssam if (IEEE80211_IS_CHAN_FHSS(c)) 2880170531Ssam strlcat(buf, " FHSS", bsize); 2881165570Ssam if (IEEE80211_IS_CHAN_A(c)) { 2882165570Ssam if (IEEE80211_IS_CHAN_HALF(c)) 2883170531Ssam strlcat(buf, " 11a/10Mhz", bsize); 2884165570Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 2885170531Ssam strlcat(buf, " 11a/5Mhz", bsize); 2886165570Ssam else 2887170531Ssam strlcat(buf, " 11a", bsize); 2888165570Ssam } 2889166015Ssam if (IEEE80211_IS_CHAN_ANYG(c)) { 2890166015Ssam if (IEEE80211_IS_CHAN_HALF(c)) 2891170531Ssam strlcat(buf, " 11g/10Mhz", bsize); 2892166015Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 2893170531Ssam strlcat(buf, " 11g/5Mhz", bsize); 2894166015Ssam else 2895170531Ssam strlcat(buf, " 11g", bsize); 2896166015Ssam } else if (IEEE80211_IS_CHAN_B(c)) 2897170531Ssam strlcat(buf, " 11b", bsize); 2898170531Ssam if (IEEE80211_IS_CHAN_TURBO(c)) 2899170531Ssam strlcat(buf, " Turbo", bsize); 2900170531Ssam if (precise) { 2901170531Ssam if (IEEE80211_IS_CHAN_HT20(c)) 2902170531Ssam strlcat(buf, " ht/20", bsize); 2903170531Ssam else if (IEEE80211_IS_CHAN_HT40D(c)) 2904170531Ssam strlcat(buf, " ht/40-", bsize); 2905170531Ssam else if (IEEE80211_IS_CHAN_HT40U(c)) 2906170531Ssam strlcat(buf, " ht/40+", bsize); 2907170531Ssam } else { 2908170531Ssam if (IEEE80211_IS_CHAN_HT(c)) 2909170531Ssam strlcat(buf, " ht", bsize); 2910170531Ssam } 2911170531Ssam return buf; 2912170531Ssam} 2913170531Ssam 2914170531Ssamstatic void 2915173275Ssamprint_chaninfo(const struct ieee80211_channel *c, int verb) 2916170531Ssam{ 2917170531Ssam char buf[14]; 2918170531Ssam 2919138593Ssam printf("Channel %3u : %u%c Mhz%-14.14s", 2920165570Ssam ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, 2921170531Ssam IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', 2922173275Ssam get_chaninfo(c, verb, buf, sizeof(buf))); 2923138593Ssam} 2924138593Ssam 2925138593Ssamstatic void 2926173275Ssamprint_channels(int s, const struct ieee80211req_chaninfo *chans, 2927173275Ssam int allchans, int verb) 2928138593Ssam{ 2929138593Ssam struct ieee80211req_chaninfo achans; 2930170531Ssam uint8_t reported[IEEE80211_CHAN_BYTES]; 2931138593Ssam const struct ieee80211_channel *c; 2932170531Ssam int i, half; 2933138593Ssam 2934170531Ssam memset(&achans, 0, sizeof(achans)); 2935170531Ssam memset(reported, 0, sizeof(reported)); 2936138593Ssam if (!allchans) { 2937138593Ssam struct ieee80211req_chanlist active; 2938138593Ssam 2939173275Ssam if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0) 2940138593Ssam errx(1, "unable to get active channel list"); 2941138593Ssam memset(&achans, 0, sizeof(achans)); 2942173275Ssam for (i = 0; i < chans->ic_nchans; i++) { 2943173275Ssam c = &chans->ic_chans[i]; 2944170531Ssam if (!isset(active.ic_channels, c->ic_ieee)) 2945170531Ssam continue; 2946170531Ssam /* 2947170531Ssam * Suppress compatible duplicates unless 2948170531Ssam * verbose. The kernel gives us it's 2949170531Ssam * complete channel list which has separate 2950170531Ssam * entries for 11g/11b and 11a/turbo. 2951170531Ssam */ 2952173275Ssam if (isset(reported, c->ic_ieee) && !verb) { 2953170531Ssam /* XXX we assume duplicates are adjacent */ 2954170531Ssam achans.ic_chans[achans.ic_nchans-1] = *c; 2955170531Ssam } else { 2956138593Ssam achans.ic_chans[achans.ic_nchans++] = *c; 2957170531Ssam setbit(reported, c->ic_ieee); 2958170531Ssam } 2959138593Ssam } 2960170531Ssam } else { 2961173275Ssam for (i = 0; i < chans->ic_nchans; i++) { 2962173275Ssam c = &chans->ic_chans[i]; 2963170531Ssam /* suppress duplicates as above */ 2964173275Ssam if (isset(reported, c->ic_ieee) && !verb) { 2965170531Ssam /* XXX we assume duplicates are adjacent */ 2966170531Ssam achans.ic_chans[achans.ic_nchans-1] = *c; 2967170531Ssam } else { 2968170531Ssam achans.ic_chans[achans.ic_nchans++] = *c; 2969170531Ssam setbit(reported, c->ic_ieee); 2970170531Ssam } 2971170531Ssam } 2972170531Ssam } 2973138593Ssam half = achans.ic_nchans / 2; 2974138593Ssam if (achans.ic_nchans % 2) 2975138593Ssam half++; 2976170531Ssam 2977138593Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 2978173275Ssam print_chaninfo(&achans.ic_chans[i], verb); 2979173275Ssam print_chaninfo(&achans.ic_chans[half+i], verb); 2980138593Ssam printf("\n"); 2981138593Ssam } 2982138593Ssam if (achans.ic_nchans % 2) { 2983173275Ssam print_chaninfo(&achans.ic_chans[i], verb); 2984138593Ssam printf("\n"); 2985138593Ssam } 2986138593Ssam} 2987138593Ssam 2988138593Ssamstatic void 2989173275Ssamlist_channels(int s, int allchans) 2990173275Ssam{ 2991173275Ssam getchaninfo(s); 2992173275Ssam print_channels(s, &chaninfo, allchans, verbose); 2993173275Ssam} 2994173275Ssam 2995173275Ssamstatic void 2996170531Ssamprint_txpow(const struct ieee80211_channel *c) 2997170531Ssam{ 2998170531Ssam printf("Channel %3u : %u Mhz %3.1f reg %2d ", 2999170531Ssam c->ic_ieee, c->ic_freq, 3000170531Ssam c->ic_maxpower/2., c->ic_maxregpower); 3001170531Ssam} 3002170531Ssam 3003170531Ssamstatic void 3004170531Ssamprint_txpow_verbose(const struct ieee80211_channel *c) 3005170531Ssam{ 3006173275Ssam print_chaninfo(c, 1); 3007170531Ssam printf("min %4.1f dBm max %3.1f dBm reg %2d dBm", 3008170531Ssam c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower); 3009170531Ssam /* indicate where regulatory cap limits power use */ 3010170531Ssam if (c->ic_maxpower > 2*c->ic_maxregpower) 3011170531Ssam printf(" <"); 3012170531Ssam} 3013170531Ssam 3014170531Ssamstatic void 3015170531Ssamlist_txpow(int s) 3016170531Ssam{ 3017170531Ssam struct ieee80211req_chaninfo achans; 3018170531Ssam uint8_t reported[IEEE80211_CHAN_BYTES]; 3019170531Ssam struct ieee80211_channel *c, *prev; 3020170531Ssam int i, half; 3021170531Ssam 3022170531Ssam getchaninfo(s); 3023170531Ssam memset(&achans, 0, sizeof(achans)); 3024170531Ssam memset(reported, 0, sizeof(reported)); 3025170531Ssam for (i = 0; i < chaninfo.ic_nchans; i++) { 3026170531Ssam c = &chaninfo.ic_chans[i]; 3027170531Ssam /* suppress duplicates as above */ 3028170531Ssam if (isset(reported, c->ic_ieee) && !verbose) { 3029170531Ssam /* XXX we assume duplicates are adjacent */ 3030170531Ssam prev = &achans.ic_chans[achans.ic_nchans-1]; 3031170531Ssam /* display highest power on channel */ 3032170531Ssam if (c->ic_maxpower > prev->ic_maxpower) 3033170531Ssam *prev = *c; 3034170531Ssam } else { 3035170531Ssam achans.ic_chans[achans.ic_nchans++] = *c; 3036170531Ssam setbit(reported, c->ic_ieee); 3037170531Ssam } 3038170531Ssam } 3039170531Ssam if (!verbose) { 3040170531Ssam half = achans.ic_nchans / 2; 3041170531Ssam if (achans.ic_nchans % 2) 3042170531Ssam half++; 3043170531Ssam 3044170531Ssam for (i = 0; i < achans.ic_nchans / 2; i++) { 3045170531Ssam print_txpow(&achans.ic_chans[i]); 3046170531Ssam print_txpow(&achans.ic_chans[half+i]); 3047170531Ssam printf("\n"); 3048170531Ssam } 3049170531Ssam if (achans.ic_nchans % 2) { 3050170531Ssam print_txpow(&achans.ic_chans[i]); 3051170531Ssam printf("\n"); 3052170531Ssam } 3053170531Ssam } else { 3054170531Ssam for (i = 0; i < achans.ic_nchans; i++) { 3055170531Ssam print_txpow_verbose(&achans.ic_chans[i]); 3056170531Ssam printf("\n"); 3057170531Ssam } 3058170531Ssam } 3059170531Ssam} 3060170531Ssam 3061170531Ssamstatic void 3062138593Ssamlist_keys(int s) 3063138593Ssam{ 3064138593Ssam} 3065138593Ssam 3066138593Ssam#define IEEE80211_C_BITS \ 3067181102Ssam "\20\1STA\7FF\10TURBOP\11IBSS\12PMGT" \ 3068178354Ssam "\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \ 3069181102Ssam "\21MONITOR\22DFS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \ 3070178354Ssam "\37TXFRAG" 3071138593Ssam 3072178354Ssam#define IEEE80211_CRYPTO_BITS \ 3073178354Ssam "\20\1WEP\2TKIP\3AES\4AES_CCM\5TKIPMIC\6CKIP\12PMGT" 3074178354Ssam 3075178354Ssam#define IEEE80211_HTCAP_BITS \ 3076178354Ssam "\20\1LDPC\2CHWIDTH40\5GREENFIELD\6SHORTGI20\7SHORTGI40\10TXSTBC" \ 3077178354Ssam "\21AMPDU\22AMSDU\23HT" 3078178354Ssam 3079138593Ssamstatic void 3080138593Ssamlist_capabilities(int s) 3081138593Ssam{ 3082178354Ssam struct ieee80211_devcaps_req dc; 3083138593Ssam 3084178354Ssam getdevcaps(s, &dc); 3085178354Ssam printb("drivercaps", dc.dc_drivercaps, IEEE80211_C_BITS); 3086178354Ssam if (dc.dc_cryptocaps != 0 || verbose) { 3087178354Ssam putchar('\n'); 3088178354Ssam printb("cryptocaps", dc.dc_cryptocaps, IEEE80211_CRYPTO_BITS); 3089178354Ssam } 3090178354Ssam if (dc.dc_htcaps != 0 || verbose) { 3091178354Ssam putchar('\n'); 3092178354Ssam printb("htcaps", dc.dc_htcaps, IEEE80211_HTCAP_BITS); 3093178354Ssam } 3094138593Ssam putchar('\n'); 3095138593Ssam} 3096138593Ssam 3097173275Ssamstatic int 3098173275Ssamget80211wme(int s, int param, int ac, int *val) 3099173275Ssam{ 3100173275Ssam struct ieee80211req ireq; 3101173275Ssam 3102173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3103173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3104173275Ssam ireq.i_type = param; 3105173275Ssam ireq.i_len = ac; 3106173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) { 3107173275Ssam warn("cannot get WME parameter %d, ac %d%s", 3108173275Ssam param, ac & IEEE80211_WMEPARAM_VAL, 3109173275Ssam ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : ""); 3110173275Ssam return -1; 3111173275Ssam } 3112173275Ssam *val = ireq.i_val; 3113173275Ssam return 0; 3114173275Ssam} 3115173275Ssam 3116138593Ssamstatic void 3117181199Ssamlist_wme_aci(int s, const char *tag, int ac) 3118138593Ssam{ 3119181199Ssam int val; 3120138593Ssam 3121181199Ssam printf("\t%s", tag); 3122138593Ssam 3123181199Ssam /* show WME BSS parameters */ 3124181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1) 3125181199Ssam printf(" cwmin %2u", val); 3126181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1) 3127181199Ssam printf(" cwmax %2u", val); 3128181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1) 3129181199Ssam printf(" aifs %2u", val); 3130181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1) 3131181199Ssam printf(" txopLimit %3u", val); 3132181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) { 3133181199Ssam if (val) 3134181199Ssam printf(" acm"); 3135181199Ssam else if (verbose) 3136181199Ssam printf(" -acm"); 3137181199Ssam } 3138181199Ssam /* !BSS only */ 3139181199Ssam if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 3140181199Ssam if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) { 3141181199Ssam if (!val) 3142181199Ssam printf(" -ack"); 3143138593Ssam else if (verbose) 3144181199Ssam printf(" ack"); 3145138593Ssam } 3146181199Ssam } 3147181199Ssam printf("\n"); 3148181199Ssam} 3149181199Ssam 3150181199Ssamstatic void 3151181199Ssamlist_wme(int s) 3152181199Ssam{ 3153181199Ssam static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 3154181199Ssam int ac; 3155181199Ssam 3156181199Ssam if (verbose) { 3157181199Ssam /* display both BSS and local settings */ 3158181199Ssam for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 3159181199Ssam again: 3160181199Ssam if (ac & IEEE80211_WMEPARAM_BSS) 3161181199Ssam list_wme_aci(s, " ", ac); 3162181199Ssam else 3163181199Ssam list_wme_aci(s, acnames[ac], ac); 3164181199Ssam if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 3165181199Ssam ac |= IEEE80211_WMEPARAM_BSS; 3166181199Ssam goto again; 3167181199Ssam } else 3168181199Ssam ac &= ~IEEE80211_WMEPARAM_BSS; 3169138593Ssam } 3170181199Ssam } else { 3171181199Ssam /* display only channel settings */ 3172181199Ssam for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) 3173181199Ssam list_wme_aci(s, acnames[ac], ac); 3174138593Ssam } 3175138593Ssam} 3176138593Ssam 3177149029Ssamstatic void 3178178354Ssamlist_roam(int s) 3179178354Ssam{ 3180178354Ssam const struct ieee80211_roamparam *rp; 3181178354Ssam int mode; 3182178354Ssam 3183178354Ssam getroam(s); 3184178354Ssam for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_11NA; mode++) { 3185178354Ssam rp = &roamparams.params[mode]; 3186178354Ssam if (rp->rssi == 0 && rp->rate == 0) 3187178354Ssam continue; 3188178354Ssam if (rp->rssi & 1) 3189178354Ssam LINE_CHECK("roam:%-6.6s rssi %2u.5dBm rate %2u Mb/s", 3190178354Ssam modename[mode], rp->rssi/2, rp->rate/2); 3191178354Ssam else 3192178354Ssam LINE_CHECK("roam:%-6.6s rssi %4udBm rate %2u Mb/s", 3193178354Ssam modename[mode], rp->rssi/2, rp->rate/2); 3194178354Ssam } 3195178354Ssam for (; mode < IEEE80211_MODE_MAX; mode++) { 3196178354Ssam rp = &roamparams.params[mode]; 3197178354Ssam if (rp->rssi == 0 && rp->rate == 0) 3198178354Ssam continue; 3199178354Ssam if (rp->rssi & 1) 3200178354Ssam LINE_CHECK("roam:%-6.6s rssi %2u.5dBm MCS %2u ", 3201178354Ssam modename[mode], rp->rssi/2, rp->rate &~ 0x80); 3202178354Ssam else 3203178354Ssam LINE_CHECK("roam:%-6.6s rssi %4udBm MCS %2u ", 3204178354Ssam modename[mode], rp->rssi/2, rp->rate &~ 0x80); 3205178354Ssam } 3206178354Ssam} 3207178354Ssam 3208178354Ssamstatic void 3209178354Ssamlist_txparams(int s) 3210178354Ssam{ 3211178354Ssam const struct ieee80211_txparam *tp; 3212178354Ssam int mode; 3213178354Ssam 3214178354Ssam gettxparams(s); 3215178354Ssam for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_11NA; mode++) { 3216178354Ssam tp = &txparams.params[mode]; 3217178354Ssam if (tp->mgmtrate == 0 && tp->mcastrate == 0) 3218178354Ssam continue; 3219178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 3220178354Ssam LINE_CHECK("%-6.6s ucast NONE mgmt %2u Mb/s " 3221178354Ssam "mcast %2u Mb/s maxretry %u", 3222178354Ssam modename[mode], tp->mgmtrate/2, 3223178354Ssam tp->mcastrate/2, tp->maxretry); 3224178354Ssam else 3225178354Ssam LINE_CHECK("%-6.6s ucast %2u Mb/s mgmt %2u Mb/s " 3226178354Ssam "mcast %2u Mb/s maxretry %u", 3227178354Ssam modename[mode], tp->ucastrate/2, tp->mgmtrate/2, 3228178354Ssam tp->mcastrate/2, tp->maxretry); 3229178354Ssam } 3230178354Ssam for (; mode < IEEE80211_MODE_MAX; mode++) { 3231178354Ssam tp = &txparams.params[mode]; 3232178354Ssam if (tp->mgmtrate == 0 && tp->mcastrate == 0) 3233178354Ssam continue; 3234178354Ssam if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 3235178354Ssam LINE_CHECK("%-6.6s ucast NONE mgmt %2u MCS " 3236178354Ssam "mcast %2u MCS maxretry %u", 3237178354Ssam modename[mode], tp->mgmtrate &~ 0x80, 3238178354Ssam tp->mcastrate &~ 0x80, tp->maxretry); 3239178354Ssam else 3240178354Ssam LINE_CHECK("%-6.6s ucast %2u MCS mgmt %2u MCS " 3241178354Ssam "mcast %2u MCS maxretry %u", 3242178354Ssam modename[mode], tp->ucastrate &~ 0x80, 3243178354Ssam tp->mgmtrate &~ 0x80, 3244178354Ssam tp->mcastrate &~ 0x80, tp->maxretry); 3245178354Ssam } 3246178354Ssam} 3247178354Ssam 3248178354Ssamstatic void 3249173275Ssamprintpolicy(int policy) 3250173275Ssam{ 3251173275Ssam switch (policy) { 3252173275Ssam case IEEE80211_MACCMD_POLICY_OPEN: 3253173275Ssam printf("policy: open\n"); 3254173275Ssam break; 3255173275Ssam case IEEE80211_MACCMD_POLICY_ALLOW: 3256173275Ssam printf("policy: allow\n"); 3257173275Ssam break; 3258173275Ssam case IEEE80211_MACCMD_POLICY_DENY: 3259173275Ssam printf("policy: deny\n"); 3260173275Ssam break; 3261178354Ssam case IEEE80211_MACCMD_POLICY_RADIUS: 3262178354Ssam printf("policy: radius\n"); 3263178354Ssam break; 3264173275Ssam default: 3265173275Ssam printf("policy: unknown (%u)\n", policy); 3266173275Ssam break; 3267173275Ssam } 3268173275Ssam} 3269173275Ssam 3270173275Ssamstatic void 3271149029Ssamlist_mac(int s) 3272149029Ssam{ 3273149029Ssam struct ieee80211req ireq; 3274149029Ssam struct ieee80211req_maclist *acllist; 3275173275Ssam int i, nacls, policy, len; 3276173275Ssam uint8_t *data; 3277149029Ssam char c; 3278149029Ssam 3279149029Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3280149029Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 3281149029Ssam ireq.i_type = IEEE80211_IOC_MACCMD; 3282149029Ssam ireq.i_val = IEEE80211_MACCMD_POLICY; 3283149029Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) { 3284149029Ssam if (errno == EINVAL) { 3285149029Ssam printf("No acl policy loaded\n"); 3286149029Ssam return; 3287149029Ssam } 3288149029Ssam err(1, "unable to get mac policy"); 3289149029Ssam } 3290149029Ssam policy = ireq.i_val; 3291149029Ssam if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 3292149029Ssam c = '*'; 3293149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 3294149029Ssam c = '+'; 3295149029Ssam } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 3296149029Ssam c = '-'; 3297178354Ssam } else if (policy == IEEE80211_MACCMD_POLICY_RADIUS) { 3298178354Ssam c = 'r'; /* NB: should never have entries */ 3299149029Ssam } else { 3300149029Ssam printf("policy: unknown (%u)\n", policy); 3301149029Ssam c = '?'; 3302149029Ssam } 3303173275Ssam if (verbose || c == '?') 3304173275Ssam printpolicy(policy); 3305173275Ssam 3306175952Ssam ireq.i_val = IEEE80211_MACCMD_LIST; 3307175952Ssam ireq.i_len = 0; 3308175952Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 3309173275Ssam err(1, "unable to get mac acl list size"); 3310175952Ssam if (ireq.i_len == 0) { /* NB: no acls */ 3311173275Ssam if (!(verbose || c == '?')) 3312173275Ssam printpolicy(policy); 3313173275Ssam return; 3314173275Ssam } 3315175952Ssam len = ireq.i_len; 3316173275Ssam 3317173275Ssam data = malloc(len); 3318173275Ssam if (data == NULL) 3319173275Ssam err(1, "out of memory for acl list"); 3320173275Ssam 3321175952Ssam ireq.i_data = data; 3322175952Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 3323173275Ssam err(1, "unable to get mac acl list"); 3324173275Ssam nacls = len / sizeof(*acllist); 3325173275Ssam acllist = (struct ieee80211req_maclist *) data; 3326149029Ssam for (i = 0; i < nacls; i++) 3327149029Ssam printf("%c%s\n", c, ether_ntoa( 3328149029Ssam (const struct ether_addr *) acllist[i].ml_macaddr)); 3329173275Ssam free(data); 3330149029Ssam} 3331149029Ssam 3332178354Ssamstatic void 3333178354Ssamprint_regdomain(const struct ieee80211_regdomain *reg, int verb) 3334178354Ssam{ 3335178354Ssam if ((reg->regdomain != 0 && 3336178354Ssam reg->regdomain != reg->country) || verb) { 3337178354Ssam const struct regdomain *rd = 3338178354Ssam lib80211_regdomain_findbysku(getregdata(), reg->regdomain); 3339178354Ssam if (rd == NULL) 3340178354Ssam LINE_CHECK("regdomain %d", reg->regdomain); 3341178354Ssam else 3342178354Ssam LINE_CHECK("regdomain %s", rd->name); 3343178354Ssam } 3344178354Ssam if (reg->country != 0 || verb) { 3345178354Ssam const struct country *cc = 3346178354Ssam lib80211_country_findbycc(getregdata(), reg->country); 3347178354Ssam if (cc == NULL) 3348178354Ssam LINE_CHECK("country %d", reg->country); 3349178354Ssam else 3350178354Ssam LINE_CHECK("country %s", cc->isoname); 3351178354Ssam } 3352178354Ssam if (reg->location == 'I') 3353178354Ssam LINE_CHECK("indoor"); 3354178354Ssam else if (reg->location == 'O') 3355178354Ssam LINE_CHECK("outdoor"); 3356178354Ssam else if (verb) 3357178354Ssam LINE_CHECK("anywhere"); 3358178354Ssam if (reg->ecm) 3359178354Ssam LINE_CHECK("ecm"); 3360178354Ssam else if (verb) 3361178354Ssam LINE_CHECK("-ecm"); 3362178354Ssam} 3363178354Ssam 3364178354Ssamstatic void 3365178354Ssamlist_regdomain(int s, int channelsalso) 3366178354Ssam{ 3367178354Ssam getregdomain(s); 3368178354Ssam if (channelsalso) { 3369178354Ssam getchaninfo(s); 3370178354Ssam spacer = ':'; 3371178354Ssam print_regdomain(®domain, 1); 3372178354Ssam LINE_BREAK(); 3373178354Ssam print_channels(s, &chaninfo, 1/*allchans*/, 1/*verbose*/); 3374178354Ssam } else 3375178354Ssam print_regdomain(®domain, verbose); 3376178354Ssam} 3377178354Ssam 3378138593Ssamstatic 3379138593SsamDECL_CMD_FUNC(set80211list, arg, d) 3380138593Ssam{ 3381138593Ssam#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 3382138593Ssam 3383173275Ssam LINE_INIT('\t'); 3384173275Ssam 3385138593Ssam if (iseq(arg, "sta")) 3386138593Ssam list_stations(s); 3387138593Ssam else if (iseq(arg, "scan") || iseq(arg, "ap")) 3388138593Ssam list_scan(s); 3389138593Ssam else if (iseq(arg, "chan") || iseq(arg, "freq")) 3390138593Ssam list_channels(s, 1); 3391138593Ssam else if (iseq(arg, "active")) 3392138593Ssam list_channels(s, 0); 3393138593Ssam else if (iseq(arg, "keys")) 3394138593Ssam list_keys(s); 3395138593Ssam else if (iseq(arg, "caps")) 3396138593Ssam list_capabilities(s); 3397178354Ssam else if (iseq(arg, "wme") || iseq(arg, "wmm")) 3398138593Ssam list_wme(s); 3399149029Ssam else if (iseq(arg, "mac")) 3400149029Ssam list_mac(s); 3401170531Ssam else if (iseq(arg, "txpow")) 3402170531Ssam list_txpow(s); 3403178354Ssam else if (iseq(arg, "roam")) 3404178354Ssam list_roam(s); 3405178354Ssam else if (iseq(arg, "txparam") || iseq(arg, "txparm")) 3406178354Ssam list_txparams(s); 3407178354Ssam else if (iseq(arg, "regdomain")) 3408178354Ssam list_regdomain(s, 1); 3409178354Ssam else if (iseq(arg, "countries")) 3410178354Ssam list_countries(); 3411138593Ssam else 3412138593Ssam errx(1, "Don't know how to list %s for %s", arg, name); 3413178354Ssam LINE_BREAK(); 3414138593Ssam#undef iseq 3415138593Ssam} 3416138593Ssam 3417138593Ssamstatic enum ieee80211_opmode 3418138593Ssamget80211opmode(int s) 3419138593Ssam{ 3420138593Ssam struct ifmediareq ifmr; 3421138593Ssam 3422138593Ssam (void) memset(&ifmr, 0, sizeof(ifmr)); 3423138593Ssam (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 3424138593Ssam 3425138593Ssam if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 3426138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) 3427138593Ssam return IEEE80211_M_IBSS; /* XXX ahdemo */ 3428138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 3429138593Ssam return IEEE80211_M_HOSTAP; 3430138593Ssam if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 3431138593Ssam return IEEE80211_M_MONITOR; 3432138593Ssam } 3433138593Ssam return IEEE80211_M_STA; 3434138593Ssam} 3435138593Ssam 3436138593Ssam#if 0 3437138593Ssamstatic void 3438138593Ssamprintcipher(int s, struct ieee80211req *ireq, int keylenop) 3439138593Ssam{ 3440138593Ssam switch (ireq->i_val) { 3441138593Ssam case IEEE80211_CIPHER_WEP: 3442138593Ssam ireq->i_type = keylenop; 3443138593Ssam if (ioctl(s, SIOCG80211, ireq) != -1) 3444138593Ssam printf("WEP-%s", 3445138593Ssam ireq->i_len <= 5 ? "40" : 3446138593Ssam ireq->i_len <= 13 ? "104" : "128"); 3447138593Ssam else 3448138593Ssam printf("WEP"); 3449138593Ssam break; 3450138593Ssam case IEEE80211_CIPHER_TKIP: 3451138593Ssam printf("TKIP"); 3452138593Ssam break; 3453138593Ssam case IEEE80211_CIPHER_AES_OCB: 3454138593Ssam printf("AES-OCB"); 3455138593Ssam break; 3456138593Ssam case IEEE80211_CIPHER_AES_CCM: 3457138593Ssam printf("AES-CCM"); 3458138593Ssam break; 3459138593Ssam case IEEE80211_CIPHER_CKIP: 3460138593Ssam printf("CKIP"); 3461138593Ssam break; 3462138593Ssam case IEEE80211_CIPHER_NONE: 3463138593Ssam printf("NONE"); 3464138593Ssam break; 3465138593Ssam default: 3466138593Ssam printf("UNKNOWN (0x%x)", ireq->i_val); 3467138593Ssam break; 3468138593Ssam } 3469138593Ssam} 3470138593Ssam#endif 3471138593Ssam 3472155931Ssamstatic void 3473138593Ssamprintkey(const struct ieee80211req_key *ik) 3474138593Ssam{ 3475138593Ssam static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 3476138593Ssam int keylen = ik->ik_keylen; 3477138593Ssam int printcontents; 3478138593Ssam 3479148001Srwatson printcontents = printkeys && 3480138593Ssam (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 3481138593Ssam if (printcontents) 3482138593Ssam LINE_BREAK(); 3483138593Ssam switch (ik->ik_type) { 3484138593Ssam case IEEE80211_CIPHER_WEP: 3485138593Ssam /* compatibility */ 3486155931Ssam LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1, 3487138593Ssam keylen <= 5 ? "40-bit" : 3488138593Ssam keylen <= 13 ? "104-bit" : "128-bit"); 3489138593Ssam break; 3490138593Ssam case IEEE80211_CIPHER_TKIP: 3491138593Ssam if (keylen > 128/8) 3492138593Ssam keylen -= 128/8; /* ignore MIC for now */ 3493155931Ssam LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3494138593Ssam break; 3495138593Ssam case IEEE80211_CIPHER_AES_OCB: 3496155931Ssam LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3497138593Ssam break; 3498138593Ssam case IEEE80211_CIPHER_AES_CCM: 3499155931Ssam LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3500138593Ssam break; 3501138593Ssam case IEEE80211_CIPHER_CKIP: 3502155931Ssam LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3503138593Ssam break; 3504138593Ssam case IEEE80211_CIPHER_NONE: 3505155931Ssam LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen); 3506138593Ssam break; 3507138593Ssam default: 3508155931Ssam LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit", 3509138593Ssam ik->ik_type, ik->ik_keyix+1, 8*keylen); 3510138593Ssam break; 3511138593Ssam } 3512138593Ssam if (printcontents) { 3513138593Ssam int i; 3514138593Ssam 3515138593Ssam printf(" <"); 3516138593Ssam for (i = 0; i < keylen; i++) 3517138593Ssam printf("%02x", ik->ik_keydata[i]); 3518138593Ssam printf(">"); 3519138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 3520138593Ssam (ik->ik_keyrsc != 0 || verbose)) 3521146873Sjhb printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 3522138593Ssam if (ik->ik_type != IEEE80211_CIPHER_WEP && 3523138593Ssam (ik->ik_keytsc != 0 || verbose)) 3524146873Sjhb printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 3525138593Ssam if (ik->ik_flags != 0 && verbose) { 3526138593Ssam const char *sep = " "; 3527138593Ssam 3528138593Ssam if (ik->ik_flags & IEEE80211_KEY_XMIT) 3529138593Ssam printf("%stx", sep), sep = "+"; 3530138593Ssam if (ik->ik_flags & IEEE80211_KEY_RECV) 3531138593Ssam printf("%srx", sep), sep = "+"; 3532138593Ssam if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 3533138593Ssam printf("%sdef", sep), sep = "+"; 3534138593Ssam } 3535138593Ssam LINE_BREAK(); 3536138593Ssam } 3537138593Ssam} 3538138593Ssam 3539138593Ssamstatic void 3540173275Ssamprintrate(const char *tag, int v, int defrate, int defmcs) 3541138593Ssam{ 3542173275Ssam if (v == 11) 3543173275Ssam LINE_CHECK("%s 5.5", tag); 3544173275Ssam else if (v & 0x80) { 3545173275Ssam if (v != defmcs) 3546173275Ssam LINE_CHECK("%s %d", tag, v &~ 0x80); 3547173275Ssam } else { 3548173275Ssam if (v != defrate) 3549173275Ssam LINE_CHECK("%s %d", tag, v/2); 3550173275Ssam } 3551173275Ssam} 3552173275Ssam 3553173275Ssamstatic int 3554173275Ssamgetssid(int s, int ix, void *data, size_t len, int *plen) 3555173275Ssam{ 3556138593Ssam struct ieee80211req ireq; 3557138593Ssam 3558138593Ssam (void) memset(&ireq, 0, sizeof(ireq)); 3559138593Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3560173275Ssam ireq.i_type = IEEE80211_IOC_SSID; 3561173275Ssam ireq.i_val = ix; 3562173275Ssam ireq.i_data = data; 3563173275Ssam ireq.i_len = len; 3564173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 3565173275Ssam return -1; 3566173275Ssam *plen = ireq.i_len; 3567173275Ssam return 0; 3568173275Ssam} 356977218Sphk 3570173275Ssamstatic void 3571173275Ssamieee80211_status(int s) 3572173275Ssam{ 3573173275Ssam static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 3574173275Ssam enum ieee80211_opmode opmode = get80211opmode(s); 3575173275Ssam int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode; 3576173275Ssam uint8_t data[32]; 3577173275Ssam const struct ieee80211_channel *c; 3578178354Ssam const struct ieee80211_roamparam *rp; 3579178354Ssam const struct ieee80211_txparam *tp; 3580173275Ssam 3581173275Ssam if (getssid(s, -1, data, sizeof(data), &len) < 0) { 3582148686Sstefanf /* If we can't get the SSID, this isn't an 802.11 device. */ 358377218Sphk return; 358477218Sphk } 3585173275Ssam 3586173275Ssam /* 3587173275Ssam * Invalidate cached state so printing status for multiple 3588173275Ssam * if's doesn't reuse the first interfaces' cached state. 3589173275Ssam */ 3590173275Ssam gotcurchan = 0; 3591178354Ssam gotroam = 0; 3592178354Ssam gottxparams = 0; 3593173275Ssam gothtconf = 0; 3594178354Ssam gotregdomain = 0; 3595173275Ssam 3596173275Ssam if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0) 3597173275Ssam num = 0; 3598138593Ssam printf("\tssid "); 3599138593Ssam if (num > 1) { 3600173275Ssam for (i = 0; i < num; i++) { 3601173275Ssam if (getssid(s, i, data, sizeof(data), &len) >= 0 && len > 0) { 3602173275Ssam printf(" %d:", i + 1); 3603173275Ssam print_string(data, len); 3604138593Ssam } 360588748Sambrisko } 3606138593Ssam } else 3607173275Ssam print_string(data, len); 360877218Sphk 3609173275Ssam c = getcurchan(s); 3610170531Ssam if (c->ic_freq != IEEE80211_CHAN_ANY) { 3611170531Ssam char buf[14]; 3612170531Ssam printf(" channel %d (%u Mhz%s)", c->ic_ieee, c->ic_freq, 3613170531Ssam get_chaninfo(c, 1, buf, sizeof(buf))); 3614138593Ssam } else if (verbose) 3615138593Ssam printf(" channel UNDEF"); 3616138593Ssam 3617173275Ssam if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 && 3618173275Ssam (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) 3619173275Ssam printf(" bssid %s", ether_ntoa((struct ether_addr *)data)); 3620138593Ssam 3621173275Ssam if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) { 3622138593Ssam printf("\n\tstationname "); 3623173275Ssam print_string(data, len); 362477218Sphk } 362577218Sphk 3626138593Ssam spacer = ' '; /* force first break */ 3627138593Ssam LINE_BREAK(); 362877218Sphk 3629178354Ssam list_regdomain(s, 0); 3630178354Ssam 3631173275Ssam wpa = 0; 3632173275Ssam if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) { 3633173275Ssam switch (val) { 3634173275Ssam case IEEE80211_AUTH_NONE: 3635173275Ssam LINE_CHECK("authmode NONE"); 3636173275Ssam break; 3637173275Ssam case IEEE80211_AUTH_OPEN: 3638173275Ssam LINE_CHECK("authmode OPEN"); 3639173275Ssam break; 3640173275Ssam case IEEE80211_AUTH_SHARED: 3641173275Ssam LINE_CHECK("authmode SHARED"); 3642173275Ssam break; 3643173275Ssam case IEEE80211_AUTH_8021X: 3644173275Ssam LINE_CHECK("authmode 802.1x"); 3645173275Ssam break; 3646173275Ssam case IEEE80211_AUTH_WPA: 3647173275Ssam if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0) 3648173275Ssam wpa = 1; /* default to WPA1 */ 3649173275Ssam switch (wpa) { 3650173275Ssam case 2: 3651173275Ssam LINE_CHECK("authmode WPA2/802.11i"); 365277218Sphk break; 3653173275Ssam case 3: 3654173275Ssam LINE_CHECK("authmode WPA1+WPA2/802.11i"); 365577218Sphk break; 3656127649Ssam default: 3657173275Ssam LINE_CHECK("authmode WPA"); 3658127649Ssam break; 3659173275Ssam } 3660173275Ssam break; 3661173275Ssam case IEEE80211_AUTH_AUTO: 3662173275Ssam LINE_CHECK("authmode AUTO"); 3663173275Ssam break; 3664173275Ssam default: 3665173275Ssam LINE_CHECK("authmode UNKNOWN (0x%x)", val); 3666173275Ssam break; 3667127649Ssam } 3668127649Ssam } 3669127649Ssam 3670173275Ssam if (wpa || verbose) { 3671178354Ssam if (get80211val(s, IEEE80211_IOC_WPS, &val) != -1) { 3672178354Ssam if (val) 3673178354Ssam LINE_CHECK("wps"); 3674178354Ssam else if (verbose) 3675178354Ssam LINE_CHECK("-wps"); 3676178354Ssam } 3677178354Ssam if (get80211val(s, IEEE80211_IOC_TSN, &val) != -1) { 3678178354Ssam if (val) 3679178354Ssam LINE_CHECK("tsn"); 3680178354Ssam else if (verbose) 3681178354Ssam LINE_CHECK("-tsn"); 3682178354Ssam } 3683173275Ssam if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) { 3684173275Ssam if (val) 3685173275Ssam LINE_CHECK("countermeasures"); 3686173275Ssam else if (verbose) 3687173275Ssam LINE_CHECK("-countermeasures"); 3688173275Ssam } 3689178354Ssam#if 0 3690178354Ssam /* XXX not interesting with WPA done in user space */ 3691178354Ssam ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 3692178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3693178354Ssam } 3694178354Ssam 3695178354Ssam ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 3696178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3697178354Ssam LINE_CHECK("mcastcipher "); 3698178354Ssam printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 3699178354Ssam spacer = ' '; 3700178354Ssam } 3701178354Ssam 3702178354Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 3703178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3704178354Ssam LINE_CHECK("ucastcipher "); 3705178354Ssam printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 3706178354Ssam } 3707178354Ssam 3708178354Ssam if (wpa & 2) { 3709178354Ssam ireq.i_type = IEEE80211_IOC_RSNCAPS; 3710178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3711178354Ssam LINE_CHECK("RSN caps 0x%x", ireq.i_val); 3712178354Ssam spacer = ' '; 3713178354Ssam } 3714178354Ssam } 3715178354Ssam 3716178354Ssam ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 3717178354Ssam if (ioctl(s, SIOCG80211, &ireq) != -1) { 3718178354Ssam } 3719178354Ssam#endif 3720173275Ssam } 3721138593Ssam 3722173275Ssam if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 && 3723173275Ssam wepmode != IEEE80211_WEP_NOSUP) { 3724173275Ssam int firstkey; 3725173275Ssam 3726138718Ssam switch (wepmode) { 3727173275Ssam case IEEE80211_WEP_OFF: 3728173275Ssam LINE_CHECK("privacy OFF"); 3729173275Ssam break; 3730173275Ssam case IEEE80211_WEP_ON: 3731173275Ssam LINE_CHECK("privacy ON"); 3732173275Ssam break; 3733173275Ssam case IEEE80211_WEP_MIXED: 3734173275Ssam LINE_CHECK("privacy MIXED"); 3735173275Ssam break; 3736173275Ssam default: 3737173275Ssam LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); 3738173275Ssam break; 373977218Sphk } 374077218Sphk 374177218Sphk /* 374277218Sphk * If we get here then we've got WEP support so we need 374377218Sphk * to print WEP status. 374491454Sbrooks */ 374577218Sphk 3746173275Ssam if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) { 374777218Sphk warn("WEP support, but no tx key!"); 374877218Sphk goto end; 374977218Sphk } 3750173275Ssam if (val != -1) 3751173275Ssam LINE_CHECK("deftxkey %d", val+1); 3752138718Ssam else if (wepmode != IEEE80211_WEP_OFF || verbose) 3753155931Ssam LINE_CHECK("deftxkey UNDEF"); 375477218Sphk 3755173275Ssam if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) { 375677218Sphk warn("WEP support, but no NUMWEPKEYS support!"); 375777218Sphk goto end; 375877218Sphk } 375977218Sphk 3760138593Ssam firstkey = 1; 3761138593Ssam for (i = 0; i < num; i++) { 3762138593Ssam struct ieee80211req_key ik; 376377218Sphk 3764138593Ssam memset(&ik, 0, sizeof(ik)); 3765138593Ssam ik.ik_keyix = i; 3766173275Ssam if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) { 376777218Sphk warn("WEP support, but can get keys!"); 376877218Sphk goto end; 376977218Sphk } 3770138593Ssam if (ik.ik_keylen != 0) { 3771138593Ssam if (verbose) 3772138593Ssam LINE_BREAK(); 3773138593Ssam printkey(&ik); 3774138593Ssam firstkey = 0; 3775138593Ssam } 3776138593Ssam } 3777173275Ssamend: 3778173275Ssam ; 3779138593Ssam } 3780138593Ssam 3781173275Ssam if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 && 3782173275Ssam val != IEEE80211_POWERSAVE_NOSUP ) { 3783173275Ssam if (val != IEEE80211_POWERSAVE_OFF || verbose) { 3784173275Ssam switch (val) { 3785173275Ssam case IEEE80211_POWERSAVE_OFF: 3786173275Ssam LINE_CHECK("powersavemode OFF"); 3787173275Ssam break; 3788173275Ssam case IEEE80211_POWERSAVE_CAM: 3789173275Ssam LINE_CHECK("powersavemode CAM"); 3790173275Ssam break; 3791173275Ssam case IEEE80211_POWERSAVE_PSP: 3792173275Ssam LINE_CHECK("powersavemode PSP"); 3793173275Ssam break; 3794173275Ssam case IEEE80211_POWERSAVE_PSP_CAM: 3795173275Ssam LINE_CHECK("powersavemode PSP-CAM"); 3796173275Ssam break; 3797138593Ssam } 3798173275Ssam if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1) 3799173275Ssam LINE_CHECK("powersavesleep %d", val); 3800138593Ssam } 3801138593Ssam } 3802138593Ssam 3803173275Ssam if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) { 3804173275Ssam if (val & 1) 3805173275Ssam LINE_CHECK("txpower %d.5", val/2); 3806173275Ssam else 3807173275Ssam LINE_CHECK("txpower %d", val/2); 3808173275Ssam } 3809138593Ssam if (verbose) { 3810173275Ssam if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1) 3811173275Ssam LINE_CHECK("txpowmax %.1f", val/2.); 3812138593Ssam } 3813138593Ssam 3814178354Ssam if (get80211val(s, IEEE80211_IOC_DOTD, &val) != -1) { 3815178354Ssam if (val) 3816178354Ssam LINE_CHECK("dotd"); 3817178354Ssam else if (verbose) 3818178354Ssam LINE_CHECK("-dotd"); 3819178354Ssam } 3820178354Ssam 3821173275Ssam if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) { 3822173275Ssam if (val != IEEE80211_RTS_MAX || verbose) 3823173275Ssam LINE_CHECK("rtsthreshold %d", val); 3824138593Ssam } 3825138593Ssam 3826173275Ssam if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) { 3827173275Ssam if (val != IEEE80211_FRAG_MAX || verbose) 3828173275Ssam LINE_CHECK("fragthreshold %d", val); 3829170531Ssam } 3830173275Ssam if (opmode == IEEE80211_M_STA || verbose) { 3831173275Ssam if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) { 3832173275Ssam if (val != IEEE80211_HWBMISS_MAX || verbose) 3833173275Ssam LINE_CHECK("bmiss %d", val); 3834153354Ssam } 3835153354Ssam } 3836153354Ssam 3837178354Ssam if (!verbose) { 3838178354Ssam gettxparams(s); 3839178354Ssam tp = &txparams.params[chan2mode(c)]; 3840178354Ssam printrate("ucastrate", tp->ucastrate, 3841178354Ssam IEEE80211_FIXED_RATE_NONE, IEEE80211_FIXED_RATE_NONE); 3842178354Ssam printrate("mcastrate", tp->mcastrate, 2*1, 0x80|0); 3843178354Ssam printrate("mgmtrate", tp->mgmtrate, 2*1, 0x80|0); 3844178354Ssam if (tp->maxretry != 6) /* XXX */ 3845178354Ssam LINE_CHECK("maxretry %d", tp->maxretry); 3846178354Ssam } else { 3847178354Ssam LINE_BREAK(); 3848178354Ssam list_txparams(s); 3849178354Ssam } 3850170531Ssam 3851173275Ssam bgscaninterval = -1; 3852173275Ssam (void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval); 3853173275Ssam 3854173275Ssam if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) { 3855173275Ssam if (val != bgscaninterval || verbose) 3856173275Ssam LINE_CHECK("scanvalid %u", val); 3857148416Ssam } 3858148416Ssam 3859173275Ssam bgscan = 0; 3860173275Ssam if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) { 3861173275Ssam if (bgscan) 3862170531Ssam LINE_CHECK("bgscan"); 3863170531Ssam else if (verbose) 3864170531Ssam LINE_CHECK("-bgscan"); 3865160687Ssam } 3866170531Ssam if (bgscan || verbose) { 3867170531Ssam if (bgscaninterval != -1) 3868170531Ssam LINE_CHECK("bgscanintvl %u", bgscaninterval); 3869173275Ssam if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1) 3870173275Ssam LINE_CHECK("bgscanidle %u", val); 3871178354Ssam if (!verbose) { 3872178354Ssam getroam(s); 3873178354Ssam rp = &roamparams.params[chan2mode(c)]; 3874178354Ssam if (rp->rssi & 1) 3875178354Ssam LINE_CHECK("roam:rssi %u.5", rp->rssi/2); 3876178354Ssam else 3877178354Ssam LINE_CHECK("roam:rssi %u", rp->rssi/2); 3878178354Ssam LINE_CHECK("roam:rate %u", rp->rate/2); 3879178354Ssam } else { 3880178354Ssam LINE_BREAK(); 3881178354Ssam list_roam(s); 3882170531Ssam } 3883170531Ssam } 3884160687Ssam 3885165570Ssam if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { 3886173275Ssam if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) { 3887173275Ssam if (val) 3888155931Ssam LINE_CHECK("pureg"); 3889147795Ssam else if (verbose) 3890155931Ssam LINE_CHECK("-pureg"); 3891147795Ssam } 3892173275Ssam if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) { 3893173275Ssam switch (val) { 3894173275Ssam case IEEE80211_PROTMODE_OFF: 3895173275Ssam LINE_CHECK("protmode OFF"); 3896173275Ssam break; 3897173275Ssam case IEEE80211_PROTMODE_CTS: 3898173275Ssam LINE_CHECK("protmode CTS"); 3899173275Ssam break; 3900173275Ssam case IEEE80211_PROTMODE_RTSCTS: 3901173275Ssam LINE_CHECK("protmode RTSCTS"); 3902173275Ssam break; 3903173275Ssam default: 3904173275Ssam LINE_CHECK("protmode UNKNOWN (0x%x)", val); 3905173275Ssam break; 3906138593Ssam } 3907138593Ssam } 3908138593Ssam } 3909138593Ssam 3910173275Ssam if (IEEE80211_IS_CHAN_HT(c) || verbose) { 3911173275Ssam gethtconf(s); 3912173275Ssam switch (htconf & 3) { 3913173275Ssam case 0: 3914173275Ssam case 2: 3915173275Ssam LINE_CHECK("-ht"); 3916173275Ssam break; 3917173275Ssam case 1: 3918173275Ssam LINE_CHECK("ht20"); 3919173275Ssam break; 3920173275Ssam case 3: 3921173275Ssam if (verbose) 3922173275Ssam LINE_CHECK("ht"); 3923173275Ssam break; 3924173275Ssam } 3925173275Ssam if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) { 3926173275Ssam if (!val) 3927173275Ssam LINE_CHECK("-htcompat"); 3928173275Ssam else if (verbose) 3929173275Ssam LINE_CHECK("htcompat"); 3930173275Ssam } 3931173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) { 3932173275Ssam switch (val) { 3933173275Ssam case 0: 3934173275Ssam LINE_CHECK("-ampdu"); 3935173275Ssam break; 3936173275Ssam case 1: 3937173275Ssam LINE_CHECK("ampdutx -ampdurx"); 3938173275Ssam break; 3939173275Ssam case 2: 3940173275Ssam LINE_CHECK("-ampdutx ampdurx"); 3941173275Ssam break; 3942173275Ssam case 3: 3943173275Ssam if (verbose) 3944173275Ssam LINE_CHECK("ampdu"); 3945173275Ssam break; 3946173275Ssam } 3947173275Ssam } 3948173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) { 3949173275Ssam switch (val) { 3950173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_8K: 3951173275Ssam LINE_CHECK("ampdulimit 8k"); 3952173275Ssam break; 3953173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_16K: 3954173275Ssam LINE_CHECK("ampdulimit 16k"); 3955173275Ssam break; 3956173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_32K: 3957173275Ssam LINE_CHECK("ampdulimit 32k"); 3958173275Ssam break; 3959173275Ssam case IEEE80211_HTCAP_MAXRXAMPDU_64K: 3960173275Ssam LINE_CHECK("ampdulimit 64k"); 3961173275Ssam break; 3962173275Ssam } 3963173275Ssam } 3964173275Ssam if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) { 3965173275Ssam switch (val) { 3966173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_NA: 3967173275Ssam if (verbose) 3968173275Ssam LINE_CHECK("ampdudensity -"); 3969173275Ssam break; 3970173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_025: 3971173275Ssam LINE_CHECK("ampdudensity .25"); 3972173275Ssam break; 3973173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_05: 3974173275Ssam LINE_CHECK("ampdudensity .5"); 3975173275Ssam break; 3976173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_1: 3977173275Ssam LINE_CHECK("ampdudensity 1"); 3978173275Ssam break; 3979173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_2: 3980173275Ssam LINE_CHECK("ampdudensity 2"); 3981173275Ssam break; 3982173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_4: 3983173275Ssam LINE_CHECK("ampdudensity 4"); 3984173275Ssam break; 3985173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_8: 3986173275Ssam LINE_CHECK("ampdudensity 8"); 3987173275Ssam break; 3988173275Ssam case IEEE80211_HTCAP_MPDUDENSITY_16: 3989173275Ssam LINE_CHECK("ampdudensity 16"); 3990173275Ssam break; 3991173275Ssam } 3992173275Ssam } 3993173275Ssam if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) { 3994173275Ssam switch (val) { 3995173275Ssam case 0: 3996173275Ssam LINE_CHECK("-amsdu"); 3997173275Ssam break; 3998173275Ssam case 1: 3999173275Ssam LINE_CHECK("amsdutx -amsdurx"); 4000173275Ssam break; 4001173275Ssam case 2: 4002173275Ssam LINE_CHECK("-amsdutx amsdurx"); 4003173275Ssam break; 4004173275Ssam case 3: 4005173275Ssam if (verbose) 4006173275Ssam LINE_CHECK("amsdu"); 4007173275Ssam break; 4008173275Ssam } 4009173275Ssam } 4010173275Ssam /* XXX amsdu limit */ 4011173275Ssam if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) { 4012173275Ssam if (val) 4013173275Ssam LINE_CHECK("shortgi"); 4014173275Ssam else if (verbose) 4015173275Ssam LINE_CHECK("-shortgi"); 4016173275Ssam } 4017173275Ssam if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) { 4018173275Ssam if (val == IEEE80211_PROTMODE_OFF) 4019173275Ssam LINE_CHECK("htprotmode OFF"); 4020173275Ssam else if (val != IEEE80211_PROTMODE_RTSCTS) 4021173275Ssam LINE_CHECK("htprotmode UNKNOWN (0x%x)", val); 4022173275Ssam else if (verbose) 4023173275Ssam LINE_CHECK("htprotmode RTSCTS"); 4024173275Ssam } 4025173275Ssam if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) { 4026173275Ssam if (val) 4027173275Ssam LINE_CHECK("puren"); 4028173275Ssam else if (verbose) 4029173275Ssam LINE_CHECK("-puren"); 4030173275Ssam } 4031173275Ssam } 4032173275Ssam 4033173275Ssam if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) { 4034138593Ssam if (wme) 4035155931Ssam LINE_CHECK("wme"); 4036138593Ssam else if (verbose) 4037155931Ssam LINE_CHECK("-wme"); 4038138593Ssam } else 4039138593Ssam wme = 0; 4040138593Ssam 4041173275Ssam if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) { 4042173275Ssam if (val) 4043155931Ssam LINE_CHECK("burst"); 4044153422Ssam else if (verbose) 4045155931Ssam LINE_CHECK("-burst"); 4046153422Ssam } 4047153422Ssam 4048173275Ssam if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) { 4049173275Ssam if (val) 4050170531Ssam LINE_CHECK("ff"); 4051170531Ssam else if (verbose) 4052170531Ssam LINE_CHECK("-ff"); 4053170531Ssam } 4054173275Ssam if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) { 4055173275Ssam if (val) 4056170531Ssam LINE_CHECK("dturbo"); 4057170531Ssam else if (verbose) 4058170531Ssam LINE_CHECK("-dturbo"); 4059170531Ssam } 4060178354Ssam if (get80211val(s, IEEE80211_IOC_DWDS, &val) != -1) { 4061178354Ssam if (val) 4062178354Ssam LINE_CHECK("dwds"); 4063178354Ssam else if (verbose) 4064178354Ssam LINE_CHECK("-dwds"); 4065178354Ssam } 4066170531Ssam 4067138593Ssam if (opmode == IEEE80211_M_HOSTAP) { 4068173275Ssam if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) { 4069173275Ssam if (val) 4070168075Ssam LINE_CHECK("hidessid"); 4071138593Ssam else if (verbose) 4072168075Ssam LINE_CHECK("-hidessid"); 4073138593Ssam } 4074173275Ssam if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) { 4075173275Ssam if (!val) 4076155931Ssam LINE_CHECK("-apbridge"); 4077138593Ssam else if (verbose) 4078155931Ssam LINE_CHECK("apbridge"); 4079138593Ssam } 4080173275Ssam if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1) 4081173275Ssam LINE_CHECK("dtimperiod %u", val); 4082138593Ssam 4083173275Ssam if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) { 4084173275Ssam if (!val) 4085170531Ssam LINE_CHECK("-doth"); 4086170531Ssam else if (verbose) 4087170531Ssam LINE_CHECK("doth"); 4088170531Ssam } 4089178354Ssam if (get80211val(s, IEEE80211_IOC_DFS, &val) != -1) { 4090178354Ssam if (!val) 4091178354Ssam LINE_CHECK("-dfs"); 4092178354Ssam else if (verbose) 4093178354Ssam LINE_CHECK("dfs"); 4094178354Ssam } 4095173275Ssam if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) { 4096173275Ssam if (!val) 4097173275Ssam LINE_CHECK("-inact"); 4098173275Ssam else if (verbose) 4099173275Ssam LINE_CHECK("inact"); 4100173275Ssam } 4101138593Ssam } else { 4102173275Ssam if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) { 4103173275Ssam if (val != IEEE80211_ROAMING_AUTO || verbose) { 4104173275Ssam switch (val) { 4105138593Ssam case IEEE80211_ROAMING_DEVICE: 4106155931Ssam LINE_CHECK("roaming DEVICE"); 4107138593Ssam break; 4108138593Ssam case IEEE80211_ROAMING_AUTO: 4109155931Ssam LINE_CHECK("roaming AUTO"); 4110138593Ssam break; 4111138593Ssam case IEEE80211_ROAMING_MANUAL: 4112155931Ssam LINE_CHECK("roaming MANUAL"); 4113138593Ssam break; 4114138593Ssam default: 4115155931Ssam LINE_CHECK("roaming UNKNOWN (0x%x)", 4116173275Ssam val); 4117138593Ssam break; 4118138593Ssam } 4119138593Ssam } 4120138593Ssam } 4121138593Ssam } 4122173275Ssam if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) { 4123173275Ssam /* XXX default define not visible */ 4124173275Ssam if (val != 100 || verbose) 4125173275Ssam LINE_CHECK("bintval %u", val); 4126138593Ssam } 4127138593Ssam 4128138593Ssam if (wme && verbose) { 4129138593Ssam LINE_BREAK(); 4130138593Ssam list_wme(s); 4131138593Ssam } 4132173275Ssam LINE_BREAK(); 4133173275Ssam} 4134138593Ssam 4135173275Ssamstatic int 4136173275Ssamget80211(int s, int type, void *data, int len) 4137173275Ssam{ 4138173275Ssam struct ieee80211req ireq; 4139138593Ssam 4140173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 4141173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4142173275Ssam ireq.i_type = type; 4143173275Ssam ireq.i_data = data; 4144173275Ssam ireq.i_len = len; 4145173275Ssam return ioctl(s, SIOCG80211, &ireq); 4146173275Ssam} 4147138593Ssam 4148173275Ssamstatic int 4149173275Ssamget80211len(int s, int type, void *data, int len, int *plen) 4150173275Ssam{ 4151173275Ssam struct ieee80211req ireq; 4152138593Ssam 4153173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 4154173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4155173275Ssam ireq.i_type = type; 4156173275Ssam ireq.i_len = len; 4157173275Ssam ireq.i_data = data; 4158173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 4159173275Ssam return -1; 4160173275Ssam *plen = ireq.i_len; 4161173275Ssam return 0; 4162173275Ssam} 4163138593Ssam 4164173275Ssamstatic int 4165173275Ssamget80211val(int s, int type, int *val) 4166173275Ssam{ 4167173275Ssam struct ieee80211req ireq; 416877218Sphk 4169173275Ssam (void) memset(&ireq, 0, sizeof(ireq)); 4170173275Ssam (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4171173275Ssam ireq.i_type = type; 4172173275Ssam if (ioctl(s, SIOCG80211, &ireq) < 0) 4173173275Ssam return -1; 4174173275Ssam *val = ireq.i_val; 4175173275Ssam return 0; 417677218Sphk} 417777218Sphk 417877218Sphkstatic void 4179170531Ssamset80211(int s, int type, int val, int len, void *data) 418077218Sphk{ 418177218Sphk struct ieee80211req ireq; 418277218Sphk 418377218Sphk (void) memset(&ireq, 0, sizeof(ireq)); 418477218Sphk (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 418577218Sphk ireq.i_type = type; 418677218Sphk ireq.i_val = val; 418777218Sphk ireq.i_len = len; 418877218Sphk ireq.i_data = data; 418991454Sbrooks if (ioctl(s, SIOCS80211, &ireq) < 0) 419077218Sphk err(1, "SIOCS80211"); 419177218Sphk} 419277218Sphk 419377218Sphkstatic const char * 419477218Sphkget_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 419577218Sphk{ 419677218Sphk int len; 419777218Sphk int hexstr; 419877218Sphk u_int8_t *p; 419977218Sphk 420077218Sphk len = *lenp; 420177218Sphk p = buf; 420277218Sphk hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 420377218Sphk if (hexstr) 420477218Sphk val += 2; 420577218Sphk for (;;) { 420677218Sphk if (*val == '\0') 420777218Sphk break; 420877218Sphk if (sep != NULL && strchr(sep, *val) != NULL) { 420977218Sphk val++; 421077218Sphk break; 421177218Sphk } 421277218Sphk if (hexstr) { 4213127831Sphk if (!isxdigit((u_char)val[0])) { 421477218Sphk warnx("bad hexadecimal digits"); 421577218Sphk return NULL; 421677218Sphk } 4217127831Sphk if (!isxdigit((u_char)val[1])) { 4218127831Sphk warnx("odd count hexadecimal digits"); 4219127831Sphk return NULL; 4220127831Sphk } 422177218Sphk } 4222127831Sphk if (p >= buf + len) { 422377218Sphk if (hexstr) 422477218Sphk warnx("hexadecimal digits too long"); 422577218Sphk else 4226127831Sphk warnx("string too long"); 422777218Sphk return NULL; 422877218Sphk } 422977218Sphk if (hexstr) { 423077218Sphk#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 423177218Sphk *p++ = (tohex((u_char)val[0]) << 4) | 423277218Sphk tohex((u_char)val[1]); 423377218Sphk#undef tohex 423477218Sphk val += 2; 423577218Sphk } else 423677218Sphk *p++ = *val++; 423777218Sphk } 423877218Sphk len = p - buf; 423977218Sphk /* The string "-" is treated as the empty string. */ 4240165045Ssam if (!hexstr && len == 1 && buf[0] == '-') { 424177218Sphk len = 0; 4242165045Ssam memset(buf, 0, *lenp); 4243165045Ssam } else if (len < *lenp) 424477218Sphk memset(p, 0, *lenp - len); 424577218Sphk *lenp = len; 424677218Sphk return val; 424777218Sphk} 424877218Sphk 424977218Sphkstatic void 425077218Sphkprint_string(const u_int8_t *buf, int len) 425177218Sphk{ 425277218Sphk int i; 425377218Sphk int hasspc; 425477218Sphk 425577218Sphk i = 0; 425677218Sphk hasspc = 0; 425791454Sbrooks for (; i < len; i++) { 425877218Sphk if (!isprint(buf[i]) && buf[i] != '\0') 425977218Sphk break; 426077218Sphk if (isspace(buf[i])) 426177218Sphk hasspc++; 426277218Sphk } 426377218Sphk if (i == len) { 426477218Sphk if (hasspc || len == 0 || buf[0] == '\0') 426577218Sphk printf("\"%.*s\"", len, buf); 426677218Sphk else 426777218Sphk printf("%.*s", len, buf); 426877218Sphk } else { 426977218Sphk printf("0x"); 427077218Sphk for (i = 0; i < len; i++) 427177218Sphk printf("%02x", buf[i]); 427277218Sphk } 427377218Sphk} 427477218Sphk 4275178354Ssam/* 4276178354Ssam * Virtual AP cloning support. 4277178354Ssam */ 4278178354Ssamstatic struct ieee80211_clone_params params = { 4279178354Ssam .icp_opmode = IEEE80211_M_STA, /* default to station mode */ 4280178354Ssam}; 4281178354Ssam 4282178354Ssamstatic void 4283178354Ssamwlan_create(int s, struct ifreq *ifr) 4284178354Ssam{ 4285178354Ssam static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 4286178354Ssam 4287178354Ssam if (params.icp_parent[0] == '\0') 4288178354Ssam errx(1, "must specify a parent when creating a wlan device"); 4289178354Ssam if (params.icp_opmode == IEEE80211_M_WDS && 4290178354Ssam memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0) 4291178354Ssam errx(1, "no bssid specified for WDS (use wlanbssid)"); 4292178354Ssam ifr->ifr_data = (caddr_t) ¶ms; 4293178354Ssam if (ioctl(s, SIOCIFCREATE2, ifr) < 0) 4294178354Ssam err(1, "SIOCIFCREATE2"); 4295178354Ssam} 4296178354Ssam 4297178354Ssamstatic 4298178354SsamDECL_CMD_FUNC(set80211clone_wlandev, arg, d) 4299178354Ssam{ 4300178354Ssam strlcpy(params.icp_parent, arg, IFNAMSIZ); 4301178354Ssam clone_setcallback(wlan_create); 4302178354Ssam} 4303178354Ssam 4304178354Ssamstatic 4305178354SsamDECL_CMD_FUNC(set80211clone_wlanbssid, arg, d) 4306178354Ssam{ 4307178354Ssam const struct ether_addr *ea; 4308178354Ssam 4309178354Ssam ea = ether_aton(arg); 4310178354Ssam if (ea == NULL) 4311178354Ssam errx(1, "%s: cannot parse bssid", arg); 4312178354Ssam memcpy(params.icp_bssid, ea->octet, IEEE80211_ADDR_LEN); 4313178354Ssam clone_setcallback(wlan_create); 4314178354Ssam} 4315178354Ssam 4316178354Ssamstatic 4317178354SsamDECL_CMD_FUNC(set80211clone_wlanaddr, arg, d) 4318178354Ssam{ 4319178354Ssam const struct ether_addr *ea; 4320178354Ssam 4321178354Ssam ea = ether_aton(arg); 4322178354Ssam if (ea == NULL) 4323178354Ssam errx(1, "%s: cannot parse addres", arg); 4324178354Ssam memcpy(params.icp_macaddr, ea->octet, IEEE80211_ADDR_LEN); 4325178354Ssam params.icp_flags |= IEEE80211_CLONE_MACADDR; 4326178354Ssam clone_setcallback(wlan_create); 4327178354Ssam} 4328178354Ssam 4329178354Ssamstatic 4330178354SsamDECL_CMD_FUNC(set80211clone_wlanmode, arg, d) 4331178354Ssam{ 4332178354Ssam#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 4333178354Ssam if (iseq(arg, "sta")) 4334178354Ssam params.icp_opmode = IEEE80211_M_STA; 4335178354Ssam else if (iseq(arg, "ahdemo") || iseq(arg, "adhoc-demo")) 4336178354Ssam params.icp_opmode = IEEE80211_M_AHDEMO; 4337178354Ssam else if (iseq(arg, "ibss") || iseq(arg, "adhoc")) 4338178354Ssam params.icp_opmode = IEEE80211_M_IBSS; 4339178354Ssam else if (iseq(arg, "ap") || iseq(arg, "host")) 4340178354Ssam params.icp_opmode = IEEE80211_M_HOSTAP; 4341178354Ssam else if (iseq(arg, "wds")) 4342178354Ssam params.icp_opmode = IEEE80211_M_WDS; 4343178354Ssam else if (iseq(arg, "monitor")) 4344178354Ssam params.icp_opmode = IEEE80211_M_MONITOR; 4345178354Ssam else 4346178354Ssam errx(1, "Don't know to create %s for %s", arg, name); 4347178354Ssam clone_setcallback(wlan_create); 4348178354Ssam#undef iseq 4349178354Ssam} 4350178354Ssam 4351178354Ssamstatic void 4352178354Ssamset80211clone_beacons(const char *val, int d, int s, const struct afswtch *rafp) 4353178354Ssam{ 4354178354Ssam /* NB: inverted sense */ 4355178354Ssam if (d) 4356178354Ssam params.icp_flags &= ~IEEE80211_CLONE_NOBEACONS; 4357178354Ssam else 4358178354Ssam params.icp_flags |= IEEE80211_CLONE_NOBEACONS; 4359178354Ssam clone_setcallback(wlan_create); 4360178354Ssam} 4361178354Ssam 4362178354Ssamstatic void 4363178354Ssamset80211clone_bssid(const char *val, int d, int s, const struct afswtch *rafp) 4364178354Ssam{ 4365178354Ssam if (d) 4366178354Ssam params.icp_flags |= IEEE80211_CLONE_BSSID; 4367178354Ssam else 4368178354Ssam params.icp_flags &= ~IEEE80211_CLONE_BSSID; 4369178354Ssam clone_setcallback(wlan_create); 4370178354Ssam} 4371178354Ssam 4372178354Ssamstatic void 4373178354Ssamset80211clone_wdslegacy(const char *val, int d, int s, const struct afswtch *rafp) 4374178354Ssam{ 4375178354Ssam if (d) 4376178354Ssam params.icp_flags |= IEEE80211_CLONE_WDSLEGACY; 4377178354Ssam else 4378178354Ssam params.icp_flags &= ~IEEE80211_CLONE_WDSLEGACY; 4379178354Ssam clone_setcallback(wlan_create); 4380178354Ssam} 4381178354Ssam 4382138593Ssamstatic struct cmd ieee80211_cmds[] = { 4383138593Ssam DEF_CMD_ARG("ssid", set80211ssid), 4384138593Ssam DEF_CMD_ARG("nwid", set80211ssid), 4385138593Ssam DEF_CMD_ARG("stationname", set80211stationname), 4386138593Ssam DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 4387138593Ssam DEF_CMD_ARG("channel", set80211channel), 4388138593Ssam DEF_CMD_ARG("authmode", set80211authmode), 4389138593Ssam DEF_CMD_ARG("powersavemode", set80211powersavemode), 4390138593Ssam DEF_CMD("powersave", 1, set80211powersave), 4391138593Ssam DEF_CMD("-powersave", 0, set80211powersave), 4392138593Ssam DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 4393138593Ssam DEF_CMD_ARG("wepmode", set80211wepmode), 4394138593Ssam DEF_CMD("wep", 1, set80211wep), 4395138593Ssam DEF_CMD("-wep", 0, set80211wep), 4396139493Ssam DEF_CMD_ARG("deftxkey", set80211weptxkey), 4397138593Ssam DEF_CMD_ARG("weptxkey", set80211weptxkey), 4398138593Ssam DEF_CMD_ARG("wepkey", set80211wepkey), 4399138593Ssam DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 4400138593Ssam DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 4401138593Ssam DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 4402138593Ssam DEF_CMD_ARG("protmode", set80211protmode), 4403138593Ssam DEF_CMD_ARG("txpower", set80211txpower), 4404138593Ssam DEF_CMD_ARG("roaming", set80211roaming), 4405138593Ssam DEF_CMD("wme", 1, set80211wme), 4406138593Ssam DEF_CMD("-wme", 0, set80211wme), 4407178354Ssam DEF_CMD("wmm", 1, set80211wme), 4408178354Ssam DEF_CMD("-wmm", 0, set80211wme), 4409138593Ssam DEF_CMD("hidessid", 1, set80211hidessid), 4410138593Ssam DEF_CMD("-hidessid", 0, set80211hidessid), 4411138593Ssam DEF_CMD("apbridge", 1, set80211apbridge), 4412138593Ssam DEF_CMD("-apbridge", 0, set80211apbridge), 4413138593Ssam DEF_CMD_ARG("chanlist", set80211chanlist), 4414138593Ssam DEF_CMD_ARG("bssid", set80211bssid), 4415138593Ssam DEF_CMD_ARG("ap", set80211bssid), 4416138593Ssam DEF_CMD("scan", 0, set80211scan), 4417138593Ssam DEF_CMD_ARG("list", set80211list), 4418138593Ssam DEF_CMD_ARG2("cwmin", set80211cwmin), 4419138593Ssam DEF_CMD_ARG2("cwmax", set80211cwmax), 4420138593Ssam DEF_CMD_ARG2("aifs", set80211aifs), 4421138593Ssam DEF_CMD_ARG2("txoplimit", set80211txoplimit), 4422148621Ssam DEF_CMD_ARG("acm", set80211acm), 4423148621Ssam DEF_CMD_ARG("-acm", set80211noacm), 4424148621Ssam DEF_CMD_ARG("ack", set80211ackpolicy), 4425148621Ssam DEF_CMD_ARG("-ack", set80211noackpolicy), 4426138593Ssam DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 4427138593Ssam DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 4428138593Ssam DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 4429138593Ssam DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 4430138593Ssam DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 4431138593Ssam DEF_CMD_ARG("bintval", set80211bintval), 4432138593Ssam DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 4433138593Ssam DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 4434138593Ssam DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 4435178354Ssam DEF_CMD("mac:radius", IEEE80211_MACCMD_POLICY_RADIUS, set80211maccmd), 4436138593Ssam DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 4437138593Ssam DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 4438138593Ssam DEF_CMD_ARG("mac:add", set80211addmac), 4439138593Ssam DEF_CMD_ARG("mac:del", set80211delmac), 4440138593Ssam DEF_CMD_ARG("mac:kick", set80211kickmac), 4441147795Ssam DEF_CMD("pureg", 1, set80211pureg), 4442147795Ssam DEF_CMD("-pureg", 0, set80211pureg), 4443170531Ssam DEF_CMD("ff", 1, set80211fastframes), 4444170531Ssam DEF_CMD("-ff", 0, set80211fastframes), 4445170531Ssam DEF_CMD("dturbo", 1, set80211dturbo), 4446170531Ssam DEF_CMD("-dturbo", 0, set80211dturbo), 4447170531Ssam DEF_CMD("bgscan", 1, set80211bgscan), 4448170531Ssam DEF_CMD("-bgscan", 0, set80211bgscan), 4449170531Ssam DEF_CMD_ARG("bgscanidle", set80211bgscanidle), 4450170531Ssam DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl), 4451170531Ssam DEF_CMD_ARG("scanvalid", set80211scanvalid), 4452178354Ssam DEF_CMD_ARG("roam:rssi", set80211roamrssi), 4453178354Ssam DEF_CMD_ARG("roam:rate", set80211roamrate), 4454153354Ssam DEF_CMD_ARG("mcastrate", set80211mcastrate), 4455178354Ssam DEF_CMD_ARG("ucastrate", set80211ucastrate), 4456178354Ssam DEF_CMD_ARG("mgtrate", set80211mgtrate), 4457178354Ssam DEF_CMD_ARG("mgmtrate", set80211mgtrate), 4458178354Ssam DEF_CMD_ARG("maxretry", set80211maxretry), 4459148416Ssam DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 4460153422Ssam DEF_CMD("burst", 1, set80211burst), 4461153422Ssam DEF_CMD("-burst", 0, set80211burst), 4462160687Ssam DEF_CMD_ARG("bmiss", set80211bmissthreshold), 4463160687Ssam DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), 4464173275Ssam DEF_CMD("shortgi", 1, set80211shortgi), 4465173275Ssam DEF_CMD("-shortgi", 0, set80211shortgi), 4466173275Ssam DEF_CMD("ampdurx", 2, set80211ampdu), 4467173275Ssam DEF_CMD("-ampdurx", -2, set80211ampdu), 4468173275Ssam DEF_CMD("ampdutx", 1, set80211ampdu), 4469173275Ssam DEF_CMD("-ampdutx", -1, set80211ampdu), 4470173275Ssam DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */ 4471173275Ssam DEF_CMD("-ampdu", -3, set80211ampdu), 4472173275Ssam DEF_CMD_ARG("ampdulimit", set80211ampdulimit), 4473173275Ssam DEF_CMD_ARG("ampdudensity", set80211ampdudensity), 4474173275Ssam DEF_CMD("amsdurx", 2, set80211amsdu), 4475173275Ssam DEF_CMD("-amsdurx", -2, set80211amsdu), 4476173275Ssam DEF_CMD("amsdutx", 1, set80211amsdu), 4477173275Ssam DEF_CMD("-amsdutx", -1, set80211amsdu), 4478173275Ssam DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */ 4479173275Ssam DEF_CMD("-amsdu", -3, set80211amsdu), 4480173275Ssam DEF_CMD_ARG("amsdulimit", set80211amsdulimit), 4481173275Ssam DEF_CMD("puren", 1, set80211puren), 4482173275Ssam DEF_CMD("-puren", 0, set80211puren), 4483170531Ssam DEF_CMD("doth", 1, set80211doth), 4484170531Ssam DEF_CMD("-doth", 0, set80211doth), 4485178354Ssam DEF_CMD("dfs", 1, set80211dfs), 4486178354Ssam DEF_CMD("-dfs", 0, set80211dfs), 4487173275Ssam DEF_CMD("htcompat", 1, set80211htcompat), 4488173275Ssam DEF_CMD("-htcompat", 0, set80211htcompat), 4489178354Ssam DEF_CMD("dwds", 1, set80211dwds), 4490178354Ssam DEF_CMD("-dwds", 0, set80211dwds), 4491173275Ssam DEF_CMD("inact", 1, set80211inact), 4492173275Ssam DEF_CMD("-inact", 0, set80211inact), 4493178354Ssam DEF_CMD("tsn", 1, set80211tsn), 4494178354Ssam DEF_CMD("-tsn", 0, set80211tsn), 4495178354Ssam DEF_CMD_ARG("regdomain", set80211regdomain), 4496178354Ssam DEF_CMD_ARG("country", set80211country), 4497178354Ssam DEF_CMD("indoor", 'I', set80211location), 4498178354Ssam DEF_CMD("-indoor", 'O', set80211location), 4499178354Ssam DEF_CMD("outdoor", 'O', set80211location), 4500178354Ssam DEF_CMD("-outdoor", 'I', set80211location), 4501178354Ssam DEF_CMD("anywhere", ' ', set80211location), 4502178354Ssam DEF_CMD("ecm", 1, set80211ecm), 4503178354Ssam DEF_CMD("-ecm", 0, set80211ecm), 4504178354Ssam DEF_CMD("dotd", 1, set80211dotd), 4505178354Ssam DEF_CMD("-dotd", 0, set80211dotd), 4506173275Ssam DEF_CMD_ARG("htprotmode", set80211htprotmode), 4507173275Ssam DEF_CMD("ht20", 1, set80211htconf), 4508173275Ssam DEF_CMD("-ht20", 0, set80211htconf), 4509173275Ssam DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */ 4510173275Ssam DEF_CMD("-ht40", 0, set80211htconf), 4511173275Ssam DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */ 4512173275Ssam DEF_CMD("-ht", 0, set80211htconf), 4513178354Ssam /* XXX for testing */ 4514178354Ssam DEF_CMD_ARG("chanswitch", set80211chanswitch), 4515178354Ssam 4516178354Ssam /* vap cloning support */ 4517178354Ssam DEF_CLONE_CMD_ARG("wlanaddr", set80211clone_wlanaddr), 4518178354Ssam DEF_CLONE_CMD_ARG("wlanbssid", set80211clone_wlanbssid), 4519178354Ssam DEF_CLONE_CMD_ARG("wlandev", set80211clone_wlandev), 4520178354Ssam DEF_CLONE_CMD_ARG("wlanmode", set80211clone_wlanmode), 4521178354Ssam DEF_CLONE_CMD("beacons", 1, set80211clone_beacons), 4522178354Ssam DEF_CLONE_CMD("-beacons", 0, set80211clone_beacons), 4523178354Ssam DEF_CLONE_CMD("bssid", 1, set80211clone_bssid), 4524178354Ssam DEF_CLONE_CMD("-bssid", 0, set80211clone_bssid), 4525178354Ssam DEF_CLONE_CMD("wdslegacy", 1, set80211clone_wdslegacy), 4526178354Ssam DEF_CLONE_CMD("-wdslegacy", 0, set80211clone_wdslegacy), 4527138593Ssam}; 4528138593Ssamstatic struct afswtch af_ieee80211 = { 4529138593Ssam .af_name = "af_ieee80211", 4530138593Ssam .af_af = AF_UNSPEC, 4531139494Ssam .af_other_status = ieee80211_status, 4532138593Ssam}; 4533138593Ssam 4534138593Ssamstatic __constructor void 4535138593Ssamieee80211_ctor(void) 4536138593Ssam{ 4537138593Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 4538138593Ssam int i; 4539138593Ssam 4540138593Ssam for (i = 0; i < N(ieee80211_cmds); i++) 4541138593Ssam cmd_register(&ieee80211_cmds[i]); 4542138593Ssam af_register(&af_ieee80211); 4543138593Ssam#undef N 4544138593Ssam} 4545