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
31 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
32 * All rights reserved.
34 * This code is derived from software contributed to The NetBSD Foundation
35 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36 * NASA Ames Research Center.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the NetBSD
49 * Foundation, Inc. and its contributors.
50 * 4. Neither the name of The NetBSD Foundation nor the names of its
51 * contributors may be used to endorse or promote products derived
52 * from this software without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
55 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
58 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64 * POSSIBILITY OF SUCH DAMAGE.
67 #include <sys/param.h>
68 #include <sys/ioctl.h>
69 #include <sys/socket.h>
70 #include <sys/sysctl.h>
73 #include <net/ethernet.h>
75 #include <net/if_dl.h>
76 #include <net/if_types.h>
77 #include <net/if_media.h>
78 #include <net/route.h>
80 #include <net80211/ieee80211.h>
81 #include <net80211/ieee80211_crypto.h>
82 #include <net80211/ieee80211_ioctl.h>
97 static void set80211(int s, int type, int val, int len, u_int8_t *data);
98 static const char *get_string(const char *val, const char *sep,
99 u_int8_t *buf, int *lenp);
100 static void print_string(const u_int8_t *buf, int len);
103 isanyarg(const char *arg)
105 return (strcmp(arg, "-") == 0 ||
106 strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
110 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
114 u_int8_t data[IEEE80211_NWID_LEN];
118 if (len > 2 && isdigit(val[0]) && val[1] == ':') {
123 bzero(data, sizeof(data));
125 if (get_string(val, NULL, data, &len) == NULL)
128 set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
132 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
137 bzero(data, sizeof(data));
139 get_string(val, NULL, data, &len);
141 set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
145 * Convert IEEE channel number to MHz frequency.
148 ieee80211_ieee2mhz(u_int chan)
152 if (chan < 14) /* 0-13 */
153 return 2407 + chan*5;
154 if (chan < 27) /* 15-26 */
155 return 2512 + ((chan-15)*20);
156 return 5000 + (chan*5);
160 * Convert MHz frequency to IEEE channel number.
163 ieee80211_mhz2ieee(u_int freq)
168 return (freq - 2407) / 5;
170 return 15 + ((freq - 2512) / 20);
171 return (freq - 5000) / 5;
175 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
177 if (!isanyarg(val)) {
179 if (v > 255) /* treat as frequency */
180 v = ieee80211_mhz2ieee(v);
181 set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
183 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
187 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
191 if (strcasecmp(val, "none") == 0) {
192 mode = IEEE80211_AUTH_NONE;
193 } else if (strcasecmp(val, "open") == 0) {
194 mode = IEEE80211_AUTH_OPEN;
195 } else if (strcasecmp(val, "shared") == 0) {
196 mode = IEEE80211_AUTH_SHARED;
197 } else if (strcasecmp(val, "8021x") == 0) {
198 mode = IEEE80211_AUTH_8021X;
199 } else if (strcasecmp(val, "wpa") == 0) {
200 mode = IEEE80211_AUTH_WPA;
202 errx(1, "unknown authmode");
205 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
209 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
213 if (strcasecmp(val, "off") == 0) {
214 mode = IEEE80211_POWERSAVE_OFF;
215 } else if (strcasecmp(val, "on") == 0) {
216 mode = IEEE80211_POWERSAVE_ON;
217 } else if (strcasecmp(val, "cam") == 0) {
218 mode = IEEE80211_POWERSAVE_CAM;
219 } else if (strcasecmp(val, "psp") == 0) {
220 mode = IEEE80211_POWERSAVE_PSP;
221 } else if (strcasecmp(val, "psp-cam") == 0) {
222 mode = IEEE80211_POWERSAVE_PSP_CAM;
224 errx(1, "unknown powersavemode");
227 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
231 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
234 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
237 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
242 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
244 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
248 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
252 if (strcasecmp(val, "off") == 0) {
253 mode = IEEE80211_WEP_OFF;
254 } else if (strcasecmp(val, "on") == 0) {
255 mode = IEEE80211_WEP_ON;
256 } else if (strcasecmp(val, "mixed") == 0) {
257 mode = IEEE80211_WEP_MIXED;
259 errx(1, "unknown wep mode");
262 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
266 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
268 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
272 isundefarg(const char *arg)
274 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
278 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
281 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
283 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
287 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
291 u_int8_t data[IEEE80211_KEYBUF_SIZE];
293 if (isdigit(val[0]) && val[1] == ':') {
298 bzero(data, sizeof(data));
300 get_string(val, NULL, data, &len);
302 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
306 * This function is purely a NetBSD compatability interface. The NetBSD
307 * interface is too inflexible, but it's there so we'll support it since
308 * it's not all that hard.
311 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
315 u_int8_t data[IEEE80211_KEYBUF_SIZE];
317 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
319 if (isdigit(val[0]) && val[1] == ':') {
320 txkey = val[0]-'0'-1;
323 for (i = 0; i < 4; i++) {
324 bzero(data, sizeof(data));
326 val = get_string(val, ",", data, &len);
330 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
333 bzero(data, sizeof(data));
335 get_string(val, NULL, data, &len);
338 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
340 bzero(data, sizeof(data));
341 for (i = 1; i < 4; i++)
342 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
345 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
349 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
351 set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
352 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
356 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
360 if (strcasecmp(val, "off") == 0) {
361 mode = IEEE80211_PROTMODE_OFF;
362 } else if (strcasecmp(val, "cts") == 0) {
363 mode = IEEE80211_PROTMODE_CTS;
364 } else if (strcasecmp(val, "rtscts") == 0) {
365 mode = IEEE80211_PROTMODE_RTSCTS;
367 errx(1, "unknown protection mode");
370 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
374 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
376 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
379 #define IEEE80211_ROAMING_DEVICE 0
380 #define IEEE80211_ROAMING_AUTO 1
381 #define IEEE80211_ROAMING_MANUAL 2
384 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
388 if (strcasecmp(val, "device") == 0) {
389 mode = IEEE80211_ROAMING_DEVICE;
390 } else if (strcasecmp(val, "auto") == 0) {
391 mode = IEEE80211_ROAMING_AUTO;
392 } else if (strcasecmp(val, "manual") == 0) {
393 mode = IEEE80211_ROAMING_MANUAL;
395 errx(1, "unknown roaming mode");
397 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
401 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
403 set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
407 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
409 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
413 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
415 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
419 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
421 struct ieee80211req_chanlist chanlist;
422 #define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
423 char *temp, *cp, *tp;
425 temp = malloc(strlen(val) + 1);
427 errx(1, "malloc failed");
429 memset(&chanlist, 0, sizeof(chanlist));
434 tp = strchr(cp, ',');
437 switch (sscanf(cp, "%u-%u", &first, &last)) {
440 errx(-1, "channel %u out of range, max %zu",
442 setbit(chanlist.ic_channels, first);
446 errx(-1, "channel %u out of range, max %zu",
449 errx(-1, "channel %u out of range, max %zu",
452 errx(-1, "void channel range, %u > %u",
454 for (f = first; f <= last; f++)
455 setbit(chanlist.ic_channels, f);
466 set80211(s, IEEE80211_IOC_CHANLIST, 0,
467 sizeof(chanlist), (uint8_t *) &chanlist);
472 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
475 if (!isanyarg(val)) {
477 struct sockaddr_dl sdl;
479 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
481 errx(1, "malloc failed");
483 strcpy(temp + 1, val);
484 sdl.sdl_len = sizeof(sdl);
485 link_addr(temp, &sdl);
487 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
488 errx(1, "malformed link-level address");
489 set80211(s, IEEE80211_IOC_BSSID, 0,
490 IEEE80211_ADDR_LEN, LLADDR(&sdl));
492 uint8_t zerobssid[IEEE80211_ADDR_LEN];
493 memset(zerobssid, 0, sizeof(zerobssid));
494 set80211(s, IEEE80211_IOC_BSSID, 0,
495 IEEE80211_ADDR_LEN, zerobssid);
500 getac(const char *ac)
502 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
504 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
506 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
508 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
510 errx(1, "unknown wme access class %s", ac);
514 DECL_CMD_FUNC2(set80211cwmin, ac, val)
516 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
520 DECL_CMD_FUNC2(set80211cwmax, ac, val)
522 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
526 DECL_CMD_FUNC2(set80211aifs, ac, val)
528 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
532 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
534 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
538 DECL_CMD_FUNC(set80211acm, ac, d)
540 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
543 DECL_CMD_FUNC(set80211noacm, ac, d)
545 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
549 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
551 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
554 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
556 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
560 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
562 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
563 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
567 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
569 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
570 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
574 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
576 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
577 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
581 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
583 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
584 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
588 DECL_CMD_FUNC(set80211dtimperiod, val, d)
590 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
594 DECL_CMD_FUNC(set80211bintval, val, d)
596 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
600 set80211macmac(int s, int op, const char *val)
603 struct sockaddr_dl sdl;
605 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
607 errx(1, "malloc failed");
609 strcpy(temp + 1, val);
610 sdl.sdl_len = sizeof(sdl);
611 link_addr(temp, &sdl);
613 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
614 errx(1, "malformed link-level address");
615 set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
619 DECL_CMD_FUNC(set80211addmac, val, d)
621 set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
625 DECL_CMD_FUNC(set80211delmac, val, d)
627 set80211macmac(s, IEEE80211_IOC_DELMAC, val);
631 DECL_CMD_FUNC(set80211kickmac, val, d)
634 struct sockaddr_dl sdl;
635 struct ieee80211req_mlme mlme;
637 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
639 errx(1, "malloc failed");
641 strcpy(temp + 1, val);
642 sdl.sdl_len = sizeof(sdl);
643 link_addr(temp, &sdl);
645 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
646 errx(1, "malformed link-level address");
647 memset(&mlme, 0, sizeof(mlme));
648 mlme.im_op = IEEE80211_MLME_DEAUTH;
649 mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
650 memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
651 set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
655 DECL_CMD_FUNC(set80211maccmd, val, d)
657 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
661 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
663 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
667 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
669 set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
673 DECL_CMD_FUNC(set80211mcastrate, val, d)
675 set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
679 DECL_CMD_FUNC(set80211fragthreshold, val, d)
681 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
682 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
686 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
688 set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
689 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
693 getmaxrate(uint8_t rates[15], uint8_t nrates)
697 for (i = 0; i < nrates; i++) {
698 int rate = rates[i] & IEEE80211_RATE_VAL;
708 static char capstring[32];
709 char *cp = capstring;
711 if (capinfo & IEEE80211_CAPINFO_ESS)
713 if (capinfo & IEEE80211_CAPINFO_IBSS)
715 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
717 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
719 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
721 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
723 if (capinfo & IEEE80211_CAPINFO_PBCC)
725 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
727 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
729 if (capinfo & IEEE80211_CAPINFO_RSN)
731 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
740 /* XXX need these publicly defined or similar */
741 #define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */
742 #define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */
743 #define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */
744 #define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */
745 static char flagstring[32];
746 char *cp = flagstring;
748 if (flags & IEEE80211_NODE_AUTH)
750 if (flags & IEEE80211_NODE_QOS)
752 if (flags & IEEE80211_NODE_ERP)
754 if (flags & IEEE80211_NODE_PWR_MGT)
758 #undef IEEE80211_NODE_AUTH
759 #undef IEEE80211_NODE_QOS
760 #undef IEEE80211_NODE_ERP
761 #undef IEEE80211_NODE_PWR_MGT
765 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
769 maxlen -= strlen(tag)+2;
770 if (2*ielen > maxlen)
773 for (; ielen > 0; ie++, ielen--) {
785 * Copy the ssid string contents into buf, truncating to fit. If the
786 * ssid is entirely printable then just copy intact. Otherwise convert
787 * to hexadecimal. If the result is truncated then replace the last
788 * three characters with "...".
791 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
797 if (essid_len > bufsize)
801 /* determine printable or not */
802 for (i = 0, p = essid; i < maxlen; i++, p++) {
803 if (*p < ' ' || *p > 0x7e)
806 if (i != maxlen) { /* not printable, print as hex */
809 strlcpy(buf, "0x", bufsize);
812 for (i = 0; i < maxlen && bufsize >= 2; i++) {
813 sprintf(&buf[2+2*i], "%02x", p[i]);
817 memcpy(&buf[2+2*i-3], "...", 3);
818 } else { /* printable, truncate as needed */
819 memcpy(buf, essid, maxlen);
820 if (maxlen != essid_len)
821 memcpy(&buf[maxlen-3], "...", 3);
826 /* unaligned little endian access */
827 #define LE_READ_4(p) \
829 ((((const u_int8_t *)(p))[0] ) | \
830 (((const u_int8_t *)(p))[1] << 8) | \
831 (((const u_int8_t *)(p))[2] << 16) | \
832 (((const u_int8_t *)(p))[3] << 24)))
835 iswpaoui(const u_int8_t *frm)
837 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
841 iswmeoui(const u_int8_t *frm)
843 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
847 isatherosoui(const u_int8_t *frm)
849 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
853 printies(const u_int8_t *vp, int ielen, int maxcols)
857 case IEEE80211_ELEMID_VENDOR:
859 printie(" WPA", vp, 2+vp[1], maxcols);
860 else if (iswmeoui(vp))
861 printie(" WME", vp, 2+vp[1], maxcols);
862 else if (isatherosoui(vp))
863 printie(" ATH", vp, 2+vp[1], maxcols);
865 printie(" VEN", vp, 2+vp[1], maxcols);
867 case IEEE80211_ELEMID_RSN:
868 printie(" RSN", vp, 2+vp[1], maxcols);
871 printie(" ???", vp, 2+vp[1], maxcols);
882 uint8_t buf[24*1024];
883 struct ieee80211req ireq;
884 char ssid[IEEE80211_NWID_LEN+1];
888 (void) memset(&ireq, 0, sizeof(ireq));
889 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
890 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
892 ireq.i_len = sizeof(buf);
893 if (ioctl(s, SIOCG80211, &ireq) < 0)
894 errx(1, "unable to get scan results");
896 if (len < sizeof(struct ieee80211req_scan_result))
899 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
900 printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
901 , ssidmax, ssidmax, "SSID"
911 struct ieee80211req_scan_result *sr;
914 sr = (struct ieee80211req_scan_result *) cp;
915 vp = (u_int8_t *)(sr+1);
916 printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
918 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
920 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
921 , ieee80211_mhz2ieee(sr->isr_freq)
922 , getmaxrate(sr->isr_rates, sr->isr_nrates)
923 , sr->isr_rssi, sr->isr_noise
925 , getcaps(sr->isr_capinfo)
927 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
929 cp += sr->isr_len, len -= sr->isr_len;
930 } while (len >= sizeof(struct ieee80211req_scan_result));
933 #include <net80211/ieee80211_freebsd.h>
938 struct ieee80211req ireq;
941 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
943 perror("socket(PF_ROUTE,SOCK_RAW)");
946 (void) memset(&ireq, 0, sizeof(ireq));
947 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
948 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
949 /* NB: only root can trigger a scan so ignore errors */
950 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
952 struct if_announcemsghdr *ifan;
953 struct rt_msghdr *rtm;
956 if (read(sroute, buf, sizeof(buf)) < 0) {
957 perror("read(PF_ROUTE)");
960 rtm = (struct rt_msghdr *) buf;
961 if (rtm->rtm_version != RTM_VERSION)
963 ifan = (struct if_announcemsghdr *) rtm;
964 } while (rtm->rtm_type != RTM_IEEE80211 ||
965 ifan->ifan_what != RTM_IEEE80211_SCAN);
971 DECL_CMD_FUNC(set80211scan, val, d)
977 static enum ieee80211_opmode get80211opmode(int s);
983 struct ieee80211req_sta_req req;
984 uint8_t buf[24*1024];
986 enum ieee80211_opmode opmode = get80211opmode(s);
987 struct ieee80211req ireq;
991 (void) memset(&ireq, 0, sizeof(ireq));
992 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
993 /* broadcast address =>'s get all stations */
994 (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
995 if (opmode == IEEE80211_M_STA) {
997 * Get information about the associated AP.
999 ireq.i_type = IEEE80211_IOC_BSSID;
1000 ireq.i_data = u.req.is_u.macaddr;
1001 ireq.i_len = IEEE80211_ADDR_LEN;
1002 (void) ioctl(s, SIOCG80211, &ireq);
1004 ireq.i_type = IEEE80211_IOC_STA_INFO;
1006 ireq.i_len = sizeof(u);
1007 if (ioctl(s, SIOCG80211, &ireq) < 0)
1008 errx(1, "unable to get station information");
1010 if (len < sizeof(struct ieee80211req_sta_info))
1013 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
1025 cp = (uint8_t *) u.req.info;
1027 struct ieee80211req_sta_info *si;
1030 si = (struct ieee80211req_sta_info *) cp;
1031 if (si->isi_len < sizeof(*si))
1033 vp = (u_int8_t *)(si+1);
1034 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %-4.4s"
1035 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1036 , IEEE80211_AID(si->isi_associd)
1037 , ieee80211_mhz2ieee(si->isi_freq)
1038 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
1043 , getcaps(si->isi_capinfo)
1044 , getflags(si->isi_state)
1046 printies(vp, si->isi_ie_len, 24);
1048 cp += si->isi_len, len -= si->isi_len;
1049 } while (len >= sizeof(struct ieee80211req_sta_info));
1053 print_chaninfo(const struct ieee80211_channel *c)
1055 #define IEEE80211_IS_CHAN_PASSIVE(_c) \
1056 (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1060 if (IEEE80211_IS_CHAN_FHSS(c))
1061 strlcat(buf, " FHSS", sizeof(buf));
1062 if (IEEE80211_IS_CHAN_A(c))
1063 strlcat(buf, " 11a", sizeof(buf));
1064 /* XXX 11g schizophrenia */
1065 if (IEEE80211_IS_CHAN_G(c) ||
1066 IEEE80211_IS_CHAN_PUREG(c))
1067 strlcat(buf, " 11g", sizeof(buf));
1068 else if (IEEE80211_IS_CHAN_B(c))
1069 strlcat(buf, " 11b", sizeof(buf));
1070 if (IEEE80211_IS_CHAN_T(c))
1071 strlcat(buf, " Turbo", sizeof(buf));
1072 printf("Channel %3u : %u%c Mhz%-14.14s",
1073 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1074 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1075 #undef IEEE80211_IS_CHAN_PASSIVE
1079 list_channels(int s, int allchans)
1081 struct ieee80211req ireq;
1082 struct ieee80211req_chaninfo chans;
1083 struct ieee80211req_chaninfo achans;
1084 const struct ieee80211_channel *c;
1087 (void) memset(&ireq, 0, sizeof(ireq));
1088 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1089 ireq.i_type = IEEE80211_IOC_CHANINFO;
1090 ireq.i_data = &chans;
1091 ireq.i_len = sizeof(chans);
1092 if (ioctl(s, SIOCG80211, &ireq) < 0)
1093 errx(1, "unable to get channel information");
1095 struct ieee80211req_chanlist active;
1097 ireq.i_type = IEEE80211_IOC_CHANLIST;
1098 ireq.i_data = &active;
1099 ireq.i_len = sizeof(active);
1100 if (ioctl(s, SIOCG80211, &ireq) < 0)
1101 errx(1, "unable to get active channel list");
1102 memset(&achans, 0, sizeof(achans));
1103 for (i = 0; i < chans.ic_nchans; i++) {
1104 c = &chans.ic_chans[i];
1105 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1106 achans.ic_chans[achans.ic_nchans++] = *c;
1110 half = achans.ic_nchans / 2;
1111 if (achans.ic_nchans % 2)
1113 for (i = 0; i < achans.ic_nchans / 2; i++) {
1114 print_chaninfo(&achans.ic_chans[i]);
1115 print_chaninfo(&achans.ic_chans[half+i]);
1118 if (achans.ic_nchans % 2) {
1119 print_chaninfo(&achans.ic_chans[i]);
1129 #define IEEE80211_C_BITS \
1130 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1131 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1132 "\31WPA2\32BURST\33WME"
1135 list_capabilities(int s)
1137 struct ieee80211req ireq;
1140 (void) memset(&ireq, 0, sizeof(ireq));
1141 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1142 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1143 if (ioctl(s, SIOCG80211, &ireq) < 0)
1144 errx(1, "unable to get driver capabilities");
1145 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
1146 printb(name, caps, IEEE80211_C_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_NUMSSIDS;
1496 if (ioctl(s, SIOCG80211, &ireq) >= 0)
1500 ireq.i_type = IEEE80211_IOC_SSID;
1501 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1502 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1503 printf(" %d:", ireq.i_val + 1);
1504 print_string(data, ireq.i_len);
1508 print_string(data, ireq.i_len);
1510 ireq.i_type = IEEE80211_IOC_CHANNEL;
1511 if (ioctl(s, SIOCG80211, &ireq) < 0)
1513 c = getchaninfo(s, ireq.i_val);
1514 if (ireq.i_val != -1) {
1515 printf(" channel %d", ireq.i_val);
1517 printf(" (%u)", c->ic_freq);
1519 printf(" channel UNDEF");
1521 ireq.i_type = IEEE80211_IOC_BSSID;
1522 ireq.i_len = IEEE80211_ADDR_LEN;
1523 if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1524 (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1525 printf(" bssid %s", ether_ntoa(ireq.i_data));
1527 ireq.i_type = IEEE80211_IOC_STATIONNAME;
1528 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1529 printf("\n\tstationname ");
1530 print_string(data, ireq.i_len);
1533 spacer = ' '; /* force first break */
1536 ireq.i_type = IEEE80211_IOC_AUTHMODE;
1537 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1538 switch (ireq.i_val) {
1539 case IEEE80211_AUTH_NONE:
1540 LINE_CHECK("authmode NONE");
1542 case IEEE80211_AUTH_OPEN:
1543 LINE_CHECK("authmode OPEN");
1545 case IEEE80211_AUTH_SHARED:
1546 LINE_CHECK("authmode SHARED");
1548 case IEEE80211_AUTH_8021X:
1549 LINE_CHECK("authmode 802.1x");
1551 case IEEE80211_AUTH_WPA:
1552 ireq.i_type = IEEE80211_IOC_WPA;
1553 if (ioctl(s, SIOCG80211, &ireq) != -1)
1556 wpa = 1; /* default to WPA1 */
1559 LINE_CHECK("authmode WPA2/802.11i");
1562 LINE_CHECK("authmode WPA1+WPA2/802.11i");
1565 LINE_CHECK("authmode WPA");
1569 case IEEE80211_AUTH_AUTO:
1570 LINE_CHECK("authmode AUTO");
1573 LINE_CHECK("authmode UNKNOWN (0x%x)",
1579 ireq.i_type = IEEE80211_IOC_WEP;
1580 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1581 ireq.i_val != IEEE80211_WEP_NOSUP) {
1582 int firstkey, wepmode;
1584 wepmode = ireq.i_val;
1586 case IEEE80211_WEP_OFF:
1587 LINE_CHECK("privacy OFF");
1589 case IEEE80211_WEP_ON:
1590 LINE_CHECK("privacy ON");
1592 case IEEE80211_WEP_MIXED:
1593 LINE_CHECK("privacy MIXED");
1596 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1601 * If we get here then we've got WEP support so we need
1602 * to print WEP status.
1605 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1606 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1607 warn("WEP support, but no tx key!");
1610 if (ireq.i_val != -1)
1611 LINE_CHECK("deftxkey %d", ireq.i_val+1);
1612 else if (wepmode != IEEE80211_WEP_OFF || verbose)
1613 LINE_CHECK("deftxkey UNDEF");
1615 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1616 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1617 warn("WEP support, but no NUMWEPKEYS support!");
1623 for (i = 0; i < num; i++) {
1624 struct ieee80211req_key ik;
1626 memset(&ik, 0, sizeof(ik));
1628 ireq.i_type = IEEE80211_IOC_WPAKEY;
1630 ireq.i_len = sizeof(ik);
1631 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1632 warn("WEP support, but can get keys!");
1635 if (ik.ik_keylen != 0) {
1644 ireq.i_type = IEEE80211_IOC_POWERSAVE;
1645 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1646 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1647 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1648 switch (ireq.i_val) {
1649 case IEEE80211_POWERSAVE_OFF:
1650 LINE_CHECK("powersavemode OFF");
1652 case IEEE80211_POWERSAVE_CAM:
1653 LINE_CHECK("powersavemode CAM");
1655 case IEEE80211_POWERSAVE_PSP:
1656 LINE_CHECK("powersavemode PSP");
1658 case IEEE80211_POWERSAVE_PSP_CAM:
1659 LINE_CHECK("powersavemode PSP-CAM");
1662 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1663 if (ioctl(s, SIOCG80211, &ireq) != -1)
1664 LINE_CHECK("powersavesleep %d", ireq.i_val);
1668 ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1669 if (ioctl(s, SIOCG80211, &ireq) != -1)
1670 LINE_CHECK("txpowmax %d", ireq.i_val);
1673 ireq.i_type = IEEE80211_IOC_TXPOWER;
1674 if (ioctl(s, SIOCG80211, &ireq) != -1)
1675 LINE_CHECK("txpower %d", ireq.i_val);
1678 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1679 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1680 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1681 LINE_CHECK("rtsthreshold %d", ireq.i_val);
1684 ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1685 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1686 if (ireq.i_val != 2*1 || verbose) {
1687 if (ireq.i_val == 11)
1688 LINE_CHECK("mcastrate 5.5");
1690 LINE_CHECK("mcastrate %d", ireq.i_val/2);
1694 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1695 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1696 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1697 LINE_CHECK("fragthreshold %d", ireq.i_val);
1700 ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
1701 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1702 if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
1703 LINE_CHECK("bmiss %d", ireq.i_val);
1706 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1707 ireq.i_type = IEEE80211_IOC_PUREG;
1708 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1710 LINE_CHECK("pureg");
1712 LINE_CHECK("-pureg");
1714 ireq.i_type = IEEE80211_IOC_PROTMODE;
1715 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1716 switch (ireq.i_val) {
1717 case IEEE80211_PROTMODE_OFF:
1718 LINE_CHECK("protmode OFF");
1720 case IEEE80211_PROTMODE_CTS:
1721 LINE_CHECK("protmode CTS");
1723 case IEEE80211_PROTMODE_RTSCTS:
1724 LINE_CHECK("protmode RTSCTS");
1727 LINE_CHECK("protmode UNKNOWN (0x%x)",
1734 ireq.i_type = IEEE80211_IOC_WME;
1735 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1744 ireq.i_type = IEEE80211_IOC_BURST;
1745 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1747 LINE_CHECK("burst");
1749 LINE_CHECK("-burst");
1752 if (opmode == IEEE80211_M_HOSTAP) {
1753 ireq.i_type = IEEE80211_IOC_HIDESSID;
1754 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1756 LINE_CHECK("ssid HIDE");
1758 LINE_CHECK("ssid SHOW");
1761 ireq.i_type = IEEE80211_IOC_APBRIDGE;
1762 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1764 LINE_CHECK("-apbridge");
1766 LINE_CHECK("apbridge");
1769 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1770 if (ioctl(s, SIOCG80211, &ireq) != -1)
1771 LINE_CHECK("dtimperiod %u", ireq.i_val);
1773 ireq.i_type = IEEE80211_IOC_ROAMING;
1774 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1775 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1776 switch (ireq.i_val) {
1777 case IEEE80211_ROAMING_DEVICE:
1778 LINE_CHECK("roaming DEVICE");
1780 case IEEE80211_ROAMING_AUTO:
1781 LINE_CHECK("roaming AUTO");
1783 case IEEE80211_ROAMING_MANUAL:
1784 LINE_CHECK("roaming MANUAL");
1787 LINE_CHECK("roaming UNKNOWN (0x%x)",
1794 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1795 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1797 LINE_CHECK("bintval %u", ireq.i_val);
1799 LINE_CHECK("bintval %u", ireq.i_val);
1802 if (wme && verbose) {
1808 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1809 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1811 LINE_CHECK("countermeasures");
1813 LINE_CHECK("-countermeasures");
1816 /* XXX not interesting with WPA done in user space */
1817 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1818 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1821 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1822 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1823 LINE_CHECK("mcastcipher ");
1824 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1828 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1829 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1830 LINE_CHECK("ucastcipher ");
1831 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1835 ireq.i_type = IEEE80211_IOC_RSNCAPS;
1836 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1837 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1842 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1843 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1855 set80211(int s, int type, int val, int len, u_int8_t *data)
1857 struct ieee80211req ireq;
1859 (void) memset(&ireq, 0, sizeof(ireq));
1860 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1865 if (ioctl(s, SIOCS80211, &ireq) < 0)
1866 err(1, "SIOCS80211");
1870 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1878 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1884 if (sep != NULL && strchr(sep, *val) != NULL) {
1889 if (!isxdigit((u_char)val[0])) {
1890 warnx("bad hexadecimal digits");
1893 if (!isxdigit((u_char)val[1])) {
1894 warnx("odd count hexadecimal digits");
1898 if (p >= buf + len) {
1900 warnx("hexadecimal digits too long");
1902 warnx("string too long");
1906 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1907 *p++ = (tohex((u_char)val[0]) << 4) |
1908 tohex((u_char)val[1]);
1915 /* The string "-" is treated as the empty string. */
1916 if (!hexstr && len == 1 && buf[0] == '-')
1919 memset(p, 0, *lenp - len);
1925 print_string(const u_int8_t *buf, int len)
1932 for (; i < len; i++) {
1933 if (!isprint(buf[i]) && buf[i] != '\0')
1935 if (isspace(buf[i]))
1939 if (hasspc || len == 0 || buf[0] == '\0')
1940 printf("\"%.*s\"", len, buf);
1942 printf("%.*s", len, buf);
1945 for (i = 0; i < len; i++)
1946 printf("%02x", buf[i]);
1950 static struct cmd ieee80211_cmds[] = {
1951 DEF_CMD_ARG("ssid", set80211ssid),
1952 DEF_CMD_ARG("nwid", set80211ssid),
1953 DEF_CMD_ARG("stationname", set80211stationname),
1954 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
1955 DEF_CMD_ARG("channel", set80211channel),
1956 DEF_CMD_ARG("authmode", set80211authmode),
1957 DEF_CMD_ARG("powersavemode", set80211powersavemode),
1958 DEF_CMD("powersave", 1, set80211powersave),
1959 DEF_CMD("-powersave", 0, set80211powersave),
1960 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
1961 DEF_CMD_ARG("wepmode", set80211wepmode),
1962 DEF_CMD("wep", 1, set80211wep),
1963 DEF_CMD("-wep", 0, set80211wep),
1964 DEF_CMD_ARG("deftxkey", set80211weptxkey),
1965 DEF_CMD_ARG("weptxkey", set80211weptxkey),
1966 DEF_CMD_ARG("wepkey", set80211wepkey),
1967 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
1968 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
1969 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
1970 DEF_CMD_ARG("protmode", set80211protmode),
1971 DEF_CMD_ARG("txpower", set80211txpower),
1972 DEF_CMD_ARG("roaming", set80211roaming),
1973 DEF_CMD("wme", 1, set80211wme),
1974 DEF_CMD("-wme", 0, set80211wme),
1975 DEF_CMD("hidessid", 1, set80211hidessid),
1976 DEF_CMD("-hidessid", 0, set80211hidessid),
1977 DEF_CMD("apbridge", 1, set80211apbridge),
1978 DEF_CMD("-apbridge", 0, set80211apbridge),
1979 DEF_CMD_ARG("chanlist", set80211chanlist),
1980 DEF_CMD_ARG("bssid", set80211bssid),
1981 DEF_CMD_ARG("ap", set80211bssid),
1982 DEF_CMD("scan", 0, set80211scan),
1983 DEF_CMD_ARG("list", set80211list),
1984 DEF_CMD_ARG2("cwmin", set80211cwmin),
1985 DEF_CMD_ARG2("cwmax", set80211cwmax),
1986 DEF_CMD_ARG2("aifs", set80211aifs),
1987 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
1988 DEF_CMD_ARG("acm", set80211acm),
1989 DEF_CMD_ARG("-acm", set80211noacm),
1990 DEF_CMD_ARG("ack", set80211ackpolicy),
1991 DEF_CMD_ARG("-ack", set80211noackpolicy),
1992 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
1993 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
1994 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
1995 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
1996 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
1997 DEF_CMD_ARG("bintval", set80211bintval),
1998 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
1999 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
2000 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
2001 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
2002 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
2003 DEF_CMD_ARG("mac:add", set80211addmac),
2004 DEF_CMD_ARG("mac:del", set80211delmac),
2005 DEF_CMD_ARG("mac:kick", set80211kickmac),
2006 DEF_CMD("pureg", 1, set80211pureg),
2007 DEF_CMD("-pureg", 0, set80211pureg),
2008 DEF_CMD_ARG("mcastrate", set80211mcastrate),
2009 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
2010 DEF_CMD("burst", 1, set80211burst),
2011 DEF_CMD("-burst", 0, set80211burst),
2012 DEF_CMD_ARG("bmiss", set80211bmissthreshold),
2013 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold),
2015 static struct afswtch af_ieee80211 = {
2016 .af_name = "af_ieee80211",
2018 .af_other_status = ieee80211_status,
2021 static __constructor void
2022 ieee80211_ctor(void)
2024 #define N(a) (sizeof(a) / sizeof(a[0]))
2027 for (i = 0; i < N(ieee80211_cmds); i++)
2028 cmd_register(&ieee80211_cmds[i]);
2029 af_register(&af_ieee80211);