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 mapgsm(u_int freq, u_int flags)
163 if (flags & IEEE80211_CHAN_QUARTER)
165 else if (flags & IEEE80211_CHAN_HALF)
169 /* NB: there is no 907/20 wide but leave room */
170 return (freq - 906*10) / 5;
174 mappsb(u_int freq, u_int flags)
176 return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5;
180 * Convert MHz frequency to IEEE channel number.
183 ieee80211_mhz2ieee(u_int freq, u_int flags)
185 if ((flags & IEEE80211_CHAN_GSM) || (907 <= freq && freq <= 922))
186 return mapgsm(freq, flags);
190 return (freq - 2407) / 5;
192 if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER))
193 return mappsb(freq, flags);
194 else if (freq > 4900)
195 return (freq - 4000) / 5;
197 return 15 + ((freq - 2512) / 20);
199 return (freq - 5000) / 5;
203 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
205 if (!isanyarg(val)) {
207 if (v > 255) /* treat as frequency */
208 v = ieee80211_mhz2ieee(v, 0);
209 set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
211 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
215 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
219 if (strcasecmp(val, "none") == 0) {
220 mode = IEEE80211_AUTH_NONE;
221 } else if (strcasecmp(val, "open") == 0) {
222 mode = IEEE80211_AUTH_OPEN;
223 } else if (strcasecmp(val, "shared") == 0) {
224 mode = IEEE80211_AUTH_SHARED;
225 } else if (strcasecmp(val, "8021x") == 0) {
226 mode = IEEE80211_AUTH_8021X;
227 } else if (strcasecmp(val, "wpa") == 0) {
228 mode = IEEE80211_AUTH_WPA;
230 errx(1, "unknown authmode");
233 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
237 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
241 if (strcasecmp(val, "off") == 0) {
242 mode = IEEE80211_POWERSAVE_OFF;
243 } else if (strcasecmp(val, "on") == 0) {
244 mode = IEEE80211_POWERSAVE_ON;
245 } else if (strcasecmp(val, "cam") == 0) {
246 mode = IEEE80211_POWERSAVE_CAM;
247 } else if (strcasecmp(val, "psp") == 0) {
248 mode = IEEE80211_POWERSAVE_PSP;
249 } else if (strcasecmp(val, "psp-cam") == 0) {
250 mode = IEEE80211_POWERSAVE_PSP_CAM;
252 errx(1, "unknown powersavemode");
255 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
259 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
262 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
265 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
270 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
272 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
276 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
280 if (strcasecmp(val, "off") == 0) {
281 mode = IEEE80211_WEP_OFF;
282 } else if (strcasecmp(val, "on") == 0) {
283 mode = IEEE80211_WEP_ON;
284 } else if (strcasecmp(val, "mixed") == 0) {
285 mode = IEEE80211_WEP_MIXED;
287 errx(1, "unknown wep mode");
290 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
294 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
296 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
300 isundefarg(const char *arg)
302 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
306 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
309 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
311 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
315 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
319 u_int8_t data[IEEE80211_KEYBUF_SIZE];
321 if (isdigit(val[0]) && val[1] == ':') {
326 bzero(data, sizeof(data));
328 get_string(val, NULL, data, &len);
330 set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
334 * This function is purely a NetBSD compatability interface. The NetBSD
335 * interface is too inflexible, but it's there so we'll support it since
336 * it's not all that hard.
339 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
343 u_int8_t data[IEEE80211_KEYBUF_SIZE];
345 set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
347 if (isdigit(val[0]) && val[1] == ':') {
348 txkey = val[0]-'0'-1;
351 for (i = 0; i < 4; i++) {
352 bzero(data, sizeof(data));
354 val = get_string(val, ",", data, &len);
358 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
361 bzero(data, sizeof(data));
363 get_string(val, NULL, data, &len);
366 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
368 bzero(data, sizeof(data));
369 for (i = 1; i < 4; i++)
370 set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
373 set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
377 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
379 set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
380 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
384 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
388 if (strcasecmp(val, "off") == 0) {
389 mode = IEEE80211_PROTMODE_OFF;
390 } else if (strcasecmp(val, "cts") == 0) {
391 mode = IEEE80211_PROTMODE_CTS;
392 } else if (strcasecmp(val, "rtscts") == 0) {
393 mode = IEEE80211_PROTMODE_RTSCTS;
395 errx(1, "unknown protection mode");
398 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
402 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
404 set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
407 #define IEEE80211_ROAMING_DEVICE 0
408 #define IEEE80211_ROAMING_AUTO 1
409 #define IEEE80211_ROAMING_MANUAL 2
412 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
416 if (strcasecmp(val, "device") == 0) {
417 mode = IEEE80211_ROAMING_DEVICE;
418 } else if (strcasecmp(val, "auto") == 0) {
419 mode = IEEE80211_ROAMING_AUTO;
420 } else if (strcasecmp(val, "manual") == 0) {
421 mode = IEEE80211_ROAMING_MANUAL;
423 errx(1, "unknown roaming mode");
425 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
429 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
431 set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
435 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
437 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
441 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
443 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
447 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
449 struct ieee80211req_chanlist chanlist;
450 #define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
451 char *temp, *cp, *tp;
453 temp = malloc(strlen(val) + 1);
455 errx(1, "malloc failed");
457 memset(&chanlist, 0, sizeof(chanlist));
462 tp = strchr(cp, ',');
465 switch (sscanf(cp, "%u-%u", &first, &last)) {
468 errx(-1, "channel %u out of range, max %zu",
470 setbit(chanlist.ic_channels, first);
474 errx(-1, "channel %u out of range, max %zu",
477 errx(-1, "channel %u out of range, max %zu",
480 errx(-1, "void channel range, %u > %u",
482 for (f = first; f <= last; f++)
483 setbit(chanlist.ic_channels, f);
494 set80211(s, IEEE80211_IOC_CHANLIST, 0,
495 sizeof(chanlist), (uint8_t *) &chanlist);
500 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
503 if (!isanyarg(val)) {
505 struct sockaddr_dl sdl;
507 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
509 errx(1, "malloc failed");
511 strcpy(temp + 1, val);
512 sdl.sdl_len = sizeof(sdl);
513 link_addr(temp, &sdl);
515 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
516 errx(1, "malformed link-level address");
517 set80211(s, IEEE80211_IOC_BSSID, 0,
518 IEEE80211_ADDR_LEN, LLADDR(&sdl));
520 uint8_t zerobssid[IEEE80211_ADDR_LEN];
521 memset(zerobssid, 0, sizeof(zerobssid));
522 set80211(s, IEEE80211_IOC_BSSID, 0,
523 IEEE80211_ADDR_LEN, zerobssid);
528 getac(const char *ac)
530 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
532 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
534 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
536 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
538 errx(1, "unknown wme access class %s", ac);
542 DECL_CMD_FUNC2(set80211cwmin, ac, val)
544 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
548 DECL_CMD_FUNC2(set80211cwmax, ac, val)
550 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
554 DECL_CMD_FUNC2(set80211aifs, ac, val)
556 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
560 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
562 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
566 DECL_CMD_FUNC(set80211acm, ac, d)
568 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
571 DECL_CMD_FUNC(set80211noacm, ac, d)
573 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
577 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
579 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
582 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
584 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
588 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
590 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
591 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
595 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
597 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
598 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
602 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
604 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
605 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
609 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
611 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
612 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
616 DECL_CMD_FUNC(set80211dtimperiod, val, d)
618 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
622 DECL_CMD_FUNC(set80211bintval, val, d)
624 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
628 set80211macmac(int s, int op, const char *val)
631 struct sockaddr_dl sdl;
633 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
635 errx(1, "malloc failed");
637 strcpy(temp + 1, val);
638 sdl.sdl_len = sizeof(sdl);
639 link_addr(temp, &sdl);
641 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
642 errx(1, "malformed link-level address");
643 set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
647 DECL_CMD_FUNC(set80211addmac, val, d)
649 set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
653 DECL_CMD_FUNC(set80211delmac, val, d)
655 set80211macmac(s, IEEE80211_IOC_DELMAC, val);
659 DECL_CMD_FUNC(set80211kickmac, val, d)
662 struct sockaddr_dl sdl;
663 struct ieee80211req_mlme mlme;
665 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
667 errx(1, "malloc failed");
669 strcpy(temp + 1, val);
670 sdl.sdl_len = sizeof(sdl);
671 link_addr(temp, &sdl);
673 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
674 errx(1, "malformed link-level address");
675 memset(&mlme, 0, sizeof(mlme));
676 mlme.im_op = IEEE80211_MLME_DEAUTH;
677 mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
678 memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
679 set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
683 DECL_CMD_FUNC(set80211maccmd, val, d)
685 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
689 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
691 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
695 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
697 set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
701 DECL_CMD_FUNC(set80211mcastrate, val, d)
703 set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
707 DECL_CMD_FUNC(set80211fragthreshold, val, d)
709 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
710 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
714 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
716 set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
717 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
721 getmaxrate(uint8_t rates[15], uint8_t nrates)
725 for (i = 0; i < nrates; i++) {
726 int rate = rates[i] & IEEE80211_RATE_VAL;
736 static char capstring[32];
737 char *cp = capstring;
739 if (capinfo & IEEE80211_CAPINFO_ESS)
741 if (capinfo & IEEE80211_CAPINFO_IBSS)
743 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
745 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
747 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
749 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
751 if (capinfo & IEEE80211_CAPINFO_PBCC)
753 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
755 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
757 if (capinfo & IEEE80211_CAPINFO_RSN)
759 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
768 /* XXX need these publicly defined or similar */
769 #define IEEE80211_NODE_AUTH 0x0001 /* authorized for data */
770 #define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */
771 #define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */
772 #define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */
773 static char flagstring[32];
774 char *cp = flagstring;
776 if (flags & IEEE80211_NODE_AUTH)
778 if (flags & IEEE80211_NODE_QOS)
780 if (flags & IEEE80211_NODE_ERP)
782 if (flags & IEEE80211_NODE_PWR_MGT)
786 #undef IEEE80211_NODE_AUTH
787 #undef IEEE80211_NODE_QOS
788 #undef IEEE80211_NODE_ERP
789 #undef IEEE80211_NODE_PWR_MGT
793 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
797 maxlen -= strlen(tag)+2;
798 if (2*ielen > maxlen)
801 for (; ielen > 0; ie++, ielen--) {
813 * Copy the ssid string contents into buf, truncating to fit. If the
814 * ssid is entirely printable then just copy intact. Otherwise convert
815 * to hexadecimal. If the result is truncated then replace the last
816 * three characters with "...".
819 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
825 if (essid_len > bufsize)
829 /* determine printable or not */
830 for (i = 0, p = essid; i < maxlen; i++, p++) {
831 if (*p < ' ' || *p > 0x7e)
834 if (i != maxlen) { /* not printable, print as hex */
837 strlcpy(buf, "0x", bufsize);
840 for (i = 0; i < maxlen && bufsize >= 2; i++) {
841 sprintf(&buf[2+2*i], "%02x", p[i]);
845 memcpy(&buf[2+2*i-3], "...", 3);
846 } else { /* printable, truncate as needed */
847 memcpy(buf, essid, maxlen);
848 if (maxlen != essid_len)
849 memcpy(&buf[maxlen-3], "...", 3);
854 /* unaligned little endian access */
855 #define LE_READ_4(p) \
857 ((((const u_int8_t *)(p))[0] ) | \
858 (((const u_int8_t *)(p))[1] << 8) | \
859 (((const u_int8_t *)(p))[2] << 16) | \
860 (((const u_int8_t *)(p))[3] << 24)))
863 iswpaoui(const u_int8_t *frm)
865 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
869 iswmeoui(const u_int8_t *frm)
871 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
875 isatherosoui(const u_int8_t *frm)
877 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
881 printies(const u_int8_t *vp, int ielen, int maxcols)
885 case IEEE80211_ELEMID_VENDOR:
887 printie(" WPA", vp, 2+vp[1], maxcols);
888 else if (iswmeoui(vp))
889 printie(" WME", vp, 2+vp[1], maxcols);
890 else if (isatherosoui(vp))
891 printie(" ATH", vp, 2+vp[1], maxcols);
893 printie(" VEN", vp, 2+vp[1], maxcols);
895 case IEEE80211_ELEMID_RSN:
896 printie(" RSN", vp, 2+vp[1], maxcols);
899 printie(" ???", vp, 2+vp[1], maxcols);
910 uint8_t buf[24*1024];
911 struct ieee80211req ireq;
912 char ssid[IEEE80211_NWID_LEN+1];
916 (void) memset(&ireq, 0, sizeof(ireq));
917 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
918 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
920 ireq.i_len = sizeof(buf);
921 if (ioctl(s, SIOCG80211, &ireq) < 0)
922 errx(1, "unable to get scan results");
924 if (len < sizeof(struct ieee80211req_scan_result))
927 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
928 printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
929 , ssidmax, ssidmax, "SSID"
939 struct ieee80211req_scan_result *sr;
942 sr = (struct ieee80211req_scan_result *) cp;
943 vp = (u_int8_t *)(sr+1);
944 printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
946 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
948 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
949 , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
950 , getmaxrate(sr->isr_rates, sr->isr_nrates)
951 , sr->isr_rssi, sr->isr_noise
953 , getcaps(sr->isr_capinfo)
955 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
957 cp += sr->isr_len, len -= sr->isr_len;
958 } while (len >= sizeof(struct ieee80211req_scan_result));
961 #include <net80211/ieee80211_freebsd.h>
966 struct ieee80211req ireq;
969 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
971 perror("socket(PF_ROUTE,SOCK_RAW)");
974 (void) memset(&ireq, 0, sizeof(ireq));
975 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
976 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
977 /* NB: only root can trigger a scan so ignore errors */
978 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
980 struct if_announcemsghdr *ifan;
981 struct rt_msghdr *rtm;
984 if (read(sroute, buf, sizeof(buf)) < 0) {
985 perror("read(PF_ROUTE)");
988 rtm = (struct rt_msghdr *) buf;
989 if (rtm->rtm_version != RTM_VERSION)
991 ifan = (struct if_announcemsghdr *) rtm;
992 } while (rtm->rtm_type != RTM_IEEE80211 ||
993 ifan->ifan_what != RTM_IEEE80211_SCAN);
999 DECL_CMD_FUNC(set80211scan, val, d)
1005 static enum ieee80211_opmode get80211opmode(int s);
1008 list_stations(int s)
1011 struct ieee80211req_sta_req req;
1012 uint8_t buf[24*1024];
1014 enum ieee80211_opmode opmode = get80211opmode(s);
1015 struct ieee80211req ireq;
1019 (void) memset(&ireq, 0, sizeof(ireq));
1020 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1021 /* broadcast address =>'s get all stations */
1022 (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
1023 if (opmode == IEEE80211_M_STA) {
1025 * Get information about the associated AP.
1027 ireq.i_type = IEEE80211_IOC_BSSID;
1028 ireq.i_data = u.req.is_u.macaddr;
1029 ireq.i_len = IEEE80211_ADDR_LEN;
1030 (void) ioctl(s, SIOCG80211, &ireq);
1032 ireq.i_type = IEEE80211_IOC_STA_INFO;
1034 ireq.i_len = sizeof(u);
1035 if (ioctl(s, SIOCG80211, &ireq) < 0)
1036 errx(1, "unable to get station information");
1038 if (len < sizeof(struct ieee80211req_sta_info))
1041 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
1053 cp = (uint8_t *) u.req.info;
1055 struct ieee80211req_sta_info *si;
1058 si = (struct ieee80211req_sta_info *) cp;
1059 if (si->isi_len < sizeof(*si))
1061 vp = (u_int8_t *)(si+1);
1062 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %-4.4s"
1063 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1064 , IEEE80211_AID(si->isi_associd)
1065 , ieee80211_mhz2ieee(si->isi_freq, si->isi_flags)
1066 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
1071 , getcaps(si->isi_capinfo)
1072 , getflags(si->isi_state)
1074 printies(vp, si->isi_ie_len, 24);
1076 cp += si->isi_len, len -= si->isi_len;
1077 } while (len >= sizeof(struct ieee80211req_sta_info));
1081 print_chaninfo(const struct ieee80211_channel *c)
1086 if (IEEE80211_IS_CHAN_FHSS(c))
1087 strlcat(buf, " FHSS", sizeof(buf));
1088 if (IEEE80211_IS_CHAN_A(c)) {
1089 if (IEEE80211_IS_CHAN_HALF(c))
1090 strlcat(buf, " 11a/10Mhz", sizeof(buf));
1091 else if (IEEE80211_IS_CHAN_QUARTER(c))
1092 strlcat(buf, " 11a/5Mhz", sizeof(buf));
1094 strlcat(buf, " 11a", sizeof(buf));
1096 if (IEEE80211_IS_CHAN_ANYG(c)) {
1097 if (IEEE80211_IS_CHAN_HALF(c))
1098 strlcat(buf, " 11g/10Mhz", sizeof(buf));
1099 else if (IEEE80211_IS_CHAN_QUARTER(c))
1100 strlcat(buf, " 11g/5Mhz", sizeof(buf));
1102 strlcat(buf, " 11g", sizeof(buf));
1103 } else if (IEEE80211_IS_CHAN_B(c))
1104 strlcat(buf, " 11b", sizeof(buf));
1105 if (IEEE80211_IS_CHAN_T(c))
1106 strlcat(buf, " Turbo", sizeof(buf));
1107 printf("Channel %3u : %u%c Mhz%-14.14s",
1108 ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
1109 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1113 list_channels(int s, int allchans)
1115 struct ieee80211req ireq;
1116 struct ieee80211req_chaninfo chans;
1117 struct ieee80211req_chaninfo achans;
1118 const struct ieee80211_channel *c;
1121 (void) memset(&ireq, 0, sizeof(ireq));
1122 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1123 ireq.i_type = IEEE80211_IOC_CHANINFO;
1124 ireq.i_data = &chans;
1125 ireq.i_len = sizeof(chans);
1126 if (ioctl(s, SIOCG80211, &ireq) < 0)
1127 errx(1, "unable to get channel information");
1129 struct ieee80211req_chanlist active;
1131 ireq.i_type = IEEE80211_IOC_CHANLIST;
1132 ireq.i_data = &active;
1133 ireq.i_len = sizeof(active);
1134 if (ioctl(s, SIOCG80211, &ireq) < 0)
1135 errx(1, "unable to get active channel list");
1136 memset(&achans, 0, sizeof(achans));
1137 for (i = 0; i < chans.ic_nchans; i++) {
1138 c = &chans.ic_chans[i];
1139 ieee = ieee80211_mhz2ieee(c->ic_freq, c->ic_flags);
1140 if (isset(active.ic_channels, ieee) || allchans)
1141 achans.ic_chans[achans.ic_nchans++] = *c;
1145 half = achans.ic_nchans / 2;
1146 if (achans.ic_nchans % 2)
1148 for (i = 0; i < achans.ic_nchans / 2; i++) {
1149 print_chaninfo(&achans.ic_chans[i]);
1150 print_chaninfo(&achans.ic_chans[half+i]);
1153 if (achans.ic_nchans % 2) {
1154 print_chaninfo(&achans.ic_chans[i]);
1164 #define IEEE80211_C_BITS \
1165 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1166 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1167 "\31WPA2\32BURST\33WME"
1170 list_capabilities(int s)
1172 struct ieee80211req ireq;
1175 (void) memset(&ireq, 0, sizeof(ireq));
1176 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1177 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1178 if (ioctl(s, SIOCG80211, &ireq) < 0)
1179 errx(1, "unable to get driver capabilities");
1180 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
1181 printb(name, caps, IEEE80211_C_BITS);
1188 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1189 struct ieee80211req ireq;
1192 (void) memset(&ireq, 0, sizeof(ireq));
1193 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1195 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1197 if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
1198 printf("\t%s", " ");
1200 printf("\t%s", acnames[ac]);
1202 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1204 /* show WME BSS parameters */
1205 ireq.i_type = IEEE80211_IOC_WME_CWMIN;
1206 if (ioctl(s, SIOCG80211, &ireq) != -1)
1207 printf(" cwmin %2u", ireq.i_val);
1208 ireq.i_type = IEEE80211_IOC_WME_CWMAX;
1209 if (ioctl(s, SIOCG80211, &ireq) != -1)
1210 printf(" cwmax %2u", ireq.i_val);
1211 ireq.i_type = IEEE80211_IOC_WME_AIFS;
1212 if (ioctl(s, SIOCG80211, &ireq) != -1)
1213 printf(" aifs %2u", ireq.i_val);
1214 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
1215 if (ioctl(s, SIOCG80211, &ireq) != -1)
1216 printf(" txopLimit %3u", ireq.i_val);
1217 ireq.i_type = IEEE80211_IOC_WME_ACM;
1218 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1225 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1226 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1227 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1235 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1236 ireq.i_len |= IEEE80211_WMEPARAM_BSS;
1239 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
1246 struct ieee80211req ireq;
1247 struct ieee80211req_maclist *acllist;
1248 int i, nacls, policy;
1251 (void) memset(&ireq, 0, sizeof(ireq));
1252 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
1253 ireq.i_type = IEEE80211_IOC_MACCMD;
1254 ireq.i_val = IEEE80211_MACCMD_POLICY;
1255 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1256 if (errno == EINVAL) {
1257 printf("No acl policy loaded\n");
1260 err(1, "unable to get mac policy");
1262 policy = ireq.i_val;
1264 ireq.i_val = IEEE80211_MACCMD_LIST;
1266 if (ioctl(s, SIOCG80211, &ireq) < 0)
1267 err(1, "unable to get mac acl list size");
1268 if (ireq.i_len == 0) /* NB: no acls */
1271 ireq.i_data = malloc(ireq.i_len);
1272 if (ireq.i_data == NULL)
1273 err(1, "out of memory for acl list");
1275 if (ioctl(s, SIOCG80211, &ireq) < 0)
1276 err(1, "unable to get mac acl list");
1277 if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
1279 printf("policy: open\n");
1281 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1283 printf("policy: allow\n");
1285 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1287 printf("policy: deny\n");
1290 printf("policy: unknown (%u)\n", policy);
1293 nacls = ireq.i_len / sizeof(*acllist);
1294 acllist = (struct ieee80211req_maclist *) ireq.i_data;
1295 for (i = 0; i < nacls; i++)
1296 printf("%c%s\n", c, ether_ntoa(
1297 (const struct ether_addr *) acllist[i].ml_macaddr));
1301 DECL_CMD_FUNC(set80211list, arg, d)
1303 #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
1305 if (iseq(arg, "sta"))
1307 else if (iseq(arg, "scan") || iseq(arg, "ap"))
1309 else if (iseq(arg, "chan") || iseq(arg, "freq"))
1310 list_channels(s, 1);
1311 else if (iseq(arg, "active"))
1312 list_channels(s, 0);
1313 else if (iseq(arg, "keys"))
1315 else if (iseq(arg, "caps"))
1316 list_capabilities(s);
1317 else if (iseq(arg, "wme"))
1319 else if (iseq(arg, "mac"))
1322 errx(1, "Don't know how to list %s for %s", arg, name);
1326 static enum ieee80211_opmode
1327 get80211opmode(int s)
1329 struct ifmediareq ifmr;
1331 (void) memset(&ifmr, 0, sizeof(ifmr));
1332 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1334 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1335 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
1336 return IEEE80211_M_IBSS; /* XXX ahdemo */
1337 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1338 return IEEE80211_M_HOSTAP;
1339 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
1340 return IEEE80211_M_MONITOR;
1342 return IEEE80211_M_STA;
1345 static const struct ieee80211_channel *
1346 getchaninfo(int s, int chan)
1348 struct ieee80211req ireq;
1349 static struct ieee80211req_chaninfo chans;
1350 static struct ieee80211_channel undef;
1351 const struct ieee80211_channel *c;
1354 (void) memset(&ireq, 0, sizeof(ireq));
1355 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1356 ireq.i_type = IEEE80211_IOC_CHANINFO;
1357 ireq.i_data = &chans;
1358 ireq.i_len = sizeof(chans);
1359 if (ioctl(s, SIOCG80211, &ireq) < 0)
1360 errx(1, "unable to get channel information");
1361 freq = ieee80211_ieee2mhz(chan);
1362 for (i = 0; i < chans.ic_nchans; i++) {
1363 c = &chans.ic_chans[i];
1364 if (c->ic_freq == freq)
1372 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1374 switch (ireq->i_val) {
1375 case IEEE80211_CIPHER_WEP:
1376 ireq->i_type = keylenop;
1377 if (ioctl(s, SIOCG80211, ireq) != -1)
1379 ireq->i_len <= 5 ? "40" :
1380 ireq->i_len <= 13 ? "104" : "128");
1384 case IEEE80211_CIPHER_TKIP:
1387 case IEEE80211_CIPHER_AES_OCB:
1390 case IEEE80211_CIPHER_AES_CCM:
1393 case IEEE80211_CIPHER_CKIP:
1396 case IEEE80211_CIPHER_NONE:
1400 printf("UNKNOWN (0x%x)", ireq->i_val);
1413 if (spacer != '\t') {
1417 col = 8; /* 8-col tab */
1421 LINE_CHECK(const char *fmt, ...)
1428 n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1441 printkey(const struct ieee80211req_key *ik)
1443 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1444 int keylen = ik->ik_keylen;
1447 printcontents = printkeys &&
1448 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
1451 switch (ik->ik_type) {
1452 case IEEE80211_CIPHER_WEP:
1454 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
1455 keylen <= 5 ? "40-bit" :
1456 keylen <= 13 ? "104-bit" : "128-bit");
1458 case IEEE80211_CIPHER_TKIP:
1460 keylen -= 128/8; /* ignore MIC for now */
1461 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1463 case IEEE80211_CIPHER_AES_OCB:
1464 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1466 case IEEE80211_CIPHER_AES_CCM:
1467 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1469 case IEEE80211_CIPHER_CKIP:
1470 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1472 case IEEE80211_CIPHER_NONE:
1473 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1476 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
1477 ik->ik_type, ik->ik_keyix+1, 8*keylen);
1480 if (printcontents) {
1484 for (i = 0; i < keylen; i++)
1485 printf("%02x", ik->ik_keydata[i]);
1487 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1488 (ik->ik_keyrsc != 0 || verbose))
1489 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
1490 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1491 (ik->ik_keytsc != 0 || verbose))
1492 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
1493 if (ik->ik_flags != 0 && verbose) {
1494 const char *sep = " ";
1496 if (ik->ik_flags & IEEE80211_KEY_XMIT)
1497 printf("%stx", sep), sep = "+";
1498 if (ik->ik_flags & IEEE80211_KEY_RECV)
1499 printf("%srx", sep), sep = "+";
1500 if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
1501 printf("%sdef", sep), sep = "+";
1508 ieee80211_status(int s)
1510 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1511 enum ieee80211_opmode opmode = get80211opmode(s);
1512 int i, num, wpa, wme;
1513 struct ieee80211req ireq;
1515 const struct ieee80211_channel *c;
1517 (void) memset(&ireq, 0, sizeof(ireq));
1518 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1519 ireq.i_data = &data;
1521 wpa = 0; /* unknown/not set */
1523 ireq.i_type = IEEE80211_IOC_SSID;
1525 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1526 /* If we can't get the SSID, this isn't an 802.11 device. */
1530 ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1531 if (ioctl(s, SIOCG80211, &ireq) >= 0)
1535 ireq.i_type = IEEE80211_IOC_SSID;
1536 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1537 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1538 printf(" %d:", ireq.i_val + 1);
1539 print_string(data, ireq.i_len);
1543 print_string(data, ireq.i_len);
1545 ireq.i_type = IEEE80211_IOC_CHANNEL;
1546 if (ioctl(s, SIOCG80211, &ireq) < 0)
1548 c = getchaninfo(s, ireq.i_val);
1549 if (ireq.i_val != -1) {
1550 printf(" channel %d", ireq.i_val);
1552 printf(" (%u)", c->ic_freq);
1554 printf(" channel UNDEF");
1556 ireq.i_type = IEEE80211_IOC_BSSID;
1557 ireq.i_len = IEEE80211_ADDR_LEN;
1558 if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1559 (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1560 printf(" bssid %s", ether_ntoa(ireq.i_data));
1562 ireq.i_type = IEEE80211_IOC_STATIONNAME;
1563 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1564 printf("\n\tstationname ");
1565 print_string(data, ireq.i_len);
1568 spacer = ' '; /* force first break */
1571 ireq.i_type = IEEE80211_IOC_AUTHMODE;
1572 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1573 switch (ireq.i_val) {
1574 case IEEE80211_AUTH_NONE:
1575 LINE_CHECK("authmode NONE");
1577 case IEEE80211_AUTH_OPEN:
1578 LINE_CHECK("authmode OPEN");
1580 case IEEE80211_AUTH_SHARED:
1581 LINE_CHECK("authmode SHARED");
1583 case IEEE80211_AUTH_8021X:
1584 LINE_CHECK("authmode 802.1x");
1586 case IEEE80211_AUTH_WPA:
1587 ireq.i_type = IEEE80211_IOC_WPA;
1588 if (ioctl(s, SIOCG80211, &ireq) != -1)
1591 wpa = 1; /* default to WPA1 */
1594 LINE_CHECK("authmode WPA2/802.11i");
1597 LINE_CHECK("authmode WPA1+WPA2/802.11i");
1600 LINE_CHECK("authmode WPA");
1604 case IEEE80211_AUTH_AUTO:
1605 LINE_CHECK("authmode AUTO");
1608 LINE_CHECK("authmode UNKNOWN (0x%x)",
1614 ireq.i_type = IEEE80211_IOC_WEP;
1615 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1616 ireq.i_val != IEEE80211_WEP_NOSUP) {
1617 int firstkey, wepmode;
1619 wepmode = ireq.i_val;
1621 case IEEE80211_WEP_OFF:
1622 LINE_CHECK("privacy OFF");
1624 case IEEE80211_WEP_ON:
1625 LINE_CHECK("privacy ON");
1627 case IEEE80211_WEP_MIXED:
1628 LINE_CHECK("privacy MIXED");
1631 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1636 * If we get here then we've got WEP support so we need
1637 * to print WEP status.
1640 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1641 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1642 warn("WEP support, but no tx key!");
1645 if (ireq.i_val != -1)
1646 LINE_CHECK("deftxkey %d", ireq.i_val+1);
1647 else if (wepmode != IEEE80211_WEP_OFF || verbose)
1648 LINE_CHECK("deftxkey UNDEF");
1650 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1651 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1652 warn("WEP support, but no NUMWEPKEYS support!");
1658 for (i = 0; i < num; i++) {
1659 struct ieee80211req_key ik;
1661 memset(&ik, 0, sizeof(ik));
1663 ireq.i_type = IEEE80211_IOC_WPAKEY;
1665 ireq.i_len = sizeof(ik);
1666 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1667 warn("WEP support, but can get keys!");
1670 if (ik.ik_keylen != 0) {
1679 ireq.i_type = IEEE80211_IOC_POWERSAVE;
1680 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1681 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1682 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1683 switch (ireq.i_val) {
1684 case IEEE80211_POWERSAVE_OFF:
1685 LINE_CHECK("powersavemode OFF");
1687 case IEEE80211_POWERSAVE_CAM:
1688 LINE_CHECK("powersavemode CAM");
1690 case IEEE80211_POWERSAVE_PSP:
1691 LINE_CHECK("powersavemode PSP");
1693 case IEEE80211_POWERSAVE_PSP_CAM:
1694 LINE_CHECK("powersavemode PSP-CAM");
1697 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1698 if (ioctl(s, SIOCG80211, &ireq) != -1)
1699 LINE_CHECK("powersavesleep %d", ireq.i_val);
1703 ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1704 if (ioctl(s, SIOCG80211, &ireq) != -1)
1705 LINE_CHECK("txpowmax %d", ireq.i_val);
1708 ireq.i_type = IEEE80211_IOC_TXPOWER;
1709 if (ioctl(s, SIOCG80211, &ireq) != -1)
1710 LINE_CHECK("txpower %d", ireq.i_val);
1713 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1714 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1715 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1716 LINE_CHECK("rtsthreshold %d", ireq.i_val);
1719 ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1720 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1721 if (ireq.i_val != 2*1 || verbose) {
1722 if (ireq.i_val == 11)
1723 LINE_CHECK("mcastrate 5.5");
1725 LINE_CHECK("mcastrate %d", ireq.i_val/2);
1729 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1730 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1731 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1732 LINE_CHECK("fragthreshold %d", ireq.i_val);
1735 ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
1736 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1737 if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
1738 LINE_CHECK("bmiss %d", ireq.i_val);
1741 if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
1742 ireq.i_type = IEEE80211_IOC_PUREG;
1743 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1745 LINE_CHECK("pureg");
1747 LINE_CHECK("-pureg");
1749 ireq.i_type = IEEE80211_IOC_PROTMODE;
1750 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1751 switch (ireq.i_val) {
1752 case IEEE80211_PROTMODE_OFF:
1753 LINE_CHECK("protmode OFF");
1755 case IEEE80211_PROTMODE_CTS:
1756 LINE_CHECK("protmode CTS");
1758 case IEEE80211_PROTMODE_RTSCTS:
1759 LINE_CHECK("protmode RTSCTS");
1762 LINE_CHECK("protmode UNKNOWN (0x%x)",
1769 ireq.i_type = IEEE80211_IOC_WME;
1770 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1779 ireq.i_type = IEEE80211_IOC_BURST;
1780 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1782 LINE_CHECK("burst");
1784 LINE_CHECK("-burst");
1787 if (opmode == IEEE80211_M_HOSTAP) {
1788 ireq.i_type = IEEE80211_IOC_HIDESSID;
1789 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1791 LINE_CHECK("hidessid");
1793 LINE_CHECK("-hidessid");
1796 ireq.i_type = IEEE80211_IOC_APBRIDGE;
1797 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1799 LINE_CHECK("-apbridge");
1801 LINE_CHECK("apbridge");
1804 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1805 if (ioctl(s, SIOCG80211, &ireq) != -1)
1806 LINE_CHECK("dtimperiod %u", ireq.i_val);
1808 ireq.i_type = IEEE80211_IOC_ROAMING;
1809 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1810 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1811 switch (ireq.i_val) {
1812 case IEEE80211_ROAMING_DEVICE:
1813 LINE_CHECK("roaming DEVICE");
1815 case IEEE80211_ROAMING_AUTO:
1816 LINE_CHECK("roaming AUTO");
1818 case IEEE80211_ROAMING_MANUAL:
1819 LINE_CHECK("roaming MANUAL");
1822 LINE_CHECK("roaming UNKNOWN (0x%x)",
1829 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1830 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1832 LINE_CHECK("bintval %u", ireq.i_val);
1834 LINE_CHECK("bintval %u", ireq.i_val);
1837 if (wme && verbose) {
1843 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1844 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1846 LINE_CHECK("countermeasures");
1848 LINE_CHECK("-countermeasures");
1851 /* XXX not interesting with WPA done in user space */
1852 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1853 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1856 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1857 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1858 LINE_CHECK("mcastcipher ");
1859 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1863 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1864 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1865 LINE_CHECK("ucastcipher ");
1866 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1870 ireq.i_type = IEEE80211_IOC_RSNCAPS;
1871 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1872 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1877 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1878 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1890 set80211(int s, int type, int val, int len, u_int8_t *data)
1892 struct ieee80211req ireq;
1894 (void) memset(&ireq, 0, sizeof(ireq));
1895 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1900 if (ioctl(s, SIOCS80211, &ireq) < 0)
1901 err(1, "SIOCS80211");
1905 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1913 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1919 if (sep != NULL && strchr(sep, *val) != NULL) {
1924 if (!isxdigit((u_char)val[0])) {
1925 warnx("bad hexadecimal digits");
1928 if (!isxdigit((u_char)val[1])) {
1929 warnx("odd count hexadecimal digits");
1933 if (p >= buf + len) {
1935 warnx("hexadecimal digits too long");
1937 warnx("string too long");
1941 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1942 *p++ = (tohex((u_char)val[0]) << 4) |
1943 tohex((u_char)val[1]);
1950 /* The string "-" is treated as the empty string. */
1951 if (!hexstr && len == 1 && buf[0] == '-') {
1953 memset(buf, 0, *lenp);
1954 } else if (len < *lenp)
1955 memset(p, 0, *lenp - len);
1961 print_string(const u_int8_t *buf, int len)
1968 for (; i < len; i++) {
1969 if (!isprint(buf[i]) && buf[i] != '\0')
1971 if (isspace(buf[i]))
1975 if (hasspc || len == 0 || buf[0] == '\0')
1976 printf("\"%.*s\"", len, buf);
1978 printf("%.*s", len, buf);
1981 for (i = 0; i < len; i++)
1982 printf("%02x", buf[i]);
1986 static struct cmd ieee80211_cmds[] = {
1987 DEF_CMD_ARG("ssid", set80211ssid),
1988 DEF_CMD_ARG("nwid", set80211ssid),
1989 DEF_CMD_ARG("stationname", set80211stationname),
1990 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
1991 DEF_CMD_ARG("channel", set80211channel),
1992 DEF_CMD_ARG("authmode", set80211authmode),
1993 DEF_CMD_ARG("powersavemode", set80211powersavemode),
1994 DEF_CMD("powersave", 1, set80211powersave),
1995 DEF_CMD("-powersave", 0, set80211powersave),
1996 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
1997 DEF_CMD_ARG("wepmode", set80211wepmode),
1998 DEF_CMD("wep", 1, set80211wep),
1999 DEF_CMD("-wep", 0, set80211wep),
2000 DEF_CMD_ARG("deftxkey", set80211weptxkey),
2001 DEF_CMD_ARG("weptxkey", set80211weptxkey),
2002 DEF_CMD_ARG("wepkey", set80211wepkey),
2003 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
2004 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
2005 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
2006 DEF_CMD_ARG("protmode", set80211protmode),
2007 DEF_CMD_ARG("txpower", set80211txpower),
2008 DEF_CMD_ARG("roaming", set80211roaming),
2009 DEF_CMD("wme", 1, set80211wme),
2010 DEF_CMD("-wme", 0, set80211wme),
2011 DEF_CMD("hidessid", 1, set80211hidessid),
2012 DEF_CMD("-hidessid", 0, set80211hidessid),
2013 DEF_CMD("apbridge", 1, set80211apbridge),
2014 DEF_CMD("-apbridge", 0, set80211apbridge),
2015 DEF_CMD_ARG("chanlist", set80211chanlist),
2016 DEF_CMD_ARG("bssid", set80211bssid),
2017 DEF_CMD_ARG("ap", set80211bssid),
2018 DEF_CMD("scan", 0, set80211scan),
2019 DEF_CMD_ARG("list", set80211list),
2020 DEF_CMD_ARG2("cwmin", set80211cwmin),
2021 DEF_CMD_ARG2("cwmax", set80211cwmax),
2022 DEF_CMD_ARG2("aifs", set80211aifs),
2023 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
2024 DEF_CMD_ARG("acm", set80211acm),
2025 DEF_CMD_ARG("-acm", set80211noacm),
2026 DEF_CMD_ARG("ack", set80211ackpolicy),
2027 DEF_CMD_ARG("-ack", set80211noackpolicy),
2028 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
2029 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
2030 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
2031 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
2032 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
2033 DEF_CMD_ARG("bintval", set80211bintval),
2034 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
2035 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
2036 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
2037 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
2038 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
2039 DEF_CMD_ARG("mac:add", set80211addmac),
2040 DEF_CMD_ARG("mac:del", set80211delmac),
2041 DEF_CMD_ARG("mac:kick", set80211kickmac),
2042 DEF_CMD("pureg", 1, set80211pureg),
2043 DEF_CMD("-pureg", 0, set80211pureg),
2044 DEF_CMD_ARG("mcastrate", set80211mcastrate),
2045 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
2046 DEF_CMD("burst", 1, set80211burst),
2047 DEF_CMD("-burst", 0, set80211burst),
2048 DEF_CMD_ARG("bmiss", set80211bmissthreshold),
2049 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold),
2051 static struct afswtch af_ieee80211 = {
2052 .af_name = "af_ieee80211",
2054 .af_other_status = ieee80211_status,
2057 static __constructor void
2058 ieee80211_ctor(void)
2060 #define N(a) (sizeof(a) / sizeof(a[0]))
2063 for (i = 0; i < N(ieee80211_cmds); i++)
2064 cmd_register(&ieee80211_cmds[i]);
2065 af_register(&af_ieee80211);