2 * Copyright 2001 The Aerospace Corporation. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of The Aerospace Corporation may not be used to endorse or
13 * promote products derived from this software.
15 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.18.2.9 2006/03/07 17:50:23 sam Exp $
28 * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.12 2006/08/03 16:40:46 swildner Exp $
32 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
33 * All rights reserved.
35 * This code is derived from software contributed to The NetBSD Foundation
36 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
37 * NASA Ames Research Center.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 * must display the following acknowledgement:
49 * This product includes software developed by the NetBSD
50 * Foundation, Inc. and its contributors.
51 * 4. Neither the name of The NetBSD Foundation nor the names of its
52 * contributors may be used to endorse or promote products derived
53 * from this software without specific prior written permission.
55 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
56 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
57 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
58 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
59 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
60 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
61 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
62 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
65 * POSSIBILITY OF SUCH DAMAGE.
68 #include <sys/param.h>
69 #include <sys/ioctl.h>
70 #include <sys/socket.h>
71 #include <sys/sysctl.h>
74 #include <net/ethernet.h>
76 #include <net/if_dl.h>
77 #include <net/if_types.h>
78 #include <net/if_media.h>
79 #include <net/route.h>
81 #include <netproto/802_11/ieee80211.h>
82 #include <netproto/802_11/ieee80211_crypto.h>
83 #include <netproto/802_11/ieee80211_ioctl.h>
98 static void set80211(int s, int type, int val, int len, u_int8_t *data);
99 static const char *get_string(const char *val, const char *sep,
100 u_int8_t *buf, int *lenp);
101 static void print_string(const u_int8_t *buf, int len);
104 isanyarg(const char *arg)
106 return (strcmp(arg, "-") == 0 ||
107 strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
111 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
115 u_int8_t data[IEEE80211_NWID_LEN];
119 if (len > 2 && isdigit(val[0]) && val[1] == ':') {
124 bzero(data, sizeof(data));
126 if (get_string(val, NULL, data, &len) == NULL)
129 set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
133 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
138 bzero(data, sizeof(data));
140 get_string(val, NULL, data, &len);
142 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
146 * Convert IEEE channel number to MHz frequency.
149 ieee80211_ieee2mhz(u_int chan)
153 if (chan < 14) /* 0-13 */
154 return 2407 + chan*5;
155 if (chan < 27) /* 15-26 */
156 return 2512 + ((chan-15)*20);
157 return 5000 + (chan*5);
161 * Convert MHz frequency to IEEE channel number.
164 ieee80211_mhz2ieee(u_int freq)
169 return (freq - 2407) / 5;
171 return 15 + ((freq - 2512) / 20);
172 return (freq - 5000) / 5;
176 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
178 if (!isanyarg(val)) {
180 if (v > 255) /* treat as frequency */
181 v = ieee80211_mhz2ieee(v);
182 set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
184 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
188 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
192 if (strcasecmp(val, "none") == 0) {
193 mode = IEEE80211_AUTH_NONE;
194 } else if (strcasecmp(val, "open") == 0) {
195 mode = IEEE80211_AUTH_OPEN;
196 } else if (strcasecmp(val, "shared") == 0) {
197 mode = IEEE80211_AUTH_SHARED;
198 } else if (strcasecmp(val, "8021x") == 0) {
199 mode = IEEE80211_AUTH_8021X;
200 } else if (strcasecmp(val, "wpa") == 0) {
201 mode = IEEE80211_AUTH_WPA;
203 errx(1, "unknown authmode");
206 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
210 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
214 if (strcasecmp(val, "off") == 0) {
215 mode = IEEE80211_POWERSAVE_OFF;
216 } else if (strcasecmp(val, "on") == 0) {
217 mode = IEEE80211_POWERSAVE_ON;
218 } else if (strcasecmp(val, "cam") == 0) {
219 mode = IEEE80211_POWERSAVE_CAM;
220 } else if (strcasecmp(val, "psp") == 0) {
221 mode = IEEE80211_POWERSAVE_PSP;
222 } else if (strcasecmp(val, "psp-cam") == 0) {
223 mode = IEEE80211_POWERSAVE_PSP_CAM;
225 errx(1, "unknown powersavemode");
228 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
232 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
235 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
238 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
243 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
245 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
249 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
253 if (strcasecmp(val, "off") == 0) {
254 mode = IEEE80211_WEP_OFF;
255 } else if (strcasecmp(val, "on") == 0) {
256 mode = IEEE80211_WEP_ON;
257 } else if (strcasecmp(val, "mixed") == 0) {
258 mode = IEEE80211_WEP_MIXED;
260 errx(1, "unknown wep mode");
263 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
267 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
269 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
273 isundefarg(const char *arg)
275 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
279 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
282 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
284 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
288 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
292 u_int8_t data[IEEE80211_KEYBUF_SIZE];
294 if (isdigit(val[0]) && val[1] == ':') {
299 bzero(data, sizeof(data));
301 get_string(val, NULL, data, &len);
303 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
307 * This function is purely a NetBSD compatability interface. The NetBSD
308 * interface is too inflexible, but it's there so we'll support it since
309 * it's not all that hard.
312 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
316 u_int8_t data[IEEE80211_KEYBUF_SIZE];
318 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
320 if (isdigit(val[0]) && val[1] == ':') {
321 txkey = val[0]-'0'-1;
324 for (i = 0; i < 4; i++) {
325 bzero(data, sizeof(data));
327 val = get_string(val, ",", data, &len);
331 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
334 bzero(data, sizeof(data));
336 get_string(val, NULL, data, &len);
339 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
341 bzero(data, sizeof(data));
342 for (i = 1; i < 4; i++)
343 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
346 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
350 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
352 set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
353 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
357 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
361 if (strcasecmp(val, "off") == 0) {
362 mode = IEEE80211_PROTMODE_OFF;
363 } else if (strcasecmp(val, "cts") == 0) {
364 mode = IEEE80211_PROTMODE_CTS;
365 } else if (strcasecmp(val, "rtscts") == 0) {
366 mode = IEEE80211_PROTMODE_RTSCTS;
368 errx(1, "unknown protection mode");
371 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
375 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
377 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
380 #define IEEE80211_ROAMING_DEVICE 0
381 #define IEEE80211_ROAMING_AUTO 1
382 #define IEEE80211_ROAMING_MANUAL 2
385 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
389 if (strcasecmp(val, "device") == 0) {
390 mode = IEEE80211_ROAMING_DEVICE;
391 } else if (strcasecmp(val, "auto") == 0) {
392 mode = IEEE80211_ROAMING_AUTO;
393 } else if (strcasecmp(val, "manual") == 0) {
394 mode = IEEE80211_ROAMING_MANUAL;
396 errx(1, "unknown roaming mode");
398 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
402 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
404 set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
408 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
410 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
414 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
416 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
420 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
422 struct ieee80211req_chanlist chanlist;
423 #define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
424 char *temp, *cp, *tp;
426 temp = malloc(strlen(val) + 1);
428 errx(1, "malloc failed");
430 memset(&chanlist, 0, sizeof(chanlist));
435 tp = strchr(cp, ',');
438 switch (sscanf(cp, "%u-%u", &first, &last)) {
441 errx(-1, "channel %u out of range, max %zu",
443 setbit(chanlist.ic_channels, first);
447 errx(-1, "channel %u out of range, max %zu",
450 errx(-1, "channel %u out of range, max %zu",
453 errx(-1, "void channel range, %u > %u",
455 for (f = first; f <= last; f++)
456 setbit(chanlist.ic_channels, f);
467 set80211(s, IEEE80211_IOC_CHANLIST, 0,
468 sizeof(chanlist), (uint8_t *) &chanlist);
473 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
476 if (!isanyarg(val)) {
478 struct sockaddr_dl sdl;
480 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
482 errx(1, "malloc failed");
484 strcpy(temp + 1, val);
485 sdl.sdl_len = sizeof(sdl);
486 link_addr(temp, &sdl);
488 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
489 errx(1, "malformed link-level address");
490 set80211(s, IEEE80211_IOC_BSSID, 0,
491 IEEE80211_ADDR_LEN, LLADDR(&sdl));
493 uint8_t zerobssid[IEEE80211_ADDR_LEN];
494 memset(zerobssid, 0, sizeof(zerobssid));
495 set80211(s, IEEE80211_IOC_BSSID, 0,
496 IEEE80211_ADDR_LEN, zerobssid);
501 getac(const char *ac)
503 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
505 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
507 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
509 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
511 errx(1, "unknown wme access class %s", ac);
515 DECL_CMD_FUNC2(set80211cwmin, ac, val)
517 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
521 DECL_CMD_FUNC2(set80211cwmax, ac, val)
523 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
527 DECL_CMD_FUNC2(set80211aifs, ac, val)
529 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
533 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
535 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
539 DECL_CMD_FUNC(set80211acm, ac, d)
541 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
544 DECL_CMD_FUNC(set80211noacm, ac, d)
546 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
550 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
552 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
555 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
557 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
561 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
563 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
564 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
568 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
570 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
571 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
575 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
577 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
578 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
582 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
584 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
585 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
589 DECL_CMD_FUNC(set80211dtimperiod, val, d)
591 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
595 DECL_CMD_FUNC(set80211bintval, val, d)
597 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
601 set80211macmac(int s, int op, const char *val)
604 struct sockaddr_dl sdl;
606 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
608 errx(1, "malloc failed");
610 strcpy(temp + 1, val);
611 sdl.sdl_len = sizeof(sdl);
612 link_addr(temp, &sdl);
614 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
615 errx(1, "malformed link-level address");
616 set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
620 DECL_CMD_FUNC(set80211addmac, val, d)
622 set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
626 DECL_CMD_FUNC(set80211delmac, val, d)
628 set80211macmac(s, IEEE80211_IOC_DELMAC, val);
632 DECL_CMD_FUNC(set80211kickmac, val, d)
635 struct sockaddr_dl sdl;
636 struct ieee80211req_mlme mlme;
638 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
640 errx(1, "malloc failed");
642 strcpy(temp + 1, val);
643 sdl.sdl_len = sizeof(sdl);
644 link_addr(temp, &sdl);
646 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
647 errx(1, "malformed link-level address");
648 memset(&mlme, 0, sizeof(mlme));
649 mlme.im_op = IEEE80211_MLME_DEAUTH;
650 mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
651 memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
652 set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
656 DECL_CMD_FUNC(set80211maccmd, val, d)
658 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
662 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
664 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
668 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
670 set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
674 DECL_CMD_FUNC(set80211mcastrate, val, d)
676 set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
680 DECL_CMD_FUNC(set80211fragthreshold, val, d)
682 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
683 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
687 getmaxrate(uint8_t rates[15], uint8_t nrates)
691 for (i = 0; i < nrates; i++) {
692 int rate = rates[i] & IEEE80211_RATE_VAL;
702 static char capstring[32];
703 char *cp = capstring;
705 if (capinfo & IEEE80211_CAPINFO_ESS)
707 if (capinfo & IEEE80211_CAPINFO_IBSS)
709 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
711 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
713 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
715 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
717 if (capinfo & IEEE80211_CAPINFO_PBCC)
719 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
721 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
723 if (capinfo & IEEE80211_CAPINFO_RSN)
725 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
732 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
736 maxlen -= strlen(tag)+2;
737 if (2*ielen > maxlen)
740 for (; ielen > 0; ie++, ielen--) {
752 * Copy the ssid string contents into buf, truncating to fit. If the
753 * ssid is entirely printable then just copy intact. Otherwise convert
754 * to hexadecimal. If the result is truncated then replace the last
755 * three characters with "...".
758 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
764 if (essid_len > bufsize)
768 /* determine printable or not */
769 for (i = 0, p = essid; i < maxlen; i++, p++) {
770 if (*p < ' ' || *p > 0x7e)
773 if (i != maxlen) { /* not printable, print as hex */
776 strlcpy(buf, "0x", bufsize);
779 for (i = 0; i < maxlen && bufsize >= 2; i++) {
780 sprintf(&buf[2+2*i], "%02x", p[i]);
784 memcpy(&buf[2+2*i-3], "...", 3);
785 } else { /* printable, truncate as needed */
786 memcpy(buf, essid, maxlen);
787 if (maxlen != essid_len)
788 memcpy(&buf[maxlen-3], "...", 3);
793 /* unaligned little endian access */
794 #define LE_READ_4(p) \
796 ((((const u_int8_t *)(p))[0] ) | \
797 (((const u_int8_t *)(p))[1] << 8) | \
798 (((const u_int8_t *)(p))[2] << 16) | \
799 (((const u_int8_t *)(p))[3] << 24)))
802 iswpaoui(const u_int8_t *frm)
804 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
808 iswmeoui(const u_int8_t *frm)
810 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
814 isatherosoui(const u_int8_t *frm)
816 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
820 printies(const u_int8_t *vp, int ielen, int maxcols)
824 case IEEE80211_ELEMID_VENDOR:
826 printie(" WPA", vp, 2+vp[1], maxcols);
827 else if (iswmeoui(vp))
828 printie(" WME", vp, 2+vp[1], maxcols);
829 else if (isatherosoui(vp))
830 printie(" ATH", vp, 2+vp[1], maxcols);
832 printie(" VEN", vp, 2+vp[1], maxcols);
834 case IEEE80211_ELEMID_RSN:
835 printie(" RSN", vp, 2+vp[1], maxcols);
838 printie(" ???", vp, 2+vp[1], maxcols);
849 uint8_t buf[24*1024];
850 struct ieee80211req ireq;
851 char ssid[IEEE80211_NWID_LEN+1];
855 (void) memset(&ireq, 0, sizeof(ireq));
856 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
857 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
859 ireq.i_len = sizeof(buf);
860 if (ioctl(s, SIOCG80211, &ireq) < 0)
861 errx(1, "unable to get scan results");
863 if (len < sizeof(struct ieee80211req_scan_result))
866 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
867 printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
868 , ssidmax, ssidmax, "SSID"
878 struct ieee80211req_scan_result *sr;
881 sr = (struct ieee80211req_scan_result *) cp;
882 vp = (u_int8_t *)(sr+1);
883 printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
885 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
887 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
888 , ieee80211_mhz2ieee(sr->isr_freq)
889 , getmaxrate(sr->isr_rates, sr->isr_nrates)
890 , sr->isr_rssi, sr->isr_noise
892 , getcaps(sr->isr_capinfo)
894 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
896 cp += sr->isr_len, len -= sr->isr_len;
897 } while (len >= sizeof(struct ieee80211req_scan_result));
900 #include <netproto/802_11/ieee80211_dragonfly.h>
905 struct ieee80211req ireq;
908 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
910 perror("socket(PF_ROUTE,SOCK_RAW)");
913 (void) memset(&ireq, 0, sizeof(ireq));
914 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
915 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
916 /* NB: only root can trigger a scan so ignore errors */
917 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
919 struct if_announcemsghdr *ifan;
920 struct rt_msghdr *rtm;
923 if (read(sroute, buf, sizeof(buf)) < 0) {
924 perror("read(PF_ROUTE)");
927 rtm = (struct rt_msghdr *) buf;
928 if (rtm->rtm_version != RTM_VERSION)
930 ifan = (struct if_announcemsghdr *) rtm;
931 } while (rtm->rtm_type != RTM_IEEE80211 ||
932 ifan->ifan_what != RTM_IEEE80211_SCAN);
938 DECL_CMD_FUNC(set80211scan, val, d)
947 uint8_t buf[24*1024];
948 struct ieee80211req ireq;
952 (void) memset(&ireq, 0, sizeof(ireq));
953 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
954 ireq.i_type = IEEE80211_IOC_STA_INFO;
956 ireq.i_len = sizeof(buf);
957 if (ioctl(s, SIOCG80211, &ireq) < 0)
958 errx(1, "unable to get station information");
960 if (len < sizeof(struct ieee80211req_sta_info))
963 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
977 struct ieee80211req_sta_info *si;
980 si = (struct ieee80211req_sta_info *) cp;
981 vp = (u_int8_t *)(si+1);
982 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
983 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
984 , IEEE80211_AID(si->isi_associd)
985 , ieee80211_mhz2ieee(si->isi_freq)
986 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
991 , getcaps(si->isi_capinfo)
994 printies(vp, si->isi_ie_len, 24);
996 cp += si->isi_len, len -= si->isi_len;
997 } while (len >= sizeof(struct ieee80211req_sta_info));
1001 print_chaninfo(const struct ieee80211_channel *c)
1003 #define IEEE80211_IS_CHAN_PASSIVE(_c) \
1004 (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1008 if (IEEE80211_IS_CHAN_FHSS(c))
1009 strlcat(buf, " FHSS", sizeof(buf));
1010 if (IEEE80211_IS_CHAN_A(c))
1011 strlcat(buf, " 11a", sizeof(buf));
1012 /* XXX 11g schizophrenia */
1013 if (IEEE80211_IS_CHAN_G(c) ||
1014 IEEE80211_IS_CHAN_PUREG(c))
1015 strlcat(buf, " 11g", sizeof(buf));
1016 else if (IEEE80211_IS_CHAN_B(c))
1017 strlcat(buf, " 11b", sizeof(buf));
1018 if (IEEE80211_IS_CHAN_T(c))
1019 strlcat(buf, " Turbo", sizeof(buf));
1020 printf("Channel %3u : %u%c Mhz%-14.14s",
1021 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1022 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1023 #undef IEEE80211_IS_CHAN_PASSIVE
1027 list_channels(int s, int allchans)
1029 struct ieee80211req ireq;
1030 struct ieee80211req_chaninfo chans;
1031 struct ieee80211req_chaninfo achans;
1032 const struct ieee80211_channel *c;
1035 (void) memset(&ireq, 0, sizeof(ireq));
1036 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1037 ireq.i_type = IEEE80211_IOC_CHANINFO;
1038 ireq.i_data = &chans;
1039 ireq.i_len = sizeof(chans);
1040 if (ioctl(s, SIOCG80211, &ireq) < 0)
1041 errx(1, "unable to get channel information");
1043 struct ieee80211req_chanlist active;
1045 ireq.i_type = IEEE80211_IOC_CHANLIST;
1046 ireq.i_data = &active;
1047 ireq.i_len = sizeof(active);
1048 if (ioctl(s, SIOCG80211, &ireq) < 0)
1049 errx(1, "unable to get active channel list");
1050 memset(&achans, 0, sizeof(achans));
1051 for (i = 0; i < chans.ic_nchans; i++) {
1052 c = &chans.ic_chans[i];
1053 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1054 achans.ic_chans[achans.ic_nchans++] = *c;
1058 half = achans.ic_nchans / 2;
1059 if (achans.ic_nchans % 2)
1061 for (i = 0; i < achans.ic_nchans / 2; i++) {
1062 print_chaninfo(&achans.ic_chans[i]);
1063 print_chaninfo(&achans.ic_chans[half+i]);
1066 if (achans.ic_nchans % 2) {
1067 print_chaninfo(&achans.ic_chans[i]);
1077 #define IEEE80211_C_BITS \
1078 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1079 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1080 "\31WPA2\32BURST\33WME"
1083 list_capabilities(int s)
1085 struct ieee80211req ireq;
1088 (void) memset(&ireq, 0, sizeof(ireq));
1089 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1090 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1091 if (ioctl(s, SIOCG80211, &ireq) < 0)
1092 errx(1, "unable to get driver capabilities");
1093 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
1094 printb(name, caps, IEEE80211_C_BITS);
1101 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1102 struct ieee80211req ireq;
1105 (void) memset(&ireq, 0, sizeof(ireq));
1106 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1108 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1110 if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
1111 printf("\t%s", " ");
1113 printf("\t%s", acnames[ac]);
1115 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1117 /* show WME BSS parameters */
1118 ireq.i_type = IEEE80211_IOC_WME_CWMIN;
1119 if (ioctl(s, SIOCG80211, &ireq) != -1)
1120 printf(" cwmin %2u", ireq.i_val);
1121 ireq.i_type = IEEE80211_IOC_WME_CWMAX;
1122 if (ioctl(s, SIOCG80211, &ireq) != -1)
1123 printf(" cwmax %2u", ireq.i_val);
1124 ireq.i_type = IEEE80211_IOC_WME_AIFS;
1125 if (ioctl(s, SIOCG80211, &ireq) != -1)
1126 printf(" aifs %2u", ireq.i_val);
1127 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
1128 if (ioctl(s, SIOCG80211, &ireq) != -1)
1129 printf(" txopLimit %3u", ireq.i_val);
1130 ireq.i_type = IEEE80211_IOC_WME_ACM;
1131 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1138 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1139 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1140 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1148 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1149 ireq.i_len |= IEEE80211_WMEPARAM_BSS;
1152 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
1159 struct ieee80211req ireq;
1160 struct ieee80211req_maclist *acllist;
1161 int i, nacls, policy;
1164 (void) memset(&ireq, 0, sizeof(ireq));
1165 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
1166 ireq.i_type = IEEE80211_IOC_MACCMD;
1167 ireq.i_val = IEEE80211_MACCMD_POLICY;
1168 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1169 if (errno == EINVAL) {
1170 printf("No acl policy loaded\n");
1173 err(1, "unable to get mac policy");
1175 policy = ireq.i_val;
1177 ireq.i_val = IEEE80211_MACCMD_LIST;
1179 if (ioctl(s, SIOCG80211, &ireq) < 0)
1180 err(1, "unable to get mac acl list size");
1181 if (ireq.i_len == 0) /* NB: no acls */
1184 ireq.i_data = malloc(ireq.i_len);
1185 if (ireq.i_data == NULL)
1186 err(1, "out of memory for acl list");
1188 if (ioctl(s, SIOCG80211, &ireq) < 0)
1189 err(1, "unable to get mac acl list");
1190 if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
1192 printf("policy: open\n");
1194 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1196 printf("policy: allow\n");
1198 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1200 printf("policy: deny\n");
1203 printf("policy: unknown (%u)\n", policy);
1206 nacls = ireq.i_len / sizeof(*acllist);
1207 acllist = (struct ieee80211req_maclist *) ireq.i_data;
1208 for (i = 0; i < nacls; i++)
1209 printf("%c%s\n", c, ether_ntoa(
1210 (const struct ether_addr *) acllist[i].ml_macaddr));
1214 DECL_CMD_FUNC(set80211list, arg, d)
1216 #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
1218 if (iseq(arg, "sta"))
1220 else if (iseq(arg, "scan") || iseq(arg, "ap"))
1222 else if (iseq(arg, "chan") || iseq(arg, "freq"))
1223 list_channels(s, 1);
1224 else if (iseq(arg, "active"))
1225 list_channels(s, 0);
1226 else if (iseq(arg, "keys"))
1228 else if (iseq(arg, "caps"))
1229 list_capabilities(s);
1230 else if (iseq(arg, "wme"))
1232 else if (iseq(arg, "mac"))
1235 errx(1, "Don't know how to list %s for %s", arg, name);
1239 static enum ieee80211_opmode
1240 get80211opmode(int s)
1242 struct ifmediareq ifmr;
1244 (void) memset(&ifmr, 0, sizeof(ifmr));
1245 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1247 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1248 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
1249 return IEEE80211_M_IBSS; /* XXX ahdemo */
1250 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1251 return IEEE80211_M_HOSTAP;
1252 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
1253 return IEEE80211_M_MONITOR;
1255 return IEEE80211_M_STA;
1258 static const struct ieee80211_channel *
1259 getchaninfo(int s, int chan)
1261 struct ieee80211req ireq;
1262 static struct ieee80211req_chaninfo chans;
1263 static struct ieee80211_channel undef;
1264 const struct ieee80211_channel *c;
1267 (void) memset(&ireq, 0, sizeof(ireq));
1268 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1269 ireq.i_type = IEEE80211_IOC_CHANINFO;
1270 ireq.i_data = &chans;
1271 ireq.i_len = sizeof(chans);
1272 if (ioctl(s, SIOCG80211, &ireq) < 0)
1273 errx(1, "unable to get channel information");
1274 freq = ieee80211_ieee2mhz(chan);
1275 for (i = 0; i < chans.ic_nchans; i++) {
1276 c = &chans.ic_chans[i];
1277 if (c->ic_freq == freq)
1285 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1287 switch (ireq->i_val) {
1288 case IEEE80211_CIPHER_WEP:
1289 ireq->i_type = keylenop;
1290 if (ioctl(s, SIOCG80211, ireq) != -1)
1292 ireq->i_len <= 5 ? "40" :
1293 ireq->i_len <= 13 ? "104" : "128");
1297 case IEEE80211_CIPHER_TKIP:
1300 case IEEE80211_CIPHER_AES_OCB:
1303 case IEEE80211_CIPHER_AES_CCM:
1306 case IEEE80211_CIPHER_CKIP:
1309 case IEEE80211_CIPHER_NONE:
1313 printf("UNKNOWN (0x%x)", ireq->i_val);
1326 if (spacer != '\t') {
1330 col = 8; /* 8-col tab */
1334 LINE_CHECK(const char *fmt, ...)
1341 n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1354 printkey(const struct ieee80211req_key *ik)
1356 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1357 int keylen = ik->ik_keylen;
1360 printcontents = printkeys &&
1361 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
1364 switch (ik->ik_type) {
1365 case IEEE80211_CIPHER_WEP:
1367 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
1368 keylen <= 5 ? "40-bit" :
1369 keylen <= 13 ? "104-bit" : "128-bit");
1371 case IEEE80211_CIPHER_TKIP:
1373 keylen -= 128/8; /* ignore MIC for now */
1374 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1376 case IEEE80211_CIPHER_AES_OCB:
1377 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1379 case IEEE80211_CIPHER_AES_CCM:
1380 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1382 case IEEE80211_CIPHER_CKIP:
1383 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1385 case IEEE80211_CIPHER_NONE:
1386 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1389 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
1390 ik->ik_type, ik->ik_keyix+1, 8*keylen);
1393 if (printcontents) {
1397 for (i = 0; i < keylen; i++)
1398 printf("%02x", ik->ik_keydata[i]);
1400 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1401 (ik->ik_keyrsc != 0 || verbose))
1402 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
1403 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1404 (ik->ik_keytsc != 0 || verbose))
1405 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
1406 if (ik->ik_flags != 0 && verbose) {
1407 const char *sep = " ";
1409 if (ik->ik_flags & IEEE80211_KEY_XMIT)
1410 printf("%stx", sep), sep = "+";
1411 if (ik->ik_flags & IEEE80211_KEY_RECV)
1412 printf("%srx", sep), sep = "+";
1413 if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
1414 printf("%sdef", sep), sep = "+";
1421 ieee80211_status(int s)
1423 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1424 enum ieee80211_opmode opmode = get80211opmode(s);
1425 int i, num, wpa, wme;
1426 struct ieee80211req ireq;
1428 const struct ieee80211_channel *c;
1430 (void) memset(&ireq, 0, sizeof(ireq));
1431 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1432 ireq.i_data = &data;
1434 wpa = 0; /* unknown/not set */
1436 ireq.i_type = IEEE80211_IOC_SSID;
1438 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1439 /* If we can't get the SSID, this isn't an 802.11 device. */
1443 ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1444 if (ioctl(s, SIOCG80211, &ireq) >= 0)
1448 ireq.i_type = IEEE80211_IOC_SSID;
1449 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1450 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1451 printf(" %d:", ireq.i_val + 1);
1452 print_string(data, ireq.i_len);
1456 print_string(data, ireq.i_len);
1458 ireq.i_type = IEEE80211_IOC_CHANNEL;
1459 if (ioctl(s, SIOCG80211, &ireq) < 0)
1461 c = getchaninfo(s, ireq.i_val);
1462 if (ireq.i_val != -1) {
1463 printf(" channel %d", ireq.i_val);
1465 printf(" (%u)", c->ic_freq);
1467 printf(" channel UNDEF");
1469 ireq.i_type = IEEE80211_IOC_BSSID;
1470 ireq.i_len = IEEE80211_ADDR_LEN;
1471 if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1472 (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1473 printf(" bssid %s", ether_ntoa(ireq.i_data));
1475 ireq.i_type = IEEE80211_IOC_STATIONNAME;
1476 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1477 printf("\n\tstationname ");
1478 print_string(data, ireq.i_len);
1481 spacer = ' '; /* force first break */
1484 ireq.i_type = IEEE80211_IOC_AUTHMODE;
1485 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1486 switch (ireq.i_val) {
1487 case IEEE80211_AUTH_NONE:
1488 LINE_CHECK("authmode NONE");
1490 case IEEE80211_AUTH_OPEN:
1491 LINE_CHECK("authmode OPEN");
1493 case IEEE80211_AUTH_SHARED:
1494 LINE_CHECK("authmode SHARED");
1496 case IEEE80211_AUTH_8021X:
1497 LINE_CHECK("authmode 802.1x");
1499 case IEEE80211_AUTH_WPA:
1500 ireq.i_type = IEEE80211_IOC_WPA;
1501 if (ioctl(s, SIOCG80211, &ireq) != -1)
1504 wpa = 1; /* default to WPA1 */
1507 LINE_CHECK("authmode WPA2/802.11i");
1510 LINE_CHECK("authmode WPA1+WPA2/802.11i");
1513 LINE_CHECK("authmode WPA");
1517 case IEEE80211_AUTH_AUTO:
1518 LINE_CHECK("authmode AUTO");
1521 LINE_CHECK("authmode UNKNOWN (0x%x)",
1527 ireq.i_type = IEEE80211_IOC_WEP;
1528 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1529 ireq.i_val != IEEE80211_WEP_NOSUP) {
1530 int firstkey, wepmode;
1532 wepmode = ireq.i_val;
1534 case IEEE80211_WEP_OFF:
1535 LINE_CHECK("privacy OFF");
1537 case IEEE80211_WEP_ON:
1538 LINE_CHECK("privacy ON");
1540 case IEEE80211_WEP_MIXED:
1541 LINE_CHECK("privacy MIXED");
1544 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1549 * If we get here then we've got WEP support so we need
1550 * to print WEP status.
1553 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1554 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1555 warn("WEP support, but no tx key!");
1558 if (ireq.i_val != -1)
1559 LINE_CHECK("deftxkey %d", ireq.i_val+1);
1560 else if (wepmode != IEEE80211_WEP_OFF || verbose)
1561 LINE_CHECK("deftxkey UNDEF");
1563 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1564 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1565 warn("WEP support, but no NUMWEPKEYS support!");
1571 for (i = 0; i < num; i++) {
1572 struct ieee80211req_key ik;
1574 memset(&ik, 0, sizeof(ik));
1576 ireq.i_type = IEEE80211_IOC_WPAKEY;
1578 ireq.i_len = sizeof(ik);
1579 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1580 warn("WEP support, but can get keys!");
1583 if (ik.ik_keylen != 0) {
1592 ireq.i_type = IEEE80211_IOC_POWERSAVE;
1593 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1594 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1595 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1596 switch (ireq.i_val) {
1597 case IEEE80211_POWERSAVE_OFF:
1598 LINE_CHECK("powersavemode OFF");
1600 case IEEE80211_POWERSAVE_CAM:
1601 LINE_CHECK("powersavemode CAM");
1603 case IEEE80211_POWERSAVE_PSP:
1604 LINE_CHECK("powersavemode PSP");
1606 case IEEE80211_POWERSAVE_PSP_CAM:
1607 LINE_CHECK("powersavemode PSP-CAM");
1610 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1611 if (ioctl(s, SIOCG80211, &ireq) != -1)
1612 LINE_CHECK("powersavesleep %d", ireq.i_val);
1616 ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1617 if (ioctl(s, SIOCG80211, &ireq) != -1)
1618 LINE_CHECK("txpowmax %d", ireq.i_val);
1621 ireq.i_type = IEEE80211_IOC_TXPOWER;
1622 if (ioctl(s, SIOCG80211, &ireq) != -1)
1623 LINE_CHECK("txpower %d", ireq.i_val);
1626 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1627 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1628 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1629 LINE_CHECK("rtsthreshold %d", ireq.i_val);
1632 ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1633 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1634 if (ireq.i_val != 2*1 || verbose) {
1635 if (ireq.i_val == 11)
1636 LINE_CHECK("mcastrate 5.5");
1638 LINE_CHECK("mcastrate %d", ireq.i_val/2);
1642 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1643 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1644 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1645 LINE_CHECK("fragthreshold %d", ireq.i_val);
1648 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1649 ireq.i_type = IEEE80211_IOC_PUREG;
1650 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1652 LINE_CHECK("pureg");
1654 LINE_CHECK("-pureg");
1656 ireq.i_type = IEEE80211_IOC_PROTMODE;
1657 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1658 switch (ireq.i_val) {
1659 case IEEE80211_PROTMODE_OFF:
1660 LINE_CHECK("protmode OFF");
1662 case IEEE80211_PROTMODE_CTS:
1663 LINE_CHECK("protmode CTS");
1665 case IEEE80211_PROTMODE_RTSCTS:
1666 LINE_CHECK("protmode RTSCTS");
1669 LINE_CHECK("protmode UNKNOWN (0x%x)",
1676 ireq.i_type = IEEE80211_IOC_WME;
1677 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1686 ireq.i_type = IEEE80211_IOC_BURST;
1687 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1689 LINE_CHECK("burst");
1691 LINE_CHECK("-burst");
1694 if (opmode == IEEE80211_M_HOSTAP) {
1695 ireq.i_type = IEEE80211_IOC_HIDESSID;
1696 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1698 LINE_CHECK("ssid HIDE");
1700 LINE_CHECK("ssid SHOW");
1703 ireq.i_type = IEEE80211_IOC_APBRIDGE;
1704 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1706 LINE_CHECK("-apbridge");
1708 LINE_CHECK("apbridge");
1711 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1712 if (ioctl(s, SIOCG80211, &ireq) != -1)
1713 LINE_CHECK("dtimperiod %u", ireq.i_val);
1715 ireq.i_type = IEEE80211_IOC_ROAMING;
1716 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1717 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1718 switch (ireq.i_val) {
1719 case IEEE80211_ROAMING_DEVICE:
1720 LINE_CHECK("roaming DEVICE");
1722 case IEEE80211_ROAMING_AUTO:
1723 LINE_CHECK("roaming AUTO");
1725 case IEEE80211_ROAMING_MANUAL:
1726 LINE_CHECK("roaming MANUAL");
1729 LINE_CHECK("roaming UNKNOWN (0x%x)",
1736 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1737 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1739 LINE_CHECK("bintval %u", ireq.i_val);
1741 LINE_CHECK("bintval %u", ireq.i_val);
1744 if (wme && verbose) {
1750 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1751 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1753 LINE_CHECK("countermeasures");
1755 LINE_CHECK("-countermeasures");
1758 /* XXX not interesting with WPA done in user space */
1759 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1760 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1763 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1764 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1765 LINE_CHECK("mcastcipher ");
1766 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1770 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1771 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1772 LINE_CHECK("ucastcipher ");
1773 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1777 ireq.i_type = IEEE80211_IOC_RSNCAPS;
1778 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1779 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1784 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1785 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1797 set80211(int s, int type, int val, int len, u_int8_t *data)
1799 struct ieee80211req ireq;
1801 (void) memset(&ireq, 0, sizeof(ireq));
1802 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1807 if (ioctl(s, SIOCS80211, &ireq) < 0)
1808 err(1, "SIOCS80211");
1812 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1820 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1826 if (sep != NULL && strchr(sep, *val) != NULL) {
1831 if (!isxdigit((u_char)val[0])) {
1832 warnx("bad hexadecimal digits");
1835 if (!isxdigit((u_char)val[1])) {
1836 warnx("odd count hexadecimal digits");
1840 if (p >= buf + len) {
1842 warnx("hexadecimal digits too long");
1844 warnx("string too long");
1848 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1849 *p++ = (tohex((u_char)val[0]) << 4) |
1850 tohex((u_char)val[1]);
1857 /* The string "-" is treated as the empty string. */
1858 if (!hexstr && len == 1 && buf[0] == '-')
1861 memset(p, 0, *lenp - len);
1867 print_string(const u_int8_t *buf, int len)
1874 for (; i < len; i++) {
1875 if (!isprint(buf[i]) && buf[i] != '\0')
1877 if (isspace(buf[i]))
1881 if (hasspc || len == 0 || buf[0] == '\0')
1882 printf("\"%.*s\"", len, buf);
1884 printf("%.*s", len, buf);
1887 for (i = 0; i < len; i++)
1888 printf("%02x", buf[i]);
1892 static struct cmd ieee80211_cmds[] = {
1893 DEF_CMD_ARG("ssid", set80211ssid),
1894 DEF_CMD_ARG("nwid", set80211ssid),
1895 DEF_CMD_ARG("stationname", set80211stationname),
1896 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
1897 DEF_CMD_ARG("channel", set80211channel),
1898 DEF_CMD_ARG("authmode", set80211authmode),
1899 DEF_CMD_ARG("powersavemode", set80211powersavemode),
1900 DEF_CMD("powersave", 1, set80211powersave),
1901 DEF_CMD("-powersave", 0, set80211powersave),
1902 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
1903 DEF_CMD_ARG("wepmode", set80211wepmode),
1904 DEF_CMD("wep", 1, set80211wep),
1905 DEF_CMD("-wep", 0, set80211wep),
1906 DEF_CMD_ARG("deftxkey", set80211weptxkey),
1907 DEF_CMD_ARG("weptxkey", set80211weptxkey),
1908 DEF_CMD_ARG("wepkey", set80211wepkey),
1909 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
1910 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
1911 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
1912 DEF_CMD_ARG("protmode", set80211protmode),
1913 DEF_CMD_ARG("txpower", set80211txpower),
1914 DEF_CMD_ARG("roaming", set80211roaming),
1915 DEF_CMD("wme", 1, set80211wme),
1916 DEF_CMD("-wme", 0, set80211wme),
1917 DEF_CMD("hidessid", 1, set80211hidessid),
1918 DEF_CMD("-hidessid", 0, set80211hidessid),
1919 DEF_CMD("apbridge", 1, set80211apbridge),
1920 DEF_CMD("-apbridge", 0, set80211apbridge),
1921 DEF_CMD_ARG("chanlist", set80211chanlist),
1922 DEF_CMD_ARG("bssid", set80211bssid),
1923 DEF_CMD_ARG("ap", set80211bssid),
1924 DEF_CMD("scan", 0, set80211scan),
1925 DEF_CMD_ARG("list", set80211list),
1926 DEF_CMD_ARG2("cwmin", set80211cwmin),
1927 DEF_CMD_ARG2("cwmax", set80211cwmax),
1928 DEF_CMD_ARG2("aifs", set80211aifs),
1929 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
1930 DEF_CMD_ARG("acm", set80211acm),
1931 DEF_CMD_ARG("-acm", set80211noacm),
1932 DEF_CMD_ARG("ack", set80211ackpolicy),
1933 DEF_CMD_ARG("-ack", set80211noackpolicy),
1934 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
1935 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
1936 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
1937 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
1938 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
1939 DEF_CMD_ARG("bintval", set80211bintval),
1940 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
1941 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
1942 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
1943 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
1944 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
1945 DEF_CMD_ARG("mac:add", set80211addmac),
1946 DEF_CMD_ARG("mac:del", set80211delmac),
1947 DEF_CMD_ARG("mac:kick", set80211kickmac),
1948 DEF_CMD("pureg", 1, set80211pureg),
1949 DEF_CMD("-pureg", 0, set80211pureg),
1950 DEF_CMD_ARG("mcastrate", set80211mcastrate),
1951 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
1952 DEF_CMD("burst", 1, set80211burst),
1953 DEF_CMD("-burst", 0, set80211burst),
1955 static struct afswtch af_ieee80211 = {
1956 .af_name = "af_ieee80211",
1958 .af_other_status = ieee80211_status,
1961 static __constructor void
1962 ieee80211_ctor(void)
1964 #define N(a) (sizeof(a) / sizeof(a[0]))
1967 for (i = 0; i < N(ieee80211_cmds); i++)
1968 cmd_register(&ieee80211_cmds[i]);
1969 af_register(&af_ieee80211);