2 * Copyright 2001 The Aerospace Corporation. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of The Aerospace Corporation may not be used to endorse or
13 * promote products derived from this software.
15 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.18.2.9 2006/03/07 17:50:23 sam Exp $
28 * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.13 2006/09/01 15:12:11 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;
684 errx(1, "unknown ratectl");
686 set80211(s, IEEE80211_IOC_RATECTL, ratectl, 0, NULL);
690 DECL_CMD_FUNC(set80211mcastrate, val, d)
692 set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
696 DECL_CMD_FUNC(set80211fragthreshold, val, d)
698 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
699 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
703 getmaxrate(uint8_t rates[15], uint8_t nrates)
707 for (i = 0; i < nrates; i++) {
708 int rate = rates[i] & IEEE80211_RATE_VAL;
718 static char capstring[32];
719 char *cp = capstring;
721 if (capinfo & IEEE80211_CAPINFO_ESS)
723 if (capinfo & IEEE80211_CAPINFO_IBSS)
725 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
727 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
729 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
731 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
733 if (capinfo & IEEE80211_CAPINFO_PBCC)
735 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
737 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
739 if (capinfo & IEEE80211_CAPINFO_RSN)
741 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
748 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
752 maxlen -= strlen(tag)+2;
753 if (2*ielen > maxlen)
756 for (; ielen > 0; ie++, ielen--) {
768 * Copy the ssid string contents into buf, truncating to fit. If the
769 * ssid is entirely printable then just copy intact. Otherwise convert
770 * to hexadecimal. If the result is truncated then replace the last
771 * three characters with "...".
774 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
780 if (essid_len > bufsize)
784 /* determine printable or not */
785 for (i = 0, p = essid; i < maxlen; i++, p++) {
786 if (*p < ' ' || *p > 0x7e)
789 if (i != maxlen) { /* not printable, print as hex */
792 strlcpy(buf, "0x", bufsize);
795 for (i = 0; i < maxlen && bufsize >= 2; i++) {
796 sprintf(&buf[2+2*i], "%02x", p[i]);
800 memcpy(&buf[2+2*i-3], "...", 3);
801 } else { /* printable, truncate as needed */
802 memcpy(buf, essid, maxlen);
803 if (maxlen != essid_len)
804 memcpy(&buf[maxlen-3], "...", 3);
809 /* unaligned little endian access */
810 #define LE_READ_4(p) \
812 ((((const u_int8_t *)(p))[0] ) | \
813 (((const u_int8_t *)(p))[1] << 8) | \
814 (((const u_int8_t *)(p))[2] << 16) | \
815 (((const u_int8_t *)(p))[3] << 24)))
818 iswpaoui(const u_int8_t *frm)
820 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
824 iswmeoui(const u_int8_t *frm)
826 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
830 isatherosoui(const u_int8_t *frm)
832 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
836 printies(const u_int8_t *vp, int ielen, int maxcols)
840 case IEEE80211_ELEMID_VENDOR:
842 printie(" WPA", vp, 2+vp[1], maxcols);
843 else if (iswmeoui(vp))
844 printie(" WME", vp, 2+vp[1], maxcols);
845 else if (isatherosoui(vp))
846 printie(" ATH", vp, 2+vp[1], maxcols);
848 printie(" VEN", vp, 2+vp[1], maxcols);
850 case IEEE80211_ELEMID_RSN:
851 printie(" RSN", vp, 2+vp[1], maxcols);
854 printie(" ???", vp, 2+vp[1], maxcols);
865 uint8_t buf[24*1024];
866 struct ieee80211req ireq;
867 char ssid[IEEE80211_NWID_LEN+1];
871 (void) memset(&ireq, 0, sizeof(ireq));
872 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
873 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
875 ireq.i_len = sizeof(buf);
876 if (ioctl(s, SIOCG80211, &ireq) < 0)
877 errx(1, "unable to get scan results");
879 if (len < sizeof(struct ieee80211req_scan_result))
882 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
883 printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
884 , ssidmax, ssidmax, "SSID"
894 struct ieee80211req_scan_result *sr;
897 sr = (struct ieee80211req_scan_result *) cp;
898 vp = (u_int8_t *)(sr+1);
899 printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
901 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
903 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
904 , ieee80211_mhz2ieee(sr->isr_freq)
905 , getmaxrate(sr->isr_rates, sr->isr_nrates)
906 , sr->isr_rssi, sr->isr_noise
908 , getcaps(sr->isr_capinfo)
910 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
912 cp += sr->isr_len, len -= sr->isr_len;
913 } while (len >= sizeof(struct ieee80211req_scan_result));
916 #include <netproto/802_11/ieee80211_dragonfly.h>
921 struct ieee80211req ireq;
924 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
926 perror("socket(PF_ROUTE,SOCK_RAW)");
929 (void) memset(&ireq, 0, sizeof(ireq));
930 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
931 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
932 /* NB: only root can trigger a scan so ignore errors */
933 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
935 struct if_announcemsghdr *ifan;
936 struct rt_msghdr *rtm;
939 if (read(sroute, buf, sizeof(buf)) < 0) {
940 perror("read(PF_ROUTE)");
943 rtm = (struct rt_msghdr *) buf;
944 if (rtm->rtm_version != RTM_VERSION)
946 ifan = (struct if_announcemsghdr *) rtm;
947 } while (rtm->rtm_type != RTM_IEEE80211 ||
948 ifan->ifan_what != RTM_IEEE80211_SCAN);
954 DECL_CMD_FUNC(set80211scan, val, d)
963 uint8_t buf[24*1024];
964 struct ieee80211req ireq;
968 (void) memset(&ireq, 0, sizeof(ireq));
969 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
970 ireq.i_type = IEEE80211_IOC_STA_INFO;
972 ireq.i_len = sizeof(buf);
973 if (ioctl(s, SIOCG80211, &ireq) < 0)
974 errx(1, "unable to get station information");
976 if (len < sizeof(struct ieee80211req_sta_info))
979 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
993 struct ieee80211req_sta_info *si;
996 si = (struct ieee80211req_sta_info *) cp;
997 vp = (u_int8_t *)(si+1);
998 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
999 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1000 , IEEE80211_AID(si->isi_associd)
1001 , ieee80211_mhz2ieee(si->isi_freq)
1002 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
1007 , getcaps(si->isi_capinfo)
1010 printies(vp, si->isi_ie_len, 24);
1012 cp += si->isi_len, len -= si->isi_len;
1013 } while (len >= sizeof(struct ieee80211req_sta_info));
1017 print_chaninfo(const struct ieee80211_channel *c)
1019 #define IEEE80211_IS_CHAN_PASSIVE(_c) \
1020 (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1024 if (IEEE80211_IS_CHAN_FHSS(c))
1025 strlcat(buf, " FHSS", sizeof(buf));
1026 if (IEEE80211_IS_CHAN_A(c))
1027 strlcat(buf, " 11a", sizeof(buf));
1028 /* XXX 11g schizophrenia */
1029 if (IEEE80211_IS_CHAN_G(c) ||
1030 IEEE80211_IS_CHAN_PUREG(c))
1031 strlcat(buf, " 11g", sizeof(buf));
1032 else if (IEEE80211_IS_CHAN_B(c))
1033 strlcat(buf, " 11b", sizeof(buf));
1034 if (IEEE80211_IS_CHAN_T(c))
1035 strlcat(buf, " Turbo", sizeof(buf));
1036 printf("Channel %3u : %u%c Mhz%-14.14s",
1037 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1038 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1039 #undef IEEE80211_IS_CHAN_PASSIVE
1043 list_channels(int s, int allchans)
1045 struct ieee80211req ireq;
1046 struct ieee80211req_chaninfo chans;
1047 struct ieee80211req_chaninfo achans;
1048 const struct ieee80211_channel *c;
1051 (void) memset(&ireq, 0, sizeof(ireq));
1052 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1053 ireq.i_type = IEEE80211_IOC_CHANINFO;
1054 ireq.i_data = &chans;
1055 ireq.i_len = sizeof(chans);
1056 if (ioctl(s, SIOCG80211, &ireq) < 0)
1057 errx(1, "unable to get channel information");
1059 struct ieee80211req_chanlist active;
1061 ireq.i_type = IEEE80211_IOC_CHANLIST;
1062 ireq.i_data = &active;
1063 ireq.i_len = sizeof(active);
1064 if (ioctl(s, SIOCG80211, &ireq) < 0)
1065 errx(1, "unable to get active channel list");
1066 memset(&achans, 0, sizeof(achans));
1067 for (i = 0; i < chans.ic_nchans; i++) {
1068 c = &chans.ic_chans[i];
1069 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1070 achans.ic_chans[achans.ic_nchans++] = *c;
1074 half = achans.ic_nchans / 2;
1075 if (achans.ic_nchans % 2)
1077 for (i = 0; i < achans.ic_nchans / 2; i++) {
1078 print_chaninfo(&achans.ic_chans[i]);
1079 print_chaninfo(&achans.ic_chans[half+i]);
1082 if (achans.ic_nchans % 2) {
1083 print_chaninfo(&achans.ic_chans[i]);
1093 #define IEEE80211_C_BITS \
1094 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1095 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1096 "\31WPA2\32BURST\33WME"
1099 list_capabilities(int s)
1101 struct ieee80211req ireq;
1104 (void) memset(&ireq, 0, sizeof(ireq));
1105 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1106 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1107 if (ioctl(s, SIOCG80211, &ireq) < 0)
1108 errx(1, "unable to get driver capabilities");
1109 caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
1110 printb(name, caps, IEEE80211_C_BITS);
1117 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1118 struct ieee80211req ireq;
1121 (void) memset(&ireq, 0, sizeof(ireq));
1122 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1124 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1126 if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
1127 printf("\t%s", " ");
1129 printf("\t%s", acnames[ac]);
1131 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1133 /* show WME BSS parameters */
1134 ireq.i_type = IEEE80211_IOC_WME_CWMIN;
1135 if (ioctl(s, SIOCG80211, &ireq) != -1)
1136 printf(" cwmin %2u", ireq.i_val);
1137 ireq.i_type = IEEE80211_IOC_WME_CWMAX;
1138 if (ioctl(s, SIOCG80211, &ireq) != -1)
1139 printf(" cwmax %2u", ireq.i_val);
1140 ireq.i_type = IEEE80211_IOC_WME_AIFS;
1141 if (ioctl(s, SIOCG80211, &ireq) != -1)
1142 printf(" aifs %2u", ireq.i_val);
1143 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
1144 if (ioctl(s, SIOCG80211, &ireq) != -1)
1145 printf(" txopLimit %3u", ireq.i_val);
1146 ireq.i_type = IEEE80211_IOC_WME_ACM;
1147 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1154 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1155 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1156 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1164 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1165 ireq.i_len |= IEEE80211_WMEPARAM_BSS;
1168 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
1175 struct ieee80211req ireq;
1176 struct ieee80211req_maclist *acllist;
1177 int i, nacls, policy;
1180 (void) memset(&ireq, 0, sizeof(ireq));
1181 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
1182 ireq.i_type = IEEE80211_IOC_MACCMD;
1183 ireq.i_val = IEEE80211_MACCMD_POLICY;
1184 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1185 if (errno == EINVAL) {
1186 printf("No acl policy loaded\n");
1189 err(1, "unable to get mac policy");
1191 policy = ireq.i_val;
1193 ireq.i_val = IEEE80211_MACCMD_LIST;
1195 if (ioctl(s, SIOCG80211, &ireq) < 0)
1196 err(1, "unable to get mac acl list size");
1197 if (ireq.i_len == 0) /* NB: no acls */
1200 ireq.i_data = malloc(ireq.i_len);
1201 if (ireq.i_data == NULL)
1202 err(1, "out of memory for acl list");
1204 if (ioctl(s, SIOCG80211, &ireq) < 0)
1205 err(1, "unable to get mac acl list");
1206 if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
1208 printf("policy: open\n");
1210 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1212 printf("policy: allow\n");
1214 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1216 printf("policy: deny\n");
1219 printf("policy: unknown (%u)\n", policy);
1222 nacls = ireq.i_len / sizeof(*acllist);
1223 acllist = (struct ieee80211req_maclist *) ireq.i_data;
1224 for (i = 0; i < nacls; i++)
1225 printf("%c%s\n", c, ether_ntoa(
1226 (const struct ether_addr *) acllist[i].ml_macaddr));
1230 DECL_CMD_FUNC(set80211list, arg, d)
1232 #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
1234 if (iseq(arg, "sta"))
1236 else if (iseq(arg, "scan") || iseq(arg, "ap"))
1238 else if (iseq(arg, "chan") || iseq(arg, "freq"))
1239 list_channels(s, 1);
1240 else if (iseq(arg, "active"))
1241 list_channels(s, 0);
1242 else if (iseq(arg, "keys"))
1244 else if (iseq(arg, "caps"))
1245 list_capabilities(s);
1246 else if (iseq(arg, "wme"))
1248 else if (iseq(arg, "mac"))
1251 errx(1, "Don't know how to list %s for %s", arg, name);
1255 static enum ieee80211_opmode
1256 get80211opmode(int s)
1258 struct ifmediareq ifmr;
1260 (void) memset(&ifmr, 0, sizeof(ifmr));
1261 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1263 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1264 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
1265 return IEEE80211_M_IBSS; /* XXX ahdemo */
1266 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1267 return IEEE80211_M_HOSTAP;
1268 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
1269 return IEEE80211_M_MONITOR;
1271 return IEEE80211_M_STA;
1274 static const struct ieee80211_channel *
1275 getchaninfo(int s, int chan)
1277 struct ieee80211req ireq;
1278 static struct ieee80211req_chaninfo chans;
1279 static struct ieee80211_channel undef;
1280 const struct ieee80211_channel *c;
1283 (void) memset(&ireq, 0, sizeof(ireq));
1284 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1285 ireq.i_type = IEEE80211_IOC_CHANINFO;
1286 ireq.i_data = &chans;
1287 ireq.i_len = sizeof(chans);
1288 if (ioctl(s, SIOCG80211, &ireq) < 0)
1289 errx(1, "unable to get channel information");
1290 freq = ieee80211_ieee2mhz(chan);
1291 for (i = 0; i < chans.ic_nchans; i++) {
1292 c = &chans.ic_chans[i];
1293 if (c->ic_freq == freq)
1301 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1303 switch (ireq->i_val) {
1304 case IEEE80211_CIPHER_WEP:
1305 ireq->i_type = keylenop;
1306 if (ioctl(s, SIOCG80211, ireq) != -1)
1308 ireq->i_len <= 5 ? "40" :
1309 ireq->i_len <= 13 ? "104" : "128");
1313 case IEEE80211_CIPHER_TKIP:
1316 case IEEE80211_CIPHER_AES_OCB:
1319 case IEEE80211_CIPHER_AES_CCM:
1322 case IEEE80211_CIPHER_CKIP:
1325 case IEEE80211_CIPHER_NONE:
1329 printf("UNKNOWN (0x%x)", ireq->i_val);
1342 if (spacer != '\t') {
1346 col = 8; /* 8-col tab */
1350 LINE_CHECK(const char *fmt, ...)
1357 n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1370 printkey(const struct ieee80211req_key *ik)
1372 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1373 int keylen = ik->ik_keylen;
1376 printcontents = printkeys &&
1377 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
1380 switch (ik->ik_type) {
1381 case IEEE80211_CIPHER_WEP:
1383 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
1384 keylen <= 5 ? "40-bit" :
1385 keylen <= 13 ? "104-bit" : "128-bit");
1387 case IEEE80211_CIPHER_TKIP:
1389 keylen -= 128/8; /* ignore MIC for now */
1390 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1392 case IEEE80211_CIPHER_AES_OCB:
1393 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1395 case IEEE80211_CIPHER_AES_CCM:
1396 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1398 case IEEE80211_CIPHER_CKIP:
1399 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1401 case IEEE80211_CIPHER_NONE:
1402 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1405 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
1406 ik->ik_type, ik->ik_keyix+1, 8*keylen);
1409 if (printcontents) {
1413 for (i = 0; i < keylen; i++)
1414 printf("%02x", ik->ik_keydata[i]);
1416 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1417 (ik->ik_keyrsc != 0 || verbose))
1418 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
1419 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1420 (ik->ik_keytsc != 0 || verbose))
1421 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
1422 if (ik->ik_flags != 0 && verbose) {
1423 const char *sep = " ";
1425 if (ik->ik_flags & IEEE80211_KEY_XMIT)
1426 printf("%stx", sep), sep = "+";
1427 if (ik->ik_flags & IEEE80211_KEY_RECV)
1428 printf("%srx", sep), sep = "+";
1429 if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
1430 printf("%sdef", sep), sep = "+";
1437 ieee80211_status(int s)
1439 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1440 enum ieee80211_opmode opmode = get80211opmode(s);
1441 int i, num, wpa, wme;
1442 struct ieee80211req ireq;
1444 const struct ieee80211_channel *c;
1446 (void) memset(&ireq, 0, sizeof(ireq));
1447 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1448 ireq.i_data = &data;
1450 wpa = 0; /* unknown/not set */
1452 ireq.i_type = IEEE80211_IOC_SSID;
1454 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1455 /* If we can't get the SSID, this isn't an 802.11 device. */
1459 ireq.i_type = IEEE80211_IOC_RATECTL;
1460 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1463 switch (ireq.i_val) {
1464 case IEEE80211_RATECTL_ONOE:
1465 printf("\tratectl: onoe");
1467 case IEEE80211_RATECTL_AMRR:
1468 printf("\tratectl: amrr");
1472 printf("\tratectl: none");
1482 ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1483 if (ioctl(s, SIOCG80211, &ireq) >= 0)
1487 ireq.i_type = IEEE80211_IOC_SSID;
1488 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1489 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1490 printf(" %d:", ireq.i_val + 1);
1491 print_string(data, ireq.i_len);
1495 print_string(data, ireq.i_len);
1497 ireq.i_type = IEEE80211_IOC_CHANNEL;
1498 if (ioctl(s, SIOCG80211, &ireq) < 0)
1500 c = getchaninfo(s, ireq.i_val);
1501 if (ireq.i_val != -1) {
1502 printf(" channel %d", ireq.i_val);
1504 printf(" (%u)", c->ic_freq);
1506 printf(" channel UNDEF");
1508 ireq.i_type = IEEE80211_IOC_BSSID;
1509 ireq.i_len = IEEE80211_ADDR_LEN;
1510 if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1511 (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1512 printf(" bssid %s", ether_ntoa(ireq.i_data));
1514 ireq.i_type = IEEE80211_IOC_STATIONNAME;
1515 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1516 printf("\n\tstationname ");
1517 print_string(data, ireq.i_len);
1520 spacer = ' '; /* force first break */
1523 ireq.i_type = IEEE80211_IOC_AUTHMODE;
1524 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1525 switch (ireq.i_val) {
1526 case IEEE80211_AUTH_NONE:
1527 LINE_CHECK("authmode NONE");
1529 case IEEE80211_AUTH_OPEN:
1530 LINE_CHECK("authmode OPEN");
1532 case IEEE80211_AUTH_SHARED:
1533 LINE_CHECK("authmode SHARED");
1535 case IEEE80211_AUTH_8021X:
1536 LINE_CHECK("authmode 802.1x");
1538 case IEEE80211_AUTH_WPA:
1539 ireq.i_type = IEEE80211_IOC_WPA;
1540 if (ioctl(s, SIOCG80211, &ireq) != -1)
1543 wpa = 1; /* default to WPA1 */
1546 LINE_CHECK("authmode WPA2/802.11i");
1549 LINE_CHECK("authmode WPA1+WPA2/802.11i");
1552 LINE_CHECK("authmode WPA");
1556 case IEEE80211_AUTH_AUTO:
1557 LINE_CHECK("authmode AUTO");
1560 LINE_CHECK("authmode UNKNOWN (0x%x)",
1566 ireq.i_type = IEEE80211_IOC_WEP;
1567 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1568 ireq.i_val != IEEE80211_WEP_NOSUP) {
1569 int firstkey, wepmode;
1571 wepmode = ireq.i_val;
1573 case IEEE80211_WEP_OFF:
1574 LINE_CHECK("privacy OFF");
1576 case IEEE80211_WEP_ON:
1577 LINE_CHECK("privacy ON");
1579 case IEEE80211_WEP_MIXED:
1580 LINE_CHECK("privacy MIXED");
1583 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1588 * If we get here then we've got WEP support so we need
1589 * to print WEP status.
1592 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1593 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1594 warn("WEP support, but no tx key!");
1597 if (ireq.i_val != -1)
1598 LINE_CHECK("deftxkey %d", ireq.i_val+1);
1599 else if (wepmode != IEEE80211_WEP_OFF || verbose)
1600 LINE_CHECK("deftxkey UNDEF");
1602 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1603 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1604 warn("WEP support, but no NUMWEPKEYS support!");
1610 for (i = 0; i < num; i++) {
1611 struct ieee80211req_key ik;
1613 memset(&ik, 0, sizeof(ik));
1615 ireq.i_type = IEEE80211_IOC_WPAKEY;
1617 ireq.i_len = sizeof(ik);
1618 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1619 warn("WEP support, but can get keys!");
1622 if (ik.ik_keylen != 0) {
1631 ireq.i_type = IEEE80211_IOC_POWERSAVE;
1632 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1633 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1634 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1635 switch (ireq.i_val) {
1636 case IEEE80211_POWERSAVE_OFF:
1637 LINE_CHECK("powersavemode OFF");
1639 case IEEE80211_POWERSAVE_CAM:
1640 LINE_CHECK("powersavemode CAM");
1642 case IEEE80211_POWERSAVE_PSP:
1643 LINE_CHECK("powersavemode PSP");
1645 case IEEE80211_POWERSAVE_PSP_CAM:
1646 LINE_CHECK("powersavemode PSP-CAM");
1649 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1650 if (ioctl(s, SIOCG80211, &ireq) != -1)
1651 LINE_CHECK("powersavesleep %d", ireq.i_val);
1655 ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1656 if (ioctl(s, SIOCG80211, &ireq) != -1)
1657 LINE_CHECK("txpowmax %d", ireq.i_val);
1660 ireq.i_type = IEEE80211_IOC_TXPOWER;
1661 if (ioctl(s, SIOCG80211, &ireq) != -1)
1662 LINE_CHECK("txpower %d", ireq.i_val);
1665 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1666 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1667 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1668 LINE_CHECK("rtsthreshold %d", ireq.i_val);
1671 ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1672 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1673 if (ireq.i_val != 2*1 || verbose) {
1674 if (ireq.i_val == 11)
1675 LINE_CHECK("mcastrate 5.5");
1677 LINE_CHECK("mcastrate %d", ireq.i_val/2);
1681 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1682 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1683 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1684 LINE_CHECK("fragthreshold %d", ireq.i_val);
1687 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1688 ireq.i_type = IEEE80211_IOC_PUREG;
1689 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1691 LINE_CHECK("pureg");
1693 LINE_CHECK("-pureg");
1695 ireq.i_type = IEEE80211_IOC_PROTMODE;
1696 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1697 switch (ireq.i_val) {
1698 case IEEE80211_PROTMODE_OFF:
1699 LINE_CHECK("protmode OFF");
1701 case IEEE80211_PROTMODE_CTS:
1702 LINE_CHECK("protmode CTS");
1704 case IEEE80211_PROTMODE_RTSCTS:
1705 LINE_CHECK("protmode RTSCTS");
1708 LINE_CHECK("protmode UNKNOWN (0x%x)",
1715 ireq.i_type = IEEE80211_IOC_WME;
1716 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1725 ireq.i_type = IEEE80211_IOC_BURST;
1726 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1728 LINE_CHECK("burst");
1730 LINE_CHECK("-burst");
1733 if (opmode == IEEE80211_M_HOSTAP) {
1734 ireq.i_type = IEEE80211_IOC_HIDESSID;
1735 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1737 LINE_CHECK("ssid HIDE");
1739 LINE_CHECK("ssid SHOW");
1742 ireq.i_type = IEEE80211_IOC_APBRIDGE;
1743 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1745 LINE_CHECK("-apbridge");
1747 LINE_CHECK("apbridge");
1750 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1751 if (ioctl(s, SIOCG80211, &ireq) != -1)
1752 LINE_CHECK("dtimperiod %u", ireq.i_val);
1754 ireq.i_type = IEEE80211_IOC_ROAMING;
1755 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1756 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1757 switch (ireq.i_val) {
1758 case IEEE80211_ROAMING_DEVICE:
1759 LINE_CHECK("roaming DEVICE");
1761 case IEEE80211_ROAMING_AUTO:
1762 LINE_CHECK("roaming AUTO");
1764 case IEEE80211_ROAMING_MANUAL:
1765 LINE_CHECK("roaming MANUAL");
1768 LINE_CHECK("roaming UNKNOWN (0x%x)",
1775 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1776 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1778 LINE_CHECK("bintval %u", ireq.i_val);
1780 LINE_CHECK("bintval %u", ireq.i_val);
1783 if (wme && verbose) {
1789 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1790 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1792 LINE_CHECK("countermeasures");
1794 LINE_CHECK("-countermeasures");
1797 /* XXX not interesting with WPA done in user space */
1798 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1799 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1802 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1803 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1804 LINE_CHECK("mcastcipher ");
1805 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1809 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1810 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1811 LINE_CHECK("ucastcipher ");
1812 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1816 ireq.i_type = IEEE80211_IOC_RSNCAPS;
1817 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1818 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1823 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1824 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1836 set80211(int s, int type, int val, int len, u_int8_t *data)
1838 struct ieee80211req ireq;
1840 (void) memset(&ireq, 0, sizeof(ireq));
1841 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1846 if (ioctl(s, SIOCS80211, &ireq) < 0)
1847 err(1, "SIOCS80211");
1851 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1859 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1865 if (sep != NULL && strchr(sep, *val) != NULL) {
1870 if (!isxdigit((u_char)val[0])) {
1871 warnx("bad hexadecimal digits");
1874 if (!isxdigit((u_char)val[1])) {
1875 warnx("odd count hexadecimal digits");
1879 if (p >= buf + len) {
1881 warnx("hexadecimal digits too long");
1883 warnx("string too long");
1887 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1888 *p++ = (tohex((u_char)val[0]) << 4) |
1889 tohex((u_char)val[1]);
1896 /* The string "-" is treated as the empty string. */
1897 if (!hexstr && len == 1 && buf[0] == '-')
1900 memset(p, 0, *lenp - len);
1906 print_string(const u_int8_t *buf, int len)
1913 for (; i < len; i++) {
1914 if (!isprint(buf[i]) && buf[i] != '\0')
1916 if (isspace(buf[i]))
1920 if (hasspc || len == 0 || buf[0] == '\0')
1921 printf("\"%.*s\"", len, buf);
1923 printf("%.*s", len, buf);
1926 for (i = 0; i < len; i++)
1927 printf("%02x", buf[i]);
1931 static struct cmd ieee80211_cmds[] = {
1932 DEF_CMD_ARG("ssid", set80211ssid),
1933 DEF_CMD_ARG("nwid", set80211ssid),
1934 DEF_CMD_ARG("stationname", set80211stationname),
1935 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
1936 DEF_CMD_ARG("channel", set80211channel),
1937 DEF_CMD_ARG("authmode", set80211authmode),
1938 DEF_CMD_ARG("powersavemode", set80211powersavemode),
1939 DEF_CMD("powersave", 1, set80211powersave),
1940 DEF_CMD("-powersave", 0, set80211powersave),
1941 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
1942 DEF_CMD_ARG("wepmode", set80211wepmode),
1943 DEF_CMD("wep", 1, set80211wep),
1944 DEF_CMD("-wep", 0, set80211wep),
1945 DEF_CMD_ARG("deftxkey", set80211weptxkey),
1946 DEF_CMD_ARG("weptxkey", set80211weptxkey),
1947 DEF_CMD_ARG("wepkey", set80211wepkey),
1948 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
1949 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
1950 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
1951 DEF_CMD_ARG("protmode", set80211protmode),
1952 DEF_CMD_ARG("txpower", set80211txpower),
1953 DEF_CMD_ARG("roaming", set80211roaming),
1954 DEF_CMD("wme", 1, set80211wme),
1955 DEF_CMD("-wme", 0, set80211wme),
1956 DEF_CMD("hidessid", 1, set80211hidessid),
1957 DEF_CMD("-hidessid", 0, set80211hidessid),
1958 DEF_CMD("apbridge", 1, set80211apbridge),
1959 DEF_CMD("-apbridge", 0, set80211apbridge),
1960 DEF_CMD_ARG("chanlist", set80211chanlist),
1961 DEF_CMD_ARG("bssid", set80211bssid),
1962 DEF_CMD_ARG("ap", set80211bssid),
1963 DEF_CMD("scan", 0, set80211scan),
1964 DEF_CMD_ARG("list", set80211list),
1965 DEF_CMD_ARG2("cwmin", set80211cwmin),
1966 DEF_CMD_ARG2("cwmax", set80211cwmax),
1967 DEF_CMD_ARG2("aifs", set80211aifs),
1968 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
1969 DEF_CMD_ARG("acm", set80211acm),
1970 DEF_CMD_ARG("-acm", set80211noacm),
1971 DEF_CMD_ARG("ack", set80211ackpolicy),
1972 DEF_CMD_ARG("-ack", set80211noackpolicy),
1973 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
1974 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
1975 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
1976 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
1977 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
1978 DEF_CMD_ARG("bintval", set80211bintval),
1979 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
1980 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
1981 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
1982 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
1983 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
1984 DEF_CMD_ARG("mac:add", set80211addmac),
1985 DEF_CMD_ARG("mac:del", set80211delmac),
1986 DEF_CMD_ARG("mac:kick", set80211kickmac),
1987 DEF_CMD("pureg", 1, set80211pureg),
1988 DEF_CMD("-pureg", 0, set80211pureg),
1989 DEF_CMD_ARG("mcastrate", set80211mcastrate),
1990 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
1991 DEF_CMD("burst", 1, set80211burst),
1992 DEF_CMD("-burst", 0, set80211burst),
1993 DEF_CMD_ARG("ratectl", set80211ratectl)
1995 static struct afswtch af_ieee80211 = {
1996 .af_name = "af_ieee80211",
1998 .af_other_status = ieee80211_status,
2001 static __constructor void
2002 ieee80211_ctor(void)
2004 #define N(a) (sizeof(a) / sizeof(a[0]))
2007 for (i = 0; i < N(ieee80211_cmds); i++)
2008 cmd_register(&ieee80211_cmds[i]);
2009 af_register(&af_ieee80211);