ifieee80211.c revision 224219
1148330Snetchild/* 2148330Snetchild * Copyright 2001 The Aerospace Corporation. All rights reserved. 3148330Snetchild * 4148330Snetchild * Redistribution and use in source and binary forms, with or without 5148330Snetchild * modification, are permitted provided that the following conditions 6148330Snetchild * are met: 7148330Snetchild * 1. Redistributions of source code must retain the above copyright 8148330Snetchild * notice, this list of conditions and the following disclaimer. 9148330Snetchild * 2. Redistributions in binary form must reproduce the above copyright 10148330Snetchild * notice, this list of conditions and the following disclaimer in the 11148330Snetchild * documentation and/or other materials provided with the distribution. 12148330Snetchild * 3. The name of The Aerospace Corporation may not be used to endorse or 13148330Snetchild * promote products derived from this software. 14148543Snetchild * 15148543Snetchild * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND 16148330Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17173466Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18173466Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE 19173662Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20173662Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21173662Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22173662Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23173662Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24173662Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25172983Smtm * SUCH DAMAGE. 26172983Smtm * 27172390Sbushman * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 224219 2011-07-19 15:22:35Z adrian $ 28173176Sbushman */ 29172390Sbushman 30172390Sbushman/*- 31172570Sru * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 32172570Sru * All rights reserved. 33171786Smarcel * 34171786Smarcel * This code is derived from software contributed to The NetBSD Foundation 35171786Smarcel * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 36171786Smarcel * NASA Ames Research Center. 37171696Sbz * 38171696Sbz * Redistribution and use in source and binary forms, with or without 39171461Srwatson * modification, are permitted provided that the following conditions 40171461Srwatson * are met: 41171461Srwatson * 1. Redistributions of source code must retain the above copyright 42171461Srwatson * notice, this list of conditions and the following disclaimer. 43171461Srwatson * 2. Redistributions in binary form must reproduce the above copyright 44171461Srwatson * notice, this list of conditions and the following disclaimer in the 45171461Srwatson * documentation and/or other materials provided with the distribution. 46171461Srwatson * 47171461Srwatson * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 48171461Srwatson * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 49171461Srwatson * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 50171461Srwatson * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 51171461Srwatson * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 52171461Srwatson * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 53171461Srwatson * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 54171461Srwatson * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 55171461Srwatson * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 56171461Srwatson * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 57171461Srwatson * POSSIBILITY OF SUCH DAMAGE. 58171461Srwatson */ 59171461Srwatson 60171461Srwatson#include <sys/param.h> 61171461Srwatson#include <sys/ioctl.h> 62171461Srwatson#include <sys/socket.h> 63171461Srwatson#include <sys/sysctl.h> 64171461Srwatson#include <sys/time.h> 65171461Srwatson 66171461Srwatson#include <net/ethernet.h> 67171461Srwatson#include <net/if.h> 68171461Srwatson#include <net/if_dl.h> 69171461Srwatson#include <net/if_types.h> 70171461Srwatson#include <net/if_media.h> 71171461Srwatson#include <net/route.h> 72171461Srwatson 73171461Srwatson#include <net80211/ieee80211_ioctl.h> 74171461Srwatson#include <net80211/ieee80211_freebsd.h> 75171461Srwatson#include <net80211/ieee80211_superg.h> 76171461Srwatson#include <net80211/ieee80211_tdma.h> 77171461Srwatson#include <net80211/ieee80211_mesh.h> 78171461Srwatson 79171461Srwatson#include <assert.h> 80171461Srwatson#include <ctype.h> 81171461Srwatson#include <err.h> 82171461Srwatson#include <errno.h> 83171461Srwatson#include <fcntl.h> 84171461Srwatson#include <inttypes.h> 85171461Srwatson#include <stdio.h> 86171461Srwatson#include <stdlib.h> 87171461Srwatson#include <string.h> 88171461Srwatson#include <unistd.h> 89171461Srwatson#include <stdarg.h> 90171461Srwatson#include <stddef.h> /* NB: for offsetof */ 91171461Srwatson 92171461Srwatson#include "ifconfig.h" 93171461Srwatson#include "regdomain.h" 94171461Srwatson 95171461Srwatson#ifndef IEEE80211_FIXED_RATE_NONE 96171461Srwatson#define IEEE80211_FIXED_RATE_NONE 0xff 97171461Srwatson#endif 98171461Srwatson 99171461Srwatson/* XXX need these publicly defined or similar */ 100171461Srwatson#ifndef IEEE80211_NODE_AUTH 101171461Srwatson#define IEEE80211_NODE_AUTH 0x000001 /* authorized for data */ 102171461Srwatson#define IEEE80211_NODE_QOS 0x000002 /* QoS enabled */ 103171461Srwatson#define IEEE80211_NODE_ERP 0x000004 /* ERP enabled */ 104171461Srwatson#define IEEE80211_NODE_PWR_MGT 0x000010 /* power save mode enabled */ 105171461Srwatson#define IEEE80211_NODE_AREF 0x000020 /* authentication ref held */ 106171461Srwatson#define IEEE80211_NODE_HT 0x000040 /* HT enabled */ 107171461Srwatson#define IEEE80211_NODE_HTCOMPAT 0x000080 /* HT setup w/ vendor OUI's */ 108171461Srwatson#define IEEE80211_NODE_WPS 0x000100 /* WPS association */ 109171461Srwatson#define IEEE80211_NODE_TSN 0x000200 /* TSN association */ 110171461Srwatson#define IEEE80211_NODE_AMPDU_RX 0x000400 /* AMPDU rx enabled */ 111171461Srwatson#define IEEE80211_NODE_AMPDU_TX 0x000800 /* AMPDU tx enabled */ 112171274Sbz#define IEEE80211_NODE_MIMO_PS 0x001000 /* MIMO power save enabled */ 113171274Sbz#define IEEE80211_NODE_MIMO_RTS 0x002000 /* send RTS in MIMO PS */ 114171274Sbz#define IEEE80211_NODE_RIFS 0x004000 /* RIFS enabled */ 115171274Sbz#define IEEE80211_NODE_SGI20 0x008000 /* Short GI in HT20 enabled */ 116171274Sbz#define IEEE80211_NODE_SGI40 0x010000 /* Short GI in HT40 enabled */ 117171274Sbz#define IEEE80211_NODE_ASSOCID 0x020000 /* xmit requires associd */ 118171274Sbz#define IEEE80211_NODE_AMSDU_RX 0x040000 /* AMSDU rx enabled */ 119171274Sbz#define IEEE80211_NODE_AMSDU_TX 0x080000 /* AMSDU tx enabled */ 120171274Sbz#endif 121171205Sbz 122171205Sbz#define MAXCHAN 1536 /* max 1.5K channels */ 123171205Sbz 124171205Sbz#define MAXCOL 78 125171205Sbzstatic int col; 126171205Sbzstatic char spacer; 127171175Smlaier 128171175Smlaierstatic void LINE_INIT(char c); 129171137Sbzstatic void LINE_BREAK(void); 130171137Sbzstatic void LINE_CHECK(const char *fmt, ...); 131171137Sbz 132171137Sbzstatic const char *modename[IEEE80211_MODE_MAX] = { 133171137Sbz [IEEE80211_MODE_AUTO] = "auto", 134171137Sbz [IEEE80211_MODE_11A] = "11a", 135171137Sbz [IEEE80211_MODE_11B] = "11b", 136171137Sbz [IEEE80211_MODE_11G] = "11g", 137171137Sbz [IEEE80211_MODE_FH] = "fh", 138171137Sbz [IEEE80211_MODE_TURBO_A] = "turboA", 139171137Sbz [IEEE80211_MODE_TURBO_G] = "turboG", 140171137Sbz [IEEE80211_MODE_STURBO_A] = "sturbo", 141171137Sbz [IEEE80211_MODE_11NA] = "11na", 142171137Sbz [IEEE80211_MODE_11NG] = "11ng", 143171137Sbz [IEEE80211_MODE_HALF] = "half", 144171137Sbz [IEEE80211_MODE_QUARTER] = "quarter" 145171137Sbz}; 146171137Sbz 147171137Sbzstatic void set80211(int s, int type, int val, int len, void *data); 148171131Sthompsastatic int get80211(int s, int type, void *data, int len); 149171131Sthompsastatic int get80211len(int s, int type, void *data, int len, int *plen); 150171143Sthompsastatic int get80211val(int s, int type, int *val); 151171023Srafanstatic const char *get_string(const char *val, const char *sep, 152171023Srafan u_int8_t *buf, int *lenp); 153171023Srafanstatic void print_string(const u_int8_t *buf, int len); 154171023Srafanstatic void print_regdomain(const struct ieee80211_regdomain *, int); 155171023Srafanstatic void print_channels(int, const struct ieee80211req_chaninfo *, 156171023Srafan int allchans, int verbose); 157171388Sdougbstatic void regdomain_makechannels(struct ieee80211_regdomain_req *, 158171388Sdougb const struct ieee80211_devcaps_req *); 159171388Sdougbstatic const char *mesh_linkstate_string(uint8_t state); 160171388Sdougb 161170926Srafanstatic struct ieee80211req_chaninfo *chaninfo; 162170926Srafanstatic struct ieee80211_regdomain regdomain; 163170926Srafanstatic int gotregdomain = 0; 164170926Srafanstatic struct ieee80211_roamparams_req roamparams; 165170926Srafanstatic int gotroam = 0; 166170926Srafanstatic struct ieee80211_txparams_req txparams; 167170926Srafanstatic int gottxparams = 0; 168170926Srafanstatic struct ieee80211_channel curchan; 169170926Srafanstatic int gotcurchan = 0; 170170926Srafanstatic struct ifmediareq *ifmr; 171170926Srafanstatic int htconf = 0; 172170926Srafanstatic int gothtconf = 0; 173170926Srafan 174170926Srafanstatic void 175170926Srafangethtconf(int s) 176170926Srafan{ 177170926Srafan if (gothtconf) 178170926Srafan return; 179170926Srafan if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0) 180170926Srafan warn("unable to get HT configuration information"); 181170926Srafan gothtconf = 1; 182170926Srafan} 183170926Srafan 184170926Srafan/* 185170926Srafan * Collect channel info from the kernel. We use this (mostly) 186170926Srafan * to handle mapping between frequency and IEEE channel number. 187170926Srafan */ 188170926Srafanstatic void 189170926Srafangetchaninfo(int s) 190170926Srafan{ 191170926Srafan if (chaninfo != NULL) 192170926Srafan return; 193170926Srafan chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN)); 194170926Srafan if (chaninfo == NULL) 195170926Srafan errx(1, "no space for channel list"); 196170926Srafan if (get80211(s, IEEE80211_IOC_CHANINFO, chaninfo, 197170926Srafan IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0) 198170926Srafan err(1, "unable to get channel information"); 199170926Srafan ifmr = ifmedia_getstate(s); 200170926Srafan gethtconf(s); 201170926Srafan} 202171476Sdelphij 203171476Sdelphijstatic struct regdata * 204170312Sdelphijgetregdata(void) 205170312Sdelphij{ 206170926Srafan static struct regdata *rdp = NULL; 207170926Srafan if (rdp == NULL) { 208169815Sdelphij rdp = lib80211_alloc_regdata(); 209169815Sdelphij if (rdp == NULL) 210169815Sdelphij errx(-1, "missing or corrupted regdomain database"); 211169815Sdelphij } 212169815Sdelphij return rdp; 213169815Sdelphij} 214169815Sdelphij 215169815Sdelphij/* 216169815Sdelphij * Given the channel at index i with attributes from, 217169815Sdelphij * check if there is a channel with attributes to in 218169815Sdelphij * the channel table. With suitable attributes this 219169815Sdelphij * allows the caller to look for promotion; e.g. from 220170204Sru * 11b > 11g. 221169815Sdelphij */ 222169815Sdelphijstatic int 223169815Sdelphijcanpromote(int i, int from, int to) 224169815Sdelphij{ 225170204Sru const struct ieee80211_channel *fc = &chaninfo->ic_chans[i]; 226169815Sdelphij int j; 227169815Sdelphij 228169815Sdelphij if ((fc->ic_flags & from) != from) 229169815Sdelphij return i; 230169815Sdelphij /* NB: quick check exploiting ordering of chans w/ same frequency */ 231169815Sdelphij if (i+1 < chaninfo->ic_nchans && 232169815Sdelphij chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq && 233169815Sdelphij (chaninfo->ic_chans[i+1].ic_flags & to) == to) 234169815Sdelphij return i+1; 235169815Sdelphij /* brute force search in case channel list is not ordered */ 236169815Sdelphij for (j = 0; j < chaninfo->ic_nchans; j++) { 237169815Sdelphij const struct ieee80211_channel *tc = &chaninfo->ic_chans[j]; 238169815Sdelphij if (j != i && 239169815Sdelphij tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to) 240169815Sdelphij return j; 241169815Sdelphij } 242169815Sdelphij return i; 243169815Sdelphij} 244169815Sdelphij 245169815Sdelphij/* 246169815Sdelphij * Handle channel promotion. When a channel is specified with 247169815Sdelphij * only a frequency we want to promote it to the ``best'' channel 248169815Sdelphij * available. The channel list has separate entries for 11b, 11g, 249169815Sdelphij * 11a, and 11n[ga] channels so specifying a frequency w/o any 250169815Sdelphij * attributes requires we upgrade, e.g. from 11b -> 11g. This 251169815Sdelphij * gets complicated when the channel is specified on the same 252169815Sdelphij * command line with a media request that constrains the available 253169815Sdelphij * channe list (e.g. mode 11a); we want to honor that to avoid 254169815Sdelphij * confusing behaviour. 255169815Sdelphij */ 256169815Sdelphijstatic int 257169815Sdelphijpromote(int i) 258169815Sdelphij{ 259169815Sdelphij /* 260169815Sdelphij * Query the current mode of the interface in case it's 261169815Sdelphij * constrained (e.g. to 11a). We must do this carefully 262170204Sru * as there may be a pending ifmedia request in which case 263169815Sdelphij * asking the kernel will give us the wrong answer. This 264169815Sdelphij * is an unfortunate side-effect of the way ifconfig is 265169815Sdelphij * structure for modularity (yech). 266170917Srafan * 267169815Sdelphij * NB: ifmr is actually setup in getchaninfo (above); we 268169815Sdelphij * assume it's called coincident with to this call so 269169815Sdelphij * we have a ``current setting''; otherwise we must pass 270169815Sdelphij * the socket descriptor down to here so we can make 271169815Sdelphij * the ifmedia_getstate call ourselves. 272169815Sdelphij */ 273169815Sdelphij int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO; 274169815Sdelphij 275169815Sdelphij /* when ambiguous promote to ``best'' */ 276169815Sdelphij /* NB: we abitrarily pick HT40+ over HT40- */ 277169815Sdelphij if (chanmode != IFM_IEEE80211_11B) 278169815Sdelphij i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G); 279169815Sdelphij if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) { 280169815Sdelphij i = canpromote(i, IEEE80211_CHAN_G, 281169815Sdelphij IEEE80211_CHAN_G | IEEE80211_CHAN_HT20); 282169815Sdelphij if (htconf & 2) { 283169815Sdelphij i = canpromote(i, IEEE80211_CHAN_G, 284169815Sdelphij IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D); 285169815Sdelphij i = canpromote(i, IEEE80211_CHAN_G, 286169815Sdelphij IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U); 287169815Sdelphij } 288169815Sdelphij } 289169815Sdelphij if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) { 290169815Sdelphij i = canpromote(i, IEEE80211_CHAN_A, 291169815Sdelphij IEEE80211_CHAN_A | IEEE80211_CHAN_HT20); 292169815Sdelphij if (htconf & 2) { 293169815Sdelphij i = canpromote(i, IEEE80211_CHAN_A, 294169815Sdelphij IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D); 295169815Sdelphij i = canpromote(i, IEEE80211_CHAN_A, 296169815Sdelphij IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U); 297169815Sdelphij } 298169815Sdelphij } 299169815Sdelphij return i; 300169815Sdelphij} 301169815Sdelphij 302169815Sdelphijstatic void 303169815Sdelphijmapfreq(struct ieee80211_channel *chan, int freq, int flags) 304169815Sdelphij{ 305169815Sdelphij int i; 306169815Sdelphij 307169815Sdelphij for (i = 0; i < chaninfo->ic_nchans; i++) { 308169815Sdelphij const struct ieee80211_channel *c = &chaninfo->ic_chans[i]; 309169815Sdelphij 310169815Sdelphij if (c->ic_freq == freq && (c->ic_flags & flags) == flags) { 311169815Sdelphij if (flags == 0) { 312169815Sdelphij /* when ambiguous promote to ``best'' */ 313169815Sdelphij c = &chaninfo->ic_chans[promote(i)]; 314169815Sdelphij } 315169815Sdelphij *chan = *c; 316170204Sru return; 317169815Sdelphij } 318169815Sdelphij } 319169815Sdelphij errx(1, "unknown/undefined frequency %u/0x%x", freq, flags); 320169815Sdelphij} 321169815Sdelphij 322170190Srustatic void 323169815Sdelphijmapchan(struct ieee80211_channel *chan, int ieee, int flags) 324169815Sdelphij{ 325169815Sdelphij int i; 326169815Sdelphij 327169815Sdelphij for (i = 0; i < chaninfo->ic_nchans; i++) { 328169815Sdelphij const struct ieee80211_channel *c = &chaninfo->ic_chans[i]; 329169815Sdelphij 330169815Sdelphij if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) { 331169815Sdelphij if (flags == 0) { 332169815Sdelphij /* when ambiguous promote to ``best'' */ 333169815Sdelphij c = &chaninfo->ic_chans[promote(i)]; 334169815Sdelphij } 335170190Sru *chan = *c; 336170190Sru return; 337170190Sru } 338170190Sru } 339170190Sru errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags); 340170190Sru} 341170190Sru 342171476Sdelphijstatic const struct ieee80211_channel * 343171476Sdelphijgetcurchan(int s) 344171476Sdelphij{ 345171476Sdelphij if (gotcurchan) 346171476Sdelphij return &curchan; 347171476Sdelphij if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) { 348171476Sdelphij int val; 349171476Sdelphij /* fall back to legacy ioctl */ 350171476Sdelphij if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0) 351171476Sdelphij err(-1, "cannot figure out current channel"); 352171476Sdelphij getchaninfo(s); 353171476Sdelphij mapchan(&curchan, val, 0); 354171476Sdelphij } 355171476Sdelphij gotcurchan = 1; 356171476Sdelphij return &curchan; 357171476Sdelphij} 358171476Sdelphij 359171476Sdelphijstatic enum ieee80211_phymode 360171476Sdelphijchan2mode(const struct ieee80211_channel *c) 361171476Sdelphij{ 362171476Sdelphij if (IEEE80211_IS_CHAN_HTA(c)) 363171476Sdelphij return IEEE80211_MODE_11NA; 364171476Sdelphij if (IEEE80211_IS_CHAN_HTG(c)) 365171476Sdelphij return IEEE80211_MODE_11NG; 366171476Sdelphij if (IEEE80211_IS_CHAN_108A(c)) 367171476Sdelphij return IEEE80211_MODE_TURBO_A; 368171476Sdelphij if (IEEE80211_IS_CHAN_108G(c)) 369171476Sdelphij return IEEE80211_MODE_TURBO_G; 370171476Sdelphij if (IEEE80211_IS_CHAN_ST(c)) 371171476Sdelphij return IEEE80211_MODE_STURBO_A; 372171476Sdelphij if (IEEE80211_IS_CHAN_FHSS(c)) 373171476Sdelphij return IEEE80211_MODE_FH; 374171476Sdelphij if (IEEE80211_IS_CHAN_HALF(c)) 375171476Sdelphij return IEEE80211_MODE_HALF; 376171476Sdelphij if (IEEE80211_IS_CHAN_QUARTER(c)) 377171476Sdelphij return IEEE80211_MODE_QUARTER; 378171476Sdelphij if (IEEE80211_IS_CHAN_A(c)) 379171476Sdelphij return IEEE80211_MODE_11A; 380171476Sdelphij if (IEEE80211_IS_CHAN_ANYG(c)) 381171476Sdelphij return IEEE80211_MODE_11G; 382171476Sdelphij if (IEEE80211_IS_CHAN_B(c)) 383171476Sdelphij return IEEE80211_MODE_11B; 384171476Sdelphij return IEEE80211_MODE_AUTO; 385171476Sdelphij} 386171476Sdelphij 387171476Sdelphijstatic void 388171476Sdelphijgetroam(int s) 389171476Sdelphij{ 390171476Sdelphij if (gotroam) 391171476Sdelphij return; 392171476Sdelphij if (get80211(s, IEEE80211_IOC_ROAM, 393171476Sdelphij &roamparams, sizeof(roamparams)) < 0) 394171476Sdelphij err(1, "unable to get roaming parameters"); 395171476Sdelphij gotroam = 1; 396171476Sdelphij} 397171476Sdelphij 398171476Sdelphijstatic void 399171476Sdelphijsetroam_cb(int s, void *arg) 400171476Sdelphij{ 401171476Sdelphij struct ieee80211_roamparams_req *roam = arg; 402171476Sdelphij set80211(s, IEEE80211_IOC_ROAM, 0, sizeof(*roam), roam); 403171476Sdelphij} 404171476Sdelphij 405171476Sdelphijstatic void 406171476Sdelphijgettxparams(int s) 407171476Sdelphij{ 408171476Sdelphij if (gottxparams) 409171476Sdelphij return; 410171476Sdelphij if (get80211(s, IEEE80211_IOC_TXPARAMS, 411171476Sdelphij &txparams, sizeof(txparams)) < 0) 412171476Sdelphij err(1, "unable to get transmit parameters"); 413171476Sdelphij gottxparams = 1; 414171476Sdelphij} 415171476Sdelphij 416171476Sdelphijstatic void 417171476Sdelphijsettxparams_cb(int s, void *arg) 418171476Sdelphij{ 419171476Sdelphij struct ieee80211_txparams_req *txp = arg; 420171476Sdelphij set80211(s, IEEE80211_IOC_TXPARAMS, 0, sizeof(*txp), txp); 421171476Sdelphij} 422171476Sdelphij 423171476Sdelphijstatic void 424171476Sdelphijgetregdomain(int s) 425171476Sdelphij{ 426171476Sdelphij if (gotregdomain) 427171476Sdelphij return; 428171476Sdelphij if (get80211(s, IEEE80211_IOC_REGDOMAIN, 429171476Sdelphij ®domain, sizeof(regdomain)) < 0) 430171476Sdelphij err(1, "unable to get regulatory domain info"); 431171476Sdelphij gotregdomain = 1; 432171476Sdelphij} 433171476Sdelphij 434171476Sdelphijstatic void 435171476Sdelphijgetdevcaps(int s, struct ieee80211_devcaps_req *dc) 436171476Sdelphij{ 437171476Sdelphij if (get80211(s, IEEE80211_IOC_DEVCAPS, dc, 438171476Sdelphij IEEE80211_DEVCAPS_SPACE(dc)) < 0) 439171476Sdelphij err(1, "unable to get device capabilities"); 440171476Sdelphij} 441171476Sdelphij 442171476Sdelphijstatic void 443171476Sdelphijsetregdomain_cb(int s, void *arg) 444171476Sdelphij{ 445171476Sdelphij struct ieee80211_regdomain_req *req; 446171476Sdelphij struct ieee80211_regdomain *rd = arg; 447171476Sdelphij struct ieee80211_devcaps_req *dc; 448171476Sdelphij struct regdata *rdp = getregdata(); 449171476Sdelphij 450171476Sdelphij if (rd->country != NO_COUNTRY) { 451171476Sdelphij const struct country *cc; 452171476Sdelphij /* 453171476Sdelphij * Check current country seting to make sure it's 454171476Sdelphij * compatible with the new regdomain. If not, then 455171476Sdelphij * override it with any default country for this 456171476Sdelphij * SKU. If we cannot arrange a match, then abort. 457171476Sdelphij */ 458171476Sdelphij cc = lib80211_country_findbycc(rdp, rd->country); 459171476Sdelphij if (cc == NULL) 460171476Sdelphij errx(1, "unknown ISO country code %d", rd->country); 461171476Sdelphij if (cc->rd->sku != rd->regdomain) { 462171476Sdelphij const struct regdomain *rp; 463171476Sdelphij /* 464171476Sdelphij * Check if country is incompatible with regdomain. 465171476Sdelphij * To enable multiple regdomains for a country code 466171476Sdelphij * we permit a mismatch between the regdomain and 467171476Sdelphij * the country's associated regdomain when the 468171476Sdelphij * regdomain is setup w/o a default country. For 469171476Sdelphij * example, US is bound to the FCC regdomain but 470171476Sdelphij * we allow US to be combined with FCC3 because FCC3 471171476Sdelphij * has not default country. This allows bogus 472171476Sdelphij * combinations like FCC3+DK which are resolved when 473171476Sdelphij * constructing the channel list by deferring to the 474171476Sdelphij * regdomain to construct the channel list. 475171476Sdelphij */ 476171476Sdelphij rp = lib80211_regdomain_findbysku(rdp, rd->regdomain); 477171476Sdelphij if (rp == NULL) 478171476Sdelphij errx(1, "country %s (%s) is not usable with " 479171476Sdelphij "regdomain %d", cc->isoname, cc->name, 480171476Sdelphij rd->regdomain); 481171476Sdelphij else if (rp->cc != NULL && rp->cc != cc) 482171476Sdelphij errx(1, "country %s (%s) is not usable with " 483171476Sdelphij "regdomain %s", cc->isoname, cc->name, 484171476Sdelphij rp->name); 485171476Sdelphij } 486171476Sdelphij } 487171476Sdelphij /* 488171476Sdelphij * Fetch the device capabilities and calculate the 489171476Sdelphij * full set of netbands for which we request a new 490171476Sdelphij * channel list be constructed. Once that's done we 491171476Sdelphij * push the regdomain info + channel list to the kernel. 492171476Sdelphij */ 493171476Sdelphij dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN)); 494171476Sdelphij if (dc == NULL) 495171476Sdelphij errx(1, "no space for device capabilities"); 496171476Sdelphij dc->dc_chaninfo.ic_nchans = MAXCHAN; 497171476Sdelphij getdevcaps(s, dc); 498171476Sdelphij#if 0 499171476Sdelphij if (verbose) { 500171476Sdelphij printf("drivercaps: 0x%x\n", dc->dc_drivercaps); 501171476Sdelphij printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps); 502171476Sdelphij printf("htcaps : 0x%x\n", dc->dc_htcaps); 503171476Sdelphij memcpy(chaninfo, &dc->dc_chaninfo, 504171476Sdelphij IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo)); 505171476Sdelphij print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/); 506171476Sdelphij } 507171476Sdelphij#endif 508171476Sdelphij req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans)); 509171476Sdelphij if (req == NULL) 510171476Sdelphij errx(1, "no space for regdomain request"); 511171476Sdelphij req->rd = *rd; 512171476Sdelphij regdomain_makechannels(req, dc); 513171476Sdelphij if (verbose) { 514171476Sdelphij LINE_INIT(':'); 515171476Sdelphij print_regdomain(rd, 1/*verbose*/); 516171476Sdelphij LINE_BREAK(); 517171476Sdelphij /* blech, reallocate channel list for new data */ 518171476Sdelphij if (chaninfo != NULL) 519171476Sdelphij free(chaninfo); 520171476Sdelphij chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo)); 521171476Sdelphij if (chaninfo == NULL) 522171476Sdelphij errx(1, "no space for channel list"); 523171476Sdelphij memcpy(chaninfo, &req->chaninfo, 524171476Sdelphij IEEE80211_CHANINFO_SPACE(&req->chaninfo)); 525171476Sdelphij print_channels(s, &req->chaninfo, 1/*allchans*/, 1/*verbose*/); 526171476Sdelphij } 527171476Sdelphij if (req->chaninfo.ic_nchans == 0) 528171476Sdelphij errx(1, "no channels calculated"); 529171476Sdelphij set80211(s, IEEE80211_IOC_REGDOMAIN, 0, 530171476Sdelphij IEEE80211_REGDOMAIN_SPACE(req), req); 531171476Sdelphij free(req); 532171476Sdelphij free(dc); 533171476Sdelphij} 534171476Sdelphij 535171476Sdelphijstatic int 536171476Sdelphijieee80211_mhz2ieee(int freq, int flags) 537171476Sdelphij{ 538171476Sdelphij struct ieee80211_channel chan; 539171476Sdelphij mapfreq(&chan, freq, flags); 540171476Sdelphij return chan.ic_ieee; 541171476Sdelphij} 542171476Sdelphij 543171476Sdelphijstatic int 544171476Sdelphijisanyarg(const char *arg) 545171476Sdelphij{ 546171476Sdelphij return (strncmp(arg, "-", 1) == 0 || 547171476Sdelphij strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0); 548171476Sdelphij} 549171476Sdelphij 550171476Sdelphijstatic void 551171476Sdelphijset80211ssid(const char *val, int d, int s, const struct afswtch *rafp) 552171476Sdelphij{ 553171476Sdelphij int ssid; 554171476Sdelphij int len; 555171476Sdelphij u_int8_t data[IEEE80211_NWID_LEN]; 556171476Sdelphij 557171476Sdelphij ssid = 0; 558171476Sdelphij len = strlen(val); 559171476Sdelphij if (len > 2 && isdigit((int)val[0]) && val[1] == ':') { 560171476Sdelphij ssid = atoi(val)-1; 561171476Sdelphij val += 2; 562171476Sdelphij } 563171476Sdelphij 564171476Sdelphij bzero(data, sizeof(data)); 565171476Sdelphij len = sizeof(data); 566169445Sroberto if (get_string(val, NULL, data, &len) == NULL) 567169445Sroberto exit(1); 568169445Sroberto 569169026Semax set80211(s, IEEE80211_IOC_SSID, ssid, len, data); 570169026Semax} 571168916Sbrueffer 572168916Sbruefferstatic void 573168796Sthompsaset80211meshid(const char *val, int d, int s, const struct afswtch *rafp) 574168796Sthompsa{ 575168544Spjd int len; 576168544Spjd u_int8_t data[IEEE80211_NWID_LEN]; 577167980Sdelphij 578167980Sdelphij memset(data, 0, sizeof(data)); 579167699Sdelphij len = sizeof(data); 580167699Sdelphij if (get_string(val, NULL, data, &len) == NULL) 581167137Sbms exit(1); 582167137Sbms 583170190Sru set80211(s, IEEE80211_IOC_MESH_ID, 0, len, data); 584166981Sru} 585166981Sru 586170192Srustatic void 587170218Struckmanset80211stationname(const char *val, int d, int s, const struct afswtch *rafp) 588166668Sbrueffer{ 589166668Sbrueffer int len; 590166389Srafan u_int8_t data[33]; 591166389Srafan 592166389Srafan bzero(data, sizeof(data)); 593172882Sru len = sizeof(data); 594172882Sru get_string(val, NULL, data, &len); 595172882Sru 596172882Sru set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data); 597170190Sru} 598170190Sru 599170190Sru/* 600170190Sru * Parse a channel specification for attributes/flags. 601172882Sru * The syntax is: 602172882Sru * freq/xx channel width (5,10,20,40,40+,40-) 603172882Sru * freq:mode channel mode (a,b,g,h,n,t,s,d) 604170190Sru * 605166308Sphk * These can be combined in either order; e.g. 2437:ng/40. 606166308Sphk * Modes are case insensitive. 607170192Sru * 608170192Sru * The result is not validated here; it's assumed to be 609166246Speter * checked against the channel table fetched from the kernel. 610166246Speter */ 611166246Speterstatic int 612166246Spetergetchannelflags(const char *val, int freq) 613166246Speter{ 614164796Spiso#define _CHAN_HT 0x80000000 615164796Spiso const char *cp; 616164796Spiso int flags; 617164796Spiso 618164796Spiso flags = 0; 619164796Spiso 620164796Spiso cp = strchr(val, ':'); 621164796Spiso if (cp != NULL) { 622164796Spiso for (cp++; isalpha((int) *cp); cp++) { 623166672Sbrueffer /* accept mixed case */ 624164796Spiso int c = *cp; 625164796Spiso if (isupper(c)) 626164796Spiso c = tolower(c); 627164796Spiso switch (c) { 628164796Spiso case 'a': /* 802.11a */ 629164796Spiso flags |= IEEE80211_CHAN_A; 630164796Spiso break; 631164796Spiso case 'b': /* 802.11b */ 632165726Skientzle flags |= IEEE80211_CHAN_B; 633165726Skientzle break; 634164610Simp case 'g': /* 802.11g */ 635164610Simp flags |= IEEE80211_CHAN_G; 636164537Srodrigc break; 637164537Srodrigc case 'h': /* ht = 802.11n */ 638164537Srodrigc case 'n': /* 802.11n */ 639164537Srodrigc flags |= _CHAN_HT; /* NB: private */ 640164537Srodrigc break; 641164537Srodrigc case 'd': /* dt = Atheros Dynamic Turbo */ 642164537Srodrigc flags |= IEEE80211_CHAN_TURBO; 643170190Sru break; 644170190Sru case 't': /* ht, dt, st, t */ 645170190Sru /* dt and unadorned t specify Dynamic Turbo */ 646170190Sru if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0) 647170190Sru flags |= IEEE80211_CHAN_TURBO; 648170190Sru break; 649164537Srodrigc case 's': /* st = Atheros Static Turbo */ 650164537Srodrigc flags |= IEEE80211_CHAN_STURBO; 651164537Srodrigc break; 652164537Srodrigc default: 653164537Srodrigc errx(-1, "%s: Invalid channel attribute %c\n", 654164537Srodrigc val, *cp); 655164344Sbrueffer } 656164344Sbrueffer } 657170220Struckman } 658170220Struckman cp = strchr(val, '/'); 659164088Smarcel if (cp != NULL) { 660164088Smarcel char *ep; 661164088Smarcel u_long cw = strtoul(cp+1, &ep, 10); 662164088Smarcel 663163570Sru switch (cw) { 664163570Sru case 5: 665162837Sdelphij flags |= IEEE80211_CHAN_QUARTER; 666162837Sdelphij break; 667162780Sbms case 10: 668162780Sbms flags |= IEEE80211_CHAN_HALF; 669162780Sbms break; 670162780Sbms case 20: 671162780Sbms /* NB: this may be removed below */ 672162780Sbms flags |= IEEE80211_CHAN_HT20; 673162780Sbms break; 674162780Sbms case 40: 675162780Sbms if (ep != NULL && *ep == '+') 676162598Ssimon flags |= IEEE80211_CHAN_HT40U; 677162598Ssimon else if (ep != NULL && *ep == '-') 678162598Ssimon flags |= IEEE80211_CHAN_HT40D; 679162716Sdelphij break; 680162716Sdelphij default: 681161529Sflz errx(-1, "%s: Invalid channel width\n", val); 682161529Sflz } 683161529Sflz } 684170192Sru /* 685170192Sru * Cleanup specifications. 686170192Sru */ 687170192Sru if ((flags & _CHAN_HT) == 0) { 688170192Sru /* 689170192Sru * If user specified freq/20 or freq/40 quietly remove 690170192Sru * HT cw attributes depending on channel use. To give 691170192Sru * an explicit 20/40 width for an HT channel you must 692170192Sru * indicate it is an HT channel since all HT channels 693170192Sru * are also usable for legacy operation; e.g. freq:n/40. 694170192Sru */ 695170192Sru flags &= ~IEEE80211_CHAN_HT; 696170192Sru } else { 697160983Sbrooks /* 698160983Sbrooks * Remove private indicator that this is an HT channel 699170255Struckman * and if no explicit channel width has been given 700170255Struckman * provide the default settings. 701170255Struckman */ 702170255Struckman flags &= ~_CHAN_HT; 703158687Sphk if ((flags & IEEE80211_CHAN_HT) == 0) { 704158687Sphk struct ieee80211_channel chan; 705158687Sphk /* 706158687Sphk * Consult the channel list to see if we can use 707158687Sphk * HT40+ or HT40- (if both the map routines choose). 708158687Sphk */ 709158687Sphk if (freq > 255) 710158687Sphk mapfreq(&chan, freq, 0); 711158687Sphk else 712158687Sphk mapchan(&chan, freq, 0); 713158687Sphk flags |= (chan.ic_flags & IEEE80211_CHAN_HT); 714158687Sphk } 715158687Sphk } 716158687Sphk return flags; 717158687Sphk#undef _CHAN_HT 718158687Sphk} 719158687Sphk 720158687Sphkstatic void 721158687Sphkgetchannel(int s, struct ieee80211_channel *chan, const char *val) 722158687Sphk{ 723158687Sphk int v, flags; 724158687Sphk char *eptr; 725158687Sphk 726158687Sphk memset(chan, 0, sizeof(*chan)); 727158687Sphk if (isanyarg(val)) { 728158687Sphk chan->ic_freq = IEEE80211_CHAN_ANY; 729158687Sphk return; 730158687Sphk } 731158687Sphk getchaninfo(s); 732158687Sphk errno = 0; 733158687Sphk v = strtol(val, &eptr, 10); 734158687Sphk if (val[0] == '\0' || val == eptr || errno == ERANGE || 735158687Sphk /* channel may be suffixed with nothing, :flag, or /width */ 736158687Sphk (eptr[0] != '\0' && eptr[0] != ':' && eptr[0] != '/')) 737158687Sphk errx(1, "invalid channel specification%s", 738158687Sphk errno == ERANGE ? " (out of range)" : ""); 739158687Sphk flags = getchannelflags(val, v); 740158687Sphk if (v > 255) { /* treat as frequency */ 741158687Sphk mapfreq(chan, v, flags); 742158687Sphk } else { 743158687Sphk mapchan(chan, v, flags); 744158687Sphk } 745158687Sphk} 746158687Sphk 747158687Sphkstatic void 748158687Sphkset80211channel(const char *val, int d, int s, const struct afswtch *rafp) 749158687Sphk{ 750158687Sphk struct ieee80211_channel chan; 751158687Sphk 752158687Sphk getchannel(s, &chan, val); 753158687Sphk set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan); 754158687Sphk} 755158687Sphk 756158618Smaximstatic void 757158618Smaximset80211chanswitch(const char *val, int d, int s, const struct afswtch *rafp) 758158618Smaxim{ 759158512Smlaier struct ieee80211_chanswitch_req csr; 760158512Smlaier 761158512Smlaier getchannel(s, &csr.csa_chan, val); 762158512Smlaier csr.csa_mode = 1; 763158512Smlaier csr.csa_count = 5; 764158754Smarcel set80211(s, IEEE80211_IOC_CHANSWITCH, 0, sizeof(csr), &csr); 765158754Smarcel} 766157221Ssimon 767157221Ssimonstatic void 768156676Shartiset80211authmode(const char *val, int d, int s, const struct afswtch *rafp) 769156676Sharti{ 770170190Sru int mode; 771170190Sru 772170190Sru if (strcasecmp(val, "none") == 0) { 773170190Sru mode = IEEE80211_AUTH_NONE; 774170190Sru } else if (strcasecmp(val, "open") == 0) { 775170190Sru mode = IEEE80211_AUTH_OPEN; 776170190Sru } else if (strcasecmp(val, "shared") == 0) { 777170190Sru mode = IEEE80211_AUTH_SHARED; 778153662Sjhb } else if (strcasecmp(val, "8021x") == 0) { 779153662Sjhb mode = IEEE80211_AUTH_8021X; 780153430Siedowse } else if (strcasecmp(val, "wpa") == 0) { 781153430Siedowse mode = IEEE80211_AUTH_WPA; 782153430Siedowse } else { 783153430Siedowse errx(1, "unknown authmode"); 784153430Siedowse } 785151845Syar 786151845Syar set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL); 787151271Spjd} 788151271Spjd 789162025Smatusitastatic void 790162025Smatusitaset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp) 791162025Smatusita{ 792162025Smatusita int mode; 793150676Smlaier 794150677Smlaier if (strcasecmp(val, "off") == 0) { 795150002Snetchild mode = IEEE80211_POWERSAVE_OFF; 796150002Snetchild } else if (strcasecmp(val, "on") == 0) { 797150002Snetchild mode = IEEE80211_POWERSAVE_ON; 798150002Snetchild } else if (strcasecmp(val, "cam") == 0) { 799149454Sglebius mode = IEEE80211_POWERSAVE_CAM; 800148808Sru } else if (strcasecmp(val, "psp") == 0) { 801148808Sru mode = IEEE80211_POWERSAVE_PSP; 802148825Snetchild } else if (strcasecmp(val, "psp-cam") == 0) { 803148825Snetchild mode = IEEE80211_POWERSAVE_PSP_CAM; 804148356Sdougb } else { 805148356Sdougb errx(1, "unknown powersavemode"); 806148572Snetchild } 807170220Struckman 808170220Struckman set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL); 809170220Struckman} 810170220Struckman 811170220Struckmanstatic void 812148330Snetchildset80211powersave(const char *val, int d, int s, const struct afswtch *rafp) 813148330Snetchild{ 814148330Snetchild if (d == 0) 815148330Snetchild set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF, 816148572Snetchild 0, NULL); 817148572Snetchild else 818149105Simp set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON, 819148572Snetchild 0, NULL); 820148572Snetchild} 821148572Snetchild 822172026Syarstatic void 823172026Syarset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp) 824172026Syar{ 825172026Syar set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL); 826148572Snetchild} 827148572Snetchild 828148572Snetchildstatic void 829148572Snetchildset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp) 830148572Snetchild{ 831148572Snetchild int mode; 832148572Snetchild 833148572Snetchild if (strcasecmp(val, "off") == 0) { 834148572Snetchild mode = IEEE80211_WEP_OFF; 835148572Snetchild } else if (strcasecmp(val, "on") == 0) { 836148572Snetchild mode = IEEE80211_WEP_ON; 837153939Snetchild } else if (strcasecmp(val, "mixed") == 0) { 838153939Snetchild mode = IEEE80211_WEP_MIXED; 839153939Snetchild } else { 840153939Snetchild errx(1, "unknown wep mode"); 841148330Snetchild } 842148330Snetchild 843148423Sdougb set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL); 844148423Sdougb} 845148330Snetchild 846148330Snetchildstatic void 847148330Snetchildset80211wep(const char *val, int d, int s, const struct afswtch *rafp) 848148330Snetchild{ 849148572Snetchild set80211(s, IEEE80211_IOC_WEP, d, 0, NULL); 850148572Snetchild} 851148353Sdougb 852148353Sdougbstatic int 853149105Simpisundefarg(const char *arg) 854149105Simp{ 855148572Snetchild return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0); 856148572Snetchild} 857172026Syar 858149105Simpstatic void 859148572Snetchildset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp) 860155813Snetchild{ 861155813Snetchild if (isundefarg(val)) 862155813Snetchild set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL); 863155813Snetchild else 864148330Snetchild set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL); 865148330Snetchild} 866148330Snetchild 867163991Strhodesstatic void 868163991Strhodesset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp) 869163991Strhodes{ 870163991Strhodes int key = 0; 871163991Strhodes int len; 872163991Strhodes u_int8_t data[IEEE80211_KEYBUF_SIZE]; 873163991Strhodes 874163991Strhodes if (isdigit((int)val[0]) && val[1] == ':') { 875163991Strhodes key = atoi(val)-1; 876163991Strhodes val += 2; 877163991Strhodes } 878148330Snetchild 879148330Snetchild bzero(data, sizeof(data)); 880148330Snetchild len = sizeof(data); 881148330Snetchild get_string(val, NULL, data, &len); 882155813Snetchild 883148330Snetchild set80211(s, IEEE80211_IOC_WEPKEY, key, len, data); 884148330Snetchild} 885148330Snetchild 886148330Snetchild/* 887148330Snetchild * This function is purely a NetBSD compatability interface. The NetBSD 888148330Snetchild * interface is too inflexible, but it's there so we'll support it since 889148543Snetchild * it's not all that hard. 890148543Snetchild */ 891148543Snetchildstatic void 892148543Snetchildset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp) 893148543Snetchild{ 894148543Snetchild int txkey; 895148543Snetchild int i, len; 896148543Snetchild u_int8_t data[IEEE80211_KEYBUF_SIZE]; 897148543Snetchild 898148543Snetchild set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL); 899148543Snetchild 900148543Snetchild if (isdigit((int)val[0]) && val[1] == ':') { 901148543Snetchild txkey = val[0]-'0'-1; 902148543Snetchild val += 2; 903148543Snetchild 904148543Snetchild for (i = 0; i < 4; i++) { 905148543Snetchild bzero(data, sizeof(data)); 906148543Snetchild len = sizeof(data); 907148543Snetchild val = get_string(val, ",", data, &len); 908148543Snetchild if (val == NULL) 909148543Snetchild exit(1); 910148572Snetchild 911148572Snetchild set80211(s, IEEE80211_IOC_WEPKEY, i, len, data); 912148572Snetchild } 913148572Snetchild } else { 914148572Snetchild bzero(data, sizeof(data)); 915148572Snetchild len = sizeof(data); 916148572Snetchild get_string(val, NULL, data, &len); 917148572Snetchild txkey = 0; 918148572Snetchild 919148572Snetchild set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data); 920148572Snetchild 921148572Snetchild bzero(data, sizeof(data)); 922148572Snetchild for (i = 1; i < 4; i++) 923148572Snetchild set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data); 924148572Snetchild } 925148572Snetchild 926148572Snetchild set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL); 927148572Snetchild} 928148572Snetchild 929148572Snetchildstatic void 930148572Snetchildset80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp) 931148572Snetchild{ 932148572Snetchild set80211(s, IEEE80211_IOC_RTSTHRESHOLD, 933148572Snetchild isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL); 934148572Snetchild} 935148572Snetchild 936148572Snetchildstatic void 937148572Snetchildset80211protmode(const char *val, int d, int s, const struct afswtch *rafp) 938148572Snetchild{ 939148572Snetchild int mode; 940148572Snetchild 941148572Snetchild if (strcasecmp(val, "off") == 0) { 942148572Snetchild mode = IEEE80211_PROTMODE_OFF; 943148572Snetchild } else if (strcasecmp(val, "cts") == 0) { 944148572Snetchild mode = IEEE80211_PROTMODE_CTS; 945148572Snetchild } else if (strncasecmp(val, "rtscts", 3) == 0) { 946148572Snetchild mode = IEEE80211_PROTMODE_RTSCTS; 947148572Snetchild } else { 948148572Snetchild errx(1, "unknown protection mode"); 949148572Snetchild } 950148572Snetchild 951148572Snetchild set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL); 952148572Snetchild} 953148572Snetchild 954148572Snetchildstatic void 955148572Snetchildset80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp) 956148572Snetchild{ 957148572Snetchild int mode; 958148572Snetchild 959148572Snetchild if (strcasecmp(val, "off") == 0) { 960148572Snetchild mode = IEEE80211_PROTMODE_OFF; 961148572Snetchild } else if (strncasecmp(val, "rts", 3) == 0) { 962148572Snetchild mode = IEEE80211_PROTMODE_RTSCTS; 963148572Snetchild } else { 964148572Snetchild errx(1, "unknown protection mode"); 965148572Snetchild } 966148572Snetchild 967148572Snetchild set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL); 968148572Snetchild} 969148572Snetchild 970148572Snetchildstatic void 971148572Snetchildset80211txpower(const char *val, int d, int s, const struct afswtch *rafp) 972148572Snetchild{ 973148572Snetchild double v = atof(val); 974148572Snetchild int txpow; 975148572Snetchild 976148572Snetchild txpow = (int) (2*v); 977148572Snetchild if (txpow != 2*v) 978148572Snetchild errx(-1, "invalid tx power (must be .5 dBm units)"); 979148572Snetchild set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL); 980148572Snetchild} 981148572Snetchild 982148572Snetchild#define IEEE80211_ROAMING_DEVICE 0 983148572Snetchild#define IEEE80211_ROAMING_AUTO 1 984148572Snetchild#define IEEE80211_ROAMING_MANUAL 2 985148572Snetchild 986148572Snetchildstatic void 987148572Snetchildset80211roaming(const char *val, int d, int s, const struct afswtch *rafp) 988148572Snetchild{ 989148572Snetchild int mode; 990148572Snetchild 991148572Snetchild if (strcasecmp(val, "device") == 0) { 992148572Snetchild mode = IEEE80211_ROAMING_DEVICE; 993148572Snetchild } else if (strcasecmp(val, "auto") == 0) { 994148572Snetchild mode = IEEE80211_ROAMING_AUTO; 995148572Snetchild } else if (strcasecmp(val, "manual") == 0) { 996148572Snetchild mode = IEEE80211_ROAMING_MANUAL; 997148572Snetchild } else { 998148572Snetchild errx(1, "unknown roaming mode"); 999148572Snetchild } 1000148572Snetchild set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL); 1001148572Snetchild} 1002148572Snetchild 1003148572Snetchildstatic void 1004148572Snetchildset80211wme(const char *val, int d, int s, const struct afswtch *rafp) 1005148572Snetchild{ 1006148572Snetchild set80211(s, IEEE80211_IOC_WME, d, 0, NULL); 1007148572Snetchild} 1008148572Snetchild 1009148572Snetchildstatic void 1010148572Snetchildset80211hidessid(const char *val, int d, int s, const struct afswtch *rafp) 1011148572Snetchild{ 1012148572Snetchild set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL); 1013148572Snetchild} 1014148572Snetchild 1015148572Snetchildstatic void 1016148572Snetchildset80211apbridge(const char *val, int d, int s, const struct afswtch *rafp) 1017148572Snetchild{ 1018148330Snetchild set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL); 1019148330Snetchild} 1020148330Snetchild 1021148330Snetchildstatic void 1022148330Snetchildset80211fastframes(const char *val, int d, int s, const struct afswtch *rafp) 1023148572Snetchild{ 1024148572Snetchild set80211(s, IEEE80211_IOC_FF, d, 0, NULL); 1025148572Snetchild} 1026148572Snetchild 1027148572Snetchildstatic void 1028148572Snetchildset80211dturbo(const char *val, int d, int s, const struct afswtch *rafp) 1029148572Snetchild{ 1030148572Snetchild set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL); 1031148572Snetchild} 1032148572Snetchild 1033149113Simpstatic void 1034149113Simpset80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) 1035149113Simp{ 1036149113Simp struct ieee80211req_chanlist chanlist; 1037149113Simp char *temp, *cp, *tp; 1038149113Simp 1039149113Simp temp = malloc(strlen(val) + 1); 1040148572Snetchild if (temp == NULL) 1041148572Snetchild errx(1, "malloc failed"); 1042148572Snetchild strcpy(temp, val); 1043148572Snetchild memset(&chanlist, 0, sizeof(chanlist)); 1044148572Snetchild cp = temp; 1045149105Simp for (;;) { 1046148572Snetchild int first, last, f, c; 1047148572Snetchild 1048148572Snetchild tp = strchr(cp, ','); 1049148572Snetchild if (tp != NULL) 1050148572Snetchild *tp++ = '\0'; 1051148572Snetchild switch (sscanf(cp, "%u-%u", &first, &last)) { 1052148572Snetchild case 1: 1053148572Snetchild if (first > IEEE80211_CHAN_MAX) 1054170220Struckman errx(-1, "channel %u out of range, max %u", 1055170220Struckman first, IEEE80211_CHAN_MAX); 1056156385Syar setbit(chanlist.ic_channels, first); 1057156385Syar break; 1058148330Snetchild case 2: 1059148330Snetchild if (first > IEEE80211_CHAN_MAX) 1060148330Snetchild errx(-1, "channel %u out of range, max %u", 1061148330Snetchild first, IEEE80211_CHAN_MAX); 1062148330Snetchild if (last > IEEE80211_CHAN_MAX) 1063148330Snetchild errx(-1, "channel %u out of range, max %u", 1064148330Snetchild last, IEEE80211_CHAN_MAX); 1065148330Snetchild if (first > last) 1066148330Snetchild errx(-1, "void channel range, %u > %u", 1067148330Snetchild first, last); 1068148330Snetchild for (f = first; f <= last; f++) 1069148330Snetchild setbit(chanlist.ic_channels, f); 1070148330Snetchild break; 1071148330Snetchild } 1072148330Snetchild if (tp == NULL) 1073148330Snetchild break; 1074148330Snetchild c = *tp; 1075148330Snetchild while (isspace(c)) 1076148330Snetchild tp++; 1077148330Snetchild if (!isdigit(c)) 1078148330Snetchild break; 1079148572Snetchild cp = tp; 1080148572Snetchild } 1081149105Simp set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist); 1082148572Snetchild} 1083148572Snetchild 1084148572Snetchildstatic void 1085148572Snetchildset80211bssid(const char *val, int d, int s, const struct afswtch *rafp) 1086148572Snetchild{ 1087148572Snetchild 1088148572Snetchild if (!isanyarg(val)) { 1089155279Savatar char *temp; 1090155279Savatar struct sockaddr_dl sdl; 1091155279Savatar 1092155279Savatar temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 1093148572Snetchild if (temp == NULL) 1094148572Snetchild errx(1, "malloc failed"); 1095148572Snetchild temp[0] = ':'; 1096148330Snetchild strcpy(temp + 1, val); 1097148330Snetchild sdl.sdl_len = sizeof(sdl); 1098148330Snetchild link_addr(temp, &sdl); 1099148330Snetchild free(temp); 1100148330Snetchild if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 1101148330Snetchild errx(1, "malformed link-level address"); 1102148330Snetchild set80211(s, IEEE80211_IOC_BSSID, 0, 1103148330Snetchild IEEE80211_ADDR_LEN, LLADDR(&sdl)); 1104148330Snetchild } else { 1105148330Snetchild uint8_t zerobssid[IEEE80211_ADDR_LEN]; 1106148330Snetchild memset(zerobssid, 0, sizeof(zerobssid)); 1107148330Snetchild set80211(s, IEEE80211_IOC_BSSID, 0, 1108148330Snetchild IEEE80211_ADDR_LEN, zerobssid); 1109148330Snetchild } 1110148330Snetchild} 1111148330Snetchild 1112149105Simpstatic int 1113149105Simpgetac(const char *ac) 1114148572Snetchild{ 1115170219Struckman if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0) 1116148572Snetchild return WME_AC_BE; 1117148572Snetchild if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0) 1118148572Snetchild return WME_AC_BK; 1119148330Snetchild if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0) 1120148330Snetchild return WME_AC_VI; 1121148330Snetchild if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0) 1122148330Snetchild return WME_AC_VO; 1123148330Snetchild errx(1, "unknown wme access class %s", ac); 1124148330Snetchild} 1125148330Snetchild 1126148330Snetchildstatic 1127148330SnetchildDECL_CMD_FUNC2(set80211cwmin, ac, val) 1128148330Snetchild{ 1129148330Snetchild set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL); 1130148330Snetchild} 1131148330Snetchild 1132148330Snetchildstatic 1133148330SnetchildDECL_CMD_FUNC2(set80211cwmax, ac, val) 1134148330Snetchild{ 1135148330Snetchild set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL); 1136148330Snetchild} 1137148330Snetchild 1138148330Snetchildstatic 1139148330SnetchildDECL_CMD_FUNC2(set80211aifs, ac, val) 1140148330Snetchild{ 1141148330Snetchild set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL); 1142148572Snetchild} 1143148572Snetchild 1144148572Snetchildstatic 1145148572SnetchildDECL_CMD_FUNC2(set80211txoplimit, ac, val) 1146148572Snetchild{ 1147148572Snetchild set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL); 1148148572Snetchild} 1149148572Snetchild 1150148572Snetchildstatic 1151148572SnetchildDECL_CMD_FUNC(set80211acm, ac, d) 1152148572Snetchild{ 1153148572Snetchild set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL); 1154148572Snetchild} 1155148572Snetchildstatic 1156148572SnetchildDECL_CMD_FUNC(set80211noacm, ac, d) 1157148572Snetchild{ 1158148572Snetchild set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL); 1159148572Snetchild} 1160148572Snetchild 1161148572Snetchildstatic 1162148572SnetchildDECL_CMD_FUNC(set80211ackpolicy, ac, d) 1163148572Snetchild{ 1164148572Snetchild set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL); 1165148572Snetchild} 1166148572Snetchildstatic 1167148572SnetchildDECL_CMD_FUNC(set80211noackpolicy, ac, d) 1168148572Snetchild{ 1169148572Snetchild set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL); 1170148572Snetchild} 1171148572Snetchild 1172148572Snetchildstatic 1173148572SnetchildDECL_CMD_FUNC2(set80211bsscwmin, ac, val) 1174148572Snetchild{ 1175148572Snetchild set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), 1176148572Snetchild getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 1177148572Snetchild} 1178148572Snetchild 1179148572Snetchildstatic 1180148572SnetchildDECL_CMD_FUNC2(set80211bsscwmax, ac, val) 1181148572Snetchild{ 1182148572Snetchild set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), 1183148572Snetchild getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 1184148572Snetchild} 1185148572Snetchild 1186148572Snetchildstatic 1187148572SnetchildDECL_CMD_FUNC2(set80211bssaifs, ac, val) 1188148572Snetchild{ 1189148572Snetchild set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), 1190148572Snetchild getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 1191148572Snetchild} 1192148572Snetchild 1193148572Snetchildstatic 1194148572SnetchildDECL_CMD_FUNC2(set80211bsstxoplimit, ac, val) 1195148572Snetchild{ 1196148572Snetchild set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), 1197148572Snetchild getac(ac)|IEEE80211_WMEPARAM_BSS, NULL); 1198148572Snetchild} 1199148572Snetchild 1200148572Snetchildstatic 1201148572SnetchildDECL_CMD_FUNC(set80211dtimperiod, val, d) 1202148572Snetchild{ 1203148572Snetchild set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL); 1204148572Snetchild} 1205148572Snetchild 1206148572Snetchildstatic 1207148572SnetchildDECL_CMD_FUNC(set80211bintval, val, d) 1208148572Snetchild{ 1209148572Snetchild set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL); 1210148572Snetchild} 1211148572Snetchild 1212148572Snetchildstatic void 1213148572Snetchildset80211macmac(int s, int op, const char *val) 1214148572Snetchild{ 1215148572Snetchild char *temp; 1216148572Snetchild struct sockaddr_dl sdl; 1217148572Snetchild 1218148572Snetchild temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 1219148572Snetchild if (temp == NULL) 1220148572Snetchild errx(1, "malloc failed"); 1221148572Snetchild temp[0] = ':'; 1222148572Snetchild strcpy(temp + 1, val); 1223148572Snetchild sdl.sdl_len = sizeof(sdl); 1224148572Snetchild link_addr(temp, &sdl); 1225148572Snetchild free(temp); 1226148572Snetchild if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 1227148572Snetchild errx(1, "malformed link-level address"); 1228148572Snetchild set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl)); 1229148572Snetchild} 1230148572Snetchild 1231148572Snetchildstatic 1232148572SnetchildDECL_CMD_FUNC(set80211addmac, val, d) 1233148572Snetchild{ 1234148572Snetchild set80211macmac(s, IEEE80211_IOC_ADDMAC, val); 1235148572Snetchild} 1236148572Snetchild 1237148572Snetchildstatic 1238148572SnetchildDECL_CMD_FUNC(set80211delmac, val, d) 1239148572Snetchild{ 1240148572Snetchild set80211macmac(s, IEEE80211_IOC_DELMAC, val); 1241149105Simp} 1242149105Simp 1243149105Simpstatic 1244149105SimpDECL_CMD_FUNC(set80211kickmac, val, d) 1245148572Snetchild{ 1246164619Snetchild char *temp; 1247164619Snetchild struct sockaddr_dl sdl; 1248148572Snetchild struct ieee80211req_mlme mlme; 1249148572Snetchild 1250148572Snetchild temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 1251148572Snetchild if (temp == NULL) 1252148572Snetchild errx(1, "malloc failed"); 1253148572Snetchild temp[0] = ':'; 1254148572Snetchild strcpy(temp + 1, val); 1255148572Snetchild sdl.sdl_len = sizeof(sdl); 1256148572Snetchild link_addr(temp, &sdl); 1257148572Snetchild free(temp); 1258148572Snetchild if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 1259148572Snetchild errx(1, "malformed link-level address"); 1260148572Snetchild memset(&mlme, 0, sizeof(mlme)); 1261148572Snetchild mlme.im_op = IEEE80211_MLME_DEAUTH; 1262148572Snetchild mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; 1263148572Snetchild memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN); 1264148572Snetchild set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme); 1265148572Snetchild} 1266148572Snetchild 1267148572Snetchildstatic 1268148572SnetchildDECL_CMD_FUNC(set80211maccmd, val, d) 1269148572Snetchild{ 1270148572Snetchild set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL); 1271148572Snetchild} 1272148572Snetchild 1273148572Snetchildstatic void 1274148572Snetchildset80211meshrtmac(int s, int req, const char *val) 1275148572Snetchild{ 1276148572Snetchild char *temp; 1277148572Snetchild struct sockaddr_dl sdl; 1278148572Snetchild 1279148572Snetchild temp = malloc(strlen(val) + 2); /* ':' and '\0' */ 1280148572Snetchild if (temp == NULL) 1281148572Snetchild errx(1, "malloc failed"); 1282148572Snetchild temp[0] = ':'; 1283148572Snetchild strcpy(temp + 1, val); 1284148572Snetchild sdl.sdl_len = sizeof(sdl); 1285148572Snetchild link_addr(temp, &sdl); 1286148572Snetchild free(temp); 1287148572Snetchild if (sdl.sdl_alen != IEEE80211_ADDR_LEN) 1288148572Snetchild errx(1, "malformed link-level address"); 1289148572Snetchild set80211(s, IEEE80211_IOC_MESH_RTCMD, req, 1290148572Snetchild IEEE80211_ADDR_LEN, LLADDR(&sdl)); 1291148572Snetchild} 1292148572Snetchild 1293148572Snetchildstatic 1294148572SnetchildDECL_CMD_FUNC(set80211addmeshrt, val, d) 1295148572Snetchild{ 1296148572Snetchild set80211meshrtmac(s, IEEE80211_MESH_RTCMD_ADD, val); 1297148572Snetchild} 1298148572Snetchild 1299148572Snetchildstatic 1300148572SnetchildDECL_CMD_FUNC(set80211delmeshrt, val, d) 1301148572Snetchild{ 1302148572Snetchild set80211meshrtmac(s, IEEE80211_MESH_RTCMD_DELETE, val); 1303148572Snetchild} 1304148572Snetchild 1305148572Snetchildstatic 1306149105SimpDECL_CMD_FUNC(set80211meshrtcmd, val, d) 1307149105Simp{ 1308149105Simp set80211(s, IEEE80211_IOC_MESH_RTCMD, d, 0, NULL); 1309149105Simp} 1310149105Simp 1311149105Simpstatic 1312149105SimpDECL_CMD_FUNC(set80211hwmprootmode, val, d) 1313149105Simp{ 1314148572Snetchild int mode; 1315148572Snetchild 1316160165Savatar if (strcasecmp(val, "normal") == 0) 1317160165Savatar mode = IEEE80211_HWMP_ROOTMODE_NORMAL; 1318148330Snetchild else if (strcasecmp(val, "proactive") == 0) 1319148330Snetchild mode = IEEE80211_HWMP_ROOTMODE_PROACTIVE; 1320148330Snetchild else if (strcasecmp(val, "rann") == 0) 1321149105Simp mode = IEEE80211_HWMP_ROOTMODE_RANN; 1322149105Simp else 1323163831Sjmg mode = IEEE80211_HWMP_ROOTMODE_DISABLED; 1324149105Simp set80211(s, IEEE80211_IOC_HWMP_ROOTMODE, mode, 0, NULL); 1325163831Sjmg} 1326149105Simp 1327149105Simpstatic 1328149105SimpDECL_CMD_FUNC(set80211hwmpmaxhops, val, d) 1329149105Simp{ 1330149105Simp set80211(s, IEEE80211_IOC_HWMP_MAXHOPS, atoi(val), 0, NULL); 1331149105Simp} 1332149105Simp 1333149105Simpstatic void 1334149105Simpset80211pureg(const char *val, int d, int s, const struct afswtch *rafp) 1335149105Simp{ 1336149105Simp set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL); 1337149105Simp} 1338149105Simp 1339149105Simpstatic void 1340149105Simpset80211bgscan(const char *val, int d, int s, const struct afswtch *rafp) 1341149105Simp{ 1342149105Simp set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL); 1343149105Simp} 1344149105Simp 1345149105Simpstatic 1346149105SimpDECL_CMD_FUNC(set80211bgscanidle, val, d) 1347149105Simp{ 1348160165Savatar set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL); 1349160165Savatar} 1350160165Savatar 1351148330Snetchildstatic 1352148330SnetchildDECL_CMD_FUNC(set80211bgscanintvl, val, d) 1353148330Snetchild{ 1354148330Snetchild set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL); 1355148330Snetchild} 1356148330Snetchild 1357148330Snetchildstatic 1358148330SnetchildDECL_CMD_FUNC(set80211scanvalid, val, d) 1359149105Simp{ 1360149105Simp set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL); 1361149105Simp} 1362149105Simp 1363149105Simp/* 1364148330Snetchild * Parse an optional trailing specification of which netbands 1365149105Simp * to apply a parameter to. This is basically the same syntax 1366149105Simp * as used for channels but you can concatenate to specify 1367149105Simp * multiple. For example: 1368149105Simp * 14:abg apply to 11a, 11b, and 11g 1369149105Simp * 6:ht apply to 11na and 11ng 1370149105Simp * We don't make a big effort to catch silly things; this is 1371149105Simp * really a convenience mechanism. 1372149105Simp */ 1373149105Simpstatic int 1374149105Simpgetmodeflags(const char *val) 1375149105Simp{ 1376149105Simp const char *cp; 1377149105Simp int flags; 1378164971Savatar 1379164971Savatar flags = 0; 1380164971Savatar 1381164971Savatar cp = strchr(val, ':'); 1382164971Savatar if (cp != NULL) { 1383164971Savatar for (cp++; isalpha((int) *cp); cp++) { 1384164971Savatar /* accept mixed case */ 1385164971Savatar int c = *cp; 1386164971Savatar if (isupper(c)) 1387164971Savatar c = tolower(c); 1388164971Savatar switch (c) { 1389164971Savatar case 'a': /* 802.11a */ 1390164971Savatar flags |= IEEE80211_CHAN_A; 1391164971Savatar break; 1392164971Savatar case 'b': /* 802.11b */ 1393164971Savatar flags |= IEEE80211_CHAN_B; 1394164971Savatar break; 1395164971Savatar case 'g': /* 802.11g */ 1396164971Savatar flags |= IEEE80211_CHAN_G; 1397164971Savatar break; 1398164971Savatar case 'n': /* 802.11n */ 1399164971Savatar flags |= IEEE80211_CHAN_HT; 1400164971Savatar break; 1401164971Savatar case 'd': /* dt = Atheros Dynamic Turbo */ 1402164971Savatar flags |= IEEE80211_CHAN_TURBO; 1403160165Savatar break; 1404160165Savatar case 't': /* ht, dt, st, t */ 1405160165Savatar /* dt and unadorned t specify Dynamic Turbo */ 1406148330Snetchild if ((flags & (IEEE80211_CHAN_STURBO|IEEE80211_CHAN_HT)) == 0) 1407148330Snetchild flags |= IEEE80211_CHAN_TURBO; 1408148330Snetchild break; 1409148330Snetchild case 's': /* st = Atheros Static Turbo */ 1410149105Simp flags |= IEEE80211_CHAN_STURBO; 1411149105Simp break; 1412149105Simp case 'h': /* 1/2-width channels */ 1413164302Smatteo flags |= IEEE80211_CHAN_HALF; 1414164302Smatteo break; 1415148330Snetchild case 'q': /* 1/4-width channels */ 1416148330Snetchild flags |= IEEE80211_CHAN_QUARTER; 1417148330Snetchild break; 1418148330Snetchild default: 1419148330Snetchild errx(-1, "%s: Invalid mode attribute %c\n", 1420148330Snetchild val, *cp); 1421148330Snetchild } 1422148330Snetchild } 1423148330Snetchild } 1424148330Snetchild return flags; 1425148330Snetchild} 1426148330Snetchild 1427148330Snetchild#define IEEE80211_CHAN_HTA (IEEE80211_CHAN_HT|IEEE80211_CHAN_5GHZ) 1428148330Snetchild#define IEEE80211_CHAN_HTG (IEEE80211_CHAN_HT|IEEE80211_CHAN_2GHZ) 1429148330Snetchild 1430148330Snetchild#define _APPLY(_flags, _base, _param, _v) do { \ 1431148543Snetchild if (_flags & IEEE80211_CHAN_HT) { \ 1432149113Simp if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\ 1433149113Simp _base.params[IEEE80211_MODE_11NA]._param = _v; \ 1434149113Simp _base.params[IEEE80211_MODE_11NG]._param = _v; \ 1435149113Simp } else if (_flags & IEEE80211_CHAN_5GHZ) \ 1436149113Simp _base.params[IEEE80211_MODE_11NA]._param = _v; \ 1437149113Simp else \ 1438149113Simp _base.params[IEEE80211_MODE_11NG]._param = _v; \ 1439149113Simp } \ 1440149113Simp if (_flags & IEEE80211_CHAN_TURBO) { \ 1441149113Simp if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\ 1442149113Simp _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ 1443148330Snetchild _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ 1444148330Snetchild } else if (_flags & IEEE80211_CHAN_5GHZ) \ 1445149113Simp _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ 1446149113Simp else \ 1447149113Simp _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ 1448149113Simp } \ 1449149113Simp if (_flags & IEEE80211_CHAN_STURBO) \ 1450149113Simp _base.params[IEEE80211_MODE_STURBO_A]._param = _v; \ 1451149113Simp if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \ 1452149113Simp _base.params[IEEE80211_MODE_11A]._param = _v; \ 1453149113Simp if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \ 1454149113Simp _base.params[IEEE80211_MODE_11G]._param = _v; \ 1455149113Simp if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \ 1456149113Simp _base.params[IEEE80211_MODE_11B]._param = _v; \ 1457149113Simp if (_flags & IEEE80211_CHAN_HALF) \ 1458149113Simp _base.params[IEEE80211_MODE_HALF]._param = _v; \ 1459149113Simp if (_flags & IEEE80211_CHAN_QUARTER) \ 1460149113Simp _base.params[IEEE80211_MODE_QUARTER]._param = _v; \ 1461149113Simp} while (0) 1462149113Simp#define _APPLY1(_flags, _base, _param, _v) do { \ 1463149113Simp if (_flags & IEEE80211_CHAN_HT) { \ 1464149113Simp if (_flags & IEEE80211_CHAN_5GHZ) \ 1465149113Simp _base.params[IEEE80211_MODE_11NA]._param = _v; \ 1466149113Simp else \ 1467149113Simp _base.params[IEEE80211_MODE_11NG]._param = _v; \ 1468149113Simp } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) \ 1469149113Simp _base.params[IEEE80211_MODE_TURBO_A]._param = _v; \ 1470149113Simp else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) \ 1471149113Simp _base.params[IEEE80211_MODE_TURBO_G]._param = _v; \ 1472149113Simp else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) \ 1473149113Simp _base.params[IEEE80211_MODE_STURBO_A]._param = _v; \ 1474149113Simp else if (_flags & IEEE80211_CHAN_HALF) \ 1475149113Simp _base.params[IEEE80211_MODE_HALF]._param = _v; \ 1476149113Simp else if (_flags & IEEE80211_CHAN_QUARTER) \ 1477148330Snetchild _base.params[IEEE80211_MODE_QUARTER]._param = _v; \ 1478148330Snetchild else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) \ 1479148330Snetchild _base.params[IEEE80211_MODE_11A]._param = _v; \ 1480148330Snetchild else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) \ 1481148330Snetchild _base.params[IEEE80211_MODE_11G]._param = _v; \ 1482148330Snetchild else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) \ 1483148330Snetchild _base.params[IEEE80211_MODE_11B]._param = _v; \ 1484151378Snetchild} while (0) 1485151378Snetchild#define _APPLY_RATE(_flags, _base, _param, _v) do { \ 1486151378Snetchild if (_flags & IEEE80211_CHAN_HT) { \ 1487151378Snetchild (_v) = (_v / 2) | IEEE80211_RATE_MCS; \ 1488151378Snetchild } \ 1489151378Snetchild _APPLY(_flags, _base, _param, _v); \ 1490151378Snetchild} while (0) 1491151378Snetchild#define _APPLY_RATE1(_flags, _base, _param, _v) do { \ 1492151378Snetchild if (_flags & IEEE80211_CHAN_HT) { \ 1493151378Snetchild (_v) = (_v / 2) | IEEE80211_RATE_MCS; \ 1494161201Snetchild } \ 1495151378Snetchild _APPLY1(_flags, _base, _param, _v); \ 1496151378Snetchild} while (0) 1497151378Snetchild 1498151378Snetchildstatic 1499151378SnetchildDECL_CMD_FUNC(set80211roamrssi, val, d) 1500151378Snetchild{ 1501151378Snetchild double v = atof(val); 1502151378Snetchild int rssi, flags; 1503151378Snetchild 1504151378Snetchild rssi = (int) (2*v); 1505151378Snetchild if (rssi != 2*v) 1506151378Snetchild errx(-1, "invalid rssi (must be .5 dBm units)"); 1507151378Snetchild flags = getmodeflags(val); 1508151378Snetchild getroam(s); 1509151378Snetchild if (flags == 0) { /* NB: no flags => current channel */ 1510151378Snetchild flags = getcurchan(s)->ic_flags; 1511151378Snetchild _APPLY1(flags, roamparams, rssi, rssi); 1512151378Snetchild } else 1513151378Snetchild _APPLY(flags, roamparams, rssi, rssi); 1514151378Snetchild callback_register(setroam_cb, &roamparams); 1515151378Snetchild} 1516151378Snetchild 1517151378Snetchildstatic int 1518151378Snetchildgetrate(const char *val, const char *tag) 1519151378Snetchild{ 1520151378Snetchild double v = atof(val); 1521151378Snetchild int rate; 1522151378Snetchild 1523151378Snetchild rate = (int) (2*v); 1524151378Snetchild if (rate != 2*v) 1525151378Snetchild errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag); 1526151378Snetchild return rate; /* NB: returns 2x the specified value */ 1527151378Snetchild} 1528151378Snetchild 1529151378Snetchildstatic 1530151378SnetchildDECL_CMD_FUNC(set80211roamrate, val, d) 1531151378Snetchild{ 1532151378Snetchild int rate, flags; 1533151378Snetchild 1534151378Snetchild rate = getrate(val, "roam"); 1535151378Snetchild flags = getmodeflags(val); 1536151378Snetchild getroam(s); 1537151378Snetchild if (flags == 0) { /* NB: no flags => current channel */ 1538151378Snetchild flags = getcurchan(s)->ic_flags; 1539151378Snetchild _APPLY_RATE1(flags, roamparams, rate, rate); 1540151378Snetchild } else 1541151378Snetchild _APPLY_RATE(flags, roamparams, rate, rate); 1542151378Snetchild callback_register(setroam_cb, &roamparams); 1543151378Snetchild} 1544151378Snetchild 1545151378Snetchildstatic 1546151378SnetchildDECL_CMD_FUNC(set80211mcastrate, val, d) 1547151378Snetchild{ 1548151378Snetchild int rate, flags; 1549151378Snetchild 1550151378Snetchild rate = getrate(val, "mcast"); 1551151378Snetchild flags = getmodeflags(val); 1552151378Snetchild gettxparams(s); 1553151378Snetchild if (flags == 0) { /* NB: no flags => current channel */ 1554151378Snetchild flags = getcurchan(s)->ic_flags; 1555151378Snetchild _APPLY_RATE1(flags, txparams, mcastrate, rate); 1556151378Snetchild } else 1557151378Snetchild _APPLY_RATE(flags, txparams, mcastrate, rate); 1558151378Snetchild callback_register(settxparams_cb, &txparams); 1559151378Snetchild} 1560151378Snetchild 1561151378Snetchildstatic 1562151378SnetchildDECL_CMD_FUNC(set80211mgtrate, val, d) 1563151378Snetchild{ 1564151378Snetchild int rate, flags; 1565151378Snetchild 1566151378Snetchild rate = getrate(val, "mgmt"); 1567151378Snetchild flags = getmodeflags(val); 1568151378Snetchild gettxparams(s); 1569151378Snetchild if (flags == 0) { /* NB: no flags => current channel */ 1570151378Snetchild flags = getcurchan(s)->ic_flags; 1571151378Snetchild _APPLY_RATE1(flags, txparams, mgmtrate, rate); 1572151378Snetchild } else 1573151378Snetchild _APPLY_RATE(flags, txparams, mgmtrate, rate); 1574151378Snetchild callback_register(settxparams_cb, &txparams); 1575151378Snetchild} 1576151378Snetchild 1577151378Snetchildstatic 1578151378SnetchildDECL_CMD_FUNC(set80211ucastrate, val, d) 1579151378Snetchild{ 1580151378Snetchild int flags; 1581151378Snetchild 1582151378Snetchild gettxparams(s); 1583151378Snetchild flags = getmodeflags(val); 1584151378Snetchild if (isanyarg(val)) { 1585151378Snetchild if (flags == 0) { /* NB: no flags => current channel */ 1586151378Snetchild flags = getcurchan(s)->ic_flags; 1587151378Snetchild _APPLY1(flags, txparams, ucastrate, 1588151378Snetchild IEEE80211_FIXED_RATE_NONE); 1589151378Snetchild } else 1590151378Snetchild _APPLY(flags, txparams, ucastrate, 1591151378Snetchild IEEE80211_FIXED_RATE_NONE); 1592151378Snetchild } else { 1593151378Snetchild int rate = getrate(val, "ucast"); 1594151378Snetchild if (flags == 0) { /* NB: no flags => current channel */ 1595151378Snetchild flags = getcurchan(s)->ic_flags; 1596151378Snetchild _APPLY_RATE1(flags, txparams, ucastrate, rate); 1597151378Snetchild } else 1598151378Snetchild _APPLY_RATE(flags, txparams, ucastrate, rate); 1599151378Snetchild } 1600151378Snetchild callback_register(settxparams_cb, &txparams); 1601151378Snetchild} 1602151378Snetchild 1603151378Snetchildstatic 1604151378SnetchildDECL_CMD_FUNC(set80211maxretry, val, d) 1605151378Snetchild{ 1606151378Snetchild int v = atoi(val), flags; 1607151378Snetchild 1608151378Snetchild flags = getmodeflags(val); 1609151378Snetchild gettxparams(s); 1610151378Snetchild if (flags == 0) { /* NB: no flags => current channel */ 1611151378Snetchild flags = getcurchan(s)->ic_flags; 1612151378Snetchild _APPLY1(flags, txparams, maxretry, v); 1613151378Snetchild } else 1614151378Snetchild _APPLY(flags, txparams, maxretry, v); 1615151378Snetchild callback_register(settxparams_cb, &txparams); 1616151378Snetchild} 1617151378Snetchild#undef _APPLY_RATE 1618151378Snetchild#undef _APPLY 1619151378Snetchild#undef IEEE80211_CHAN_HTA 1620151378Snetchild#undef IEEE80211_CHAN_HTG 1621151378Snetchild 1622151378Snetchildstatic 1623151378SnetchildDECL_CMD_FUNC(set80211fragthreshold, val, d) 1624151378Snetchild{ 1625151378Snetchild set80211(s, IEEE80211_IOC_FRAGTHRESHOLD, 1626151378Snetchild isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL); 1627151378Snetchild} 1628151378Snetchild 1629151378Snetchildstatic 1630151378SnetchildDECL_CMD_FUNC(set80211bmissthreshold, val, d) 1631151378Snetchild{ 1632151378Snetchild set80211(s, IEEE80211_IOC_BMISSTHRESHOLD, 1633151378Snetchild isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL); 1634151378Snetchild} 1635151378Snetchild 1636151378Snetchildstatic void 1637151378Snetchildset80211burst(const char *val, int d, int s, const struct afswtch *rafp) 1638151378Snetchild{ 1639151378Snetchild set80211(s, IEEE80211_IOC_BURST, d, 0, NULL); 1640151378Snetchild} 1641151378Snetchild 1642151378Snetchildstatic void 1643151378Snetchildset80211doth(const char *val, int d, int s, const struct afswtch *rafp) 1644151378Snetchild{ 1645151378Snetchild set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL); 1646151378Snetchild} 1647151378Snetchild 1648151378Snetchildstatic void 1649151378Snetchildset80211dfs(const char *val, int d, int s, const struct afswtch *rafp) 1650151378Snetchild{ 1651151378Snetchild set80211(s, IEEE80211_IOC_DFS, d, 0, NULL); 1652151378Snetchild} 1653151378Snetchild 1654151378Snetchildstatic void 1655151378Snetchildset80211shortgi(const char *val, int d, int s, const struct afswtch *rafp) 1656151378Snetchild{ 1657151378Snetchild set80211(s, IEEE80211_IOC_SHORTGI, 1658151378Snetchild d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0, 1659151378Snetchild 0, NULL); 1660151378Snetchild} 1661151378Snetchild 1662151378Snetchildstatic void 1663151378Snetchildset80211ampdu(const char *val, int d, int s, const struct afswtch *rafp) 1664151378Snetchild{ 1665151378Snetchild int ampdu; 1666151378Snetchild 1667151378Snetchild if (get80211val(s, IEEE80211_IOC_AMPDU, &du) < 0) 1668151378Snetchild errx(-1, "cannot get AMPDU setting"); 1669151378Snetchild if (d < 0) { 1670151378Snetchild d = -d; 1671151378Snetchild ampdu &= ~d; 1672151378Snetchild } else 1673151378Snetchild ampdu |= d; 1674151378Snetchild set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL); 1675151378Snetchild} 1676151378Snetchild 1677151378Snetchildstatic 1678151378SnetchildDECL_CMD_FUNC(set80211ampdulimit, val, d) 1679151378Snetchild{ 1680151378Snetchild int v; 1681151378Snetchild 1682151378Snetchild switch (atoi(val)) { 1683151378Snetchild case 8: 1684151378Snetchild case 8*1024: 1685151378Snetchild v = IEEE80211_HTCAP_MAXRXAMPDU_8K; 1686151378Snetchild break; 1687151378Snetchild case 16: 1688151378Snetchild case 16*1024: 1689151378Snetchild v = IEEE80211_HTCAP_MAXRXAMPDU_16K; 1690151378Snetchild break; 1691151378Snetchild case 32: 1692151378Snetchild case 32*1024: 1693151378Snetchild v = IEEE80211_HTCAP_MAXRXAMPDU_32K; 1694151378Snetchild break; 1695151378Snetchild case 64: 1696151378Snetchild case 64*1024: 1697151378Snetchild v = IEEE80211_HTCAP_MAXRXAMPDU_64K; 1698151378Snetchild break; 1699151378Snetchild default: 1700151378Snetchild errx(-1, "invalid A-MPDU limit %s", val); 1701151378Snetchild } 1702151378Snetchild set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL); 1703151378Snetchild} 1704151378Snetchild 1705151378Snetchildstatic 1706151378SnetchildDECL_CMD_FUNC(set80211ampdudensity, val, d) 1707151378Snetchild{ 1708151378Snetchild int v; 1709151378Snetchild 1710151378Snetchild if (isanyarg(val) || strcasecmp(val, "na") == 0) 1711151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_NA; 1712151378Snetchild else switch ((int)(atof(val)*4)) { 1713151378Snetchild case 0: 1714151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_NA; 1715151378Snetchild break; 1716151378Snetchild case 1: 1717151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_025; 1718151378Snetchild break; 1719151378Snetchild case 2: 1720151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_05; 1721151378Snetchild break; 1722151378Snetchild case 4: 1723151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_1; 1724151378Snetchild break; 1725151378Snetchild case 8: 1726151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_2; 1727151378Snetchild break; 1728151378Snetchild case 16: 1729151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_4; 1730151378Snetchild break; 1731151378Snetchild case 32: 1732151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_8; 1733151378Snetchild break; 1734151378Snetchild case 64: 1735151378Snetchild v = IEEE80211_HTCAP_MPDUDENSITY_16; 1736151378Snetchild break; 1737151378Snetchild default: 1738151378Snetchild errx(-1, "invalid A-MPDU density %s", val); 1739151378Snetchild } 1740151378Snetchild set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL); 1741151378Snetchild} 1742151378Snetchild 1743151378Snetchildstatic void 1744151378Snetchildset80211amsdu(const char *val, int d, int s, const struct afswtch *rafp) 1745151378Snetchild{ 1746151378Snetchild int amsdu; 1747151378Snetchild 1748151378Snetchild if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0) 1749151378Snetchild err(-1, "cannot get AMSDU setting"); 1750151378Snetchild if (d < 0) { 1751151378Snetchild d = -d; 1752151378Snetchild amsdu &= ~d; 1753151378Snetchild } else 1754151378Snetchild amsdu |= d; 1755151378Snetchild set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL); 1756151378Snetchild} 1757151378Snetchild 1758151378Snetchildstatic 1759151378SnetchildDECL_CMD_FUNC(set80211amsdulimit, val, d) 1760151378Snetchild{ 1761151378Snetchild set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL); 1762151378Snetchild} 1763151378Snetchild 1764151378Snetchildstatic void 1765151378Snetchildset80211puren(const char *val, int d, int s, const struct afswtch *rafp) 1766151378Snetchild{ 1767151378Snetchild set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL); 1768151378Snetchild} 1769151378Snetchild 1770151378Snetchildstatic void 1771151378Snetchildset80211htcompat(const char *val, int d, int s, const struct afswtch *rafp) 1772151378Snetchild{ 1773151378Snetchild set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL); 1774151378Snetchild} 1775151378Snetchild 1776151378Snetchildstatic void 1777151378Snetchildset80211htconf(const char *val, int d, int s, const struct afswtch *rafp) 1778151378Snetchild{ 1779151378Snetchild set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL); 1780151378Snetchild htconf = d; 1781151378Snetchild} 1782151378Snetchild 1783151378Snetchildstatic void 1784151378Snetchildset80211dwds(const char *val, int d, int s, const struct afswtch *rafp) 1785151378Snetchild{ 1786151378Snetchild set80211(s, IEEE80211_IOC_DWDS, d, 0, NULL); 1787151378Snetchild} 1788151378Snetchild 1789151378Snetchildstatic void 1790151378Snetchildset80211inact(const char *val, int d, int s, const struct afswtch *rafp) 1791151378Snetchild{ 1792151378Snetchild set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL); 1793151378Snetchild} 1794151378Snetchild 1795151378Snetchildstatic void 1796151378Snetchildset80211tsn(const char *val, int d, int s, const struct afswtch *rafp) 1797151378Snetchild{ 1798151378Snetchild set80211(s, IEEE80211_IOC_TSN, d, 0, NULL); 1799151378Snetchild} 1800151378Snetchild 1801151378Snetchildstatic void 1802151378Snetchildset80211dotd(const char *val, int d, int s, const struct afswtch *rafp) 1803151378Snetchild{ 1804151378Snetchild set80211(s, IEEE80211_IOC_DOTD, d, 0, NULL); 1805151378Snetchild} 1806151378Snetchild 1807151378Snetchildstatic void 1808151378Snetchildset80211smps(const char *val, int d, int s, const struct afswtch *rafp) 1809151378Snetchild{ 1810151378Snetchild set80211(s, IEEE80211_IOC_SMPS, d, 0, NULL); 1811151378Snetchild} 1812151378Snetchild 1813151378Snetchildstatic void 1814151378Snetchildset80211rifs(const char *val, int d, int s, const struct afswtch *rafp) 1815151378Snetchild{ 1816151378Snetchild set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL); 1817151378Snetchild} 1818151378Snetchild 1819151378Snetchildstatic 1820151378SnetchildDECL_CMD_FUNC(set80211tdmaslot, val, d) 1821151378Snetchild{ 1822151378Snetchild set80211(s, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL); 1823151378Snetchild} 1824151378Snetchild 1825151378Snetchildstatic 1826151378SnetchildDECL_CMD_FUNC(set80211tdmaslotcnt, val, d) 1827151378Snetchild{ 1828151378Snetchild set80211(s, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL); 1829151378Snetchild} 1830151378Snetchild 1831151378Snetchildstatic 1832151378SnetchildDECL_CMD_FUNC(set80211tdmaslotlen, val, d) 1833151378Snetchild{ 1834151378Snetchild set80211(s, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL); 1835151378Snetchild} 1836151378Snetchild 1837151378Snetchildstatic 1838151378SnetchildDECL_CMD_FUNC(set80211tdmabintval, val, d) 1839151378Snetchild{ 1840151378Snetchild set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL); 1841151378Snetchild} 1842151378Snetchild 1843151378Snetchildstatic 1844151378SnetchildDECL_CMD_FUNC(set80211meshttl, val, d) 1845151378Snetchild{ 1846151378Snetchild set80211(s, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL); 1847151378Snetchild} 1848151378Snetchild 1849151378Snetchildstatic 1850151378SnetchildDECL_CMD_FUNC(set80211meshforward, val, d) 1851151378Snetchild{ 1852151378Snetchild set80211(s, IEEE80211_IOC_MESH_FWRD, atoi(val), 0, NULL); 1853151378Snetchild} 1854151378Snetchild 1855151378Snetchildstatic 1856151378SnetchildDECL_CMD_FUNC(set80211meshpeering, val, d) 1857151378Snetchild{ 1858151378Snetchild set80211(s, IEEE80211_IOC_MESH_AP, atoi(val), 0, NULL); 1859151378Snetchild} 1860151378Snetchild 1861151378Snetchildstatic 1862151378SnetchildDECL_CMD_FUNC(set80211meshmetric, val, d) 1863151378Snetchild{ 1864151378Snetchild char v[12]; 1865151378Snetchild 1866151378Snetchild memcpy(v, val, sizeof(v)); 1867151378Snetchild set80211(s, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v); 1868151378Snetchild} 1869151378Snetchild 1870151378Snetchildstatic 1871151378SnetchildDECL_CMD_FUNC(set80211meshpath, val, d) 1872151378Snetchild{ 1873151378Snetchild char v[12]; 1874151378Snetchild 1875151378Snetchild memcpy(v, val, sizeof(v)); 1876151378Snetchild set80211(s, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v); 1877151378Snetchild} 1878151378Snetchild 1879151378Snetchildstatic int 1880151378Snetchildregdomain_sort(const void *a, const void *b) 1881151378Snetchild{ 1882151378Snetchild#define CHAN_ALL \ 1883151378Snetchild (IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER) 1884151378Snetchild const struct ieee80211_channel *ca = a; 1885151378Snetchild const struct ieee80211_channel *cb = b; 1886151378Snetchild 1887151378Snetchild return ca->ic_freq == cb->ic_freq ? 1888151378Snetchild (ca->ic_flags & CHAN_ALL) - (cb->ic_flags & CHAN_ALL) : 1889151378Snetchild ca->ic_freq - cb->ic_freq; 1890151378Snetchild#undef CHAN_ALL 1891151378Snetchild} 1892151378Snetchild 1893151378Snetchildstatic const struct ieee80211_channel * 1894151378Snetchildchanlookup(const struct ieee80211_channel chans[], int nchans, 1895151378Snetchild int freq, int flags) 1896151378Snetchild{ 1897151378Snetchild int i; 1898151378Snetchild 1899151378Snetchild flags &= IEEE80211_CHAN_ALLTURBO; 1900151378Snetchild for (i = 0; i < nchans; i++) { 1901151378Snetchild const struct ieee80211_channel *c = &chans[i]; 1902151378Snetchild if (c->ic_freq == freq && 1903151378Snetchild (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags) 1904151378Snetchild return c; 1905151378Snetchild } 1906151378Snetchild return NULL; 1907151378Snetchild} 1908151378Snetchild 1909151378Snetchildstatic int 1910151378Snetchildchanfind(const struct ieee80211_channel chans[], int nchans, int flags) 1911151378Snetchild{ 1912151378Snetchild int i; 1913151378Snetchild 1914151378Snetchild for (i = 0; i < nchans; i++) { 1915151378Snetchild const struct ieee80211_channel *c = &chans[i]; 1916151378Snetchild if ((c->ic_flags & flags) == flags) 1917151378Snetchild return 1; 1918151378Snetchild } 1919151378Snetchild return 0; 1920151378Snetchild} 1921151378Snetchild 1922151378Snetchild/* 1923151378Snetchild * Check channel compatibility. 1924151378Snetchild */ 1925151378Snetchildstatic int 1926151378Snetchildcheckchan(const struct ieee80211req_chaninfo *avail, int freq, int flags) 1927151378Snetchild{ 1928151378Snetchild flags &= ~REQ_FLAGS; 1929151378Snetchild /* 1930151378Snetchild * Check if exact channel is in the calibration table; 1931151378Snetchild * everything below is to deal with channels that we 1932151378Snetchild * want to include but that are not explicitly listed. 1933151378Snetchild */ 1934151378Snetchild if (flags & IEEE80211_CHAN_HT40) { 1935151378Snetchild /* NB: we use an HT40 channel center that matches HT20 */ 1936151378Snetchild flags = (flags &~ IEEE80211_CHAN_HT40) | IEEE80211_CHAN_HT20; 1937151378Snetchild } 1938151378Snetchild if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL) 1939151378Snetchild return 1; 1940151378Snetchild if (flags & IEEE80211_CHAN_GSM) { 1941151378Snetchild /* 1942151378Snetchild * XXX GSM frequency mapping is handled in the kernel 1943151378Snetchild * so we cannot find them in the calibration table; 1944151378Snetchild * just accept the channel and the kernel will reject 1945151378Snetchild * the channel list if it's wrong. 1946151378Snetchild */ 1947151378Snetchild return 1; 1948151378Snetchild } 1949151378Snetchild /* 1950151378Snetchild * If this is a 1/2 or 1/4 width channel allow it if a full 1951151378Snetchild * width channel is present for this frequency, and the device 1952151378Snetchild * supports fractional channels on this band. This is a hack 1953151378Snetchild * that avoids bloating the calibration table; it may be better 1954151378Snetchild * by per-band attributes though (we are effectively calculating 1955151378Snetchild * this attribute by scanning the channel list ourself). 1956151378Snetchild */ 1957151378Snetchild if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0) 1958151378Snetchild return 0; 1959151378Snetchild if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, 1960151378Snetchild flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL) 1961151378Snetchild return 0; 1962151378Snetchild if (flags & IEEE80211_CHAN_HALF) { 1963151378Snetchild return chanfind(avail->ic_chans, avail->ic_nchans, 1964151378Snetchild IEEE80211_CHAN_HALF | 1965151378Snetchild (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ))); 1966151378Snetchild } else { 1967151378Snetchild return chanfind(avail->ic_chans, avail->ic_nchans, 1968151378Snetchild IEEE80211_CHAN_QUARTER | 1969151378Snetchild (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ))); 1970151378Snetchild } 1971151378Snetchild} 1972151378Snetchild 1973151378Snetchildstatic void 1974151378Snetchildregdomain_addchans(struct ieee80211req_chaninfo *ci, 1975151378Snetchild const netband_head *bands, 1976151378Snetchild const struct ieee80211_regdomain *reg, 1977151378Snetchild uint32_t chanFlags, 1978151378Snetchild const struct ieee80211req_chaninfo *avail) 1979151378Snetchild{ 1980151378Snetchild const struct netband *nb; 1981151378Snetchild const struct freqband *b; 1982151378Snetchild struct ieee80211_channel *c, *prev; 1983151378Snetchild int freq, hi_adj, lo_adj, channelSep; 1984151378Snetchild uint32_t flags; 1985151378Snetchild 1986151378Snetchild hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0; 1987151378Snetchild lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0; 1988151378Snetchild channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40; 1989151378Snetchild LIST_FOREACH(nb, bands, next) { 1990151378Snetchild b = nb->band; 1991151378Snetchild if (verbose) { 1992151378Snetchild printf("%s:", __func__); 1993151378Snetchild printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS); 1994151378Snetchild printb(" bandFlags", nb->flags | b->flags, 1995151378Snetchild IEEE80211_CHAN_BITS); 1996151378Snetchild putchar('\n'); 1997151378Snetchild } 1998151378Snetchild prev = NULL; 1999151378Snetchild for (freq = b->freqStart + lo_adj; 2000151378Snetchild freq <= b->freqEnd + hi_adj; freq += b->chanSep) { 2001151378Snetchild /* 2002151378Snetchild * Construct flags for the new channel. We take 2003151378Snetchild * the attributes from the band descriptions except 2004151378Snetchild * for HT40 which is enabled generically (i.e. +/- 2005151378Snetchild * extension channel) in the band description and 2006151378Snetchild * then constrained according by channel separation. 2007151378Snetchild */ 2008151378Snetchild flags = nb->flags | b->flags; 2009151378Snetchild if (flags & IEEE80211_CHAN_HT) { 2010151378Snetchild /* 2011151378Snetchild * HT channels are generated specially; we're 2012151378Snetchild * called to add HT20, HT40+, and HT40- chan's 2013151378Snetchild * so we need to expand only band specs for 2014151378Snetchild * the HT channel type being added. 2015151378Snetchild */ 2016151378Snetchild if ((chanFlags & IEEE80211_CHAN_HT20) && 2017151378Snetchild (flags & IEEE80211_CHAN_HT20) == 0) { 2018151378Snetchild if (verbose) 2019151378Snetchild printf("%u: skip, not an " 2020151378Snetchild "HT20 channel\n", freq); 2021151378Snetchild continue; 2022151378Snetchild } 2023151378Snetchild if ((chanFlags & IEEE80211_CHAN_HT40) && 2024151378Snetchild (flags & IEEE80211_CHAN_HT40) == 0) { 2025151378Snetchild if (verbose) 2026151378Snetchild printf("%u: skip, not an " 2027151378Snetchild "HT40 channel\n", freq); 2028151378Snetchild continue; 2029151378Snetchild } 2030151378Snetchild /* 2031151378Snetchild * DFS and HT40 don't mix. This should be 2032151378Snetchild * expressed in the regdomain database but 2033151378Snetchild * just in case enforce it here. 2034151378Snetchild */ 2035151378Snetchild if ((chanFlags & IEEE80211_CHAN_HT40) && 2036151378Snetchild (flags & IEEE80211_CHAN_DFS)) { 2037151378Snetchild if (verbose) 2038151378Snetchild printf("%u: skip, HT40+DFS " 2039151378Snetchild "not permitted\n", freq); 2040151378Snetchild continue; 2041151378Snetchild } 2042151378Snetchild /* NB: HT attribute comes from caller */ 2043151378Snetchild flags &= ~IEEE80211_CHAN_HT; 2044151378Snetchild flags |= chanFlags & IEEE80211_CHAN_HT; 2045151378Snetchild } 2046151378Snetchild /* 2047151378Snetchild * Check if device can operate on this frequency. 2048151378Snetchild */ 2049151378Snetchild if (!checkchan(avail, freq, flags)) { 2050151378Snetchild if (verbose) { 2051151378Snetchild printf("%u: skip, ", freq); 2052151378Snetchild printb("flags", flags, 2053151378Snetchild IEEE80211_CHAN_BITS); 2054151378Snetchild printf(" not available\n"); 2055151378Snetchild } 2056151378Snetchild continue; 2057151378Snetchild } 2058151378Snetchild if ((flags & REQ_ECM) && !reg->ecm) { 2059151378Snetchild if (verbose) 2060151378Snetchild printf("%u: skip, ECM channel\n", freq); 2061151378Snetchild continue; 2062151378Snetchild } 2063151378Snetchild if ((flags & REQ_INDOOR) && reg->location == 'O') { 2064151378Snetchild if (verbose) 2065151378Snetchild printf("%u: skip, indoor channel\n", 2066151378Snetchild freq); 2067151378Snetchild continue; 2068151378Snetchild } 2069151378Snetchild if ((flags & REQ_OUTDOOR) && reg->location == 'I') { 2070151378Snetchild if (verbose) 2071151378Snetchild printf("%u: skip, outdoor channel\n", 2072151378Snetchild freq); 2073151378Snetchild continue; 2074151378Snetchild } 2075151378Snetchild if ((flags & IEEE80211_CHAN_HT40) && 2076151378Snetchild prev != NULL && (freq - prev->ic_freq) < channelSep) { 2077151378Snetchild if (verbose) 2078151378Snetchild printf("%u: skip, only %u channel " 2079151378Snetchild "separation, need %d\n", freq, 2080151378Snetchild freq - prev->ic_freq, channelSep); 2081151378Snetchild continue; 2082151378Snetchild } 2083151378Snetchild if (ci->ic_nchans == IEEE80211_CHAN_MAX) { 2084151378Snetchild if (verbose) 2085151378Snetchild printf("%u: skip, channel table full\n", 2086151378Snetchild freq); 2087151378Snetchild break; 2088151378Snetchild } 2089151378Snetchild c = &ci->ic_chans[ci->ic_nchans++]; 2090151378Snetchild memset(c, 0, sizeof(*c)); 2091151378Snetchild c->ic_freq = freq; 2092151378Snetchild c->ic_flags = flags; 2093151378Snetchild if (c->ic_flags & IEEE80211_CHAN_DFS) 2094151378Snetchild c->ic_maxregpower = nb->maxPowerDFS; 2095151378Snetchild else 2096151378Snetchild c->ic_maxregpower = nb->maxPower; 2097151378Snetchild if (verbose) { 2098151378Snetchild printf("[%3d] add freq %u ", 2099151378Snetchild ci->ic_nchans-1, c->ic_freq); 2100151378Snetchild printb("flags", c->ic_flags, IEEE80211_CHAN_BITS); 2101151378Snetchild printf(" power %u\n", c->ic_maxregpower); 2102151378Snetchild } 2103151378Snetchild /* NB: kernel fills in other fields */ 2104151378Snetchild prev = c; 2105151378Snetchild } 2106151378Snetchild } 2107151378Snetchild} 2108151378Snetchild 2109151378Snetchildstatic void 2110151378Snetchildregdomain_makechannels( 2111151378Snetchild struct ieee80211_regdomain_req *req, 2112151378Snetchild const struct ieee80211_devcaps_req *dc) 2113151378Snetchild{ 2114151378Snetchild struct regdata *rdp = getregdata(); 2115151378Snetchild const struct country *cc; 2116151378Snetchild const struct ieee80211_regdomain *reg = &req->rd; 2117151378Snetchild struct ieee80211req_chaninfo *ci = &req->chaninfo; 2118151378Snetchild const struct regdomain *rd; 2119151378Snetchild 2120151378Snetchild /* 2121151378Snetchild * Locate construction table for new channel list. We treat 2122151378Snetchild * the regdomain/SKU as definitive so a country can be in 2123151378Snetchild * multiple with different properties (e.g. US in FCC+FCC3). 2124151378Snetchild * If no regdomain is specified then we fallback on the country 2125151378Snetchild * code to find the associated regdomain since countries always 2126151378Snetchild * belong to at least one regdomain. 2127151378Snetchild */ 2128151378Snetchild if (reg->regdomain == 0) { 2129151378Snetchild cc = lib80211_country_findbycc(rdp, reg->country); 2130151378Snetchild if (cc == NULL) 2131151378Snetchild errx(1, "internal error, country %d not found", 2132151378Snetchild reg->country); 2133151378Snetchild rd = cc->rd; 2134151378Snetchild } else 2135151378Snetchild rd = lib80211_regdomain_findbysku(rdp, reg->regdomain); 2136151378Snetchild if (rd == NULL) 2137151378Snetchild errx(1, "internal error, regdomain %d not found", 2138151378Snetchild reg->regdomain); 2139151378Snetchild if (rd->sku != SKU_DEBUG) { 2140151378Snetchild /* 2141151378Snetchild * regdomain_addchans incrememnts the channel count for 2142151378Snetchild * each channel it adds so initialize ic_nchans to zero. 2143151378Snetchild * Note that we know we have enough space to hold all possible 2144151378Snetchild * channels because the devcaps list size was used to 2145151378Snetchild * allocate our request. 2146151378Snetchild */ 2147151378Snetchild ci->ic_nchans = 0; 2148151378Snetchild if (!LIST_EMPTY(&rd->bands_11b)) 2149151378Snetchild regdomain_addchans(ci, &rd->bands_11b, reg, 2150151378Snetchild IEEE80211_CHAN_B, &dc->dc_chaninfo); 2151151378Snetchild if (!LIST_EMPTY(&rd->bands_11g)) 2152151378Snetchild regdomain_addchans(ci, &rd->bands_11g, reg, 2153151378Snetchild IEEE80211_CHAN_G, &dc->dc_chaninfo); 2154151378Snetchild if (!LIST_EMPTY(&rd->bands_11a)) 2155151378Snetchild regdomain_addchans(ci, &rd->bands_11a, reg, 2156151378Snetchild IEEE80211_CHAN_A, &dc->dc_chaninfo); 2157151378Snetchild if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) { 2158151378Snetchild regdomain_addchans(ci, &rd->bands_11na, reg, 2159151378Snetchild IEEE80211_CHAN_A | IEEE80211_CHAN_HT20, 2160151378Snetchild &dc->dc_chaninfo); 2161151378Snetchild if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) { 2162151378Snetchild regdomain_addchans(ci, &rd->bands_11na, reg, 2163151378Snetchild IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U, 2164151378Snetchild &dc->dc_chaninfo); 2165151378Snetchild regdomain_addchans(ci, &rd->bands_11na, reg, 2166151378Snetchild IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D, 2167151378Snetchild &dc->dc_chaninfo); 2168151378Snetchild } 2169151378Snetchild } 2170151378Snetchild if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) { 2171151378Snetchild regdomain_addchans(ci, &rd->bands_11ng, reg, 2172151378Snetchild IEEE80211_CHAN_G | IEEE80211_CHAN_HT20, 2173151378Snetchild &dc->dc_chaninfo); 2174151378Snetchild if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) { 2175151378Snetchild regdomain_addchans(ci, &rd->bands_11ng, reg, 2176151378Snetchild IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U, 2177151378Snetchild &dc->dc_chaninfo); 2178151378Snetchild regdomain_addchans(ci, &rd->bands_11ng, reg, 2179151378Snetchild IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D, 2180151378Snetchild &dc->dc_chaninfo); 2181151378Snetchild } 2182151378Snetchild } 2183151378Snetchild qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]), 2184151378Snetchild regdomain_sort); 2185151378Snetchild } else 2186151378Snetchild memcpy(ci, &dc->dc_chaninfo, 2187151378Snetchild IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo)); 2188151378Snetchild} 2189151378Snetchild 2190151378Snetchildstatic void 2191151378Snetchildlist_countries(void) 2192151378Snetchild{ 2193151378Snetchild struct regdata *rdp = getregdata(); 2194151378Snetchild const struct country *cp; 2195151378Snetchild const struct regdomain *dp; 2196151378Snetchild int i; 2197151378Snetchild 2198151378Snetchild i = 0; 2199151378Snetchild printf("\nCountry codes:\n"); 2200151378Snetchild LIST_FOREACH(cp, &rdp->countries, next) { 2201151378Snetchild printf("%2s %-15.15s%s", cp->isoname, 2202151378Snetchild cp->name, ((i+1)%4) == 0 ? "\n" : " "); 2203151378Snetchild i++; 2204151378Snetchild } 2205151378Snetchild i = 0; 2206151378Snetchild printf("\nRegulatory domains:\n"); 2207151378Snetchild LIST_FOREACH(dp, &rdp->domains, next) { 2208151378Snetchild printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " "); 2209151378Snetchild i++; 2210151378Snetchild } 2211151378Snetchild printf("\n"); 2212151378Snetchild} 2213151378Snetchild 2214151378Snetchildstatic void 2215151378Snetchilddefaultcountry(const struct regdomain *rd) 2216151378Snetchild{ 2217151378Snetchild struct regdata *rdp = getregdata(); 2218151378Snetchild const struct country *cc; 2219151378Snetchild 2220151378Snetchild cc = lib80211_country_findbycc(rdp, rd->cc->code); 2221151378Snetchild if (cc == NULL) 2222151378Snetchild errx(1, "internal error, ISO country code %d not " 2223151378Snetchild "defined for regdomain %s", rd->cc->code, rd->name); 2224151378Snetchild regdomain.country = cc->code; 2225151378Snetchild regdomain.isocc[0] = cc->isoname[0]; 2226151378Snetchild regdomain.isocc[1] = cc->isoname[1]; 2227151378Snetchild} 2228151378Snetchild 2229151378Snetchildstatic 2230151378SnetchildDECL_CMD_FUNC(set80211regdomain, val, d) 2231151378Snetchild{ 2232151378Snetchild struct regdata *rdp = getregdata(); 2233151378Snetchild const struct regdomain *rd; 2234151378Snetchild 2235151378Snetchild rd = lib80211_regdomain_findbyname(rdp, val); 2236151378Snetchild if (rd == NULL) { 2237151378Snetchild char *eptr; 2238151378Snetchild long sku = strtol(val, &eptr, 0); 2239151378Snetchild 2240151378Snetchild if (eptr != val) 2241151378Snetchild rd = lib80211_regdomain_findbysku(rdp, sku); 2242151378Snetchild if (eptr == val || rd == NULL) 2243151378Snetchild errx(1, "unknown regdomain %s", val); 2244151378Snetchild } 2245151378Snetchild getregdomain(s); 2246151378Snetchild regdomain.regdomain = rd->sku; 2247151378Snetchild if (regdomain.country == 0 && rd->cc != NULL) { 2248151378Snetchild /* 2249151378Snetchild * No country code setup and there's a default 2250151378Snetchild * one for this regdomain fill it in. 2251151378Snetchild */ 2252151378Snetchild defaultcountry(rd); 2253151378Snetchild } 2254151378Snetchild callback_register(setregdomain_cb, ®domain); 2255151378Snetchild} 2256151378Snetchild 2257151378Snetchildstatic 2258151378SnetchildDECL_CMD_FUNC(set80211country, val, d) 2259151378Snetchild{ 2260151378Snetchild struct regdata *rdp = getregdata(); 2261151378Snetchild const struct country *cc; 2262151378Snetchild 2263151378Snetchild cc = lib80211_country_findbyname(rdp, val); 2264151378Snetchild if (cc == NULL) { 2265151378Snetchild char *eptr; 2266151378Snetchild long code = strtol(val, &eptr, 0); 2267151378Snetchild 2268151378Snetchild if (eptr != val) 2269151378Snetchild cc = lib80211_country_findbycc(rdp, code); 2270151378Snetchild if (eptr == val || cc == NULL) 2271151378Snetchild errx(1, "unknown ISO country code %s", val); 2272151378Snetchild } 2273151378Snetchild getregdomain(s); 2274151378Snetchild regdomain.regdomain = cc->rd->sku; 2275151378Snetchild regdomain.country = cc->code; 2276151378Snetchild regdomain.isocc[0] = cc->isoname[0]; 2277151378Snetchild regdomain.isocc[1] = cc->isoname[1]; 2278151378Snetchild callback_register(setregdomain_cb, ®domain); 2279151378Snetchild} 2280151378Snetchild 2281151378Snetchildstatic void 2282151378Snetchildset80211location(const char *val, int d, int s, const struct afswtch *rafp) 2283151378Snetchild{ 2284151378Snetchild getregdomain(s); 2285151378Snetchild regdomain.location = d; 2286151378Snetchild callback_register(setregdomain_cb, ®domain); 2287151378Snetchild} 2288151378Snetchild 2289151378Snetchildstatic void 2290151378Snetchildset80211ecm(const char *val, int d, int s, const struct afswtch *rafp) 2291151378Snetchild{ 2292151378Snetchild getregdomain(s); 2293151378Snetchild regdomain.ecm = d; 2294151378Snetchild callback_register(setregdomain_cb, ®domain); 2295151378Snetchild} 2296151378Snetchild 2297151378Snetchildstatic void 2298151378SnetchildLINE_INIT(char c) 2299151378Snetchild{ 2300151378Snetchild spacer = c; 2301151378Snetchild if (c == '\t') 2302151378Snetchild col = 8; 2303151378Snetchild else 2304151378Snetchild col = 1; 2305151378Snetchild} 2306151378Snetchild 2307151378Snetchildstatic void 2308151378SnetchildLINE_BREAK(void) 2309151378Snetchild{ 2310151378Snetchild if (spacer != '\t') { 2311151378Snetchild printf("\n"); 2312151378Snetchild spacer = '\t'; 2313151378Snetchild } 2314151378Snetchild col = 8; /* 8-col tab */ 2315151378Snetchild} 2316151378Snetchild 2317151378Snetchildstatic void 2318151378SnetchildLINE_CHECK(const char *fmt, ...) 2319151378Snetchild{ 2320151378Snetchild char buf[80]; 2321151378Snetchild va_list ap; 2322151378Snetchild int n; 2323151378Snetchild 2324151378Snetchild va_start(ap, fmt); 2325151378Snetchild n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap); 2326151378Snetchild va_end(ap); 2327151378Snetchild col += 1+n; 2328151378Snetchild if (col > MAXCOL) { 2329151378Snetchild LINE_BREAK(); 2330151378Snetchild col += n; 2331151378Snetchild } 2332151378Snetchild buf[0] = spacer; 2333151378Snetchild printf("%s", buf); 2334151378Snetchild spacer = ' '; 2335151378Snetchild} 2336151378Snetchild 2337151378Snetchildstatic int 2338151378Snetchildgetmaxrate(const uint8_t rates[15], uint8_t nrates) 2339151378Snetchild{ 2340151378Snetchild int i, maxrate = -1; 2341151378Snetchild 2342151378Snetchild for (i = 0; i < nrates; i++) { 2343151378Snetchild int rate = rates[i] & IEEE80211_RATE_VAL; 2344151378Snetchild if (rate > maxrate) 2345151378Snetchild maxrate = rate; 2346151378Snetchild } 2347151378Snetchild return maxrate / 2; 2348151378Snetchild} 2349151378Snetchild 2350151378Snetchildstatic const char * 2351151378Snetchildgetcaps(int capinfo) 2352151378Snetchild{ 2353151378Snetchild static char capstring[32]; 2354151378Snetchild char *cp = capstring; 2355151378Snetchild 2356151378Snetchild if (capinfo & IEEE80211_CAPINFO_ESS) 2357151378Snetchild *cp++ = 'E'; 2358151378Snetchild if (capinfo & IEEE80211_CAPINFO_IBSS) 2359151378Snetchild *cp++ = 'I'; 2360151378Snetchild if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE) 2361151378Snetchild *cp++ = 'c'; 2362151378Snetchild if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ) 2363151378Snetchild *cp++ = 'C'; 2364151378Snetchild if (capinfo & IEEE80211_CAPINFO_PRIVACY) 2365151378Snetchild *cp++ = 'P'; 2366151378Snetchild if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) 2367151378Snetchild *cp++ = 'S'; 2368151378Snetchild if (capinfo & IEEE80211_CAPINFO_PBCC) 2369151378Snetchild *cp++ = 'B'; 2370151378Snetchild if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY) 2371151378Snetchild *cp++ = 'A'; 2372151378Snetchild if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) 2373151378Snetchild *cp++ = 's'; 2374151378Snetchild if (capinfo & IEEE80211_CAPINFO_RSN) 2375151378Snetchild *cp++ = 'R'; 2376151378Snetchild if (capinfo & IEEE80211_CAPINFO_DSSSOFDM) 2377151378Snetchild *cp++ = 'D'; 2378151378Snetchild *cp = '\0'; 2379151378Snetchild return capstring; 2380151378Snetchild} 2381151378Snetchild 2382151378Snetchildstatic const char * 2383151378Snetchildgetflags(int flags) 2384151378Snetchild{ 2385151378Snetchild static char flagstring[32]; 2386151378Snetchild char *cp = flagstring; 2387151378Snetchild 2388151378Snetchild if (flags & IEEE80211_NODE_AUTH) 2389151378Snetchild *cp++ = 'A'; 2390151378Snetchild if (flags & IEEE80211_NODE_QOS) 2391151378Snetchild *cp++ = 'Q'; 2392151378Snetchild if (flags & IEEE80211_NODE_ERP) 2393151378Snetchild *cp++ = 'E'; 2394151378Snetchild if (flags & IEEE80211_NODE_PWR_MGT) 2395151378Snetchild *cp++ = 'P'; 2396151378Snetchild if (flags & IEEE80211_NODE_HT) { 2397151378Snetchild *cp++ = 'H'; 2398151378Snetchild if (flags & IEEE80211_NODE_HTCOMPAT) 2399151378Snetchild *cp++ = '+'; 2400151378Snetchild } 2401151378Snetchild if (flags & IEEE80211_NODE_WPS) 2402151378Snetchild *cp++ = 'W'; 2403151378Snetchild if (flags & IEEE80211_NODE_TSN) 2404151378Snetchild *cp++ = 'N'; 2405151378Snetchild if (flags & IEEE80211_NODE_AMPDU_TX) 2406151378Snetchild *cp++ = 'T'; 2407151378Snetchild if (flags & IEEE80211_NODE_AMPDU_RX) 2408151378Snetchild *cp++ = 'R'; 2409151378Snetchild if (flags & IEEE80211_NODE_MIMO_PS) { 2410151378Snetchild *cp++ = 'M'; 2411151378Snetchild if (flags & IEEE80211_NODE_MIMO_RTS) 2412151378Snetchild *cp++ = '+'; 2413151378Snetchild } 2414151378Snetchild if (flags & IEEE80211_NODE_RIFS) 2415151378Snetchild *cp++ = 'I'; 2416151378Snetchild if (flags & IEEE80211_NODE_SGI40) { 2417151378Snetchild *cp++ = 'S'; 2418151378Snetchild if (flags & IEEE80211_NODE_SGI20) 2419151378Snetchild *cp++ = '+'; 2420151378Snetchild } else if (flags & IEEE80211_NODE_SGI20) 2421151378Snetchild *cp++ = 's'; 2422151378Snetchild if (flags & IEEE80211_NODE_AMSDU_TX) 2423151378Snetchild *cp++ = 't'; 2424151378Snetchild if (flags & IEEE80211_NODE_AMSDU_RX) 2425151378Snetchild *cp++ = 'r'; 2426151378Snetchild *cp = '\0'; 2427151378Snetchild return flagstring; 2428151378Snetchild} 2429151378Snetchild 2430151378Snetchildstatic void 2431151378Snetchildprintie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) 2432151378Snetchild{ 2433151378Snetchild printf("%s", tag); 2434151378Snetchild if (verbose) { 2435151378Snetchild maxlen -= strlen(tag)+2; 2436151378Snetchild if (2*ielen > maxlen) 2437151378Snetchild maxlen--; 2438151378Snetchild printf("<"); 2439151378Snetchild for (; ielen > 0; ie++, ielen--) { 2440151378Snetchild if (maxlen-- <= 0) 2441151378Snetchild break; 2442151378Snetchild printf("%02x", *ie); 2443151378Snetchild } 2444151378Snetchild if (ielen != 0) 2445151378Snetchild printf("-"); 2446151378Snetchild printf(">"); 2447151378Snetchild } 2448151378Snetchild} 2449151378Snetchild 2450151378Snetchild#define LE_READ_2(p) \ 2451151378Snetchild ((u_int16_t) \ 2452151378Snetchild ((((const u_int8_t *)(p))[0] ) | \ 2453151378Snetchild (((const u_int8_t *)(p))[1] << 8))) 2454151378Snetchild#define LE_READ_4(p) \ 2455151378Snetchild ((u_int32_t) \ 2456151378Snetchild ((((const u_int8_t *)(p))[0] ) | \ 2457151378Snetchild (((const u_int8_t *)(p))[1] << 8) | \ 2458151378Snetchild (((const u_int8_t *)(p))[2] << 16) | \ 2459151378Snetchild (((const u_int8_t *)(p))[3] << 24))) 2460151378Snetchild 2461151378Snetchild/* 2462151378Snetchild * NB: The decoding routines assume a properly formatted ie 2463151378Snetchild * which should be safe as the kernel only retains them 2464151378Snetchild * if they parse ok. 2465151378Snetchild */ 2466151378Snetchild 2467151378Snetchildstatic void 2468151378Snetchildprintwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2469151378Snetchild{ 2470151378Snetchild#define MS(_v, _f) (((_v) & _f) >> _f##_S) 2471151378Snetchild static const char *acnames[] = { "BE", "BK", "VO", "VI" }; 2472151378Snetchild const struct ieee80211_wme_param *wme = 2473151378Snetchild (const struct ieee80211_wme_param *) ie; 2474151378Snetchild int i; 2475151378Snetchild 2476151378Snetchild printf("%s", tag); 2477151378Snetchild if (!verbose) 2478151378Snetchild return; 2479151378Snetchild printf("<qosinfo 0x%x", wme->param_qosInfo); 2480151378Snetchild ie += offsetof(struct ieee80211_wme_param, params_acParams); 2481151378Snetchild for (i = 0; i < WME_NUM_AC; i++) { 2482151378Snetchild const struct ieee80211_wme_acparams *ac = 2483151378Snetchild &wme->params_acParams[i]; 2484151378Snetchild 2485151378Snetchild printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]" 2486151378Snetchild , acnames[i] 2487151378Snetchild , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : "" 2488151378Snetchild , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN) 2489151378Snetchild , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN) 2490151378Snetchild , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX) 2491151378Snetchild , LE_READ_2(&ac->acp_txop) 2492151378Snetchild ); 2493151378Snetchild } 2494151378Snetchild printf(">"); 2495151378Snetchild#undef MS 2496151378Snetchild} 2497151378Snetchild 2498151378Snetchildstatic void 2499151378Snetchildprintwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2500151378Snetchild{ 2501151378Snetchild printf("%s", tag); 2502151378Snetchild if (verbose) { 2503151378Snetchild const struct ieee80211_wme_info *wme = 2504151378Snetchild (const struct ieee80211_wme_info *) ie; 2505151378Snetchild printf("<version 0x%x info 0x%x>", 2506151378Snetchild wme->wme_version, wme->wme_info); 2507151378Snetchild } 2508151378Snetchild} 2509151378Snetchild 2510151378Snetchildstatic void 2511151378Snetchildprinthtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2512151378Snetchild{ 2513151378Snetchild printf("%s", tag); 2514151378Snetchild if (verbose) { 2515151378Snetchild const struct ieee80211_ie_htcap *htcap = 2516151378Snetchild (const struct ieee80211_ie_htcap *) ie; 2517151378Snetchild const char *sep; 2518151378Snetchild int i, j; 2519151378Snetchild 2520151378Snetchild printf("<cap 0x%x param 0x%x", 2521151378Snetchild LE_READ_2(&htcap->hc_cap), htcap->hc_param); 2522151378Snetchild printf(" mcsset["); 2523151378Snetchild sep = ""; 2524151378Snetchild for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) 2525151378Snetchild if (isset(htcap->hc_mcsset, i)) { 2526151378Snetchild for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) 2527151378Snetchild if (isclr(htcap->hc_mcsset, j)) 2528151378Snetchild break; 2529151378Snetchild j--; 2530151378Snetchild if (i == j) 2531151378Snetchild printf("%s%u", sep, i); 2532151378Snetchild else 2533151378Snetchild printf("%s%u-%u", sep, i, j); 2534151378Snetchild i += j-i; 2535151378Snetchild sep = ","; 2536151378Snetchild } 2537151378Snetchild printf("] extcap 0x%x txbf 0x%x antenna 0x%x>", 2538151378Snetchild LE_READ_2(&htcap->hc_extcap), 2539151378Snetchild LE_READ_4(&htcap->hc_txbf), 2540151378Snetchild htcap->hc_antenna); 2541151378Snetchild } 2542151378Snetchild} 2543151378Snetchild 2544151378Snetchildstatic void 2545151378Snetchildprinthtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2546151378Snetchild{ 2547151378Snetchild printf("%s", tag); 2548151378Snetchild if (verbose) { 2549151378Snetchild const struct ieee80211_ie_htinfo *htinfo = 2550151378Snetchild (const struct ieee80211_ie_htinfo *) ie; 2551151378Snetchild const char *sep; 2552151378Snetchild int i, j; 2553151378Snetchild 2554151378Snetchild printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel, 2555151378Snetchild htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3, 2556151378Snetchild LE_READ_2(&htinfo->hi_byte45)); 2557151378Snetchild printf(" basicmcs["); 2558151378Snetchild sep = ""; 2559151378Snetchild for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) 2560151378Snetchild if (isset(htinfo->hi_basicmcsset, i)) { 2561151378Snetchild for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) 2562151378Snetchild if (isclr(htinfo->hi_basicmcsset, j)) 2563151378Snetchild break; 2564151378Snetchild j--; 2565151378Snetchild if (i == j) 2566151378Snetchild printf("%s%u", sep, i); 2567151378Snetchild else 2568151378Snetchild printf("%s%u-%u", sep, i, j); 2569151378Snetchild i += j-i; 2570151378Snetchild sep = ","; 2571151378Snetchild } 2572151378Snetchild printf("]>"); 2573151378Snetchild } 2574151378Snetchild} 2575151378Snetchild 2576151378Snetchildstatic void 2577151378Snetchildprintathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2578151378Snetchild{ 2579151378Snetchild 2580151378Snetchild printf("%s", tag); 2581151378Snetchild if (verbose) { 2582151378Snetchild const struct ieee80211_ath_ie *ath = 2583151378Snetchild (const struct ieee80211_ath_ie *)ie; 2584151378Snetchild 2585151378Snetchild printf("<"); 2586151378Snetchild if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME) 2587151378Snetchild printf("DTURBO,"); 2588151378Snetchild if (ath->ath_capability & ATHEROS_CAP_COMPRESSION) 2589151378Snetchild printf("COMP,"); 2590151378Snetchild if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME) 2591151378Snetchild printf("FF,"); 2592151378Snetchild if (ath->ath_capability & ATHEROS_CAP_XR) 2593151378Snetchild printf("XR,"); 2594151378Snetchild if (ath->ath_capability & ATHEROS_CAP_AR) 2595151378Snetchild printf("AR,"); 2596151378Snetchild if (ath->ath_capability & ATHEROS_CAP_BURST) 2597151378Snetchild printf("BURST,"); 2598151378Snetchild if (ath->ath_capability & ATHEROS_CAP_WME) 2599151378Snetchild printf("WME,"); 2600151378Snetchild if (ath->ath_capability & ATHEROS_CAP_BOOST) 2601151378Snetchild printf("BOOST,"); 2602151378Snetchild printf("0x%x>", LE_READ_2(ath->ath_defkeyix)); 2603151378Snetchild } 2604151378Snetchild} 2605151378Snetchild 2606151378Snetchild 2607151378Snetchildstatic void 2608151378Snetchildprintmeshconf(const char *tag, const uint8_t *ie, size_t ielen, int maxlen) 2609151378Snetchild{ 2610151378Snetchild#define MATCHOUI(field, oui, string) \ 2611151378Snetchilddo { \ 2612151378Snetchild if (memcmp(field, oui, 4) == 0) \ 2613151378Snetchild printf("%s", string); \ 2614151378Snetchild} while (0) 2615151378Snetchild 2616151378Snetchild printf("%s", tag); 2617151378Snetchild if (verbose) { 2618151378Snetchild const struct ieee80211_meshconf_ie *mconf = 2619151378Snetchild (const struct ieee80211_meshconf_ie *)ie; 2620151378Snetchild printf("<PATH:"); 2621151378Snetchild if (mconf->conf_pselid == IEEE80211_MESHCONF_PATH_HWMP) 2622151378Snetchild printf("HWMP"); 2623151378Snetchild else 2624151378Snetchild printf("UNKNOWN"); 2625151378Snetchild printf(" LINK:"); 2626151378Snetchild if (mconf->conf_pmetid == IEEE80211_MESHCONF_METRIC_AIRTIME) 2627151378Snetchild printf("AIRTIME"); 2628151378Snetchild else 2629151378Snetchild printf("UNKNOWN"); 2630151378Snetchild printf(" CONGESTION:"); 2631151378Snetchild if (mconf->conf_ccid == IEEE80211_MESHCONF_CC_DISABLED) 2632151378Snetchild printf("DISABLED"); 2633151378Snetchild else 2634151378Snetchild printf("UNKNOWN"); 2635151378Snetchild printf(" SYNC:"); 2636151378Snetchild if (mconf->conf_syncid == IEEE80211_MESHCONF_SYNC_NEIGHOFF) 2637151378Snetchild printf("NEIGHOFF"); 2638151378Snetchild else 2639151378Snetchild printf("UNKNOWN"); 2640151378Snetchild printf(" AUTH:"); 2641151378Snetchild if (mconf->conf_authid == IEEE80211_MESHCONF_AUTH_DISABLED) 2642151378Snetchild printf("DISABLED"); 2643151378Snetchild else 2644151378Snetchild printf("UNKNOWN"); 2645151378Snetchild printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form, 2646151378Snetchild mconf->conf_cap); 2647151378Snetchild } 2648151378Snetchild#undef MATCHOUI 2649151378Snetchild} 2650151378Snetchild 2651151378Snetchildstatic const char * 2652151378Snetchildwpa_cipher(const u_int8_t *sel) 2653151378Snetchild{ 2654151378Snetchild#define WPA_SEL(x) (((x)<<24)|WPA_OUI) 2655151378Snetchild u_int32_t w = LE_READ_4(sel); 2656151378Snetchild 2657151378Snetchild switch (w) { 2658151378Snetchild case WPA_SEL(WPA_CSE_NULL): 2659151378Snetchild return "NONE"; 2660151378Snetchild case WPA_SEL(WPA_CSE_WEP40): 2661151378Snetchild return "WEP40"; 2662151378Snetchild case WPA_SEL(WPA_CSE_WEP104): 2663151378Snetchild return "WEP104"; 2664151378Snetchild case WPA_SEL(WPA_CSE_TKIP): 2665151378Snetchild return "TKIP"; 2666151378Snetchild case WPA_SEL(WPA_CSE_CCMP): 2667151378Snetchild return "AES-CCMP"; 2668151378Snetchild } 2669151378Snetchild return "?"; /* NB: so 1<< is discarded */ 2670151378Snetchild#undef WPA_SEL 2671151378Snetchild} 2672151378Snetchild 2673151378Snetchildstatic const char * 2674151378Snetchildwpa_keymgmt(const u_int8_t *sel) 2675151378Snetchild{ 2676151378Snetchild#define WPA_SEL(x) (((x)<<24)|WPA_OUI) 2677151378Snetchild u_int32_t w = LE_READ_4(sel); 2678151378Snetchild 2679151378Snetchild switch (w) { 2680151378Snetchild case WPA_SEL(WPA_ASE_8021X_UNSPEC): 2681151378Snetchild return "8021X-UNSPEC"; 2682151378Snetchild case WPA_SEL(WPA_ASE_8021X_PSK): 2683151378Snetchild return "8021X-PSK"; 2684151378Snetchild case WPA_SEL(WPA_ASE_NONE): 2685151378Snetchild return "NONE"; 2686151378Snetchild } 2687151378Snetchild return "?"; 2688151378Snetchild#undef WPA_SEL 2689151378Snetchild} 2690151378Snetchild 2691151378Snetchildstatic void 2692151378Snetchildprintwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2693151378Snetchild{ 2694151378Snetchild u_int8_t len = ie[1]; 2695151378Snetchild 2696151378Snetchild printf("%s", tag); 2697151378Snetchild if (verbose) { 2698151378Snetchild const char *sep; 2699151378Snetchild int n; 2700151378Snetchild 2701151378Snetchild ie += 6, len -= 4; /* NB: len is payload only */ 2702151378Snetchild 2703151378Snetchild printf("<v%u", LE_READ_2(ie)); 2704151378Snetchild ie += 2, len -= 2; 2705151378Snetchild 2706151378Snetchild printf(" mc:%s", wpa_cipher(ie)); 2707151378Snetchild ie += 4, len -= 4; 2708151378Snetchild 2709151378Snetchild /* unicast ciphers */ 2710151378Snetchild n = LE_READ_2(ie); 2711151378Snetchild ie += 2, len -= 2; 2712151378Snetchild sep = " uc:"; 2713151378Snetchild for (; n > 0; n--) { 2714151378Snetchild printf("%s%s", sep, wpa_cipher(ie)); 2715151378Snetchild ie += 4, len -= 4; 2716151378Snetchild sep = "+"; 2717151378Snetchild } 2718151378Snetchild 2719151378Snetchild /* key management algorithms */ 2720151378Snetchild n = LE_READ_2(ie); 2721151378Snetchild ie += 2, len -= 2; 2722151378Snetchild sep = " km:"; 2723151378Snetchild for (; n > 0; n--) { 2724151378Snetchild printf("%s%s", sep, wpa_keymgmt(ie)); 2725151378Snetchild ie += 4, len -= 4; 2726151378Snetchild sep = "+"; 2727151378Snetchild } 2728151378Snetchild 2729151378Snetchild if (len > 2) /* optional capabilities */ 2730151378Snetchild printf(", caps 0x%x", LE_READ_2(ie)); 2731151378Snetchild printf(">"); 2732151378Snetchild } 2733151378Snetchild} 2734151378Snetchild 2735151378Snetchildstatic const char * 2736151378Snetchildrsn_cipher(const u_int8_t *sel) 2737151378Snetchild{ 2738151378Snetchild#define RSN_SEL(x) (((x)<<24)|RSN_OUI) 2739151378Snetchild u_int32_t w = LE_READ_4(sel); 2740151378Snetchild 2741151378Snetchild switch (w) { 2742151378Snetchild case RSN_SEL(RSN_CSE_NULL): 2743151378Snetchild return "NONE"; 2744151378Snetchild case RSN_SEL(RSN_CSE_WEP40): 2745151378Snetchild return "WEP40"; 2746151378Snetchild case RSN_SEL(RSN_CSE_WEP104): 2747151378Snetchild return "WEP104"; 2748151378Snetchild case RSN_SEL(RSN_CSE_TKIP): 2749151378Snetchild return "TKIP"; 2750151378Snetchild case RSN_SEL(RSN_CSE_CCMP): 2751151378Snetchild return "AES-CCMP"; 2752151378Snetchild case RSN_SEL(RSN_CSE_WRAP): 2753151378Snetchild return "AES-OCB"; 2754151378Snetchild } 2755151378Snetchild return "?"; 2756151378Snetchild#undef WPA_SEL 2757151378Snetchild} 2758151378Snetchild 2759151378Snetchildstatic const char * 2760151378Snetchildrsn_keymgmt(const u_int8_t *sel) 2761151378Snetchild{ 2762151378Snetchild#define RSN_SEL(x) (((x)<<24)|RSN_OUI) 2763151378Snetchild u_int32_t w = LE_READ_4(sel); 2764151378Snetchild 2765151378Snetchild switch (w) { 2766151378Snetchild case RSN_SEL(RSN_ASE_8021X_UNSPEC): 2767151378Snetchild return "8021X-UNSPEC"; 2768151378Snetchild case RSN_SEL(RSN_ASE_8021X_PSK): 2769151378Snetchild return "8021X-PSK"; 2770151378Snetchild case RSN_SEL(RSN_ASE_NONE): 2771151378Snetchild return "NONE"; 2772151378Snetchild } 2773151378Snetchild return "?"; 2774151378Snetchild#undef RSN_SEL 2775151378Snetchild} 2776151378Snetchild 2777151378Snetchildstatic void 2778151378Snetchildprintrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2779151378Snetchild{ 2780151378Snetchild printf("%s", tag); 2781151378Snetchild if (verbose) { 2782151378Snetchild const char *sep; 2783151378Snetchild int n; 2784151378Snetchild 2785151378Snetchild ie += 2, ielen -= 2; 2786151378Snetchild 2787151378Snetchild printf("<v%u", LE_READ_2(ie)); 2788151378Snetchild ie += 2, ielen -= 2; 2789151378Snetchild 2790151378Snetchild printf(" mc:%s", rsn_cipher(ie)); 2791151378Snetchild ie += 4, ielen -= 4; 2792151378Snetchild 2793151378Snetchild /* unicast ciphers */ 2794151378Snetchild n = LE_READ_2(ie); 2795151378Snetchild ie += 2, ielen -= 2; 2796151378Snetchild sep = " uc:"; 2797151378Snetchild for (; n > 0; n--) { 2798151378Snetchild printf("%s%s", sep, rsn_cipher(ie)); 2799151378Snetchild ie += 4, ielen -= 4; 2800151378Snetchild sep = "+"; 2801151378Snetchild } 2802151378Snetchild 2803151378Snetchild /* key management algorithms */ 2804151378Snetchild n = LE_READ_2(ie); 2805151378Snetchild ie += 2, ielen -= 2; 2806151378Snetchild sep = " km:"; 2807151378Snetchild for (; n > 0; n--) { 2808151378Snetchild printf("%s%s", sep, rsn_keymgmt(ie)); 2809151378Snetchild ie += 4, ielen -= 4; 2810151378Snetchild sep = "+"; 2811151378Snetchild } 2812151378Snetchild 2813151378Snetchild if (ielen > 2) /* optional capabilities */ 2814151378Snetchild printf(", caps 0x%x", LE_READ_2(ie)); 2815151378Snetchild /* XXXPMKID */ 2816151378Snetchild printf(">"); 2817151378Snetchild } 2818151378Snetchild} 2819151378Snetchild 2820151378Snetchild/* XXX move to a public include file */ 2821151378Snetchild#define IEEE80211_WPS_DEV_PASS_ID 0x1012 2822151378Snetchild#define IEEE80211_WPS_SELECTED_REG 0x1041 2823151378Snetchild#define IEEE80211_WPS_SETUP_STATE 0x1044 2824151378Snetchild#define IEEE80211_WPS_UUID_E 0x1047 2825151378Snetchild#define IEEE80211_WPS_VERSION 0x104a 2826151378Snetchild 2827151378Snetchild#define BE_READ_2(p) \ 2828151378Snetchild ((u_int16_t) \ 2829151378Snetchild ((((const u_int8_t *)(p))[1] ) | \ 2830151378Snetchild (((const u_int8_t *)(p))[0] << 8))) 2831151378Snetchild 2832151378Snetchildstatic void 2833151378Snetchildprintwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2834151378Snetchild{ 2835151378Snetchild#define N(a) (sizeof(a) / sizeof(a[0])) 2836151378Snetchild u_int8_t len = ie[1]; 2837151378Snetchild 2838151378Snetchild printf("%s", tag); 2839151378Snetchild if (verbose) { 2840151378Snetchild static const char *dev_pass_id[] = { 2841151378Snetchild "D", /* Default (PIN) */ 2842151378Snetchild "U", /* User-specified */ 2843151378Snetchild "M", /* Machine-specified */ 2844151378Snetchild "K", /* Rekey */ 2845151378Snetchild "P", /* PushButton */ 2846151378Snetchild "R" /* Registrar-specified */ 2847151378Snetchild }; 2848151378Snetchild int n; 2849151378Snetchild 2850151378Snetchild ie +=6, len -= 4; /* NB: len is payload only */ 2851151378Snetchild 2852151378Snetchild /* WPS IE in Beacon and Probe Resp frames have different fields */ 2853151378Snetchild printf("<"); 2854151378Snetchild while (len) { 2855151378Snetchild uint16_t tlv_type = BE_READ_2(ie); 2856151378Snetchild uint16_t tlv_len = BE_READ_2(ie + 2); 2857151378Snetchild 2858151378Snetchild ie += 4, len -= 4; 2859151378Snetchild 2860151378Snetchild switch (tlv_type) { 2861151378Snetchild case IEEE80211_WPS_VERSION: 2862151378Snetchild printf("v:%d.%d", *ie >> 4, *ie & 0xf); 2863151378Snetchild break; 2864151378Snetchild case IEEE80211_WPS_SETUP_STATE: 2865151378Snetchild /* Only 1 and 2 are valid */ 2866151378Snetchild if (*ie == 0 || *ie >= 3) 2867151378Snetchild printf(" state:B"); 2868151378Snetchild else 2869151378Snetchild printf(" st:%s", *ie == 1 ? "N" : "C"); 2870151378Snetchild break; 2871151378Snetchild case IEEE80211_WPS_SELECTED_REG: 2872151378Snetchild printf(" sel:%s", *ie ? "T" : "F"); 2873151378Snetchild break; 2874151378Snetchild case IEEE80211_WPS_DEV_PASS_ID: 2875151378Snetchild n = LE_READ_2(ie); 2876151378Snetchild if (n < N(dev_pass_id)) 2877151378Snetchild printf(" dpi:%s", dev_pass_id[n]); 2878151378Snetchild break; 2879151378Snetchild case IEEE80211_WPS_UUID_E: 2880151378Snetchild printf(" uuid-e:"); 2881151378Snetchild for (n = 0; n < (tlv_len - 1); n++) 2882151378Snetchild printf("%02x-", ie[n]); 2883151378Snetchild printf("%02x", ie[n]); 2884151378Snetchild break; 2885151378Snetchild } 2886151378Snetchild ie += tlv_len, len -= tlv_len; 2887151378Snetchild } 2888151378Snetchild printf(">"); 2889151378Snetchild } 2890151378Snetchild#undef N 2891151378Snetchild} 2892151378Snetchild 2893151378Snetchildstatic void 2894151378Snetchildprinttdmaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2895151378Snetchild{ 2896151378Snetchild printf("%s", tag); 2897151378Snetchild if (verbose && ielen >= sizeof(struct ieee80211_tdma_param)) { 2898151378Snetchild const struct ieee80211_tdma_param *tdma = 2899151378Snetchild (const struct ieee80211_tdma_param *) ie; 2900151378Snetchild 2901151378Snetchild /* XXX tstamp */ 2902151378Snetchild printf("<v%u slot:%u slotcnt:%u slotlen:%u bintval:%u inuse:0x%x>", 2903151378Snetchild tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt, 2904151378Snetchild LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval, 2905151378Snetchild tdma->tdma_inuse[0]); 2906151378Snetchild } 2907151378Snetchild} 2908151378Snetchild 2909151378Snetchild/* 2910151378Snetchild * Copy the ssid string contents into buf, truncating to fit. If the 2911151378Snetchild * ssid is entirely printable then just copy intact. Otherwise convert 2912151378Snetchild * to hexadecimal. If the result is truncated then replace the last 2913151378Snetchild * three characters with "...". 2914151378Snetchild */ 2915151378Snetchildstatic int 2916151378Snetchildcopy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) 2917151378Snetchild{ 2918151378Snetchild const u_int8_t *p; 2919151378Snetchild size_t maxlen; 2920151378Snetchild int i; 2921151378Snetchild 2922151378Snetchild if (essid_len > bufsize) 2923151378Snetchild maxlen = bufsize; 2924151378Snetchild else 2925151378Snetchild maxlen = essid_len; 2926151378Snetchild /* determine printable or not */ 2927151378Snetchild for (i = 0, p = essid; i < maxlen; i++, p++) { 2928151378Snetchild if (*p < ' ' || *p > 0x7e) 2929151378Snetchild break; 2930151378Snetchild } 2931151378Snetchild if (i != maxlen) { /* not printable, print as hex */ 2932151378Snetchild if (bufsize < 3) 2933151378Snetchild return 0; 2934151378Snetchild strlcpy(buf, "0x", bufsize); 2935151378Snetchild bufsize -= 2; 2936151378Snetchild p = essid; 2937151378Snetchild for (i = 0; i < maxlen && bufsize >= 2; i++) { 2938151378Snetchild sprintf(&buf[2+2*i], "%02x", p[i]); 2939151378Snetchild bufsize -= 2; 2940151378Snetchild } 2941151378Snetchild if (i != essid_len) 2942151378Snetchild memcpy(&buf[2+2*i-3], "...", 3); 2943151378Snetchild } else { /* printable, truncate as needed */ 2944151378Snetchild memcpy(buf, essid, maxlen); 2945151378Snetchild if (maxlen != essid_len) 2946151378Snetchild memcpy(&buf[maxlen-3], "...", 3); 2947151378Snetchild } 2948151378Snetchild return maxlen; 2949151378Snetchild} 2950151378Snetchild 2951151378Snetchildstatic void 2952151378Snetchildprintssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2953151378Snetchild{ 2954151378Snetchild char ssid[2*IEEE80211_NWID_LEN+1]; 2955151378Snetchild 2956151378Snetchild printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid); 2957151378Snetchild} 2958151378Snetchild 2959151378Snetchildstatic void 2960151378Snetchildprintrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2961151378Snetchild{ 2962151378Snetchild const char *sep; 2963151378Snetchild int i; 2964151378Snetchild 2965151378Snetchild printf("%s", tag); 2966151378Snetchild sep = "<"; 2967151378Snetchild for (i = 2; i < ielen; i++) { 2968151378Snetchild printf("%s%s%d", sep, 2969151378Snetchild ie[i] & IEEE80211_RATE_BASIC ? "B" : "", 2970151378Snetchild ie[i] & IEEE80211_RATE_VAL); 2971151378Snetchild sep = ","; 2972151378Snetchild } 2973151378Snetchild printf(">"); 2974151378Snetchild} 2975151378Snetchild 2976151378Snetchildstatic void 2977151378Snetchildprintcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) 2978151378Snetchild{ 2979151378Snetchild const struct ieee80211_country_ie *cie = 2980151378Snetchild (const struct ieee80211_country_ie *) ie; 2981151378Snetchild int i, nbands, schan, nchan; 2982151378Snetchild 2983151378Snetchild printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]); 2984151378Snetchild nbands = (cie->len - 3) / sizeof(cie->band[0]); 2985151378Snetchild for (i = 0; i < nbands; i++) { 2986151378Snetchild schan = cie->band[i].schan; 2987151378Snetchild nchan = cie->band[i].nchan; 2988151378Snetchild if (nchan != 1) 2989151378Snetchild printf(" %u-%u,%u", schan, schan + nchan-1, 2990151378Snetchild cie->band[i].maxtxpwr); 2991151378Snetchild else 2992151378Snetchild printf(" %u,%u", schan, cie->band[i].maxtxpwr); 2993151378Snetchild } 2994151378Snetchild printf(">"); 2995151378Snetchild} 2996151378Snetchild 2997151378Snetchild/* unaligned little endian access */ 2998151378Snetchild#define LE_READ_4(p) \ 2999151378Snetchild ((u_int32_t) \ 3000151378Snetchild ((((const u_int8_t *)(p))[0] ) | \ 3001151378Snetchild (((const u_int8_t *)(p))[1] << 8) | \ 3002151378Snetchild (((const u_int8_t *)(p))[2] << 16) | \ 3003151378Snetchild (((const u_int8_t *)(p))[3] << 24))) 3004151378Snetchild 3005151378Snetchildstatic __inline int 3006151378Snetchildiswpaoui(const u_int8_t *frm) 3007151378Snetchild{ 3008151378Snetchild return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI); 3009151378Snetchild} 3010151378Snetchild 3011151378Snetchildstatic __inline int 3012151378Snetchildiswmeinfo(const u_int8_t *frm) 3013151378Snetchild{ 3014151378Snetchild return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 3015151378Snetchild frm[6] == WME_INFO_OUI_SUBTYPE; 3016151378Snetchild} 3017151378Snetchild 3018151378Snetchildstatic __inline int 3019151378Snetchildiswmeparam(const u_int8_t *frm) 3020151378Snetchild{ 3021151378Snetchild return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && 3022151378Snetchild frm[6] == WME_PARAM_OUI_SUBTYPE; 3023151378Snetchild} 3024151378Snetchild 3025151378Snetchildstatic __inline int 3026151378Snetchildisatherosoui(const u_int8_t *frm) 3027151378Snetchild{ 3028151378Snetchild return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); 3029151378Snetchild} 3030151378Snetchild 3031151378Snetchildstatic __inline int 3032151378Snetchildistdmaoui(const uint8_t *frm) 3033151378Snetchild{ 3034151378Snetchild return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI); 3035151378Snetchild} 3036151378Snetchild 3037151378Snetchildstatic __inline int 3038151378Snetchildiswpsoui(const uint8_t *frm) 3039151378Snetchild{ 3040151378Snetchild return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI); 3041151378Snetchild} 3042151378Snetchild 3043151378Snetchildstatic const char * 3044151378Snetchildiename(int elemid) 3045151378Snetchild{ 3046151378Snetchild switch (elemid) { 3047151378Snetchild case IEEE80211_ELEMID_FHPARMS: return " FHPARMS"; 3048151378Snetchild case IEEE80211_ELEMID_CFPARMS: return " CFPARMS"; 3049151378Snetchild case IEEE80211_ELEMID_TIM: return " TIM"; 3050151378Snetchild case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS"; 3051151378Snetchild case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE"; 3052151378Snetchild case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR"; 3053151378Snetchild case IEEE80211_ELEMID_PWRCAP: return " PWRCAP"; 3054151378Snetchild case IEEE80211_ELEMID_TPCREQ: return " TPCREQ"; 3055151378Snetchild case IEEE80211_ELEMID_TPCREP: return " TPCREP"; 3056151378Snetchild case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN"; 3057151378Snetchild case IEEE80211_ELEMID_CSA: return " CSA"; 3058151378Snetchild case IEEE80211_ELEMID_MEASREQ: return " MEASREQ"; 3059151378Snetchild case IEEE80211_ELEMID_MEASREP: return " MEASREP"; 3060151378Snetchild case IEEE80211_ELEMID_QUIET: return " QUIET"; 3061151378Snetchild case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS"; 3062151378Snetchild case IEEE80211_ELEMID_TPC: return " TPC"; 3063151378Snetchild case IEEE80211_ELEMID_CCKM: return " CCKM"; 3064151378Snetchild } 3065151378Snetchild return " ???"; 3066151378Snetchild} 3067151378Snetchild 3068151378Snetchildstatic void 3069151378Snetchildprinties(const u_int8_t *vp, int ielen, int maxcols) 3070151378Snetchild{ 3071151378Snetchild while (ielen > 0) { 3072151378Snetchild switch (vp[0]) { 3073151378Snetchild case IEEE80211_ELEMID_SSID: 3074151378Snetchild if (verbose) 3075151378Snetchild printssid(" SSID", vp, 2+vp[1], maxcols); 3076151378Snetchild break; 3077151378Snetchild case IEEE80211_ELEMID_RATES: 3078151378Snetchild case IEEE80211_ELEMID_XRATES: 3079151378Snetchild if (verbose) 3080151378Snetchild printrates(vp[0] == IEEE80211_ELEMID_RATES ? 3081151378Snetchild " RATES" : " XRATES", vp, 2+vp[1], maxcols); 3082151378Snetchild break; 3083151378Snetchild case IEEE80211_ELEMID_DSPARMS: 3084151378Snetchild if (verbose) 3085151378Snetchild printf(" DSPARMS<%u>", vp[2]); 3086151378Snetchild break; 3087151378Snetchild case IEEE80211_ELEMID_COUNTRY: 3088151378Snetchild if (verbose) 3089151378Snetchild printcountry(" COUNTRY", vp, 2+vp[1], maxcols); 3090151378Snetchild break; 3091151378Snetchild case IEEE80211_ELEMID_ERP: 3092151378Snetchild if (verbose) 3093151378Snetchild printf(" ERP<0x%x>", vp[2]); 3094151378Snetchild break; 3095151378Snetchild case IEEE80211_ELEMID_VENDOR: 3096151378Snetchild if (iswpaoui(vp)) 3097151378Snetchild printwpaie(" WPA", vp, 2+vp[1], maxcols); 3098151378Snetchild else if (iswmeinfo(vp)) 3099151378Snetchild printwmeinfo(" WME", vp, 2+vp[1], maxcols); 3100151378Snetchild else if (iswmeparam(vp)) 3101151378Snetchild printwmeparam(" WME", vp, 2+vp[1], maxcols); 3102151378Snetchild else if (isatherosoui(vp)) 3103151378Snetchild printathie(" ATH", vp, 2+vp[1], maxcols); 3104151378Snetchild else if (iswpsoui(vp)) 3105151378Snetchild printwpsie(" WPS", vp, 2+vp[1], maxcols); 3106151378Snetchild else if (istdmaoui(vp)) 3107151378Snetchild printtdmaie(" TDMA", vp, 2+vp[1], maxcols); 3108151378Snetchild else if (verbose) 3109151378Snetchild printie(" VEN", vp, 2+vp[1], maxcols); 3110151378Snetchild break; 3111151378Snetchild case IEEE80211_ELEMID_RSN: 3112151378Snetchild printrsnie(" RSN", vp, 2+vp[1], maxcols); 3113151378Snetchild break; 3114151378Snetchild case IEEE80211_ELEMID_HTCAP: 3115151378Snetchild printhtcap(" HTCAP", vp, 2+vp[1], maxcols); 3116151378Snetchild break; 3117151378Snetchild case IEEE80211_ELEMID_HTINFO: 3118151378Snetchild if (verbose) 3119151378Snetchild printhtinfo(" HTINFO", vp, 2+vp[1], maxcols); 3120151378Snetchild break; 3121151378Snetchild case IEEE80211_ELEMID_MESHID: 3122151378Snetchild if (verbose) 3123151378Snetchild printssid(" MESHID", vp, 2+vp[1], maxcols); 3124151378Snetchild break; 3125151378Snetchild case IEEE80211_ELEMID_MESHCONF: 3126151378Snetchild printmeshconf(" MESHCONF", vp, 2+vp[1], maxcols); 3127151378Snetchild break; 3128151378Snetchild default: 3129151378Snetchild if (verbose) 3130151378Snetchild printie(iename(vp[0]), vp, 2+vp[1], maxcols); 3131151378Snetchild break; 3132151378Snetchild } 3133151378Snetchild ielen -= 2+vp[1]; 3134151378Snetchild vp += 2+vp[1]; 3135151378Snetchild } 3136151378Snetchild} 3137151378Snetchild 3138151378Snetchildstatic void 3139151378Snetchildprintmimo(const struct ieee80211_mimo_info *mi) 3140151378Snetchild{ 3141151378Snetchild /* NB: don't muddy display unless there's something to show */ 3142151378Snetchild if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) { 3143151378Snetchild /* XXX ignore EVM for now */ 3144151378Snetchild printf(" (rssi %d:%d:%d nf %d:%d:%d)", 3145151378Snetchild mi->rssi[0], mi->rssi[1], mi->rssi[2], 3146151378Snetchild mi->noise[0], mi->noise[1], mi->noise[2]); 3147151378Snetchild } 3148151378Snetchild} 3149151378Snetchild 3150151378Snetchildstatic void 3151151378Snetchildlist_scan(int s) 3152151378Snetchild{ 3153151378Snetchild uint8_t buf[24*1024]; 3154151378Snetchild char ssid[IEEE80211_NWID_LEN+1]; 3155151378Snetchild const uint8_t *cp; 3156151378Snetchild int len, ssidmax, idlen; 3157151378Snetchild 3158151378Snetchild if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0) 3159151378Snetchild errx(1, "unable to get scan results"); 3160151378Snetchild if (len < sizeof(struct ieee80211req_scan_result)) 3161151378Snetchild return; 3162151378Snetchild 3163151378Snetchild getchaninfo(s); 3164151378Snetchild 3165151378Snetchild ssidmax = verbose ? IEEE80211_NWID_LEN - 1 : 14; 3166151378Snetchild printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n" 3167151378Snetchild , ssidmax, ssidmax, "SSID/MESH ID" 3168151378Snetchild , "BSSID" 3169151378Snetchild , "CHAN" 3170151378Snetchild , "RATE" 3171151378Snetchild , " S:N" 3172151378Snetchild , "INT" 3173151378Snetchild , "CAPS" 3174151378Snetchild ); 3175151378Snetchild cp = buf; 3176151378Snetchild do { 3177153939Snetchild const struct ieee80211req_scan_result *sr; 3178153939Snetchild const uint8_t *vp, *idp; 3179153939Snetchild 3180153939Snetchild sr = (const struct ieee80211req_scan_result *) cp; 3181153939Snetchild vp = cp + sr->isr_ie_off; 3182153939Snetchild if (sr->isr_meshid_len) { 3183153939Snetchild idp = vp + sr->isr_ssid_len; 3184153939Snetchild idlen = sr->isr_meshid_len; 3185153939Snetchild } else { 3186153939Snetchild idp = vp; 3187153939Snetchild idlen = sr->isr_ssid_len; 3188153939Snetchild } 3189153939Snetchild printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s" 3190153939Snetchild , ssidmax 3191153939Snetchild , copy_essid(ssid, ssidmax, idp, idlen) 3192153939Snetchild , ssid 3193153939Snetchild , ether_ntoa((const struct ether_addr *) sr->isr_bssid) 3194153939Snetchild , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags) 3195153939Snetchild , getmaxrate(sr->isr_rates, sr->isr_nrates) 3196151378Snetchild , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise 3197151378Snetchild , sr->isr_intval 3198151378Snetchild , getcaps(sr->isr_capinfo) 3199151378Snetchild ); 3200151378Snetchild printies(vp + sr->isr_ssid_len + sr->isr_meshid_len, 3201151378Snetchild sr->isr_ie_len, 24); 3202151378Snetchild printf("\n"); 3203151378Snetchild cp += sr->isr_len, len -= sr->isr_len; 3204151378Snetchild } while (len >= sizeof(struct ieee80211req_scan_result)); 3205151378Snetchild} 3206151378Snetchild 3207151378Snetchildstatic void 3208151378Snetchildscan_and_wait(int s) 3209151378Snetchild{ 3210151378Snetchild struct ieee80211_scan_req sr; 3211151378Snetchild struct ieee80211req ireq; 3212151378Snetchild int sroute; 3213151378Snetchild 3214151378Snetchild sroute = socket(PF_ROUTE, SOCK_RAW, 0); 3215151378Snetchild if (sroute < 0) { 3216151378Snetchild perror("socket(PF_ROUTE,SOCK_RAW)"); 3217151378Snetchild return; 3218151378Snetchild } 3219151378Snetchild (void) memset(&ireq, 0, sizeof(ireq)); 3220151378Snetchild (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3221151378Snetchild ireq.i_type = IEEE80211_IOC_SCAN_REQ; 3222151378Snetchild 3223151378Snetchild memset(&sr, 0, sizeof(sr)); 3224151378Snetchild sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE 3225151378Snetchild | IEEE80211_IOC_SCAN_BGSCAN 3226151378Snetchild | IEEE80211_IOC_SCAN_NOPICK 3227151378Snetchild | IEEE80211_IOC_SCAN_ONCE; 3228151378Snetchild sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; 3229151378Snetchild sr.sr_nssid = 0; 3230151378Snetchild 3231151378Snetchild ireq.i_data = &sr; 3232151378Snetchild ireq.i_len = sizeof(sr); 3233151378Snetchild /* 3234151378Snetchild * NB: only root can trigger a scan so ignore errors. Also ignore 3235151378Snetchild * possible errors from net80211, even if no new scan could be 3236151378Snetchild * started there might still be a valid scan cache. 3237151378Snetchild */ 3238151378Snetchild if (ioctl(s, SIOCS80211, &ireq) == 0) { 3239151378Snetchild char buf[2048]; 3240151378Snetchild struct if_announcemsghdr *ifan; 3241151378Snetchild struct rt_msghdr *rtm; 3242151378Snetchild 3243151378Snetchild do { 3244151378Snetchild if (read(sroute, buf, sizeof(buf)) < 0) { 3245151378Snetchild perror("read(PF_ROUTE)"); 3246151378Snetchild break; 3247151378Snetchild } 3248151378Snetchild rtm = (struct rt_msghdr *) buf; 3249151378Snetchild if (rtm->rtm_version != RTM_VERSION) 3250151378Snetchild break; 3251151378Snetchild ifan = (struct if_announcemsghdr *) rtm; 3252151378Snetchild } while (rtm->rtm_type != RTM_IEEE80211 || 3253151378Snetchild ifan->ifan_what != RTM_IEEE80211_SCAN); 3254151378Snetchild } 3255151378Snetchild close(sroute); 3256151378Snetchild} 3257151378Snetchild 3258151378Snetchildstatic 3259151378SnetchildDECL_CMD_FUNC(set80211scan, val, d) 3260151378Snetchild{ 3261151378Snetchild scan_and_wait(s); 3262151378Snetchild list_scan(s); 3263151378Snetchild} 3264151378Snetchild 3265153939Snetchildstatic enum ieee80211_opmode get80211opmode(int s); 3266153939Snetchild 3267153939Snetchildstatic int 3268153939Snetchildgettxseq(const struct ieee80211req_sta_info *si) 3269153939Snetchild{ 3270153939Snetchild int i, txseq; 3271153939Snetchild 3272153939Snetchild if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 3273153939Snetchild return si->isi_txseqs[0]; 3274153939Snetchild /* XXX not right but usually what folks want */ 3275153939Snetchild txseq = 0; 3276153939Snetchild for (i = 0; i < IEEE80211_TID_SIZE; i++) 3277153939Snetchild if (si->isi_txseqs[i] > txseq) 3278153939Snetchild txseq = si->isi_txseqs[i]; 3279153939Snetchild return txseq; 3280153939Snetchild} 3281153939Snetchild 3282153939Snetchildstatic int 3283153939Snetchildgetrxseq(const struct ieee80211req_sta_info *si) 3284153939Snetchild{ 3285153939Snetchild int i, rxseq; 3286153939Snetchild 3287153939Snetchild if ((si->isi_state & IEEE80211_NODE_QOS) == 0) 3288153939Snetchild return si->isi_rxseqs[0]; 3289153939Snetchild /* XXX not right but usually what folks want */ 3290153939Snetchild rxseq = 0; 3291153939Snetchild for (i = 0; i < IEEE80211_TID_SIZE; i++) 3292153939Snetchild if (si->isi_rxseqs[i] > rxseq) 3293153939Snetchild rxseq = si->isi_rxseqs[i]; 3294153939Snetchild return rxseq; 3295153939Snetchild} 3296153939Snetchild 3297153939Snetchildstatic void 3298153939Snetchildlist_stations(int s) 3299153939Snetchild{ 3300153939Snetchild union { 3301153939Snetchild struct ieee80211req_sta_req req; 3302153939Snetchild uint8_t buf[24*1024]; 3303153939Snetchild } u; 3304153939Snetchild enum ieee80211_opmode opmode = get80211opmode(s); 3305153939Snetchild const uint8_t *cp; 3306153939Snetchild int len; 3307153939Snetchild 3308153939Snetchild /* broadcast address =>'s get all stations */ 3309153939Snetchild (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); 3310153939Snetchild if (opmode == IEEE80211_M_STA) { 3311153939Snetchild /* 3312153939Snetchild * Get information about the associated AP. 3313153939Snetchild */ 3314153939Snetchild (void) get80211(s, IEEE80211_IOC_BSSID, 3315153939Snetchild u.req.is_u.macaddr, IEEE80211_ADDR_LEN); 3316153939Snetchild } 3317153939Snetchild if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0) 3318153939Snetchild errx(1, "unable to get station information"); 3319153939Snetchild if (len < sizeof(struct ieee80211req_sta_info)) 3320153939Snetchild return; 3321153939Snetchild 3322153939Snetchild getchaninfo(s); 3323153939Snetchild 3324153939Snetchild if (opmode == IEEE80211_M_MBSS) 3325153939Snetchild printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n" 3326153939Snetchild , "ADDR" 3327153939Snetchild , "CHAN" 3328153939Snetchild , "LOCAL" 3329153939Snetchild , "PEER" 3330153939Snetchild , "STATE" 3331153939Snetchild , "RATE" 3332153939Snetchild , "RSSI" 3333151378Snetchild , "IDLE" 3334153939Snetchild , "TXSEQ" 3335153939Snetchild , "RXSEQ" 3336153939Snetchild ); 3337153939Snetchild else 3338153939Snetchild printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n" 3339153939Snetchild , "ADDR" 3340153939Snetchild , "AID" 3341153939Snetchild , "CHAN" 3342153939Snetchild , "RATE" 3343153939Snetchild , "RSSI" 3344153939Snetchild , "IDLE" 3345153939Snetchild , "TXSEQ" 3346153939Snetchild , "RXSEQ" 3347153939Snetchild , "CAPS" 3348153939Snetchild , "FLAG" 3349153939Snetchild ); 3350153939Snetchild cp = (const uint8_t *) u.req.info; 3351153939Snetchild do { 3352153939Snetchild const struct ieee80211req_sta_info *si; 3353153939Snetchild 3354153939Snetchild si = (const struct ieee80211req_sta_info *) cp; 3355153939Snetchild if (si->isi_len < sizeof(*si)) 3356153939Snetchild break; 3357153939Snetchild if (opmode == IEEE80211_M_MBSS) 3358153939Snetchild printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d" 3359153939Snetchild , ether_ntoa((const struct ether_addr*) 3360153939Snetchild si->isi_macaddr) 3361153939Snetchild , ieee80211_mhz2ieee(si->isi_freq, 3362153939Snetchild si->isi_flags) 3363153939Snetchild , si->isi_localid 3364153939Snetchild , si->isi_peerid 3365153939Snetchild , mesh_linkstate_string(si->isi_peerstate) 3366153939Snetchild , si->isi_txmbps/2 3367153939Snetchild , si->isi_rssi/2. 3368153939Snetchild , si->isi_inact 3369153939Snetchild , gettxseq(si) 3370153939Snetchild , getrxseq(si) 3371153939Snetchild ); 3372153939Snetchild else 3373151378Snetchild printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s" 3374151378Snetchild , ether_ntoa((const struct ether_addr*) 3375151378Snetchild si->isi_macaddr) 3376151378Snetchild , IEEE80211_AID(si->isi_associd) 3377151378Snetchild , ieee80211_mhz2ieee(si->isi_freq, 3378151378Snetchild si->isi_flags) 3379151378Snetchild , si->isi_txmbps/2 3380151378Snetchild , si->isi_rssi/2. 3381151378Snetchild , si->isi_inact 3382151378Snetchild , gettxseq(si) 3383151378Snetchild , getrxseq(si) 3384151378Snetchild , getcaps(si->isi_capinfo) 3385151378Snetchild , getflags(si->isi_state) 3386151378Snetchild ); 3387151378Snetchild printies(cp + si->isi_ie_off, si->isi_ie_len, 24); 3388151378Snetchild printmimo(&si->isi_mimo); 3389151378Snetchild printf("\n"); 3390151378Snetchild cp += si->isi_len, len -= si->isi_len; 3391151378Snetchild } while (len >= sizeof(struct ieee80211req_sta_info)); 3392151378Snetchild} 3393151378Snetchild 3394151378Snetchildstatic const char * 3395151378Snetchildmesh_linkstate_string(uint8_t state) 3396151378Snetchild{ 3397151378Snetchild#define N(a) (sizeof(a) / sizeof(a[0])) 3398151378Snetchild static const char *state_names[] = { 3399151378Snetchild [0] = "IDLE", 3400151378Snetchild [1] = "OPEN-TX", 3401151378Snetchild [2] = "OPEN-RX", 3402151378Snetchild [3] = "CONF-RX", 3403151378Snetchild [4] = "ESTAB", 3404151378Snetchild [5] = "HOLDING", 3405151378Snetchild }; 3406151378Snetchild 3407151378Snetchild if (state >= N(state_names)) { 3408151378Snetchild static char buf[10]; 3409151378Snetchild snprintf(buf, sizeof(buf), "#%u", state); 3410151378Snetchild return buf; 3411151378Snetchild } else 3412151378Snetchild return state_names[state]; 3413151378Snetchild#undef N 3414151378Snetchild} 3415151378Snetchild 3416151378Snetchildstatic const char * 3417151378Snetchildget_chaninfo(const struct ieee80211_channel *c, int precise, 3418151378Snetchild char buf[], size_t bsize) 3419151378Snetchild{ 3420151378Snetchild buf[0] = '\0'; 3421151378Snetchild if (IEEE80211_IS_CHAN_FHSS(c)) 3422151378Snetchild strlcat(buf, " FHSS", bsize); 3423151378Snetchild if (IEEE80211_IS_CHAN_A(c)) 3424151378Snetchild strlcat(buf, " 11a", bsize); 3425151378Snetchild else if (IEEE80211_IS_CHAN_ANYG(c)) 3426151378Snetchild strlcat(buf, " 11g", bsize); 3427151378Snetchild else if (IEEE80211_IS_CHAN_B(c)) 3428151378Snetchild strlcat(buf, " 11b", bsize); 3429151378Snetchild if (IEEE80211_IS_CHAN_HALF(c)) 3430151378Snetchild strlcat(buf, "/10MHz", bsize); 3431151378Snetchild if (IEEE80211_IS_CHAN_QUARTER(c)) 3432151378Snetchild strlcat(buf, "/5MHz", bsize); 3433151378Snetchild if (IEEE80211_IS_CHAN_TURBO(c)) 3434151378Snetchild strlcat(buf, " Turbo", bsize); 3435151378Snetchild if (precise) { 3436151378Snetchild if (IEEE80211_IS_CHAN_HT20(c)) 3437151378Snetchild strlcat(buf, " ht/20", bsize); 3438151378Snetchild else if (IEEE80211_IS_CHAN_HT40D(c)) 3439151378Snetchild strlcat(buf, " ht/40-", bsize); 3440151378Snetchild else if (IEEE80211_IS_CHAN_HT40U(c)) 3441151378Snetchild strlcat(buf, " ht/40+", bsize); 3442151378Snetchild } else { 3443151378Snetchild if (IEEE80211_IS_CHAN_HT(c)) 3444151378Snetchild strlcat(buf, " ht", bsize); 3445151378Snetchild } 3446151378Snetchild return buf; 3447151378Snetchild} 3448151378Snetchild 3449151378Snetchildstatic void 3450151378Snetchildprint_chaninfo(const struct ieee80211_channel *c, int verb) 3451151378Snetchild{ 3452151378Snetchild char buf[14]; 3453151378Snetchild 3454151378Snetchild if (verb) 3455151378Snetchild printf("Channel %3u : %u%c%c%c%c%c MHz%-14.14s", 3456151378Snetchild ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, 3457151378Snetchild IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', 3458151378Snetchild IEEE80211_IS_CHAN_DFS(c) ? 'D' : ' ', 3459151378Snetchild IEEE80211_IS_CHAN_RADAR(c) ? 'R' : ' ', 3460151378Snetchild IEEE80211_IS_CHAN_CWINT(c) ? 'I' : ' ', 3461151378Snetchild IEEE80211_IS_CHAN_CACDONE(c) ? 'C' : ' ', 3462151378Snetchild get_chaninfo(c, verb, buf, sizeof(buf))); 3463151378Snetchild else 3464151378Snetchild printf("Channel %3u : %u%c MHz%-14.14s", 3465151378Snetchild ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq, 3466151378Snetchild IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', 3467151378Snetchild get_chaninfo(c, verb, buf, sizeof(buf))); 3468151378Snetchild 3469151378Snetchild} 3470151378Snetchild 3471151378Snetchildstatic int 3472151378Snetchildchanpref(const struct ieee80211_channel *c) 3473161201Snetchild{ 3474161201Snetchild if (IEEE80211_IS_CHAN_HT40(c)) 3475164620Snetchild return 40; 3476164620Snetchild if (IEEE80211_IS_CHAN_HT20(c)) 3477164620Snetchild return 30; 3478164620Snetchild if (IEEE80211_IS_CHAN_HALF(c)) 3479164620Snetchild return 10; 3480164620Snetchild if (IEEE80211_IS_CHAN_QUARTER(c)) 3481164620Snetchild return 5; 3482164620Snetchild if (IEEE80211_IS_CHAN_TURBO(c)) 3483164620Snetchild return 25; 3484164620Snetchild if (IEEE80211_IS_CHAN_A(c)) 3485164620Snetchild return 20; 3486164620Snetchild if (IEEE80211_IS_CHAN_G(c)) 3487164620Snetchild return 20; 3488164620Snetchild if (IEEE80211_IS_CHAN_B(c)) 3489164620Snetchild return 15; 3490164620Snetchild if (IEEE80211_IS_CHAN_PUREG(c)) 3491164620Snetchild return 15; 3492164620Snetchild return 0; 3493164620Snetchild} 3494164620Snetchild 3495164620Snetchildstatic void 3496164620Snetchildprint_channels(int s, const struct ieee80211req_chaninfo *chans, 3497164620Snetchild int allchans, int verb) 3498164620Snetchild{ 3499164620Snetchild struct ieee80211req_chaninfo *achans; 3500164620Snetchild uint8_t reported[IEEE80211_CHAN_BYTES]; 3501164620Snetchild const struct ieee80211_channel *c; 3502164620Snetchild int i, half; 3503164620Snetchild 3504164620Snetchild achans = malloc(IEEE80211_CHANINFO_SPACE(chans)); 3505164620Snetchild if (achans == NULL) 3506164620Snetchild errx(1, "no space for active channel list"); 3507164620Snetchild achans->ic_nchans = 0; 3508164620Snetchild memset(reported, 0, sizeof(reported)); 3509164620Snetchild if (!allchans) { 3510164620Snetchild struct ieee80211req_chanlist active; 3511164620Snetchild 3512164620Snetchild if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0) 3513164620Snetchild errx(1, "unable to get active channel list"); 3514164620Snetchild for (i = 0; i < chans->ic_nchans; i++) { 3515164620Snetchild c = &chans->ic_chans[i]; 3516164620Snetchild if (!isset(active.ic_channels, c->ic_ieee)) 3517164620Snetchild continue; 3518164620Snetchild /* 3519164620Snetchild * Suppress compatible duplicates unless 3520164620Snetchild * verbose. The kernel gives us it's 3521164620Snetchild * complete channel list which has separate 3522164620Snetchild * entries for 11g/11b and 11a/turbo. 3523164620Snetchild */ 3524164620Snetchild if (isset(reported, c->ic_ieee) && !verb) { 3525164620Snetchild /* XXX we assume duplicates are adjacent */ 3526164620Snetchild achans->ic_chans[achans->ic_nchans-1] = *c; 3527164620Snetchild } else { 3528164620Snetchild achans->ic_chans[achans->ic_nchans++] = *c; 3529164620Snetchild setbit(reported, c->ic_ieee); 3530164620Snetchild } 3531164620Snetchild } 3532164620Snetchild } else { 3533164620Snetchild for (i = 0; i < chans->ic_nchans; i++) { 3534164620Snetchild c = &chans->ic_chans[i]; 3535164620Snetchild /* suppress duplicates as above */ 3536164620Snetchild if (isset(reported, c->ic_ieee) && !verb) { 3537164620Snetchild /* XXX we assume duplicates are adjacent */ 3538164620Snetchild struct ieee80211_channel *a = 3539164620Snetchild &achans->ic_chans[achans->ic_nchans-1]; 3540164620Snetchild if (chanpref(c) > chanpref(a)) 3541164620Snetchild *a = *c; 3542164620Snetchild } else { 3543164620Snetchild achans->ic_chans[achans->ic_nchans++] = *c; 3544164620Snetchild setbit(reported, c->ic_ieee); 3545164620Snetchild } 3546164620Snetchild } 3547164620Snetchild } 3548164620Snetchild half = achans->ic_nchans / 2; 3549164620Snetchild if (achans->ic_nchans % 2) 3550164620Snetchild half++; 3551164620Snetchild 3552164620Snetchild for (i = 0; i < achans->ic_nchans / 2; i++) { 3553164620Snetchild print_chaninfo(&achans->ic_chans[i], verb); 3554164620Snetchild print_chaninfo(&achans->ic_chans[half+i], verb); 3555164620Snetchild printf("\n"); 3556164620Snetchild } 3557164620Snetchild if (achans->ic_nchans % 2) { 3558164620Snetchild print_chaninfo(&achans->ic_chans[i], verb); 3559164620Snetchild printf("\n"); 3560164620Snetchild } 3561164620Snetchild free(achans); 3562164620Snetchild} 3563164620Snetchild 3564164620Snetchildstatic void 3565164620Snetchildlist_channels(int s, int allchans) 3566164620Snetchild{ 3567164620Snetchild getchaninfo(s); 3568164620Snetchild print_channels(s, chaninfo, allchans, verbose); 3569164620Snetchild} 3570164620Snetchild 3571164620Snetchildstatic void 3572164620Snetchildprint_txpow(const struct ieee80211_channel *c) 3573164620Snetchild{ 3574164620Snetchild printf("Channel %3u : %u MHz %3.1f reg %2d ", 3575164620Snetchild c->ic_ieee, c->ic_freq, 3576164620Snetchild c->ic_maxpower/2., c->ic_maxregpower); 3577164620Snetchild} 3578164620Snetchild 3579164620Snetchildstatic void 3580164620Snetchildprint_txpow_verbose(const struct ieee80211_channel *c) 3581164620Snetchild{ 3582164620Snetchild print_chaninfo(c, 1); 3583164620Snetchild printf("min %4.1f dBm max %3.1f dBm reg %2d dBm", 3584164620Snetchild c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower); 3585164620Snetchild /* indicate where regulatory cap limits power use */ 3586164620Snetchild if (c->ic_maxpower > 2*c->ic_maxregpower) 3587164620Snetchild printf(" <"); 3588164620Snetchild} 3589164620Snetchild 3590164620Snetchildstatic void 3591164620Snetchildlist_txpow(int s) 3592164620Snetchild{ 3593164620Snetchild struct ieee80211req_chaninfo *achans; 3594164620Snetchild uint8_t reported[IEEE80211_CHAN_BYTES]; 3595164620Snetchild struct ieee80211_channel *c, *prev; 3596164620Snetchild int i, half; 3597164620Snetchild 3598164620Snetchild getchaninfo(s); 3599164620Snetchild achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo)); 3600164620Snetchild if (achans == NULL) 3601164620Snetchild errx(1, "no space for active channel list"); 3602164620Snetchild achans->ic_nchans = 0; 3603164620Snetchild memset(reported, 0, sizeof(reported)); 3604164620Snetchild for (i = 0; i < chaninfo->ic_nchans; i++) { 3605164620Snetchild c = &chaninfo->ic_chans[i]; 3606164620Snetchild /* suppress duplicates as above */ 3607164620Snetchild if (isset(reported, c->ic_ieee) && !verbose) { 3608164620Snetchild /* XXX we assume duplicates are adjacent */ 3609164620Snetchild prev = &achans->ic_chans[achans->ic_nchans-1]; 3610164620Snetchild /* display highest power on channel */ 3611164620Snetchild if (c->ic_maxpower > prev->ic_maxpower) 3612164620Snetchild *prev = *c; 3613164620Snetchild } else { 3614164620Snetchild achans->ic_chans[achans->ic_nchans++] = *c; 3615164620Snetchild setbit(reported, c->ic_ieee); 3616164620Snetchild } 3617164620Snetchild } 3618164620Snetchild if (!verbose) { 3619164620Snetchild half = achans->ic_nchans / 2; 3620164620Snetchild if (achans->ic_nchans % 2) 3621164620Snetchild half++; 3622164620Snetchild 3623164620Snetchild for (i = 0; i < achans->ic_nchans / 2; i++) { 3624164620Snetchild print_txpow(&achans->ic_chans[i]); 3625164620Snetchild print_txpow(&achans->ic_chans[half+i]); 3626164620Snetchild printf("\n"); 3627164620Snetchild } 3628164620Snetchild if (achans->ic_nchans % 2) { 3629164620Snetchild print_txpow(&achans->ic_chans[i]); 3630164620Snetchild printf("\n"); 3631164620Snetchild } 3632164620Snetchild } else { 3633164620Snetchild for (i = 0; i < achans->ic_nchans; i++) { 3634164620Snetchild print_txpow_verbose(&achans->ic_chans[i]); 3635164620Snetchild printf("\n"); 3636164620Snetchild } 3637164620Snetchild } 3638164620Snetchild free(achans); 3639164620Snetchild} 3640164620Snetchild 3641164620Snetchildstatic void 3642164620Snetchildlist_keys(int s) 3643164620Snetchild{ 3644164620Snetchild} 3645164620Snetchild 3646164620Snetchild#define IEEE80211_C_BITS \ 3647164620Snetchild "\20\1STA\002803ENCAP\7FF\10TURBOP\11IBSS\12PMGT" \ 3648164620Snetchild "\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \ 3649164620Snetchild "\21MONITOR\22DFS\23MBSS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \ 3650164620Snetchild "\37TXFRAG\40TDMA" 3651164620Snetchild 3652164620Snetchildstatic void 3653164620Snetchildlist_capabilities(int s) 3654164620Snetchild{ 3655164620Snetchild struct ieee80211_devcaps_req *dc; 3656164620Snetchild 3657164620Snetchild if (verbose) 3658164620Snetchild dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN)); 3659164620Snetchild else 3660164620Snetchild dc = malloc(IEEE80211_DEVCAPS_SIZE(1)); 3661164620Snetchild if (dc == NULL) 3662164620Snetchild errx(1, "no space for device capabilities"); 3663164620Snetchild dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1; 3664164620Snetchild getdevcaps(s, dc); 3665164620Snetchild printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS); 3666164620Snetchild if (dc->dc_cryptocaps != 0 || verbose) { 3667164620Snetchild putchar('\n'); 3668164620Snetchild printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS); 3669164620Snetchild } 3670164620Snetchild if (dc->dc_htcaps != 0 || verbose) { 3671164620Snetchild putchar('\n'); 3672164620Snetchild printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS); 3673164620Snetchild } 3674164620Snetchild putchar('\n'); 3675164620Snetchild if (verbose) { 3676164620Snetchild chaninfo = &dc->dc_chaninfo; /* XXX */ 3677164620Snetchild print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, verbose); 3678164620Snetchild } 3679164620Snetchild free(dc); 3680164620Snetchild} 3681164620Snetchild 3682164620Snetchildstatic int 3683164620Snetchildget80211wme(int s, int param, int ac, int *val) 3684164620Snetchild{ 3685164620Snetchild struct ieee80211req ireq; 3686164620Snetchild 3687164620Snetchild (void) memset(&ireq, 0, sizeof(ireq)); 3688164620Snetchild (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3689164620Snetchild ireq.i_type = param; 3690164620Snetchild ireq.i_len = ac; 3691164620Snetchild if (ioctl(s, SIOCG80211, &ireq) < 0) { 3692164620Snetchild warn("cannot get WME parameter %d, ac %d%s", 3693164620Snetchild param, ac & IEEE80211_WMEPARAM_VAL, 3694164620Snetchild ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : ""); 3695164620Snetchild return -1; 3696164620Snetchild } 3697164620Snetchild *val = ireq.i_val; 3698164620Snetchild return 0; 3699164620Snetchild} 3700164620Snetchild 3701164620Snetchildstatic void 3702164620Snetchildlist_wme_aci(int s, const char *tag, int ac) 3703164620Snetchild{ 3704164620Snetchild int val; 3705164620Snetchild 3706164620Snetchild printf("\t%s", tag); 3707164620Snetchild 3708164620Snetchild /* show WME BSS parameters */ 3709164620Snetchild if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1) 3710164620Snetchild printf(" cwmin %2u", val); 3711164620Snetchild if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1) 3712164620Snetchild printf(" cwmax %2u", val); 3713164620Snetchild if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1) 3714164620Snetchild printf(" aifs %2u", val); 3715164620Snetchild if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1) 3716164620Snetchild printf(" txopLimit %3u", val); 3717164620Snetchild if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) { 3718164620Snetchild if (val) 3719164620Snetchild printf(" acm"); 3720164620Snetchild else if (verbose) 3721164620Snetchild printf(" -acm"); 3722164620Snetchild } 3723164620Snetchild /* !BSS only */ 3724164620Snetchild if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 3725164620Snetchild if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) { 3726164620Snetchild if (!val) 3727164620Snetchild printf(" -ack"); 3728164620Snetchild else if (verbose) 3729164620Snetchild printf(" ack"); 3730164620Snetchild } 3731164620Snetchild } 3732170192Sru printf("\n"); 3733164620Snetchild} 3734170192Sru 3735170192Srustatic void 3736170192Srulist_wme(int s) 3737170192Sru{ 3738170192Sru static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; 3739170192Sru int ac; 3740164620Snetchild 3741164620Snetchild if (verbose) { 3742164620Snetchild /* display both BSS and local settings */ 3743164620Snetchild for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { 3744164620Snetchild again: 3745164620Snetchild if (ac & IEEE80211_WMEPARAM_BSS) 3746164620Snetchild list_wme_aci(s, " ", ac); 3747164620Snetchild else 3748164620Snetchild list_wme_aci(s, acnames[ac], ac); 3749170192Sru if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { 3750164620Snetchild ac |= IEEE80211_WMEPARAM_BSS; 3751164620Snetchild goto again; 3752164620Snetchild } else 3753164620Snetchild ac &= ~IEEE80211_WMEPARAM_BSS; 3754164620Snetchild } 3755164620Snetchild } else { 3756164620Snetchild /* display only channel settings */ 3757170192Sru for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) 3758164620Snetchild list_wme_aci(s, acnames[ac], ac); 3759164620Snetchild } 3760164620Snetchild} 3761164620Snetchild 3762164620Snetchildstatic void 3763164620Snetchildlist_roam(int s) 3764164620Snetchild{ 3765164620Snetchild const struct ieee80211_roamparam *rp; 3766164620Snetchild int mode; 3767164620Snetchild 3768161201Snetchild getroam(s); 3769161201Snetchild for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) { 3770161201Snetchild rp = &roamparams.params[mode]; 3771161201Snetchild if (rp->rssi == 0 && rp->rate == 0) 3772161201Snetchild continue; 3773161201Snetchild if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) { 3774161201Snetchild if (rp->rssi & 1) 3775161201Snetchild LINE_CHECK("roam:%-7.7s rssi %2u.5dBm MCS %2u ", 3776161201Snetchild modename[mode], rp->rssi/2, 3777161201Snetchild rp->rate &~ IEEE80211_RATE_MCS); 3778161201Snetchild else 3779161201Snetchild LINE_CHECK("roam:%-7.7s rssi %4udBm MCS %2u ", 3780161201Snetchild modename[mode], rp->rssi/2, 3781161201Snetchild rp->rate &~ IEEE80211_RATE_MCS); 3782161201Snetchild } else { 3783161201Snetchild if (rp->rssi & 1) 3784161201Snetchild LINE_CHECK("roam:%-7.7s rssi %2u.5dBm rate %2u Mb/s", 3785170192Sru modename[mode], rp->rssi/2, rp->rate/2); 3786161201Snetchild else 3787161201Snetchild LINE_CHECK("roam:%-7.7s rssi %4udBm rate %2u Mb/s", 3788161201Snetchild modename[mode], rp->rssi/2, rp->rate/2); 3789161201Snetchild } 3790161201Snetchild } 3791161201Snetchild} 3792161201Snetchild 3793161201Snetchildstatic void 3794170192Srulist_txparams(int s) 3795161201Snetchild{ 3796161201Snetchild const struct ieee80211_txparam *tp; 3797161201Snetchild int mode; 3798161201Snetchild 3799161201Snetchild gettxparams(s); 3800161201Snetchild for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) { 3801161201Snetchild tp = &txparams.params[mode]; 3802161201Snetchild if (tp->mgmtrate == 0 && tp->mcastrate == 0) 3803161201Snetchild continue; 3804161201Snetchild if (mode == IEEE80211_MODE_11NA || mode == IEEE80211_MODE_11NG) { 3805161201Snetchild if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 3806161201Snetchild LINE_CHECK("%-7.7s ucast NONE mgmt %2u MCS " 3807161201Snetchild "mcast %2u MCS maxretry %u", 3808161201Snetchild modename[mode], 3809161201Snetchild tp->mgmtrate &~ IEEE80211_RATE_MCS, 3810161201Snetchild tp->mcastrate &~ IEEE80211_RATE_MCS, 3811161201Snetchild tp->maxretry); 3812161201Snetchild else 3813161201Snetchild LINE_CHECK("%-7.7s ucast %2u MCS mgmt %2u MCS " 3814161201Snetchild "mcast %2u MCS maxretry %u", 3815161201Snetchild modename[mode], 3816161201Snetchild tp->ucastrate &~ IEEE80211_RATE_MCS, 3817161201Snetchild tp->mgmtrate &~ IEEE80211_RATE_MCS, 3818161201Snetchild tp->mcastrate &~ IEEE80211_RATE_MCS, 3819161201Snetchild tp->maxretry); 3820161201Snetchild } else { 3821161201Snetchild if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) 3822161201Snetchild LINE_CHECK("%-7.7s ucast NONE mgmt %2u Mb/s " 3823161201Snetchild "mcast %2u Mb/s maxretry %u", 3824161201Snetchild modename[mode], 3825161201Snetchild tp->mgmtrate/2, 3826161201Snetchild tp->mcastrate/2, tp->maxretry); 3827161201Snetchild else 3828161201Snetchild LINE_CHECK("%-7.7s ucast %2u Mb/s mgmt %2u Mb/s " 3829161201Snetchild "mcast %2u Mb/s maxretry %u", 3830161201Snetchild modename[mode], 3831161201Snetchild tp->ucastrate/2, tp->mgmtrate/2, 3832161201Snetchild tp->mcastrate/2, tp->maxretry); 3833161201Snetchild } 3834161201Snetchild } 3835161201Snetchild} 3836161201Snetchild 3837161201Snetchildstatic void 3838161201Snetchildprintpolicy(int policy) 3839161201Snetchild{ 3840161201Snetchild switch (policy) { 3841161201Snetchild case IEEE80211_MACCMD_POLICY_OPEN: 3842161201Snetchild printf("policy: open\n"); 3843161201Snetchild break; 3844161201Snetchild case IEEE80211_MACCMD_POLICY_ALLOW: 3845161201Snetchild printf("policy: allow\n"); 3846161201Snetchild break; 3847161201Snetchild case IEEE80211_MACCMD_POLICY_DENY: 3848161201Snetchild printf("policy: deny\n"); 3849161201Snetchild break; 3850161201Snetchild case IEEE80211_MACCMD_POLICY_RADIUS: 3851161201Snetchild printf("policy: radius\n"); 3852161201Snetchild break; 3853161201Snetchild default: 3854161201Snetchild printf("policy: unknown (%u)\n", policy); 3855161201Snetchild break; 3856161201Snetchild } 3857161201Snetchild} 3858161201Snetchild 3859161201Snetchildstatic void 3860161201Snetchildlist_mac(int s) 3861161201Snetchild{ 3862161201Snetchild struct ieee80211req ireq; 3863161201Snetchild struct ieee80211req_maclist *acllist; 3864161201Snetchild int i, nacls, policy, len; 3865161201Snetchild uint8_t *data; 3866161201Snetchild char c; 3867161201Snetchild 3868161201Snetchild (void) memset(&ireq, 0, sizeof(ireq)); 3869161201Snetchild (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */ 3870161201Snetchild ireq.i_type = IEEE80211_IOC_MACCMD; 3871161201Snetchild ireq.i_val = IEEE80211_MACCMD_POLICY; 3872161201Snetchild if (ioctl(s, SIOCG80211, &ireq) < 0) { 3873161201Snetchild if (errno == EINVAL) { 3874161201Snetchild printf("No acl policy loaded\n"); 3875161201Snetchild return; 3876161201Snetchild } 3877161201Snetchild err(1, "unable to get mac policy"); 3878161203Snetchild } 3879161201Snetchild policy = ireq.i_val; 3880161201Snetchild if (policy == IEEE80211_MACCMD_POLICY_OPEN) { 3881161201Snetchild c = '*'; 3882161201Snetchild } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { 3883161201Snetchild c = '+'; 3884161201Snetchild } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { 3885161201Snetchild c = '-'; 3886161201Snetchild } else if (policy == IEEE80211_MACCMD_POLICY_RADIUS) { 3887161201Snetchild c = 'r'; /* NB: should never have entries */ 3888161201Snetchild } else { 3889161201Snetchild printf("policy: unknown (%u)\n", policy); 3890161201Snetchild c = '?'; 3891161201Snetchild } 3892161201Snetchild if (verbose || c == '?') 3893161201Snetchild printpolicy(policy); 3894161201Snetchild 3895161201Snetchild ireq.i_val = IEEE80211_MACCMD_LIST; 3896161201Snetchild ireq.i_len = 0; 3897161201Snetchild if (ioctl(s, SIOCG80211, &ireq) < 0) 3898161201Snetchild err(1, "unable to get mac acl list size"); 3899161203Snetchild if (ireq.i_len == 0) { /* NB: no acls */ 3900161201Snetchild if (!(verbose || c == '?')) 3901161201Snetchild printpolicy(policy); 3902161201Snetchild return; 3903161201Snetchild } 3904161201Snetchild len = ireq.i_len; 3905161201Snetchild 3906161201Snetchild data = malloc(len); 3907161201Snetchild if (data == NULL) 3908161201Snetchild err(1, "out of memory for acl list"); 3909161201Snetchild 3910161201Snetchild ireq.i_data = data; 3911161201Snetchild if (ioctl(s, SIOCG80211, &ireq) < 0) 3912161201Snetchild err(1, "unable to get mac acl list"); 3913161201Snetchild nacls = len / sizeof(*acllist); 3914161201Snetchild acllist = (struct ieee80211req_maclist *) data; 3915161201Snetchild for (i = 0; i < nacls; i++) 3916161201Snetchild printf("%c%s\n", c, ether_ntoa( 3917161201Snetchild (const struct ether_addr *) acllist[i].ml_macaddr)); 3918161201Snetchild free(data); 3919161201Snetchild} 3920161201Snetchild 3921161201Snetchildstatic void 3922169816Sdelphijprint_regdomain(const struct ieee80211_regdomain *reg, int verb) 3923161201Snetchild{ 3924161201Snetchild if ((reg->regdomain != 0 && 3925161201Snetchild reg->regdomain != reg->country) || verb) { 3926161201Snetchild const struct regdomain *rd = 3927161201Snetchild lib80211_regdomain_findbysku(getregdata(), reg->regdomain); 3928161201Snetchild if (rd == NULL) 3929161201Snetchild LINE_CHECK("regdomain %d", reg->regdomain); 3930161201Snetchild else 3931161201Snetchild LINE_CHECK("regdomain %s", rd->name); 3932161201Snetchild } 3933161201Snetchild if (reg->country != 0 || verb) { 3934161201Snetchild const struct country *cc = 3935161201Snetchild lib80211_country_findbycc(getregdata(), reg->country); 3936161201Snetchild if (cc == NULL) 3937161201Snetchild LINE_CHECK("country %d", reg->country); 3938161201Snetchild else 3939161201Snetchild LINE_CHECK("country %s", cc->isoname); 3940161201Snetchild } 3941161201Snetchild if (reg->location == 'I') 3942161201Snetchild LINE_CHECK("indoor"); 3943161201Snetchild else if (reg->location == 'O') 3944161201Snetchild LINE_CHECK("outdoor"); 3945161201Snetchild else if (verb) 3946161201Snetchild LINE_CHECK("anywhere"); 3947161201Snetchild if (reg->ecm) 3948161201Snetchild LINE_CHECK("ecm"); 3949161201Snetchild else if (verb) 3950161201Snetchild LINE_CHECK("-ecm"); 3951161201Snetchild} 3952161201Snetchild 3953161201Snetchildstatic void 3954161201Snetchildlist_regdomain(int s, int channelsalso) 3955161201Snetchild{ 3956161201Snetchild getregdomain(s); 3957161201Snetchild if (channelsalso) { 3958161201Snetchild getchaninfo(s); 3959161287Snetchild spacer = ':'; 3960161287Snetchild print_regdomain(®domain, 1); 3961161287Snetchild LINE_BREAK(); 3962161287Snetchild print_channels(s, chaninfo, 1/*allchans*/, 1/*verbose*/); 3963161287Snetchild } else 3964161287Snetchild print_regdomain(®domain, verbose); 3965161287Snetchild} 3966170190Sru 3967170190Srustatic void 3968170190Srulist_mesh(int s) 3969170190Sru{ 3970170190Sru struct ieee80211req ireq; 3971170190Sru struct ieee80211req_mesh_route routes[128]; 3972170190Sru struct ieee80211req_mesh_route *rt; 3973170190Sru 3974170190Sru (void) memset(&ireq, 0, sizeof(ireq)); 3975170190Sru (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 3976170190Sru ireq.i_type = IEEE80211_IOC_MESH_RTCMD; 3977170190Sru ireq.i_val = IEEE80211_MESH_RTCMD_LIST; 3978170190Sru ireq.i_data = &routes; 3979161189Ssimon ireq.i_len = sizeof(routes); 3980161189Ssimon if (ioctl(s, SIOCG80211, &ireq) < 0) 3981161189Ssimon err(1, "unable to get the Mesh routing table"); 3982170190Sru 3983170190Sru printf("%-17.17s %-17.17s %4s %4s %4s %6s %s\n" 3984170190Sru , "DEST" 3985170190Sru , "NEXT HOP" 3986160129Sdelphij , "HOPS" 3987160129Sdelphij , "METRIC" 3988160129Sdelphij , "LIFETIME" 3989160129Sdelphij , "MSEQ" 3990160129Sdelphij , "FLAGS"); 3991170190Sru 3992170190Sru for (rt = &routes[0]; rt - &routes[0] < ireq.i_len / sizeof(*rt); rt++){ 3993170190Sru printf("%s ", 3994170190Sru ether_ntoa((const struct ether_addr *)rt->imr_dest)); 3995170190Sru printf("%s %4u %4u %6u %6u %c%c\n", 3996157723Sru ether_ntoa((const struct ether_addr *)rt->imr_nexthop), 3997157723Sru rt->imr_nhops, rt->imr_metric, rt->imr_lifetime, 3998162937Sru rt->imr_lastmseq, 3999162937Sru (rt->imr_flags & IEEE80211_MESHRT_FLAGS_VALID) ? 4000162937Sru 'V' : '!', 4001162937Sru (rt->imr_flags & IEEE80211_MESHRT_FLAGS_PROXY) ? 4002162937Sru 'P' : ' '); 4003162937Sru } 4004162937Sru} 4005162937Sru 4006156676Shartistatic 4007156676ShartiDECL_CMD_FUNC(set80211list, arg, d) 4008170190Sru{ 4009170190Sru#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 4010170190Sru 4011170190Sru LINE_INIT('\t'); 4012170190Sru 4013170190Sru if (iseq(arg, "sta")) 4014170190Sru list_stations(s); 4015170190Sru else if (iseq(arg, "scan") || iseq(arg, "ap")) 4016170190Sru list_scan(s); 4017170190Sru else if (iseq(arg, "chan") || iseq(arg, "freq")) 4018170190Sru list_channels(s, 1); 4019148330Snetchild else if (iseq(arg, "active")) 4020148330Snetchild list_channels(s, 0); 4021148330Snetchild else if (iseq(arg, "keys")) 4022148330Snetchild list_keys(s); 4023148330Snetchild else if (iseq(arg, "caps")) 4024148330Snetchild list_capabilities(s); 4025148330Snetchild else if (iseq(arg, "wme") || iseq(arg, "wmm")) 4026148330Snetchild list_wme(s); 4027148330Snetchild else if (iseq(arg, "mac")) 4028148330Snetchild list_mac(s); 4029148330Snetchild else if (iseq(arg, "txpow")) 4030148330Snetchild list_txpow(s); 4031148330Snetchild else if (iseq(arg, "roam")) 4032148330Snetchild list_roam(s); 4033148330Snetchild else if (iseq(arg, "txparam") || iseq(arg, "txparm")) 4034148330Snetchild list_txparams(s); 4035148330Snetchild else if (iseq(arg, "regdomain")) 4036148330Snetchild list_regdomain(s, 1); 4037148330Snetchild else if (iseq(arg, "countries")) 4038148330Snetchild list_countries(); 4039148330Snetchild else if (iseq(arg, "mesh")) 4040148330Snetchild list_mesh(s); 4041148330Snetchild else 4042148330Snetchild errx(1, "Don't know how to list %s for %s", arg, name); 4043148330Snetchild LINE_BREAK(); 4044148330Snetchild#undef iseq 4045148330Snetchild} 4046148330Snetchild 4047148330Snetchildstatic enum ieee80211_opmode 4048148330Snetchildget80211opmode(int s) 4049148330Snetchild{ 4050148330Snetchild struct ifmediareq ifmr; 4051148330Snetchild 4052148330Snetchild (void) memset(&ifmr, 0, sizeof(ifmr)); 4053148330Snetchild (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 4054148330Snetchild 4055148330Snetchild if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 4056148330Snetchild if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) { 4057148330Snetchild if (ifmr.ifm_current & IFM_FLAG0) 4058148330Snetchild return IEEE80211_M_AHDEMO; 4059148330Snetchild else 4060148330Snetchild return IEEE80211_M_IBSS; 4061148330Snetchild } 4062148330Snetchild if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 4063148330Snetchild return IEEE80211_M_HOSTAP; 4064148708Sru if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 4065148330Snetchild return IEEE80211_M_MONITOR; 4066148330Snetchild if (ifmr.ifm_current & IFM_IEEE80211_MBSS) 4067148330Snetchild return IEEE80211_M_MBSS; 4068148330Snetchild } 4069148330Snetchild return IEEE80211_M_STA; 4070148330Snetchild} 4071148330Snetchild 4072148330Snetchild#if 0 4073148330Snetchildstatic void 4074148330Snetchildprintcipher(int s, struct ieee80211req *ireq, int keylenop) 4075148330Snetchild{ 4076148330Snetchild switch (ireq->i_val) { 4077148330Snetchild case IEEE80211_CIPHER_WEP: 4078148330Snetchild ireq->i_type = keylenop; 4079148330Snetchild if (ioctl(s, SIOCG80211, ireq) != -1) 4080148330Snetchild printf("WEP-%s", 4081148330Snetchild ireq->i_len <= 5 ? "40" : 4082148330Snetchild ireq->i_len <= 13 ? "104" : "128"); 4083148330Snetchild else 4084148330Snetchild printf("WEP"); 4085148330Snetchild break; 4086148330Snetchild case IEEE80211_CIPHER_TKIP: 4087148330Snetchild printf("TKIP"); 4088148330Snetchild break; 4089148330Snetchild case IEEE80211_CIPHER_AES_OCB: 4090148330Snetchild printf("AES-OCB"); 4091148330Snetchild break; 4092148330Snetchild case IEEE80211_CIPHER_AES_CCM: 4093148330Snetchild printf("AES-CCM"); 4094148330Snetchild break; 4095148330Snetchild case IEEE80211_CIPHER_CKIP: 4096148543Snetchild printf("CKIP"); 4097148543Snetchild break; 4098148543Snetchild case IEEE80211_CIPHER_NONE: 4099148543Snetchild printf("NONE"); 4100148543Snetchild break; 4101148543Snetchild default: 4102148543Snetchild printf("UNKNOWN (0x%x)", ireq->i_val); 4103148543Snetchild break; 4104148543Snetchild } 4105148543Snetchild} 4106148543Snetchild#endif 4107148543Snetchild 4108148543Snetchildstatic void 4109148543Snetchildprintkey(const struct ieee80211req_key *ik) 4110148543Snetchild{ 4111148543Snetchild static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE]; 4112148543Snetchild int keylen = ik->ik_keylen; 4113148543Snetchild int printcontents; 4114148543Snetchild 4115148543Snetchild printcontents = printkeys && 4116148543Snetchild (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose); 4117148543Snetchild if (printcontents) 4118148543Snetchild LINE_BREAK(); 4119148543Snetchild switch (ik->ik_type) { 4120148543Snetchild case IEEE80211_CIPHER_WEP: 4121148543Snetchild /* compatibility */ 4122148543Snetchild LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1, 4123148543Snetchild keylen <= 5 ? "40-bit" : 4124148330Snetchild keylen <= 13 ? "104-bit" : "128-bit"); 4125148330Snetchild break; 4126148330Snetchild case IEEE80211_CIPHER_TKIP: 4127148543Snetchild if (keylen > 128/8) 4128148543Snetchild keylen -= 128/8; /* ignore MIC for now */ 4129148543Snetchild LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 4130148543Snetchild break; 4131148330Snetchild case IEEE80211_CIPHER_AES_OCB: 4132148330Snetchild LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen); 4133155813Snetchild break; 4134155813Snetchild case IEEE80211_CIPHER_AES_CCM: 4135148330Snetchild LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen); 4136148330Snetchild break; 4137148330Snetchild case IEEE80211_CIPHER_CKIP: 4138148330Snetchild LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen); 4139148330Snetchild break; 4140148330Snetchild case IEEE80211_CIPHER_NONE: 4141148330Snetchild LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen); 4142148330Snetchild break; 4143148330Snetchild default: 4144148330Snetchild LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit", 4145148330Snetchild ik->ik_type, ik->ik_keyix+1, 8*keylen); 4146161526Sru break; 4147148330Snetchild } 4148148330Snetchild if (printcontents) { 4149148330Snetchild int i; 4150148330Snetchild 4151148330Snetchild printf(" <"); 4152148330Snetchild for (i = 0; i < keylen; i++) 4153148330Snetchild printf("%02x", ik->ik_keydata[i]); 4154148330Snetchild printf(">"); 4155148330Snetchild if (ik->ik_type != IEEE80211_CIPHER_WEP && 4156148330Snetchild (ik->ik_keyrsc != 0 || verbose)) 4157148330Snetchild printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc); 4158148330Snetchild if (ik->ik_type != IEEE80211_CIPHER_WEP && 4159148330Snetchild (ik->ik_keytsc != 0 || verbose)) 4160148330Snetchild printf(" tsc %ju", (uintmax_t)ik->ik_keytsc); 4161148330Snetchild if (ik->ik_flags != 0 && verbose) { 4162148330Snetchild const char *sep = " "; 4163148330Snetchild 4164148330Snetchild if (ik->ik_flags & IEEE80211_KEY_XMIT) 4165148330Snetchild printf("%stx", sep), sep = "+"; 4166148330Snetchild if (ik->ik_flags & IEEE80211_KEY_RECV) 4167148330Snetchild printf("%srx", sep), sep = "+"; 4168148330Snetchild if (ik->ik_flags & IEEE80211_KEY_DEFAULT) 4169148330Snetchild printf("%sdef", sep), sep = "+"; 4170148330Snetchild } 4171148330Snetchild LINE_BREAK(); 4172148330Snetchild } 4173148330Snetchild} 4174148330Snetchild 4175148330Snetchildstatic void 4176148330Snetchildprintrate(const char *tag, int v, int defrate, int defmcs) 4177148330Snetchild{ 4178148330Snetchild if ((v & IEEE80211_RATE_MCS) == 0) { 4179148330Snetchild if (v != defrate) { 4180148330Snetchild if (v & 1) 4181148330Snetchild LINE_CHECK("%s %d.5", tag, v/2); 4182148330Snetchild else 4183148330Snetchild LINE_CHECK("%s %d", tag, v/2); 4184148330Snetchild } 4185148330Snetchild } else { 4186148330Snetchild if (v != defmcs) 4187148330Snetchild LINE_CHECK("%s %d", tag, v &~ 0x80); 4188154025Snetchild } 4189154025Snetchild} 4190148330Snetchild 4191148330Snetchildstatic int 4192148330Snetchildgetid(int s, int ix, void *data, size_t len, int *plen, int mesh) 4193148330Snetchild{ 4194148330Snetchild struct ieee80211req ireq; 4195154025Snetchild 4196154025Snetchild (void) memset(&ireq, 0, sizeof(ireq)); 4197148330Snetchild (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4198148330Snetchild ireq.i_type = (!mesh) ? IEEE80211_IOC_SSID : IEEE80211_IOC_MESH_ID; 4199148330Snetchild ireq.i_val = ix; 4200148330Snetchild ireq.i_data = data; 4201148330Snetchild ireq.i_len = len; 4202148330Snetchild if (ioctl(s, SIOCG80211, &ireq) < 0) 4203148330Snetchild return -1; 4204148330Snetchild *plen = ireq.i_len; 4205148330Snetchild return 0; 4206148330Snetchild} 4207148330Snetchild 4208148330Snetchildstatic void 4209148330Snetchildieee80211_status(int s) 4210148330Snetchild{ 4211148330Snetchild static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 4212148330Snetchild enum ieee80211_opmode opmode = get80211opmode(s); 4213148330Snetchild int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode; 4214148330Snetchild uint8_t data[32]; 4215148330Snetchild const struct ieee80211_channel *c; 4216148330Snetchild const struct ieee80211_roamparam *rp; 4217148330Snetchild const struct ieee80211_txparam *tp; 4218148330Snetchild 4219148330Snetchild if (getid(s, -1, data, sizeof(data), &len, 0) < 0) { 4220148330Snetchild /* If we can't get the SSID, this isn't an 802.11 device. */ 4221148330Snetchild return; 4222148330Snetchild } 4223148330Snetchild 4224148330Snetchild /* 4225148330Snetchild * Invalidate cached state so printing status for multiple 4226148330Snetchild * if's doesn't reuse the first interfaces' cached state. 4227148330Snetchild */ 4228148330Snetchild gotcurchan = 0; 4229148330Snetchild gotroam = 0; 4230148330Snetchild gottxparams = 0; 4231148330Snetchild gothtconf = 0; 4232154025Snetchild gotregdomain = 0; 4233161201Snetchild 4234161201Snetchild printf("\t"); 4235161201Snetchild if (opmode == IEEE80211_M_MBSS) { 4236170190Sru printf("meshid "); 4237170190Sru getid(s, 0, data, sizeof(data), &len, 1); 4238170190Sru print_string(data, len); 4239170190Sru } else { 4240161201Snetchild if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0) 4241154025Snetchild num = 0; 4242161201Snetchild printf("ssid "); 4243161201Snetchild if (num > 1) { 4244161201Snetchild for (i = 0; i < num; i++) { 4245148330Snetchild if (getid(s, i, data, sizeof(data), &len, 0) >= 0 && len > 0) { 4246148543Snetchild printf(" %d:", i + 1); 4247148543Snetchild print_string(data, len); 4248148543Snetchild } 4249148543Snetchild } 4250164620Snetchild } else 4251164620Snetchild print_string(data, len); 4252164620Snetchild } 4253164620Snetchild c = getcurchan(s); 4254164620Snetchild if (c->ic_freq != IEEE80211_CHAN_ANY) { 4255164620Snetchild char buf[14]; 4256164971Savatar printf(" channel %d (%u MHz%s)", c->ic_ieee, c->ic_freq, 4257164971Savatar get_chaninfo(c, 1, buf, sizeof(buf))); 4258148330Snetchild } else if (verbose) 4259164620Snetchild printf(" channel UNDEF"); 4260157439Snetchild 4261 if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 && 4262 (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) 4263 printf(" bssid %s", ether_ntoa((struct ether_addr *)data)); 4264 4265 if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) { 4266 printf("\n\tstationname "); 4267 print_string(data, len); 4268 } 4269 4270 spacer = ' '; /* force first break */ 4271 LINE_BREAK(); 4272 4273 list_regdomain(s, 0); 4274 4275 wpa = 0; 4276 if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) { 4277 switch (val) { 4278 case IEEE80211_AUTH_NONE: 4279 LINE_CHECK("authmode NONE"); 4280 break; 4281 case IEEE80211_AUTH_OPEN: 4282 LINE_CHECK("authmode OPEN"); 4283 break; 4284 case IEEE80211_AUTH_SHARED: 4285 LINE_CHECK("authmode SHARED"); 4286 break; 4287 case IEEE80211_AUTH_8021X: 4288 LINE_CHECK("authmode 802.1x"); 4289 break; 4290 case IEEE80211_AUTH_WPA: 4291 if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0) 4292 wpa = 1; /* default to WPA1 */ 4293 switch (wpa) { 4294 case 2: 4295 LINE_CHECK("authmode WPA2/802.11i"); 4296 break; 4297 case 3: 4298 LINE_CHECK("authmode WPA1+WPA2/802.11i"); 4299 break; 4300 default: 4301 LINE_CHECK("authmode WPA"); 4302 break; 4303 } 4304 break; 4305 case IEEE80211_AUTH_AUTO: 4306 LINE_CHECK("authmode AUTO"); 4307 break; 4308 default: 4309 LINE_CHECK("authmode UNKNOWN (0x%x)", val); 4310 break; 4311 } 4312 } 4313 4314 if (wpa || verbose) { 4315 if (get80211val(s, IEEE80211_IOC_WPS, &val) != -1) { 4316 if (val) 4317 LINE_CHECK("wps"); 4318 else if (verbose) 4319 LINE_CHECK("-wps"); 4320 } 4321 if (get80211val(s, IEEE80211_IOC_TSN, &val) != -1) { 4322 if (val) 4323 LINE_CHECK("tsn"); 4324 else if (verbose) 4325 LINE_CHECK("-tsn"); 4326 } 4327 if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) { 4328 if (val) 4329 LINE_CHECK("countermeasures"); 4330 else if (verbose) 4331 LINE_CHECK("-countermeasures"); 4332 } 4333#if 0 4334 /* XXX not interesting with WPA done in user space */ 4335 ireq.i_type = IEEE80211_IOC_KEYMGTALGS; 4336 if (ioctl(s, SIOCG80211, &ireq) != -1) { 4337 } 4338 4339 ireq.i_type = IEEE80211_IOC_MCASTCIPHER; 4340 if (ioctl(s, SIOCG80211, &ireq) != -1) { 4341 LINE_CHECK("mcastcipher "); 4342 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); 4343 spacer = ' '; 4344 } 4345 4346 ireq.i_type = IEEE80211_IOC_UCASTCIPHER; 4347 if (ioctl(s, SIOCG80211, &ireq) != -1) { 4348 LINE_CHECK("ucastcipher "); 4349 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); 4350 } 4351 4352 if (wpa & 2) { 4353 ireq.i_type = IEEE80211_IOC_RSNCAPS; 4354 if (ioctl(s, SIOCG80211, &ireq) != -1) { 4355 LINE_CHECK("RSN caps 0x%x", ireq.i_val); 4356 spacer = ' '; 4357 } 4358 } 4359 4360 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; 4361 if (ioctl(s, SIOCG80211, &ireq) != -1) { 4362 } 4363#endif 4364 } 4365 4366 if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 && 4367 wepmode != IEEE80211_WEP_NOSUP) { 4368 int firstkey; 4369 4370 switch (wepmode) { 4371 case IEEE80211_WEP_OFF: 4372 LINE_CHECK("privacy OFF"); 4373 break; 4374 case IEEE80211_WEP_ON: 4375 LINE_CHECK("privacy ON"); 4376 break; 4377 case IEEE80211_WEP_MIXED: 4378 LINE_CHECK("privacy MIXED"); 4379 break; 4380 default: 4381 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); 4382 break; 4383 } 4384 4385 /* 4386 * If we get here then we've got WEP support so we need 4387 * to print WEP status. 4388 */ 4389 4390 if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) { 4391 warn("WEP support, but no tx key!"); 4392 goto end; 4393 } 4394 if (val != -1) 4395 LINE_CHECK("deftxkey %d", val+1); 4396 else if (wepmode != IEEE80211_WEP_OFF || verbose) 4397 LINE_CHECK("deftxkey UNDEF"); 4398 4399 if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) { 4400 warn("WEP support, but no NUMWEPKEYS support!"); 4401 goto end; 4402 } 4403 4404 firstkey = 1; 4405 for (i = 0; i < num; i++) { 4406 struct ieee80211req_key ik; 4407 4408 memset(&ik, 0, sizeof(ik)); 4409 ik.ik_keyix = i; 4410 if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) { 4411 warn("WEP support, but can get keys!"); 4412 goto end; 4413 } 4414 if (ik.ik_keylen != 0) { 4415 if (verbose) 4416 LINE_BREAK(); 4417 printkey(&ik); 4418 firstkey = 0; 4419 } 4420 } 4421end: 4422 ; 4423 } 4424 4425 if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 && 4426 val != IEEE80211_POWERSAVE_NOSUP ) { 4427 if (val != IEEE80211_POWERSAVE_OFF || verbose) { 4428 switch (val) { 4429 case IEEE80211_POWERSAVE_OFF: 4430 LINE_CHECK("powersavemode OFF"); 4431 break; 4432 case IEEE80211_POWERSAVE_CAM: 4433 LINE_CHECK("powersavemode CAM"); 4434 break; 4435 case IEEE80211_POWERSAVE_PSP: 4436 LINE_CHECK("powersavemode PSP"); 4437 break; 4438 case IEEE80211_POWERSAVE_PSP_CAM: 4439 LINE_CHECK("powersavemode PSP-CAM"); 4440 break; 4441 } 4442 if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1) 4443 LINE_CHECK("powersavesleep %d", val); 4444 } 4445 } 4446 4447 if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) { 4448 if (val & 1) 4449 LINE_CHECK("txpower %d.5", val/2); 4450 else 4451 LINE_CHECK("txpower %d", val/2); 4452 } 4453 if (verbose) { 4454 if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1) 4455 LINE_CHECK("txpowmax %.1f", val/2.); 4456 } 4457 4458 if (get80211val(s, IEEE80211_IOC_DOTD, &val) != -1) { 4459 if (val) 4460 LINE_CHECK("dotd"); 4461 else if (verbose) 4462 LINE_CHECK("-dotd"); 4463 } 4464 4465 if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) { 4466 if (val != IEEE80211_RTS_MAX || verbose) 4467 LINE_CHECK("rtsthreshold %d", val); 4468 } 4469 4470 if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) { 4471 if (val != IEEE80211_FRAG_MAX || verbose) 4472 LINE_CHECK("fragthreshold %d", val); 4473 } 4474 if (opmode == IEEE80211_M_STA || verbose) { 4475 if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) { 4476 if (val != IEEE80211_HWBMISS_MAX || verbose) 4477 LINE_CHECK("bmiss %d", val); 4478 } 4479 } 4480 4481 if (!verbose) { 4482 gettxparams(s); 4483 tp = &txparams.params[chan2mode(c)]; 4484 printrate("ucastrate", tp->ucastrate, 4485 IEEE80211_FIXED_RATE_NONE, IEEE80211_FIXED_RATE_NONE); 4486 printrate("mcastrate", tp->mcastrate, 2*1, 4487 IEEE80211_RATE_MCS|0); 4488 printrate("mgmtrate", tp->mgmtrate, 2*1, 4489 IEEE80211_RATE_MCS|0); 4490 if (tp->maxretry != 6) /* XXX */ 4491 LINE_CHECK("maxretry %d", tp->maxretry); 4492 } else { 4493 LINE_BREAK(); 4494 list_txparams(s); 4495 } 4496 4497 bgscaninterval = -1; 4498 (void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval); 4499 4500 if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) { 4501 if (val != bgscaninterval || verbose) 4502 LINE_CHECK("scanvalid %u", val); 4503 } 4504 4505 bgscan = 0; 4506 if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) { 4507 if (bgscan) 4508 LINE_CHECK("bgscan"); 4509 else if (verbose) 4510 LINE_CHECK("-bgscan"); 4511 } 4512 if (bgscan || verbose) { 4513 if (bgscaninterval != -1) 4514 LINE_CHECK("bgscanintvl %u", bgscaninterval); 4515 if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1) 4516 LINE_CHECK("bgscanidle %u", val); 4517 if (!verbose) { 4518 getroam(s); 4519 rp = &roamparams.params[chan2mode(c)]; 4520 if (rp->rssi & 1) 4521 LINE_CHECK("roam:rssi %u.5", rp->rssi/2); 4522 else 4523 LINE_CHECK("roam:rssi %u", rp->rssi/2); 4524 LINE_CHECK("roam:rate %u", rp->rate/2); 4525 } else { 4526 LINE_BREAK(); 4527 list_roam(s); 4528 LINE_BREAK(); 4529 } 4530 } 4531 4532 if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { 4533 if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) { 4534 if (val) 4535 LINE_CHECK("pureg"); 4536 else if (verbose) 4537 LINE_CHECK("-pureg"); 4538 } 4539 if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) { 4540 switch (val) { 4541 case IEEE80211_PROTMODE_OFF: 4542 LINE_CHECK("protmode OFF"); 4543 break; 4544 case IEEE80211_PROTMODE_CTS: 4545 LINE_CHECK("protmode CTS"); 4546 break; 4547 case IEEE80211_PROTMODE_RTSCTS: 4548 LINE_CHECK("protmode RTSCTS"); 4549 break; 4550 default: 4551 LINE_CHECK("protmode UNKNOWN (0x%x)", val); 4552 break; 4553 } 4554 } 4555 } 4556 4557 if (IEEE80211_IS_CHAN_HT(c) || verbose) { 4558 gethtconf(s); 4559 switch (htconf & 3) { 4560 case 0: 4561 case 2: 4562 LINE_CHECK("-ht"); 4563 break; 4564 case 1: 4565 LINE_CHECK("ht20"); 4566 break; 4567 case 3: 4568 if (verbose) 4569 LINE_CHECK("ht"); 4570 break; 4571 } 4572 if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) { 4573 if (!val) 4574 LINE_CHECK("-htcompat"); 4575 else if (verbose) 4576 LINE_CHECK("htcompat"); 4577 } 4578 if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) { 4579 switch (val) { 4580 case 0: 4581 LINE_CHECK("-ampdu"); 4582 break; 4583 case 1: 4584 LINE_CHECK("ampdutx -ampdurx"); 4585 break; 4586 case 2: 4587 LINE_CHECK("-ampdutx ampdurx"); 4588 break; 4589 case 3: 4590 if (verbose) 4591 LINE_CHECK("ampdu"); 4592 break; 4593 } 4594 } 4595 if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) { 4596 switch (val) { 4597 case IEEE80211_HTCAP_MAXRXAMPDU_8K: 4598 LINE_CHECK("ampdulimit 8k"); 4599 break; 4600 case IEEE80211_HTCAP_MAXRXAMPDU_16K: 4601 LINE_CHECK("ampdulimit 16k"); 4602 break; 4603 case IEEE80211_HTCAP_MAXRXAMPDU_32K: 4604 LINE_CHECK("ampdulimit 32k"); 4605 break; 4606 case IEEE80211_HTCAP_MAXRXAMPDU_64K: 4607 LINE_CHECK("ampdulimit 64k"); 4608 break; 4609 } 4610 } 4611 if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) { 4612 switch (val) { 4613 case IEEE80211_HTCAP_MPDUDENSITY_NA: 4614 if (verbose) 4615 LINE_CHECK("ampdudensity NA"); 4616 break; 4617 case IEEE80211_HTCAP_MPDUDENSITY_025: 4618 LINE_CHECK("ampdudensity .25"); 4619 break; 4620 case IEEE80211_HTCAP_MPDUDENSITY_05: 4621 LINE_CHECK("ampdudensity .5"); 4622 break; 4623 case IEEE80211_HTCAP_MPDUDENSITY_1: 4624 LINE_CHECK("ampdudensity 1"); 4625 break; 4626 case IEEE80211_HTCAP_MPDUDENSITY_2: 4627 LINE_CHECK("ampdudensity 2"); 4628 break; 4629 case IEEE80211_HTCAP_MPDUDENSITY_4: 4630 LINE_CHECK("ampdudensity 4"); 4631 break; 4632 case IEEE80211_HTCAP_MPDUDENSITY_8: 4633 LINE_CHECK("ampdudensity 8"); 4634 break; 4635 case IEEE80211_HTCAP_MPDUDENSITY_16: 4636 LINE_CHECK("ampdudensity 16"); 4637 break; 4638 } 4639 } 4640 if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) { 4641 switch (val) { 4642 case 0: 4643 LINE_CHECK("-amsdu"); 4644 break; 4645 case 1: 4646 LINE_CHECK("amsdutx -amsdurx"); 4647 break; 4648 case 2: 4649 LINE_CHECK("-amsdutx amsdurx"); 4650 break; 4651 case 3: 4652 if (verbose) 4653 LINE_CHECK("amsdu"); 4654 break; 4655 } 4656 } 4657 /* XXX amsdu limit */ 4658 if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) { 4659 if (val) 4660 LINE_CHECK("shortgi"); 4661 else if (verbose) 4662 LINE_CHECK("-shortgi"); 4663 } 4664 if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) { 4665 if (val == IEEE80211_PROTMODE_OFF) 4666 LINE_CHECK("htprotmode OFF"); 4667 else if (val != IEEE80211_PROTMODE_RTSCTS) 4668 LINE_CHECK("htprotmode UNKNOWN (0x%x)", val); 4669 else if (verbose) 4670 LINE_CHECK("htprotmode RTSCTS"); 4671 } 4672 if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) { 4673 if (val) 4674 LINE_CHECK("puren"); 4675 else if (verbose) 4676 LINE_CHECK("-puren"); 4677 } 4678 if (get80211val(s, IEEE80211_IOC_SMPS, &val) != -1) { 4679 if (val == IEEE80211_HTCAP_SMPS_DYNAMIC) 4680 LINE_CHECK("smpsdyn"); 4681 else if (val == IEEE80211_HTCAP_SMPS_ENA) 4682 LINE_CHECK("smps"); 4683 else if (verbose) 4684 LINE_CHECK("-smps"); 4685 } 4686 if (get80211val(s, IEEE80211_IOC_RIFS, &val) != -1) { 4687 if (val) 4688 LINE_CHECK("rifs"); 4689 else if (verbose) 4690 LINE_CHECK("-rifs"); 4691 } 4692 } 4693 4694 if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) { 4695 if (wme) 4696 LINE_CHECK("wme"); 4697 else if (verbose) 4698 LINE_CHECK("-wme"); 4699 } else 4700 wme = 0; 4701 4702 if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) { 4703 if (val) 4704 LINE_CHECK("burst"); 4705 else if (verbose) 4706 LINE_CHECK("-burst"); 4707 } 4708 4709 if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) { 4710 if (val) 4711 LINE_CHECK("ff"); 4712 else if (verbose) 4713 LINE_CHECK("-ff"); 4714 } 4715 if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) { 4716 if (val) 4717 LINE_CHECK("dturbo"); 4718 else if (verbose) 4719 LINE_CHECK("-dturbo"); 4720 } 4721 if (get80211val(s, IEEE80211_IOC_DWDS, &val) != -1) { 4722 if (val) 4723 LINE_CHECK("dwds"); 4724 else if (verbose) 4725 LINE_CHECK("-dwds"); 4726 } 4727 4728 if (opmode == IEEE80211_M_HOSTAP) { 4729 if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) { 4730 if (val) 4731 LINE_CHECK("hidessid"); 4732 else if (verbose) 4733 LINE_CHECK("-hidessid"); 4734 } 4735 if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) { 4736 if (!val) 4737 LINE_CHECK("-apbridge"); 4738 else if (verbose) 4739 LINE_CHECK("apbridge"); 4740 } 4741 if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1) 4742 LINE_CHECK("dtimperiod %u", val); 4743 4744 if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) { 4745 if (!val) 4746 LINE_CHECK("-doth"); 4747 else if (verbose) 4748 LINE_CHECK("doth"); 4749 } 4750 if (get80211val(s, IEEE80211_IOC_DFS, &val) != -1) { 4751 if (!val) 4752 LINE_CHECK("-dfs"); 4753 else if (verbose) 4754 LINE_CHECK("dfs"); 4755 } 4756 if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) { 4757 if (!val) 4758 LINE_CHECK("-inact"); 4759 else if (verbose) 4760 LINE_CHECK("inact"); 4761 } 4762 } else { 4763 if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) { 4764 if (val != IEEE80211_ROAMING_AUTO || verbose) { 4765 switch (val) { 4766 case IEEE80211_ROAMING_DEVICE: 4767 LINE_CHECK("roaming DEVICE"); 4768 break; 4769 case IEEE80211_ROAMING_AUTO: 4770 LINE_CHECK("roaming AUTO"); 4771 break; 4772 case IEEE80211_ROAMING_MANUAL: 4773 LINE_CHECK("roaming MANUAL"); 4774 break; 4775 default: 4776 LINE_CHECK("roaming UNKNOWN (0x%x)", 4777 val); 4778 break; 4779 } 4780 } 4781 } 4782 } 4783 4784 if (opmode == IEEE80211_M_AHDEMO) { 4785 if (get80211val(s, IEEE80211_IOC_TDMA_SLOT, &val) != -1) 4786 LINE_CHECK("tdmaslot %u", val); 4787 if (get80211val(s, IEEE80211_IOC_TDMA_SLOTCNT, &val) != -1) 4788 LINE_CHECK("tdmaslotcnt %u", val); 4789 if (get80211val(s, IEEE80211_IOC_TDMA_SLOTLEN, &val) != -1) 4790 LINE_CHECK("tdmaslotlen %u", val); 4791 if (get80211val(s, IEEE80211_IOC_TDMA_BINTERVAL, &val) != -1) 4792 LINE_CHECK("tdmabintval %u", val); 4793 } else if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) { 4794 /* XXX default define not visible */ 4795 if (val != 100 || verbose) 4796 LINE_CHECK("bintval %u", val); 4797 } 4798 4799 if (wme && verbose) { 4800 LINE_BREAK(); 4801 list_wme(s); 4802 } 4803 4804 if (opmode == IEEE80211_M_MBSS) { 4805 if (get80211val(s, IEEE80211_IOC_MESH_TTL, &val) != -1) { 4806 LINE_CHECK("meshttl %u", val); 4807 } 4808 if (get80211val(s, IEEE80211_IOC_MESH_AP, &val) != -1) { 4809 if (val) 4810 LINE_CHECK("meshpeering"); 4811 else 4812 LINE_CHECK("-meshpeering"); 4813 } 4814 if (get80211val(s, IEEE80211_IOC_MESH_FWRD, &val) != -1) { 4815 if (val) 4816 LINE_CHECK("meshforward"); 4817 else 4818 LINE_CHECK("-meshforward"); 4819 } 4820 if (get80211len(s, IEEE80211_IOC_MESH_PR_METRIC, data, 12, 4821 &len) != -1) { 4822 data[len] = '\0'; 4823 LINE_CHECK("meshmetric %s", data); 4824 } 4825 if (get80211len(s, IEEE80211_IOC_MESH_PR_PATH, data, 12, 4826 &len) != -1) { 4827 data[len] = '\0'; 4828 LINE_CHECK("meshpath %s", data); 4829 } 4830 if (get80211val(s, IEEE80211_IOC_HWMP_ROOTMODE, &val) != -1) { 4831 switch (val) { 4832 case IEEE80211_HWMP_ROOTMODE_DISABLED: 4833 LINE_CHECK("hwmprootmode DISABLED"); 4834 break; 4835 case IEEE80211_HWMP_ROOTMODE_NORMAL: 4836 LINE_CHECK("hwmprootmode NORMAL"); 4837 break; 4838 case IEEE80211_HWMP_ROOTMODE_PROACTIVE: 4839 LINE_CHECK("hwmprootmode PROACTIVE"); 4840 break; 4841 case IEEE80211_HWMP_ROOTMODE_RANN: 4842 LINE_CHECK("hwmprootmode RANN"); 4843 break; 4844 default: 4845 LINE_CHECK("hwmprootmode UNKNOWN(%d)", val); 4846 break; 4847 } 4848 } 4849 if (get80211val(s, IEEE80211_IOC_HWMP_MAXHOPS, &val) != -1) { 4850 LINE_CHECK("hwmpmaxhops %u", val); 4851 } 4852 } 4853 4854 LINE_BREAK(); 4855} 4856 4857static int 4858get80211(int s, int type, void *data, int len) 4859{ 4860 struct ieee80211req ireq; 4861 4862 (void) memset(&ireq, 0, sizeof(ireq)); 4863 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4864 ireq.i_type = type; 4865 ireq.i_data = data; 4866 ireq.i_len = len; 4867 return ioctl(s, SIOCG80211, &ireq); 4868} 4869 4870static int 4871get80211len(int s, int type, void *data, int len, int *plen) 4872{ 4873 struct ieee80211req ireq; 4874 4875 (void) memset(&ireq, 0, sizeof(ireq)); 4876 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4877 ireq.i_type = type; 4878 ireq.i_len = len; 4879 assert(ireq.i_len == len); /* NB: check for 16-bit truncation */ 4880 ireq.i_data = data; 4881 if (ioctl(s, SIOCG80211, &ireq) < 0) 4882 return -1; 4883 *plen = ireq.i_len; 4884 return 0; 4885} 4886 4887static int 4888get80211val(int s, int type, int *val) 4889{ 4890 struct ieee80211req ireq; 4891 4892 (void) memset(&ireq, 0, sizeof(ireq)); 4893 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4894 ireq.i_type = type; 4895 if (ioctl(s, SIOCG80211, &ireq) < 0) 4896 return -1; 4897 *val = ireq.i_val; 4898 return 0; 4899} 4900 4901static void 4902set80211(int s, int type, int val, int len, void *data) 4903{ 4904 struct ieee80211req ireq; 4905 4906 (void) memset(&ireq, 0, sizeof(ireq)); 4907 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); 4908 ireq.i_type = type; 4909 ireq.i_val = val; 4910 ireq.i_len = len; 4911 assert(ireq.i_len == len); /* NB: check for 16-bit truncation */ 4912 ireq.i_data = data; 4913 if (ioctl(s, SIOCS80211, &ireq) < 0) 4914 err(1, "SIOCS80211"); 4915} 4916 4917static const char * 4918get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp) 4919{ 4920 int len; 4921 int hexstr; 4922 u_int8_t *p; 4923 4924 len = *lenp; 4925 p = buf; 4926 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 4927 if (hexstr) 4928 val += 2; 4929 for (;;) { 4930 if (*val == '\0') 4931 break; 4932 if (sep != NULL && strchr(sep, *val) != NULL) { 4933 val++; 4934 break; 4935 } 4936 if (hexstr) { 4937 if (!isxdigit((u_char)val[0])) { 4938 warnx("bad hexadecimal digits"); 4939 return NULL; 4940 } 4941 if (!isxdigit((u_char)val[1])) { 4942 warnx("odd count hexadecimal digits"); 4943 return NULL; 4944 } 4945 } 4946 if (p >= buf + len) { 4947 if (hexstr) 4948 warnx("hexadecimal digits too long"); 4949 else 4950 warnx("string too long"); 4951 return NULL; 4952 } 4953 if (hexstr) { 4954#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 4955 *p++ = (tohex((u_char)val[0]) << 4) | 4956 tohex((u_char)val[1]); 4957#undef tohex 4958 val += 2; 4959 } else 4960 *p++ = *val++; 4961 } 4962 len = p - buf; 4963 /* The string "-" is treated as the empty string. */ 4964 if (!hexstr && len == 1 && buf[0] == '-') { 4965 len = 0; 4966 memset(buf, 0, *lenp); 4967 } else if (len < *lenp) 4968 memset(p, 0, *lenp - len); 4969 *lenp = len; 4970 return val; 4971} 4972 4973static void 4974print_string(const u_int8_t *buf, int len) 4975{ 4976 int i; 4977 int hasspc; 4978 4979 i = 0; 4980 hasspc = 0; 4981 for (; i < len; i++) { 4982 if (!isprint(buf[i]) && buf[i] != '\0') 4983 break; 4984 if (isspace(buf[i])) 4985 hasspc++; 4986 } 4987 if (i == len) { 4988 if (hasspc || len == 0 || buf[0] == '\0') 4989 printf("\"%.*s\"", len, buf); 4990 else 4991 printf("%.*s", len, buf); 4992 } else { 4993 printf("0x"); 4994 for (i = 0; i < len; i++) 4995 printf("%02x", buf[i]); 4996 } 4997} 4998 4999/* 5000 * Virtual AP cloning support. 5001 */ 5002static struct ieee80211_clone_params params = { 5003 .icp_opmode = IEEE80211_M_STA, /* default to station mode */ 5004}; 5005 5006static void 5007wlan_create(int s, struct ifreq *ifr) 5008{ 5009 static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; 5010 5011 if (params.icp_parent[0] == '\0') 5012 errx(1, "must specify a parent device (wlandev) when creating " 5013 "a wlan device"); 5014 if (params.icp_opmode == IEEE80211_M_WDS && 5015 memcmp(params.icp_bssid, zerobssid, sizeof(zerobssid)) == 0) 5016 errx(1, "no bssid specified for WDS (use wlanbssid)"); 5017 ifr->ifr_data = (caddr_t) ¶ms; 5018 if (ioctl(s, SIOCIFCREATE2, ifr) < 0) 5019 err(1, "SIOCIFCREATE2"); 5020} 5021 5022static 5023DECL_CMD_FUNC(set80211clone_wlandev, arg, d) 5024{ 5025 strlcpy(params.icp_parent, arg, IFNAMSIZ); 5026} 5027 5028static 5029DECL_CMD_FUNC(set80211clone_wlanbssid, arg, d) 5030{ 5031 const struct ether_addr *ea; 5032 5033 ea = ether_aton(arg); 5034 if (ea == NULL) 5035 errx(1, "%s: cannot parse bssid", arg); 5036 memcpy(params.icp_bssid, ea->octet, IEEE80211_ADDR_LEN); 5037} 5038 5039static 5040DECL_CMD_FUNC(set80211clone_wlanaddr, arg, d) 5041{ 5042 const struct ether_addr *ea; 5043 5044 ea = ether_aton(arg); 5045 if (ea == NULL) 5046 errx(1, "%s: cannot parse address", arg); 5047 memcpy(params.icp_macaddr, ea->octet, IEEE80211_ADDR_LEN); 5048 params.icp_flags |= IEEE80211_CLONE_MACADDR; 5049} 5050 5051static 5052DECL_CMD_FUNC(set80211clone_wlanmode, arg, d) 5053{ 5054#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) 5055 if (iseq(arg, "sta")) 5056 params.icp_opmode = IEEE80211_M_STA; 5057 else if (iseq(arg, "ahdemo") || iseq(arg, "adhoc-demo")) 5058 params.icp_opmode = IEEE80211_M_AHDEMO; 5059 else if (iseq(arg, "ibss") || iseq(arg, "adhoc")) 5060 params.icp_opmode = IEEE80211_M_IBSS; 5061 else if (iseq(arg, "ap") || iseq(arg, "host")) 5062 params.icp_opmode = IEEE80211_M_HOSTAP; 5063 else if (iseq(arg, "wds")) 5064 params.icp_opmode = IEEE80211_M_WDS; 5065 else if (iseq(arg, "monitor")) 5066 params.icp_opmode = IEEE80211_M_MONITOR; 5067 else if (iseq(arg, "tdma")) { 5068 params.icp_opmode = IEEE80211_M_AHDEMO; 5069 params.icp_flags |= IEEE80211_CLONE_TDMA; 5070 } else if (iseq(arg, "mesh") || iseq(arg, "mp")) /* mesh point */ 5071 params.icp_opmode = IEEE80211_M_MBSS; 5072 else 5073 errx(1, "Don't know to create %s for %s", arg, name); 5074#undef iseq 5075} 5076 5077static void 5078set80211clone_beacons(const char *val, int d, int s, const struct afswtch *rafp) 5079{ 5080 /* NB: inverted sense */ 5081 if (d) 5082 params.icp_flags &= ~IEEE80211_CLONE_NOBEACONS; 5083 else 5084 params.icp_flags |= IEEE80211_CLONE_NOBEACONS; 5085} 5086 5087static void 5088set80211clone_bssid(const char *val, int d, int s, const struct afswtch *rafp) 5089{ 5090 if (d) 5091 params.icp_flags |= IEEE80211_CLONE_BSSID; 5092 else 5093 params.icp_flags &= ~IEEE80211_CLONE_BSSID; 5094} 5095 5096static void 5097set80211clone_wdslegacy(const char *val, int d, int s, const struct afswtch *rafp) 5098{ 5099 if (d) 5100 params.icp_flags |= IEEE80211_CLONE_WDSLEGACY; 5101 else 5102 params.icp_flags &= ~IEEE80211_CLONE_WDSLEGACY; 5103} 5104 5105static struct cmd ieee80211_cmds[] = { 5106 DEF_CMD_ARG("ssid", set80211ssid), 5107 DEF_CMD_ARG("nwid", set80211ssid), 5108 DEF_CMD_ARG("meshid", set80211meshid), 5109 DEF_CMD_ARG("stationname", set80211stationname), 5110 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */ 5111 DEF_CMD_ARG("channel", set80211channel), 5112 DEF_CMD_ARG("authmode", set80211authmode), 5113 DEF_CMD_ARG("powersavemode", set80211powersavemode), 5114 DEF_CMD("powersave", 1, set80211powersave), 5115 DEF_CMD("-powersave", 0, set80211powersave), 5116 DEF_CMD_ARG("powersavesleep", set80211powersavesleep), 5117 DEF_CMD_ARG("wepmode", set80211wepmode), 5118 DEF_CMD("wep", 1, set80211wep), 5119 DEF_CMD("-wep", 0, set80211wep), 5120 DEF_CMD_ARG("deftxkey", set80211weptxkey), 5121 DEF_CMD_ARG("weptxkey", set80211weptxkey), 5122 DEF_CMD_ARG("wepkey", set80211wepkey), 5123 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */ 5124 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */ 5125 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold), 5126 DEF_CMD_ARG("protmode", set80211protmode), 5127 DEF_CMD_ARG("txpower", set80211txpower), 5128 DEF_CMD_ARG("roaming", set80211roaming), 5129 DEF_CMD("wme", 1, set80211wme), 5130 DEF_CMD("-wme", 0, set80211wme), 5131 DEF_CMD("wmm", 1, set80211wme), 5132 DEF_CMD("-wmm", 0, set80211wme), 5133 DEF_CMD("hidessid", 1, set80211hidessid), 5134 DEF_CMD("-hidessid", 0, set80211hidessid), 5135 DEF_CMD("apbridge", 1, set80211apbridge), 5136 DEF_CMD("-apbridge", 0, set80211apbridge), 5137 DEF_CMD_ARG("chanlist", set80211chanlist), 5138 DEF_CMD_ARG("bssid", set80211bssid), 5139 DEF_CMD_ARG("ap", set80211bssid), 5140 DEF_CMD("scan", 0, set80211scan), 5141 DEF_CMD_ARG("list", set80211list), 5142 DEF_CMD_ARG2("cwmin", set80211cwmin), 5143 DEF_CMD_ARG2("cwmax", set80211cwmax), 5144 DEF_CMD_ARG2("aifs", set80211aifs), 5145 DEF_CMD_ARG2("txoplimit", set80211txoplimit), 5146 DEF_CMD_ARG("acm", set80211acm), 5147 DEF_CMD_ARG("-acm", set80211noacm), 5148 DEF_CMD_ARG("ack", set80211ackpolicy), 5149 DEF_CMD_ARG("-ack", set80211noackpolicy), 5150 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin), 5151 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax), 5152 DEF_CMD_ARG2("bss:aifs", set80211bssaifs), 5153 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit), 5154 DEF_CMD_ARG("dtimperiod", set80211dtimperiod), 5155 DEF_CMD_ARG("bintval", set80211bintval), 5156 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd), 5157 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd), 5158 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd), 5159 DEF_CMD("mac:radius", IEEE80211_MACCMD_POLICY_RADIUS, set80211maccmd), 5160 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd), 5161 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd), 5162 DEF_CMD_ARG("mac:add", set80211addmac), 5163 DEF_CMD_ARG("mac:del", set80211delmac), 5164 DEF_CMD_ARG("mac:kick", set80211kickmac), 5165 DEF_CMD("pureg", 1, set80211pureg), 5166 DEF_CMD("-pureg", 0, set80211pureg), 5167 DEF_CMD("ff", 1, set80211fastframes), 5168 DEF_CMD("-ff", 0, set80211fastframes), 5169 DEF_CMD("dturbo", 1, set80211dturbo), 5170 DEF_CMD("-dturbo", 0, set80211dturbo), 5171 DEF_CMD("bgscan", 1, set80211bgscan), 5172 DEF_CMD("-bgscan", 0, set80211bgscan), 5173 DEF_CMD_ARG("bgscanidle", set80211bgscanidle), 5174 DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl), 5175 DEF_CMD_ARG("scanvalid", set80211scanvalid), 5176 DEF_CMD_ARG("roam:rssi", set80211roamrssi), 5177 DEF_CMD_ARG("roam:rate", set80211roamrate), 5178 DEF_CMD_ARG("mcastrate", set80211mcastrate), 5179 DEF_CMD_ARG("ucastrate", set80211ucastrate), 5180 DEF_CMD_ARG("mgtrate", set80211mgtrate), 5181 DEF_CMD_ARG("mgmtrate", set80211mgtrate), 5182 DEF_CMD_ARG("maxretry", set80211maxretry), 5183 DEF_CMD_ARG("fragthreshold", set80211fragthreshold), 5184 DEF_CMD("burst", 1, set80211burst), 5185 DEF_CMD("-burst", 0, set80211burst), 5186 DEF_CMD_ARG("bmiss", set80211bmissthreshold), 5187 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), 5188 DEF_CMD("shortgi", 1, set80211shortgi), 5189 DEF_CMD("-shortgi", 0, set80211shortgi), 5190 DEF_CMD("ampdurx", 2, set80211ampdu), 5191 DEF_CMD("-ampdurx", -2, set80211ampdu), 5192 DEF_CMD("ampdutx", 1, set80211ampdu), 5193 DEF_CMD("-ampdutx", -1, set80211ampdu), 5194 DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */ 5195 DEF_CMD("-ampdu", -3, set80211ampdu), 5196 DEF_CMD_ARG("ampdulimit", set80211ampdulimit), 5197 DEF_CMD_ARG("ampdudensity", set80211ampdudensity), 5198 DEF_CMD("amsdurx", 2, set80211amsdu), 5199 DEF_CMD("-amsdurx", -2, set80211amsdu), 5200 DEF_CMD("amsdutx", 1, set80211amsdu), 5201 DEF_CMD("-amsdutx", -1, set80211amsdu), 5202 DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */ 5203 DEF_CMD("-amsdu", -3, set80211amsdu), 5204 DEF_CMD_ARG("amsdulimit", set80211amsdulimit), 5205 DEF_CMD("puren", 1, set80211puren), 5206 DEF_CMD("-puren", 0, set80211puren), 5207 DEF_CMD("doth", 1, set80211doth), 5208 DEF_CMD("-doth", 0, set80211doth), 5209 DEF_CMD("dfs", 1, set80211dfs), 5210 DEF_CMD("-dfs", 0, set80211dfs), 5211 DEF_CMD("htcompat", 1, set80211htcompat), 5212 DEF_CMD("-htcompat", 0, set80211htcompat), 5213 DEF_CMD("dwds", 1, set80211dwds), 5214 DEF_CMD("-dwds", 0, set80211dwds), 5215 DEF_CMD("inact", 1, set80211inact), 5216 DEF_CMD("-inact", 0, set80211inact), 5217 DEF_CMD("tsn", 1, set80211tsn), 5218 DEF_CMD("-tsn", 0, set80211tsn), 5219 DEF_CMD_ARG("regdomain", set80211regdomain), 5220 DEF_CMD_ARG("country", set80211country), 5221 DEF_CMD("indoor", 'I', set80211location), 5222 DEF_CMD("-indoor", 'O', set80211location), 5223 DEF_CMD("outdoor", 'O', set80211location), 5224 DEF_CMD("-outdoor", 'I', set80211location), 5225 DEF_CMD("anywhere", ' ', set80211location), 5226 DEF_CMD("ecm", 1, set80211ecm), 5227 DEF_CMD("-ecm", 0, set80211ecm), 5228 DEF_CMD("dotd", 1, set80211dotd), 5229 DEF_CMD("-dotd", 0, set80211dotd), 5230 DEF_CMD_ARG("htprotmode", set80211htprotmode), 5231 DEF_CMD("ht20", 1, set80211htconf), 5232 DEF_CMD("-ht20", 0, set80211htconf), 5233 DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */ 5234 DEF_CMD("-ht40", 0, set80211htconf), 5235 DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */ 5236 DEF_CMD("-ht", 0, set80211htconf), 5237 DEF_CMD("rifs", 1, set80211rifs), 5238 DEF_CMD("-rifs", 0, set80211rifs), 5239 DEF_CMD("smps", IEEE80211_HTCAP_SMPS_ENA, set80211smps), 5240 DEF_CMD("smpsdyn", IEEE80211_HTCAP_SMPS_DYNAMIC, set80211smps), 5241 DEF_CMD("-smps", IEEE80211_HTCAP_SMPS_OFF, set80211smps), 5242 /* XXX for testing */ 5243 DEF_CMD_ARG("chanswitch", set80211chanswitch), 5244 5245 DEF_CMD_ARG("tdmaslot", set80211tdmaslot), 5246 DEF_CMD_ARG("tdmaslotcnt", set80211tdmaslotcnt), 5247 DEF_CMD_ARG("tdmaslotlen", set80211tdmaslotlen), 5248 DEF_CMD_ARG("tdmabintval", set80211tdmabintval), 5249 5250 DEF_CMD_ARG("meshttl", set80211meshttl), 5251 DEF_CMD("meshforward", 1, set80211meshforward), 5252 DEF_CMD("-meshforward", 0, set80211meshforward), 5253 DEF_CMD("meshpeering", 1, set80211meshpeering), 5254 DEF_CMD("-meshpeering", 0, set80211meshpeering), 5255 DEF_CMD_ARG("meshmetric", set80211meshmetric), 5256 DEF_CMD_ARG("meshpath", set80211meshpath), 5257 DEF_CMD("meshrt:flush", IEEE80211_MESH_RTCMD_FLUSH, set80211meshrtcmd), 5258 DEF_CMD_ARG("meshrt:add", set80211addmeshrt), 5259 DEF_CMD_ARG("meshrt:del", set80211delmeshrt), 5260 DEF_CMD_ARG("hwmprootmode", set80211hwmprootmode), 5261 DEF_CMD_ARG("hwmpmaxhops", set80211hwmpmaxhops), 5262 5263 /* vap cloning support */ 5264 DEF_CLONE_CMD_ARG("wlanaddr", set80211clone_wlanaddr), 5265 DEF_CLONE_CMD_ARG("wlanbssid", set80211clone_wlanbssid), 5266 DEF_CLONE_CMD_ARG("wlandev", set80211clone_wlandev), 5267 DEF_CLONE_CMD_ARG("wlanmode", set80211clone_wlanmode), 5268 DEF_CLONE_CMD("beacons", 1, set80211clone_beacons), 5269 DEF_CLONE_CMD("-beacons", 0, set80211clone_beacons), 5270 DEF_CLONE_CMD("bssid", 1, set80211clone_bssid), 5271 DEF_CLONE_CMD("-bssid", 0, set80211clone_bssid), 5272 DEF_CLONE_CMD("wdslegacy", 1, set80211clone_wdslegacy), 5273 DEF_CLONE_CMD("-wdslegacy", 0, set80211clone_wdslegacy), 5274}; 5275static struct afswtch af_ieee80211 = { 5276 .af_name = "af_ieee80211", 5277 .af_af = AF_UNSPEC, 5278 .af_other_status = ieee80211_status, 5279}; 5280 5281static __constructor void 5282ieee80211_ctor(void) 5283{ 5284#define N(a) (sizeof(a) / sizeof(a[0])) 5285 int i; 5286 5287 for (i = 0; i < N(ieee80211_cmds); i++) 5288 cmd_register(&ieee80211_cmds[i]); 5289 af_register(&af_ieee80211); 5290 clone_setdefcallback("wlan", wlan_create); 5291#undef N 5292} 5293