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.10 2006/08/10 06:09:23 sam Exp $
28 * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.20 2008/01/19 07:34:13 sephe 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>
84 #include <netproto/802_11/ieee80211_ratectl.h>
99 static void set80211(int s, int type, int val, int len, u_int8_t *data);
100 static const char *get_string(const char *val, const char *sep,
101 u_int8_t *buf, int *lenp);
102 static void print_string(const u_int8_t *buf, int len);
105 isanyarg(const char *arg)
107 return (strcmp(arg, "-") == 0 ||
108 strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
112 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
116 u_int8_t data[IEEE80211_NWID_LEN];
120 if (len > 2 && isdigit(val[0]) && val[1] == ':') {
125 bzero(data, sizeof(data));
127 if (get_string(val, NULL, data, &len) == NULL)
130 set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
134 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
139 bzero(data, sizeof(data));
141 get_string(val, NULL, data, &len);
143 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
147 * Convert IEEE channel number to MHz frequency.
150 ieee80211_ieee2mhz(u_int chan)
154 if (chan < 14) /* 0-13 */
155 return 2407 + chan*5;
156 if (chan < 27) /* 15-26 */
157 return 2512 + ((chan-15)*20);
158 return 5000 + (chan*5);
162 * Convert MHz frequency to IEEE channel number.
165 ieee80211_mhz2ieee(u_int freq)
170 return (freq - 2407) / 5;
172 return 15 + ((freq - 2512) / 20);
173 return (freq - 5000) / 5;
177 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
179 if (!isanyarg(val)) {
181 if (v > 255) /* treat as frequency */
182 v = ieee80211_mhz2ieee(v);
183 set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
185 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
189 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
193 if (strcasecmp(val, "none") == 0) {
194 mode = IEEE80211_AUTH_NONE;
195 } else if (strcasecmp(val, "open") == 0) {
196 mode = IEEE80211_AUTH_OPEN;
197 } else if (strcasecmp(val, "shared") == 0) {
198 mode = IEEE80211_AUTH_SHARED;
199 } else if (strcasecmp(val, "8021x") == 0) {
200 mode = IEEE80211_AUTH_8021X;
201 } else if (strcasecmp(val, "wpa") == 0) {
202 mode = IEEE80211_AUTH_WPA;
204 errx(1, "unknown authmode");
207 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
211 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
215 if (strcasecmp(val, "off") == 0) {
216 mode = IEEE80211_POWERSAVE_OFF;
217 } else if (strcasecmp(val, "on") == 0) {
218 mode = IEEE80211_POWERSAVE_ON;
219 } else if (strcasecmp(val, "cam") == 0) {
220 mode = IEEE80211_POWERSAVE_CAM;
221 } else if (strcasecmp(val, "psp") == 0) {
222 mode = IEEE80211_POWERSAVE_PSP;
223 } else if (strcasecmp(val, "psp-cam") == 0) {
224 mode = IEEE80211_POWERSAVE_PSP_CAM;
226 errx(1, "unknown powersavemode");
229 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
233 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
236 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
239 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
244 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
246 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
250 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
254 if (strcasecmp(val, "off") == 0) {
255 mode = IEEE80211_WEP_OFF;
256 } else if (strcasecmp(val, "on") == 0) {
257 mode = IEEE80211_WEP_ON;
258 } else if (strcasecmp(val, "mixed") == 0) {
259 mode = IEEE80211_WEP_MIXED;
261 errx(1, "unknown wep mode");
264 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
268 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
270 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
274 isundefarg(const char *arg)
276 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
280 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
283 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
285 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
289 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
293 u_int8_t data[IEEE80211_KEYBUF_SIZE];
295 if (isdigit(val[0]) && val[1] == ':') {
300 bzero(data, sizeof(data));
302 get_string(val, NULL, data, &len);
304 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
308 * This function is purely a NetBSD compatability interface. The NetBSD
309 * interface is too inflexible, but it's there so we'll support it since
310 * it's not all that hard.
313 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
317 u_int8_t data[IEEE80211_KEYBUF_SIZE];
319 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
321 if (isdigit(val[0]) && val[1] == ':') {
322 txkey = val[0]-'0'-1;
325 for (i = 0; i < 4; i++) {
326 bzero(data, sizeof(data));
328 val = get_string(val, ",", data, &len);
332 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
335 bzero(data, sizeof(data));
337 get_string(val, NULL, data, &len);
340 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
342 bzero(data, sizeof(data));
343 for (i = 1; i < 4; i++)
344 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
347 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
351 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
353 set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
354 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
358 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
362 if (strcasecmp(val, "off") == 0) {
363 mode = IEEE80211_PROTMODE_OFF;
364 } else if (strcasecmp(val, "cts") == 0) {
365 mode = IEEE80211_PROTMODE_CTS;
366 } else if (strcasecmp(val, "rtscts") == 0) {
367 mode = IEEE80211_PROTMODE_RTSCTS;
369 errx(1, "unknown protection mode");
372 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
376 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
378 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
381 #define IEEE80211_ROAMING_DEVICE 0
382 #define IEEE80211_ROAMING_AUTO 1
383 #define IEEE80211_ROAMING_MANUAL 2
386 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
390 if (strcasecmp(val, "device") == 0) {
391 mode = IEEE80211_ROAMING_DEVICE;
392 } else if (strcasecmp(val, "auto") == 0) {
393 mode = IEEE80211_ROAMING_AUTO;
394 } else if (strcasecmp(val, "manual") == 0) {
395 mode = IEEE80211_ROAMING_MANUAL;
397 errx(1, "unknown roaming mode");
399 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
403 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
405 set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
409 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
411 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
415 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
417 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
421 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
423 struct ieee80211req_chanlist chanlist;
424 #define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
425 char *temp, *cp, *tp;
427 temp = malloc(strlen(val) + 1);
429 errx(1, "malloc failed");
431 memset(&chanlist, 0, sizeof(chanlist));
436 tp = strchr(cp, ',');
439 switch (sscanf(cp, "%u-%u", &first, &last)) {
442 errx(-1, "channel %u out of range, max %zu",
444 setbit(chanlist.ic_channels, first);
448 errx(-1, "channel %u out of range, max %zu",
451 errx(-1, "channel %u out of range, max %zu",
454 errx(-1, "void channel range, %u > %u",
456 for (f = first; f <= last; f++)
457 setbit(chanlist.ic_channels, f);
468 set80211(s, IEEE80211_IOC_CHANLIST, 0,
469 sizeof(chanlist), (uint8_t *) &chanlist);
474 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
477 if (!isanyarg(val)) {
479 struct sockaddr_dl sdl;
481 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
483 errx(1, "malloc failed");
485 strcpy(temp + 1, val);
486 sdl.sdl_len = sizeof(sdl);
487 link_addr(temp, &sdl);
489 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
490 errx(1, "malformed link-level address");
491 set80211(s, IEEE80211_IOC_BSSID, 0,
492 IEEE80211_ADDR_LEN, LLADDR(&sdl));
494 uint8_t zerobssid[IEEE80211_ADDR_LEN];
495 memset(zerobssid, 0, sizeof(zerobssid));
496 set80211(s, IEEE80211_IOC_BSSID, 0,
497 IEEE80211_ADDR_LEN, zerobssid);
502 getac(const char *ac)
504 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
506 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
508 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
510 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
512 errx(1, "unknown wme access class %s", ac);
516 DECL_CMD_FUNC2(set80211cwmin, ac, val)
518 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
522 DECL_CMD_FUNC2(set80211cwmax, ac, val)
524 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
528 DECL_CMD_FUNC2(set80211aifs, ac, val)
530 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
534 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
536 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
540 DECL_CMD_FUNC(set80211acm, ac, d)
542 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
545 DECL_CMD_FUNC(set80211noacm, ac, d)
547 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
551 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
553 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
556 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
558 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
562 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
564 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
565 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
569 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
571 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
572 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
576 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
578 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
579 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
583 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
585 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
586 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
590 DECL_CMD_FUNC(set80211dtimperiod, val, d)
592 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
596 DECL_CMD_FUNC(set80211bintval, val, d)
598 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
602 set80211macmac(int s, int op, const char *val)
605 struct sockaddr_dl sdl;
607 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
609 errx(1, "malloc failed");
611 strcpy(temp + 1, val);
612 sdl.sdl_len = sizeof(sdl);
613 link_addr(temp, &sdl);
615 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
616 errx(1, "malformed link-level address");
617 set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
621 DECL_CMD_FUNC(set80211addmac, val, d)
623 set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
627 DECL_CMD_FUNC(set80211delmac, val, d)
629 set80211macmac(s, IEEE80211_IOC_DELMAC, val);
633 DECL_CMD_FUNC(set80211kickmac, val, d)
636 struct sockaddr_dl sdl;
637 struct ieee80211req_mlme mlme;
639 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
641 errx(1, "malloc failed");
643 strcpy(temp + 1, val);
644 sdl.sdl_len = sizeof(sdl);
645 link_addr(temp, &sdl);
647 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
648 errx(1, "malformed link-level address");
649 memset(&mlme, 0, sizeof(mlme));
650 mlme.im_op = IEEE80211_MLME_DEAUTH;
651 mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
652 memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
653 set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
657 DECL_CMD_FUNC(set80211maccmd, val, d)
659 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
663 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
665 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
669 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
671 set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
675 set80211ratectl(const char *val, int d, int s, const struct afswtch *rafp)
679 if (strcmp("onoe", val) == 0)
680 ratectl = IEEE80211_RATECTL_ONOE;
681 else if (strcmp("amrr", val) == 0)
682 ratectl = IEEE80211_RATECTL_AMRR;
683 else if (strcmp("sample", val) == 0)
684 ratectl = IEEE80211_RATECTL_SAMPLE;
686 errx(1, "unknown ratectl");
688 set80211(s, IEEE80211_IOC_RATECTL, ratectl, 0, NULL);
692 DECL_CMD_FUNC(set80211mcastrate, val, d)
694 set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
698 DECL_CMD_FUNC(set80211fragthreshold, val, d)
700 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
701 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
705 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
707 set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
708 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
712 getmaxrate(uint8_t rates[15], uint8_t nrates)
716 for (i = 0; i < nrates; i++) {
717 int rate = rates[i] & IEEE80211_RATE_VAL;
727 static char capstring[32];
728 char *cp = capstring;
730 if (capinfo & IEEE80211_CAPINFO_ESS)
732 if (capinfo & IEEE80211_CAPINFO_IBSS)
734 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
736 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
738 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
740 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
742 if (capinfo & IEEE80211_CAPINFO_PBCC)
744 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
746 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
748 if (capinfo & IEEE80211_CAPINFO_RSN)
750 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
757 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
761 maxlen -= strlen(tag)+2;
762 if (2*ielen > maxlen)
765 for (; ielen > 0; ie++, ielen--) {
777 * Copy the ssid string contents into buf, truncating to fit. If the
778 * ssid is entirely printable then just copy intact. Otherwise convert
779 * to hexadecimal. If the result is truncated then replace the last
780 * three characters with "...".
783 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
789 if (essid_len > bufsize)
793 /* determine printable or not */
794 for (i = 0, p = essid; i < maxlen; i++, p++) {
795 if (*p < ' ' || *p > 0x7e)
798 if (i != maxlen) { /* not printable, print as hex */
801 strlcpy(buf, "0x", bufsize);
804 for (i = 0; i < maxlen && bufsize >= 2; i++) {
805 sprintf(&buf[2+2*i], "%02x", p[i]);
809 memcpy(&buf[2+2*i-3], "...", 3);
810 } else { /* printable, truncate as needed */
811 memcpy(buf, essid, maxlen);
812 if (maxlen != essid_len)
813 memcpy(&buf[maxlen-3], "...", 3);
818 /* unaligned little endian access */
819 #define LE_READ_4(p) \
821 ((((const u_int8_t *)(p))[0] ) | \
822 (((const u_int8_t *)(p))[1] << 8) | \
823 (((const u_int8_t *)(p))[2] << 16) | \
824 (((const u_int8_t *)(p))[3] << 24)))
827 iswpaoui(const u_int8_t *frm)
829 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
833 iswmeoui(const u_int8_t *frm)
835 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
839 isatherosoui(const u_int8_t *frm)
841 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
845 printies(const u_int8_t *vp, int ielen, int maxcols)
849 case IEEE80211_ELEMID_VENDOR:
851 printie(" WPA", vp, 2+vp[1], maxcols);
852 else if (iswmeoui(vp))
853 printie(" WME", vp, 2+vp[1], maxcols);
854 else if (isatherosoui(vp))
855 printie(" ATH", vp, 2+vp[1], maxcols);
857 printie(" VEN", vp, 2+vp[1], maxcols);
859 case IEEE80211_ELEMID_RSN:
860 printie(" RSN", vp, 2+vp[1], maxcols);
863 printie(" ???", vp, 2+vp[1], maxcols);
874 uint8_t buf[24*1024];
875 struct ieee80211req ireq;
876 char ssid[IEEE80211_NWID_LEN+1];
880 (void) memset(&ireq, 0, sizeof(ireq));
881 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
882 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
884 ireq.i_len = sizeof(buf);
885 if (ioctl(s, SIOCG80211, &ireq) < 0)
886 errx(1, "unable to get scan results");
888 if (len < sizeof(struct ieee80211req_scan_result))
891 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
892 printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
893 , ssidmax, ssidmax, "SSID"
903 struct ieee80211req_scan_result *sr;
906 sr = (struct ieee80211req_scan_result *) cp;
907 vp = (u_int8_t *)(sr+1);
908 printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
910 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
912 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
913 , ieee80211_mhz2ieee(sr->isr_freq)
914 , getmaxrate(sr->isr_rates, sr->isr_nrates)
915 , sr->isr_rssi, sr->isr_noise
917 , getcaps(sr->isr_capinfo2)
919 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
921 cp += sr->isr_len, len -= sr->isr_len;
922 } while (len >= sizeof(struct ieee80211req_scan_result));
925 #include <netproto/802_11/ieee80211_dragonfly.h>
930 struct ieee80211req ireq;
933 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
935 perror("socket(PF_ROUTE,SOCK_RAW)");
938 (void) memset(&ireq, 0, sizeof(ireq));
939 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
940 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
941 /* NB: only root can trigger a scan so ignore errors */
942 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
944 struct if_announcemsghdr *ifan;
945 struct rt_msghdr *rtm;
948 if (read(sroute, buf, sizeof(buf)) < 0) {
949 perror("read(PF_ROUTE)");
952 rtm = (struct rt_msghdr *) buf;
953 if (rtm->rtm_version != RTM_VERSION)
955 ifan = (struct if_announcemsghdr *) rtm;
956 } while (rtm->rtm_type != RTM_IEEE80211 ||
957 ifan->ifan_what != RTM_IEEE80211_SCAN);
963 DECL_CMD_FUNC(set80211scan, val, d)
969 static enum ieee80211_opmode get80211opmode(int s);
975 struct ieee80211req_sta_req req;
976 uint8_t buf[24*1024];
978 enum ieee80211_opmode opmode = get80211opmode(s);
979 struct ieee80211req ireq;
983 (void) memset(&ireq, 0, sizeof(ireq));
984 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
985 /* broadcast address =>'s get all stations */
986 (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
987 if (opmode == IEEE80211_M_STA) {
989 * Get information about the associated AP.
991 ireq.i_type = IEEE80211_IOC_BSSID;
992 ireq.i_data = u.req.is_u.macaddr;
993 ireq.i_len = IEEE80211_ADDR_LEN;
994 (void) ioctl(s, SIOCG80211, &ireq);
996 ireq.i_type = IEEE80211_IOC_STA_INFO;
998 ireq.i_len = sizeof(u);
999 if (ioctl(s, SIOCG80211, &ireq) < 0)
1000 errx(1, "unable to get station information");
1002 if (len < sizeof(struct ieee80211req_sta_info))
1005 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
1017 cp = (uint8_t *) u.req.info;
1019 struct ieee80211req_sta_info *si;
1022 si = (struct ieee80211req_sta_info *) cp;
1023 if (si->isi_len < sizeof(*si))
1025 vp = (u_int8_t *)(si+1);
1026 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
1027 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1028 , IEEE80211_AID(si->isi_associd)
1029 , ieee80211_mhz2ieee(si->isi_freq)
1030 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
1035 , getcaps(si->isi_capinfo2)
1038 printies(vp, si->isi_ie_len, 24);
1040 cp += si->isi_len, len -= si->isi_len;
1041 } while (len >= sizeof(struct ieee80211req_sta_info));
1045 print_chaninfo(const struct ieee80211_channel *c)
1047 #define IEEE80211_IS_CHAN_PASSIVE(_c) \
1048 (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1052 if (IEEE80211_IS_CHAN_FHSS(c))
1053 strlcat(buf, " FHSS", sizeof(buf));
1054 if (IEEE80211_IS_CHAN_A(c))
1055 strlcat(buf, " 11a", sizeof(buf));
1056 /* XXX 11g schizophrenia */
1057 if (IEEE80211_IS_CHAN_G(c) ||
1058 IEEE80211_IS_CHAN_PUREG(c))
1059 strlcat(buf, " 11g", sizeof(buf));
1060 else if (IEEE80211_IS_CHAN_B(c))
1061 strlcat(buf, " 11b", sizeof(buf));
1062 if (IEEE80211_IS_CHAN_T(c))
1063 strlcat(buf, " Turbo", sizeof(buf));
1064 printf("Channel %3u : %u%c Mhz%-14.14s",
1065 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1066 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1067 #undef IEEE80211_IS_CHAN_PASSIVE
1071 list_channels(int s, int allchans)
1073 struct ieee80211req ireq;
1074 struct ieee80211req_chaninfo chans;
1075 struct ieee80211req_chaninfo achans;
1076 const struct ieee80211_channel *c;
1079 (void) memset(&ireq, 0, sizeof(ireq));
1080 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1081 ireq.i_type = IEEE80211_IOC_CHANINFO;
1082 ireq.i_data = &chans;
1083 ireq.i_len = sizeof(chans);
1084 if (ioctl(s, SIOCG80211, &ireq) < 0)
1085 errx(1, "unable to get channel information");
1087 struct ieee80211req_chanlist active;
1089 ireq.i_type = IEEE80211_IOC_CHANLIST;
1090 ireq.i_data = &active;
1091 ireq.i_len = sizeof(active);
1092 if (ioctl(s, SIOCG80211, &ireq) < 0)
1093 errx(1, "unable to get active channel list");
1094 memset(&achans, 0, sizeof(achans));
1095 for (i = 0; i < chans.ic_nchans; i++) {
1096 c = &chans.ic_chans[i];
1097 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1098 achans.ic_chans[achans.ic_nchans++] = *c;
1102 half = achans.ic_nchans / 2;
1103 if (achans.ic_nchans % 2)
1105 for (i = 0; i < achans.ic_nchans / 2; i++) {
1106 print_chaninfo(&achans.ic_chans[i]);
1107 print_chaninfo(&achans.ic_chans[half+i]);
1110 if (achans.ic_nchans % 2) {
1111 print_chaninfo(&achans.ic_chans[i]);
1121 #define IEEE80211_C_BITS \
1122 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1123 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1124 "\31WPA2\32BURST\33WME"
1126 #define IEEE80211_CEXT_BITS "\020\1PBCC"
1129 list_capabilities(int s)
1131 struct ieee80211req ireq;
1132 uint32_t caps, caps_ext;
1134 memset(&ireq, 0, sizeof(ireq));
1137 strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1138 ireq.i_data = &caps_ext;
1139 ireq.i_len = sizeof(caps_ext);
1140 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1141 if (ioctl(s, SIOCG80211, &ireq) < 0)
1142 errx(1, "unable to get driver capabilities");
1143 caps = (((uint16_t)ireq.i_val) << 16) | ((uint16_t)ireq.i_len);
1144 printb(name, caps, IEEE80211_C_BITS);
1146 printb(", ext", caps_ext, IEEE80211_CEXT_BITS);
1153 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1154 struct ieee80211req ireq;
1157 (void) memset(&ireq, 0, sizeof(ireq));
1158 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1160 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1162 if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
1163 printf("\t%s", " ");
1165 printf("\t%s", acnames[ac]);
1167 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1169 /* show WME BSS parameters */
1170 ireq.i_type = IEEE80211_IOC_WME_CWMIN;
1171 if (ioctl(s, SIOCG80211, &ireq) != -1)
1172 printf(" cwmin %2u", ireq.i_val);
1173 ireq.i_type = IEEE80211_IOC_WME_CWMAX;
1174 if (ioctl(s, SIOCG80211, &ireq) != -1)
1175 printf(" cwmax %2u", ireq.i_val);
1176 ireq.i_type = IEEE80211_IOC_WME_AIFS;
1177 if (ioctl(s, SIOCG80211, &ireq) != -1)
1178 printf(" aifs %2u", ireq.i_val);
1179 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
1180 if (ioctl(s, SIOCG80211, &ireq) != -1)
1181 printf(" txopLimit %3u", ireq.i_val);
1182 ireq.i_type = IEEE80211_IOC_WME_ACM;
1183 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1190 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1191 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1192 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1200 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1201 ireq.i_len |= IEEE80211_WMEPARAM_BSS;
1204 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
1211 struct ieee80211req ireq;
1212 struct ieee80211req_maclist *acllist;
1213 int i, nacls, policy;
1216 (void) memset(&ireq, 0, sizeof(ireq));
1217 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
1218 ireq.i_type = IEEE80211_IOC_MACCMD;
1219 ireq.i_val = IEEE80211_MACCMD_POLICY;
1220 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1221 if (errno == EINVAL) {
1222 printf("No acl policy loaded\n");
1225 err(1, "unable to get mac policy");
1227 policy = ireq.i_val;
1229 ireq.i_val = IEEE80211_MACCMD_LIST;
1231 if (ioctl(s, SIOCG80211, &ireq) < 0)
1232 err(1, "unable to get mac acl list size");
1233 if (ireq.i_len == 0) /* NB: no acls */
1236 ireq.i_data = malloc(ireq.i_len);
1237 if (ireq.i_data == NULL)
1238 err(1, "out of memory for acl list");
1240 if (ioctl(s, SIOCG80211, &ireq) < 0)
1241 err(1, "unable to get mac acl list");
1242 if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
1244 printf("policy: open\n");
1246 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1248 printf("policy: allow\n");
1250 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1252 printf("policy: deny\n");
1255 printf("policy: unknown (%u)\n", policy);
1258 nacls = ireq.i_len / sizeof(*acllist);
1259 acllist = (struct ieee80211req_maclist *) ireq.i_data;
1260 for (i = 0; i < nacls; i++)
1261 printf("%c%s\n", c, ether_ntoa(
1262 (const struct ether_addr *) acllist[i].ml_macaddr));
1266 DECL_CMD_FUNC(set80211list, arg, d)
1268 #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
1270 if (iseq(arg, "sta"))
1272 else if (iseq(arg, "scan") || iseq(arg, "ap"))
1274 else if (iseq(arg, "chan") || iseq(arg, "freq"))
1275 list_channels(s, 1);
1276 else if (iseq(arg, "active"))
1277 list_channels(s, 0);
1278 else if (iseq(arg, "keys"))
1280 else if (iseq(arg, "caps"))
1281 list_capabilities(s);
1282 else if (iseq(arg, "wme"))
1284 else if (iseq(arg, "mac"))
1287 errx(1, "Don't know how to list %s for %s", arg, name);
1291 static enum ieee80211_opmode
1292 get80211opmode(int s)
1294 struct ifmediareq ifmr;
1296 (void) memset(&ifmr, 0, sizeof(ifmr));
1297 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1299 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1300 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
1301 return IEEE80211_M_IBSS; /* XXX ahdemo */
1302 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1303 return IEEE80211_M_HOSTAP;
1304 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
1305 return IEEE80211_M_MONITOR;
1307 return IEEE80211_M_STA;
1310 static const struct ieee80211_channel *
1311 getchaninfo(int s, int chan)
1313 struct ieee80211req ireq;
1314 static struct ieee80211req_chaninfo chans;
1315 static struct ieee80211_channel undef;
1316 const struct ieee80211_channel *c;
1319 (void) memset(&ireq, 0, sizeof(ireq));
1320 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1321 ireq.i_type = IEEE80211_IOC_CHANINFO;
1322 ireq.i_data = &chans;
1323 ireq.i_len = sizeof(chans);
1324 if (ioctl(s, SIOCG80211, &ireq) < 0)
1325 errx(1, "unable to get channel information");
1326 freq = ieee80211_ieee2mhz(chan);
1327 for (i = 0; i < chans.ic_nchans; i++) {
1328 c = &chans.ic_chans[i];
1329 if (c->ic_freq == freq)
1337 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1339 switch (ireq->i_val) {
1340 case IEEE80211_CIPHER_WEP:
1341 ireq->i_type = keylenop;
1342 if (ioctl(s, SIOCG80211, ireq) != -1)
1344 ireq->i_len <= 5 ? "40" :
1345 ireq->i_len <= 13 ? "104" : "128");
1349 case IEEE80211_CIPHER_TKIP:
1352 case IEEE80211_CIPHER_AES_OCB:
1355 case IEEE80211_CIPHER_AES_CCM:
1358 case IEEE80211_CIPHER_CKIP:
1361 case IEEE80211_CIPHER_NONE:
1365 printf("UNKNOWN (0x%x)", ireq->i_val);
1378 if (spacer != '\t') {
1382 col = 8; /* 8-col tab */
1386 LINE_CHECK(const char *fmt, ...)
1393 n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1406 printkey(const struct ieee80211req_key *ik)
1408 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1409 int keylen = ik->ik_keylen;
1412 printcontents = printkeys &&
1413 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
1416 switch (ik->ik_type) {
1417 case IEEE80211_CIPHER_WEP:
1419 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
1420 keylen <= 5 ? "40-bit" :
1421 keylen <= 13 ? "104-bit" : "128-bit");
1423 case IEEE80211_CIPHER_TKIP:
1425 keylen -= 128/8; /* ignore MIC for now */
1426 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1428 case IEEE80211_CIPHER_AES_OCB:
1429 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1431 case IEEE80211_CIPHER_AES_CCM:
1432 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1434 case IEEE80211_CIPHER_CKIP:
1435 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1437 case IEEE80211_CIPHER_NONE:
1438 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1441 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
1442 ik->ik_type, ik->ik_keyix+1, 8*keylen);
1445 if (printcontents) {
1449 for (i = 0; i < keylen; i++)
1450 printf("%02x", ik->ik_keydata[i]);
1452 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1453 (ik->ik_keyrsc != 0 || verbose))
1454 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
1455 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1456 (ik->ik_keytsc != 0 || verbose))
1457 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
1458 if (ik->ik_flags != 0 && verbose) {
1459 const char *sep = " ";
1461 if (ik->ik_flags & IEEE80211_KEY_XMIT)
1462 printf("%stx", sep), sep = "+";
1463 if (ik->ik_flags & IEEE80211_KEY_RECV)
1464 printf("%srx", sep), sep = "+";
1465 if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
1466 printf("%sdef", sep), sep = "+";
1473 ieee80211_status(int s)
1475 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1476 enum ieee80211_opmode opmode = get80211opmode(s);
1477 int i, num, wpa, wme;
1478 struct ieee80211req ireq;
1480 const struct ieee80211_channel *c;
1482 (void) memset(&ireq, 0, sizeof(ireq));
1483 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1484 ireq.i_data = &data;
1486 wpa = 0; /* unknown/not set */
1488 ireq.i_type = IEEE80211_IOC_SSID;
1490 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1491 /* If we can't get the SSID, this isn't an 802.11 device. */
1495 ireq.i_type = IEEE80211_IOC_RATECTL;
1496 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1499 switch (ireq.i_val) {
1500 case IEEE80211_RATECTL_ONOE:
1501 printf("\tratectl: onoe");
1503 case IEEE80211_RATECTL_AMRR:
1504 printf("\tratectl: amrr");
1506 case IEEE80211_RATECTL_SAMPLE:
1507 printf("\tratectl: sample");
1511 printf("\tratectl: none");
1521 ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1522 if (ioctl(s, SIOCG80211, &ireq) >= 0)
1526 ireq.i_type = IEEE80211_IOC_SSID;
1527 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1528 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1529 printf(" %d:", ireq.i_val + 1);
1530 print_string(data, ireq.i_len);
1534 print_string(data, ireq.i_len);
1536 ireq.i_type = IEEE80211_IOC_CHANNEL;
1537 if (ioctl(s, SIOCG80211, &ireq) < 0)
1539 c = getchaninfo(s, ireq.i_val);
1540 if (ireq.i_val != -1) {
1541 printf(" channel %d", ireq.i_val);
1543 printf(" (%u)", c->ic_freq);
1545 printf(" channel UNDEF");
1547 ireq.i_type = IEEE80211_IOC_BSSID;
1548 ireq.i_len = IEEE80211_ADDR_LEN;
1549 if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1550 (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1551 printf(" bssid %s", ether_ntoa(ireq.i_data));
1553 ireq.i_type = IEEE80211_IOC_STATIONNAME;
1554 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1555 printf("\n\tstationname ");
1556 print_string(data, ireq.i_len);
1559 spacer = ' '; /* force first break */
1562 ireq.i_type = IEEE80211_IOC_AUTHMODE;
1563 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1564 switch (ireq.i_val) {
1565 case IEEE80211_AUTH_NONE:
1566 LINE_CHECK("authmode NONE");
1568 case IEEE80211_AUTH_OPEN:
1569 LINE_CHECK("authmode OPEN");
1571 case IEEE80211_AUTH_SHARED:
1572 LINE_CHECK("authmode SHARED");
1574 case IEEE80211_AUTH_8021X:
1575 LINE_CHECK("authmode 802.1x");
1577 case IEEE80211_AUTH_WPA:
1578 ireq.i_type = IEEE80211_IOC_WPA;
1579 if (ioctl(s, SIOCG80211, &ireq) != -1)
1582 wpa = 1; /* default to WPA1 */
1585 LINE_CHECK("authmode WPA2/802.11i");
1588 LINE_CHECK("authmode WPA1+WPA2/802.11i");
1591 LINE_CHECK("authmode WPA");
1595 case IEEE80211_AUTH_AUTO:
1596 LINE_CHECK("authmode AUTO");
1599 LINE_CHECK("authmode UNKNOWN (0x%x)",
1605 ireq.i_type = IEEE80211_IOC_WEP;
1606 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1607 ireq.i_val != IEEE80211_WEP_NOSUP) {
1608 int firstkey, wepmode;
1610 wepmode = ireq.i_val;
1612 case IEEE80211_WEP_OFF:
1613 LINE_CHECK("privacy OFF");
1615 case IEEE80211_WEP_ON:
1616 LINE_CHECK("privacy ON");
1618 case IEEE80211_WEP_MIXED:
1619 LINE_CHECK("privacy MIXED");
1622 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1627 * If we get here then we've got WEP support so we need
1628 * to print WEP status.
1631 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1632 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1633 warn("WEP support, but no tx key!");
1636 if (ireq.i_val != -1)
1637 LINE_CHECK("deftxkey %d", ireq.i_val+1);
1638 else if (wepmode != IEEE80211_WEP_OFF || verbose)
1639 LINE_CHECK("deftxkey UNDEF");
1641 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1642 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1643 warn("WEP support, but no NUMWEPKEYS support!");
1649 for (i = 0; i < num; i++) {
1650 struct ieee80211req_key ik;
1652 memset(&ik, 0, sizeof(ik));
1654 ireq.i_type = IEEE80211_IOC_WPAKEY;
1656 ireq.i_len = sizeof(ik);
1657 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1658 warn("WEP support, but can get keys!");
1661 if (ik.ik_keylen != 0) {
1670 ireq.i_type = IEEE80211_IOC_POWERSAVE;
1671 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1672 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1673 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1674 switch (ireq.i_val) {
1675 case IEEE80211_POWERSAVE_OFF:
1676 LINE_CHECK("powersavemode OFF");
1678 case IEEE80211_POWERSAVE_CAM:
1679 LINE_CHECK("powersavemode CAM");
1681 case IEEE80211_POWERSAVE_PSP:
1682 LINE_CHECK("powersavemode PSP");
1684 case IEEE80211_POWERSAVE_PSP_CAM:
1685 LINE_CHECK("powersavemode PSP-CAM");
1688 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1689 if (ioctl(s, SIOCG80211, &ireq) != -1)
1690 LINE_CHECK("powersavesleep %d", ireq.i_val);
1694 ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1695 if (ioctl(s, SIOCG80211, &ireq) != -1)
1696 LINE_CHECK("txpowmax %d", ireq.i_val);
1699 ireq.i_type = IEEE80211_IOC_TXPOWER;
1700 if (ioctl(s, SIOCG80211, &ireq) != -1)
1701 LINE_CHECK("txpower %d", ireq.i_val);
1704 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1705 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1706 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1707 LINE_CHECK("rtsthreshold %d", ireq.i_val);
1710 ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1711 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1712 if (ireq.i_val != 2*1 || verbose) {
1713 if (ireq.i_val == 11)
1714 LINE_CHECK("mcastrate 5.5");
1716 LINE_CHECK("mcastrate %d", ireq.i_val/2);
1720 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1721 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1722 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1723 LINE_CHECK("fragthreshold %d", ireq.i_val);
1726 ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
1727 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1728 if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
1729 LINE_CHECK("bmiss %d", ireq.i_val);
1732 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1733 ireq.i_type = IEEE80211_IOC_PUREG;
1734 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1736 LINE_CHECK("pureg");
1738 LINE_CHECK("-pureg");
1740 ireq.i_type = IEEE80211_IOC_PROTMODE;
1741 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1742 switch (ireq.i_val) {
1743 case IEEE80211_PROTMODE_OFF:
1744 LINE_CHECK("protmode OFF");
1746 case IEEE80211_PROTMODE_CTS:
1747 LINE_CHECK("protmode CTS");
1749 case IEEE80211_PROTMODE_RTSCTS:
1750 LINE_CHECK("protmode RTSCTS");
1753 LINE_CHECK("protmode UNKNOWN (0x%x)",
1760 ireq.i_type = IEEE80211_IOC_WME;
1761 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1770 ireq.i_type = IEEE80211_IOC_BURST;
1771 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1773 LINE_CHECK("burst");
1775 LINE_CHECK("-burst");
1778 if (opmode == IEEE80211_M_HOSTAP) {
1779 ireq.i_type = IEEE80211_IOC_HIDESSID;
1780 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1782 LINE_CHECK("ssid HIDE");
1784 LINE_CHECK("ssid SHOW");
1787 ireq.i_type = IEEE80211_IOC_APBRIDGE;
1788 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1790 LINE_CHECK("-apbridge");
1792 LINE_CHECK("apbridge");
1795 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1796 if (ioctl(s, SIOCG80211, &ireq) != -1)
1797 LINE_CHECK("dtimperiod %u", ireq.i_val);
1799 ireq.i_type = IEEE80211_IOC_ROAMING;
1800 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1801 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1802 switch (ireq.i_val) {
1803 case IEEE80211_ROAMING_DEVICE:
1804 LINE_CHECK("roaming DEVICE");
1806 case IEEE80211_ROAMING_AUTO:
1807 LINE_CHECK("roaming AUTO");
1809 case IEEE80211_ROAMING_MANUAL:
1810 LINE_CHECK("roaming MANUAL");
1813 LINE_CHECK("roaming UNKNOWN (0x%x)",
1820 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1821 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1823 LINE_CHECK("bintval %u", ireq.i_val);
1825 LINE_CHECK("bintval %u", ireq.i_val);
1828 if (wme && verbose) {
1834 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1835 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1837 LINE_CHECK("countermeasures");
1839 LINE_CHECK("-countermeasures");
1842 /* XXX not interesting with WPA done in user space */
1843 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1844 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1847 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1848 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1849 LINE_CHECK("mcastcipher ");
1850 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1854 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1855 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1856 LINE_CHECK("ucastcipher ");
1857 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1861 ireq.i_type = IEEE80211_IOC_RSNCAPS;
1862 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1863 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1868 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1869 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1881 set80211(int s, int type, int val, int len, u_int8_t *data)
1883 struct ieee80211req ireq;
1885 (void) memset(&ireq, 0, sizeof(ireq));
1886 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1891 if (ioctl(s, SIOCS80211, &ireq) < 0)
1892 err(1, "SIOCS80211");
1896 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1904 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1910 if (sep != NULL && strchr(sep, *val) != NULL) {
1915 if (!isxdigit((u_char)val[0])) {
1916 warnx("bad hexadecimal digits");
1919 if (!isxdigit((u_char)val[1])) {
1920 warnx("odd count hexadecimal digits");
1924 if (p >= buf + len) {
1926 warnx("hexadecimal digits too long");
1928 warnx("string too long");
1932 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1933 *p++ = (tohex((u_char)val[0]) << 4) |
1934 tohex((u_char)val[1]);
1942 memset(p, 0, *lenp - len);
1943 /* The string "-" is treated as the empty string. */
1944 if (!hexstr && len == 1 && buf[0] == '-')
1951 print_string(const u_int8_t *buf, int len)
1958 for (; i < len; i++) {
1959 if (!isprint(buf[i]) && buf[i] != '\0')
1961 if (isspace(buf[i]))
1965 if (hasspc || len == 0 || buf[0] == '\0')
1966 printf("\"%.*s\"", len, buf);
1968 printf("%.*s", len, buf);
1971 for (i = 0; i < len; i++)
1972 printf("%02x", buf[i]);
1976 static struct cmd ieee80211_cmds[] = {
1977 DEF_CMD_ARG("ssid", set80211ssid),
1978 DEF_CMD_ARG("nwid", set80211ssid),
1979 DEF_CMD_ARG("stationname", set80211stationname),
1980 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
1981 DEF_CMD_ARG("channel", set80211channel),
1982 DEF_CMD_ARG("authmode", set80211authmode),
1983 DEF_CMD_ARG("powersavemode", set80211powersavemode),
1984 DEF_CMD("powersave", 1, set80211powersave),
1985 DEF_CMD("-powersave", 0, set80211powersave),
1986 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
1987 DEF_CMD_ARG("wepmode", set80211wepmode),
1988 DEF_CMD("wep", 1, set80211wep),
1989 DEF_CMD("-wep", 0, set80211wep),
1990 DEF_CMD_ARG("deftxkey", set80211weptxkey),
1991 DEF_CMD_ARG("weptxkey", set80211weptxkey),
1992 DEF_CMD_ARG("wepkey", set80211wepkey),
1993 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
1994 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
1995 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
1996 DEF_CMD_ARG("protmode", set80211protmode),
1997 DEF_CMD_ARG("txpower", set80211txpower),
1998 DEF_CMD_ARG("roaming", set80211roaming),
1999 DEF_CMD("wme", 1, set80211wme),
2000 DEF_CMD("-wme", 0, set80211wme),
2001 DEF_CMD("hidessid", 1, set80211hidessid),
2002 DEF_CMD("-hidessid", 0, set80211hidessid),
2003 DEF_CMD("apbridge", 1, set80211apbridge),
2004 DEF_CMD("-apbridge", 0, set80211apbridge),
2005 DEF_CMD_ARG("chanlist", set80211chanlist),
2006 DEF_CMD_ARG("bssid", set80211bssid),
2007 DEF_CMD_ARG("ap", set80211bssid),
2008 DEF_CMD("scan", 0, set80211scan),
2009 DEF_CMD_ARG("list", set80211list),
2010 DEF_CMD_ARG2("cwmin", set80211cwmin),
2011 DEF_CMD_ARG2("cwmax", set80211cwmax),
2012 DEF_CMD_ARG2("aifs", set80211aifs),
2013 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
2014 DEF_CMD_ARG("acm", set80211acm),
2015 DEF_CMD_ARG("-acm", set80211noacm),
2016 DEF_CMD_ARG("ack", set80211ackpolicy),
2017 DEF_CMD_ARG("-ack", set80211noackpolicy),
2018 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
2019 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
2020 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
2021 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
2022 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
2023 DEF_CMD_ARG("bintval", set80211bintval),
2024 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
2025 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
2026 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
2027 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
2028 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
2029 DEF_CMD_ARG("mac:add", set80211addmac),
2030 DEF_CMD_ARG("mac:del", set80211delmac),
2031 DEF_CMD_ARG("mac:kick", set80211kickmac),
2032 DEF_CMD("pureg", 1, set80211pureg),
2033 DEF_CMD("-pureg", 0, set80211pureg),
2034 DEF_CMD_ARG("mcastrate", set80211mcastrate),
2035 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
2036 DEF_CMD("burst", 1, set80211burst),
2037 DEF_CMD("-burst", 0, set80211burst),
2038 DEF_CMD_ARG("ratectl", set80211ratectl),
2039 DEF_CMD_ARG("bmiss", set80211bmissthreshold),
2040 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold)
2042 static struct afswtch af_ieee80211 = {
2043 .af_name = "af_ieee80211",
2045 .af_other_status = ieee80211_status,
2048 static __constructor void
2049 ieee80211_ctor(void)
2051 #define N(a) (sizeof(a) / sizeof(a[0]))
2054 for (i = 0; i < N(ieee80211_cmds); i++)
2055 cmd_register(&ieee80211_cmds[i]);
2056 af_register(&af_ieee80211);