MFC:
[dragonfly.git] / sbin / ifconfig / ifieee80211.c
blob3cc768feb6b6d95b6e48101ab9802690cde9bf5c
1 /*
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
6 * are met:
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
25 * SUCH DAMAGE.
27 * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.18.2.10 2006/08/10 06:09:23 sam Exp $
28 * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.20 2008/01/19 07:34:13 sephe Exp $
31 /*-
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
41 * are met:
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>
72 #include <sys/time.h>
74 #include <net/ethernet.h>
75 #include <net/if.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>
86 #include <ctype.h>
87 #include <err.h>
88 #include <errno.h>
89 #include <fcntl.h>
90 #include <inttypes.h>
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <string.h>
94 #include <unistd.h>
95 #include <stdarg.h>
97 #include "ifconfig.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);
104 static int
105 isanyarg(const char *arg)
107 return (strcmp(arg, "-") == 0 ||
108 strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
111 static void
112 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
114 int ssid;
115 int len;
116 u_int8_t data[IEEE80211_NWID_LEN];
118 ssid = 0;
119 len = strlen(val);
120 if (len > 2 && isdigit(val[0]) && val[1] == ':') {
121 ssid = atoi(val)-1;
122 val += 2;
125 bzero(data, sizeof(data));
126 len = sizeof(data);
127 if (get_string(val, NULL, data, &len) == NULL)
128 exit(1);
130 set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
133 static void
134 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
136 int len;
137 u_int8_t data[33];
139 bzero(data, sizeof(data));
140 len = 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.
149 static u_int
150 ieee80211_ieee2mhz(u_int chan)
152 if (chan == 14)
153 return 2484;
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.
164 static u_int
165 ieee80211_mhz2ieee(u_int freq)
167 if (freq == 2484)
168 return 14;
169 if (freq < 2484)
170 return (freq - 2407) / 5;
171 if (freq < 5000)
172 return 15 + ((freq - 2512) / 20);
173 return (freq - 5000) / 5;
176 static void
177 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
179 if (!isanyarg(val)) {
180 int v = atoi(val);
181 if (v > 255) /* treat as frequency */
182 v = ieee80211_mhz2ieee(v);
183 set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
184 } else
185 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
188 static void
189 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
191 int mode;
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;
203 } else {
204 errx(1, "unknown authmode");
207 set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
210 static void
211 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
213 int mode;
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;
225 } else {
226 errx(1, "unknown powersavemode");
229 set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
232 static void
233 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
235 if (d == 0)
236 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
237 0, NULL);
238 else
239 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
240 0, NULL);
243 static void
244 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
246 set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
249 static void
250 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
252 int mode;
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;
260 } else {
261 errx(1, "unknown wep mode");
264 set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
267 static void
268 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
270 set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
273 static int
274 isundefarg(const char *arg)
276 return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
279 static void
280 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
282 if (isundefarg(val))
283 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
284 else
285 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
288 static void
289 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
291 int key = 0;
292 int len;
293 u_int8_t data[IEEE80211_KEYBUF_SIZE];
295 if (isdigit(val[0]) && val[1] == ':') {
296 key = atoi(val)-1;
297 val += 2;
300 bzero(data, sizeof(data));
301 len = 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.
312 static void
313 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
315 int txkey;
316 int i, len;
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;
323 val += 2;
325 for (i = 0; i < 4; i++) {
326 bzero(data, sizeof(data));
327 len = sizeof(data);
328 val = get_string(val, ",", data, &len);
329 if (val == NULL)
330 exit(1);
332 set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
334 } else {
335 bzero(data, sizeof(data));
336 len = sizeof(data);
337 get_string(val, NULL, data, &len);
338 txkey = 0;
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);
350 static void
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);
357 static void
358 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
360 int mode;
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;
368 } else {
369 errx(1, "unknown protection mode");
372 set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
375 static void
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
385 static void
386 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
388 int mode;
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;
396 } else {
397 errx(1, "unknown roaming mode");
399 set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
402 static void
403 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
405 set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
408 static void
409 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
411 set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
414 static void
415 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
417 set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
420 static void
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);
428 if (temp == NULL)
429 errx(1, "malloc failed");
430 strcpy(temp, val);
431 memset(&chanlist, 0, sizeof(chanlist));
432 cp = temp;
433 for (;;) {
434 int first, last, f;
436 tp = strchr(cp, ',');
437 if (tp != NULL)
438 *tp++ = '\0';
439 switch (sscanf(cp, "%u-%u", &first, &last)) {
440 case 1:
441 if (first > MAXCHAN)
442 errx(-1, "channel %u out of range, max %zu",
443 first, MAXCHAN);
444 setbit(chanlist.ic_channels, first);
445 break;
446 case 2:
447 if (first > MAXCHAN)
448 errx(-1, "channel %u out of range, max %zu",
449 first, MAXCHAN);
450 if (last > MAXCHAN)
451 errx(-1, "channel %u out of range, max %zu",
452 last, MAXCHAN);
453 if (first > last)
454 errx(-1, "void channel range, %u > %u",
455 first, last);
456 for (f = first; f <= last; f++)
457 setbit(chanlist.ic_channels, f);
458 break;
460 if (tp == NULL)
461 break;
462 while (isspace(*tp))
463 tp++;
464 if (!isdigit(*tp))
465 break;
466 cp = tp;
468 set80211(s, IEEE80211_IOC_CHANLIST, 0,
469 sizeof(chanlist), (uint8_t *) &chanlist);
470 #undef MAXCHAN
473 static void
474 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
477 if (!isanyarg(val)) {
478 char *temp;
479 struct sockaddr_dl sdl;
481 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
482 if (temp == NULL)
483 errx(1, "malloc failed");
484 temp[0] = ':';
485 strcpy(temp + 1, val);
486 sdl.sdl_len = sizeof(sdl);
487 link_addr(temp, &sdl);
488 free(temp);
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));
493 } else {
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);
501 static int
502 getac(const char *ac)
504 if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
505 return WME_AC_BE;
506 if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
507 return WME_AC_BK;
508 if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
509 return WME_AC_VI;
510 if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
511 return WME_AC_VO;
512 errx(1, "unknown wme access class %s", ac);
515 static
516 DECL_CMD_FUNC2(set80211cwmin, ac, val)
518 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
521 static
522 DECL_CMD_FUNC2(set80211cwmax, ac, val)
524 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
527 static
528 DECL_CMD_FUNC2(set80211aifs, ac, val)
530 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
533 static
534 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
536 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
539 static
540 DECL_CMD_FUNC(set80211acm, ac, d)
542 set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
544 static
545 DECL_CMD_FUNC(set80211noacm, ac, d)
547 set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
550 static
551 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
553 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
555 static
556 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
558 set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
561 static
562 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
564 set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
565 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
568 static
569 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
571 set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
572 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
575 static
576 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
578 set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
579 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
582 static
583 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
585 set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
586 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
589 static
590 DECL_CMD_FUNC(set80211dtimperiod, val, d)
592 set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
595 static
596 DECL_CMD_FUNC(set80211bintval, val, d)
598 set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
601 static void
602 set80211macmac(int s, int op, const char *val)
604 char *temp;
605 struct sockaddr_dl sdl;
607 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
608 if (temp == NULL)
609 errx(1, "malloc failed");
610 temp[0] = ':';
611 strcpy(temp + 1, val);
612 sdl.sdl_len = sizeof(sdl);
613 link_addr(temp, &sdl);
614 free(temp);
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));
620 static
621 DECL_CMD_FUNC(set80211addmac, val, d)
623 set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
626 static
627 DECL_CMD_FUNC(set80211delmac, val, d)
629 set80211macmac(s, IEEE80211_IOC_DELMAC, val);
632 static
633 DECL_CMD_FUNC(set80211kickmac, val, d)
635 char *temp;
636 struct sockaddr_dl sdl;
637 struct ieee80211req_mlme mlme;
639 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
640 if (temp == NULL)
641 errx(1, "malloc failed");
642 temp[0] = ':';
643 strcpy(temp + 1, val);
644 sdl.sdl_len = sizeof(sdl);
645 link_addr(temp, &sdl);
646 free(temp);
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);
656 static
657 DECL_CMD_FUNC(set80211maccmd, val, d)
659 set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
662 static void
663 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
665 set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
668 static void
669 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
671 set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
674 static void
675 set80211ratectl(const char *val, int d, int s, const struct afswtch *rafp)
677 int ratectl = 0;
679 if (strcmp("onoe", val) == 0)
680 ratectl = IEEE80211_RATECTL_ONOE;
681 else if (strcmp("amrr", val) == 0)
682 ratectl = IEEE80211_RATECTL_AMRR;
683 else if (strcmp("sample", val) == 0)
684 ratectl = IEEE80211_RATECTL_SAMPLE;
685 else
686 errx(1, "unknown ratectl");
688 set80211(s, IEEE80211_IOC_RATECTL, ratectl, 0, NULL);
691 static
692 DECL_CMD_FUNC(set80211mcastrate, val, d)
694 set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
697 static
698 DECL_CMD_FUNC(set80211fragthreshold, val, d)
700 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
701 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
704 static
705 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
707 set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
708 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
711 static int
712 getmaxrate(uint8_t rates[15], uint8_t nrates)
714 int i, maxrate = -1;
716 for (i = 0; i < nrates; i++) {
717 int rate = rates[i] & IEEE80211_RATE_VAL;
718 if (rate > maxrate)
719 maxrate = rate;
721 return maxrate / 2;
724 static const char *
725 getcaps(int capinfo)
727 static char capstring[32];
728 char *cp = capstring;
730 if (capinfo & IEEE80211_CAPINFO_ESS)
731 *cp++ = 'E';
732 if (capinfo & IEEE80211_CAPINFO_IBSS)
733 *cp++ = 'I';
734 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
735 *cp++ = 'c';
736 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
737 *cp++ = 'C';
738 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
739 *cp++ = 'P';
740 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
741 *cp++ = 'S';
742 if (capinfo & IEEE80211_CAPINFO_PBCC)
743 *cp++ = 'B';
744 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
745 *cp++ = 'A';
746 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
747 *cp++ = 's';
748 if (capinfo & IEEE80211_CAPINFO_RSN)
749 *cp++ = 'R';
750 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
751 *cp++ = 'D';
752 *cp = '\0';
753 return capstring;
756 static void
757 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
759 printf("%s", tag);
760 if (verbose) {
761 maxlen -= strlen(tag)+2;
762 if (2*ielen > maxlen)
763 maxlen--;
764 printf("<");
765 for (; ielen > 0; ie++, ielen--) {
766 if (maxlen-- <= 0)
767 break;
768 printf("%02x", *ie);
770 if (ielen != 0)
771 printf("-");
772 printf(">");
777 * Copy the ssid string contents into buf, truncating to fit. If the
778 * ssid is entirely printable then just copy intact. Otherwise convert
779 * to hexadecimal. If the result is truncated then replace the last
780 * three characters with "...".
782 static int
783 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
785 const u_int8_t *p;
786 size_t maxlen;
787 int i;
789 if (essid_len > bufsize)
790 maxlen = bufsize;
791 else
792 maxlen = essid_len;
793 /* determine printable or not */
794 for (i = 0, p = essid; i < maxlen; i++, p++) {
795 if (*p < ' ' || *p > 0x7e)
796 break;
798 if (i != maxlen) { /* not printable, print as hex */
799 if (bufsize < 3)
800 return 0;
801 strlcpy(buf, "0x", bufsize);
802 bufsize -= 2;
803 p = essid;
804 for (i = 0; i < maxlen && bufsize >= 2; i++) {
805 sprintf(&buf[2+2*i], "%02x", p[i]);
806 bufsize -= 2;
808 if (i != essid_len)
809 memcpy(&buf[2+2*i-3], "...", 3);
810 } else { /* printable, truncate as needed */
811 memcpy(buf, essid, maxlen);
812 if (maxlen != essid_len)
813 memcpy(&buf[maxlen-3], "...", 3);
815 return maxlen;
818 /* unaligned little endian access */
819 #define LE_READ_4(p) \
820 ((u_int32_t) \
821 ((((const u_int8_t *)(p))[0] ) | \
822 (((const u_int8_t *)(p))[1] << 8) | \
823 (((const u_int8_t *)(p))[2] << 16) | \
824 (((const u_int8_t *)(p))[3] << 24)))
826 static int __inline
827 iswpaoui(const u_int8_t *frm)
829 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
832 static int __inline
833 iswmeoui(const u_int8_t *frm)
835 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
838 static int __inline
839 isatherosoui(const u_int8_t *frm)
841 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
844 static void
845 printies(const u_int8_t *vp, int ielen, int maxcols)
847 while (ielen > 0) {
848 switch (vp[0]) {
849 case IEEE80211_ELEMID_VENDOR:
850 if (iswpaoui(vp))
851 printie(" WPA", vp, 2+vp[1], maxcols);
852 else if (iswmeoui(vp))
853 printie(" WME", vp, 2+vp[1], maxcols);
854 else if (isatherosoui(vp))
855 printie(" ATH", vp, 2+vp[1], maxcols);
856 else
857 printie(" VEN", vp, 2+vp[1], maxcols);
858 break;
859 case IEEE80211_ELEMID_RSN:
860 printie(" RSN", vp, 2+vp[1], maxcols);
861 break;
862 default:
863 printie(" ???", vp, 2+vp[1], maxcols);
864 break;
866 ielen -= 2+vp[1];
867 vp += 2+vp[1];
871 static void
872 list_scan(int s)
874 uint8_t buf[24*1024];
875 struct ieee80211req ireq;
876 char ssid[IEEE80211_NWID_LEN+1];
877 uint8_t *cp;
878 int len, ssidmax;
880 (void) memset(&ireq, 0, sizeof(ireq));
881 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
882 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
883 ireq.i_data = buf;
884 ireq.i_len = sizeof(buf);
885 if (ioctl(s, SIOCG80211, &ireq) < 0)
886 errx(1, "unable to get scan results");
887 len = ireq.i_len;
888 if (len < sizeof(struct ieee80211req_scan_result))
889 return;
891 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
892 printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
893 , ssidmax, ssidmax, "SSID"
894 , "BSSID"
895 , "CHAN"
896 , "RATE"
897 , "S:N"
898 , "INT"
899 , "CAPS"
901 cp = buf;
902 do {
903 struct ieee80211req_scan_result *sr;
904 uint8_t *vp;
906 sr = (struct ieee80211req_scan_result *) cp;
907 vp = (u_int8_t *)(sr+1);
908 printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
909 , ssidmax
910 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
911 , ssid
912 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
913 , ieee80211_mhz2ieee(sr->isr_freq)
914 , getmaxrate(sr->isr_rates, sr->isr_nrates)
915 , sr->isr_rssi, sr->isr_noise
916 , sr->isr_intval
917 , getcaps(sr->isr_capinfo2)
919 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
920 printf("\n");
921 cp += sr->isr_len, len -= sr->isr_len;
922 } while (len >= sizeof(struct ieee80211req_scan_result));
925 #include <netproto/802_11/ieee80211_dragonfly.h>
927 static void
928 scan_and_wait(int s)
930 struct ieee80211req ireq;
931 int sroute;
933 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
934 if (sroute < 0) {
935 perror("socket(PF_ROUTE,SOCK_RAW)");
936 return;
938 (void) memset(&ireq, 0, sizeof(ireq));
939 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
940 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
941 /* NB: only root can trigger a scan so ignore errors */
942 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
943 char buf[2048];
944 struct if_announcemsghdr *ifan;
945 struct rt_msghdr *rtm;
947 do {
948 if (read(sroute, buf, sizeof(buf)) < 0) {
949 perror("read(PF_ROUTE)");
950 break;
952 rtm = (struct rt_msghdr *) buf;
953 if (rtm->rtm_version != RTM_VERSION)
954 break;
955 ifan = (struct if_announcemsghdr *) rtm;
956 } while (rtm->rtm_type != RTM_IEEE80211 ||
957 ifan->ifan_what != RTM_IEEE80211_SCAN);
959 close(sroute);
962 static
963 DECL_CMD_FUNC(set80211scan, val, d)
965 scan_and_wait(s);
966 list_scan(s);
969 static enum ieee80211_opmode get80211opmode(int s);
971 static void
972 list_stations(int s)
974 union {
975 struct ieee80211req_sta_req req;
976 uint8_t buf[24*1024];
977 } u;
978 enum ieee80211_opmode opmode = get80211opmode(s);
979 struct ieee80211req ireq;
980 uint8_t *cp;
981 int len;
983 (void) memset(&ireq, 0, sizeof(ireq));
984 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
985 /* broadcast address =>'s get all stations */
986 (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
987 if (opmode == IEEE80211_M_STA) {
989 * Get information about the associated AP.
991 ireq.i_type = IEEE80211_IOC_BSSID;
992 ireq.i_data = u.req.is_u.macaddr;
993 ireq.i_len = IEEE80211_ADDR_LEN;
994 (void) ioctl(s, SIOCG80211, &ireq);
996 ireq.i_type = IEEE80211_IOC_STA_INFO;
997 ireq.i_data = &u;
998 ireq.i_len = sizeof(u);
999 if (ioctl(s, SIOCG80211, &ireq) < 0)
1000 errx(1, "unable to get station information");
1001 len = ireq.i_len;
1002 if (len < sizeof(struct ieee80211req_sta_info))
1003 return;
1005 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
1006 , "ADDR"
1007 , "AID"
1008 , "CHAN"
1009 , "RATE"
1010 , "RSSI"
1011 , "IDLE"
1012 , "TXSEQ"
1013 , "RXSEQ"
1014 , "CAPS"
1015 , "ERP"
1017 cp = (uint8_t *) u.req.info;
1018 do {
1019 struct ieee80211req_sta_info *si;
1020 uint8_t *vp;
1022 si = (struct ieee80211req_sta_info *) cp;
1023 if (si->isi_len < sizeof(*si))
1024 break;
1025 vp = (u_int8_t *)(si+1);
1026 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
1027 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1028 , IEEE80211_AID(si->isi_associd)
1029 , ieee80211_mhz2ieee(si->isi_freq)
1030 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
1031 , si->isi_rssi
1032 , si->isi_inact
1033 , si->isi_txseqs[0]
1034 , si->isi_rxseqs[0]
1035 , getcaps(si->isi_capinfo2)
1036 , si->isi_erp
1038 printies(vp, si->isi_ie_len, 24);
1039 printf("\n");
1040 cp += si->isi_len, len -= si->isi_len;
1041 } while (len >= sizeof(struct ieee80211req_sta_info));
1044 static void
1045 print_chaninfo(const struct ieee80211_channel *c)
1047 #define IEEE80211_IS_CHAN_PASSIVE(_c) \
1048 (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1049 char buf[14];
1051 buf[0] = '\0';
1052 if (IEEE80211_IS_CHAN_FHSS(c))
1053 strlcat(buf, " FHSS", sizeof(buf));
1054 if (IEEE80211_IS_CHAN_A(c))
1055 strlcat(buf, " 11a", sizeof(buf));
1056 /* XXX 11g schizophrenia */
1057 if (IEEE80211_IS_CHAN_G(c) ||
1058 IEEE80211_IS_CHAN_PUREG(c))
1059 strlcat(buf, " 11g", sizeof(buf));
1060 else if (IEEE80211_IS_CHAN_B(c))
1061 strlcat(buf, " 11b", sizeof(buf));
1062 if (IEEE80211_IS_CHAN_T(c))
1063 strlcat(buf, " Turbo", sizeof(buf));
1064 printf("Channel %3u : %u%c Mhz%-14.14s",
1065 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1066 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1067 #undef IEEE80211_IS_CHAN_PASSIVE
1070 static void
1071 list_channels(int s, int allchans)
1073 struct ieee80211req ireq;
1074 struct ieee80211req_chaninfo chans;
1075 struct ieee80211req_chaninfo achans;
1076 const struct ieee80211_channel *c;
1077 int i, half;
1079 (void) memset(&ireq, 0, sizeof(ireq));
1080 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1081 ireq.i_type = IEEE80211_IOC_CHANINFO;
1082 ireq.i_data = &chans;
1083 ireq.i_len = sizeof(chans);
1084 if (ioctl(s, SIOCG80211, &ireq) < 0)
1085 errx(1, "unable to get channel information");
1086 if (!allchans) {
1087 struct ieee80211req_chanlist active;
1089 ireq.i_type = IEEE80211_IOC_CHANLIST;
1090 ireq.i_data = &active;
1091 ireq.i_len = sizeof(active);
1092 if (ioctl(s, SIOCG80211, &ireq) < 0)
1093 errx(1, "unable to get active channel list");
1094 memset(&achans, 0, sizeof(achans));
1095 for (i = 0; i < chans.ic_nchans; i++) {
1096 c = &chans.ic_chans[i];
1097 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1098 achans.ic_chans[achans.ic_nchans++] = *c;
1100 } else
1101 achans = chans;
1102 half = achans.ic_nchans / 2;
1103 if (achans.ic_nchans % 2)
1104 half++;
1105 for (i = 0; i < achans.ic_nchans / 2; i++) {
1106 print_chaninfo(&achans.ic_chans[i]);
1107 print_chaninfo(&achans.ic_chans[half+i]);
1108 printf("\n");
1110 if (achans.ic_nchans % 2) {
1111 print_chaninfo(&achans.ic_chans[i]);
1112 printf("\n");
1116 static void
1117 list_keys(int s)
1121 #define IEEE80211_C_BITS \
1122 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1123 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1124 "\31WPA2\32BURST\33WME"
1126 #define IEEE80211_CEXT_BITS "\020\1PBCC"
1128 static void
1129 list_capabilities(int s)
1131 struct ieee80211req ireq;
1132 uint32_t caps, caps_ext;
1134 memset(&ireq, 0, sizeof(ireq));
1135 caps_ext = 0;
1137 strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1138 ireq.i_data = &caps_ext;
1139 ireq.i_len = sizeof(caps_ext);
1140 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1141 if (ioctl(s, SIOCG80211, &ireq) < 0)
1142 errx(1, "unable to get driver capabilities");
1143 caps = (((uint16_t)ireq.i_val) << 16) | ((uint16_t)ireq.i_len);
1144 printb(name, caps, IEEE80211_C_BITS);
1145 if (caps_ext != 0)
1146 printb(", ext", caps_ext, IEEE80211_CEXT_BITS);
1147 putchar('\n');
1150 static void
1151 list_wme(int s)
1153 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1154 struct ieee80211req ireq;
1155 int ac;
1157 (void) memset(&ireq, 0, sizeof(ireq));
1158 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1159 ireq.i_len = 0;
1160 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1161 again:
1162 if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
1163 printf("\t%s", " ");
1164 else
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) {
1184 if (ireq.i_val)
1185 printf(" acm");
1186 else if (verbose)
1187 printf(" -acm");
1189 /* !BSS only */
1190 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1191 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1192 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1193 if (!ireq.i_val)
1194 printf(" -ack");
1195 else if (verbose)
1196 printf(" ack");
1199 printf("\n");
1200 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1201 ireq.i_len |= IEEE80211_WMEPARAM_BSS;
1202 goto again;
1203 } else
1204 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
1208 static void
1209 list_mac(int s)
1211 struct ieee80211req ireq;
1212 struct ieee80211req_maclist *acllist;
1213 int i, nacls, policy;
1214 char c;
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");
1223 return;
1225 err(1, "unable to get mac policy");
1227 policy = ireq.i_val;
1229 ireq.i_val = IEEE80211_MACCMD_LIST;
1230 ireq.i_len = 0;
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 */
1234 return;
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) {
1243 if (verbose)
1244 printf("policy: open\n");
1245 c = '*';
1246 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1247 if (verbose)
1248 printf("policy: allow\n");
1249 c = '+';
1250 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1251 if (verbose)
1252 printf("policy: deny\n");
1253 c = '-';
1254 } else {
1255 printf("policy: unknown (%u)\n", policy);
1256 c = '?';
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));
1265 static
1266 DECL_CMD_FUNC(set80211list, arg, d)
1268 #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
1270 if (iseq(arg, "sta"))
1271 list_stations(s);
1272 else if (iseq(arg, "scan") || iseq(arg, "ap"))
1273 list_scan(s);
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"))
1279 list_keys(s);
1280 else if (iseq(arg, "caps"))
1281 list_capabilities(s);
1282 else if (iseq(arg, "wme"))
1283 list_wme(s);
1284 else if (iseq(arg, "mac"))
1285 list_mac(s);
1286 else
1287 errx(1, "Don't know how to list %s for %s", arg, name);
1288 #undef iseq
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;
1317 int i, freq;
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)
1330 return c;
1332 return &undef;
1335 #if 0
1336 static void
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)
1343 printf("WEP-%s",
1344 ireq->i_len <= 5 ? "40" :
1345 ireq->i_len <= 13 ? "104" : "128");
1346 else
1347 printf("WEP");
1348 break;
1349 case IEEE80211_CIPHER_TKIP:
1350 printf("TKIP");
1351 break;
1352 case IEEE80211_CIPHER_AES_OCB:
1353 printf("AES-OCB");
1354 break;
1355 case IEEE80211_CIPHER_AES_CCM:
1356 printf("AES-CCM");
1357 break;
1358 case IEEE80211_CIPHER_CKIP:
1359 printf("CKIP");
1360 break;
1361 case IEEE80211_CIPHER_NONE:
1362 printf("NONE");
1363 break;
1364 default:
1365 printf("UNKNOWN (0x%x)", ireq->i_val);
1366 break;
1369 #endif
1371 #define MAXCOL 78
1372 static int col;
1373 static char spacer;
1375 static void
1376 LINE_BREAK(void)
1378 if (spacer != '\t') {
1379 printf("\n");
1380 spacer = '\t';
1382 col = 8; /* 8-col tab */
1385 static void
1386 LINE_CHECK(const char *fmt, ...)
1388 char buf[80];
1389 va_list ap;
1390 int n;
1392 va_start(ap, fmt);
1393 n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1394 va_end(ap);
1395 col += 1+n;
1396 if (col > MAXCOL) {
1397 LINE_BREAK();
1398 col += n;
1400 buf[0] = spacer;
1401 printf("%s", buf);
1402 spacer = ' ';
1405 static void
1406 printkey(const struct ieee80211req_key *ik)
1408 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1409 int keylen = ik->ik_keylen;
1410 int printcontents;
1412 printcontents = printkeys &&
1413 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
1414 if (printcontents)
1415 LINE_BREAK();
1416 switch (ik->ik_type) {
1417 case IEEE80211_CIPHER_WEP:
1418 /* compatibility */
1419 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
1420 keylen <= 5 ? "40-bit" :
1421 keylen <= 13 ? "104-bit" : "128-bit");
1422 break;
1423 case IEEE80211_CIPHER_TKIP:
1424 if (keylen > 128/8)
1425 keylen -= 128/8; /* ignore MIC for now */
1426 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1427 break;
1428 case IEEE80211_CIPHER_AES_OCB:
1429 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1430 break;
1431 case IEEE80211_CIPHER_AES_CCM:
1432 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1433 break;
1434 case IEEE80211_CIPHER_CKIP:
1435 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1436 break;
1437 case IEEE80211_CIPHER_NONE:
1438 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1439 break;
1440 default:
1441 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
1442 ik->ik_type, ik->ik_keyix+1, 8*keylen);
1443 break;
1445 if (printcontents) {
1446 int i;
1448 printf(" <");
1449 for (i = 0; i < keylen; i++)
1450 printf("%02x", ik->ik_keydata[i]);
1451 printf(">");
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 = "+";
1468 LINE_BREAK();
1472 static void
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;
1479 u_int8_t data[32];
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;
1489 ireq.i_val = -1;
1490 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1491 /* If we can't get the SSID, this isn't an 802.11 device. */
1492 return;
1495 ireq.i_type = IEEE80211_IOC_RATECTL;
1496 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1497 int lineb = 1;
1499 switch (ireq.i_val) {
1500 case IEEE80211_RATECTL_ONOE:
1501 printf("\tratectl: onoe");
1502 break;
1503 case IEEE80211_RATECTL_AMRR:
1504 printf("\tratectl: amrr");
1505 break;
1506 case IEEE80211_RATECTL_SAMPLE:
1507 printf("\tratectl: sample");
1508 break;
1509 default:
1510 if (verbose)
1511 printf("\tratectl: none");
1512 else
1513 lineb = 0;
1514 break;
1516 if (lineb)
1517 LINE_BREAK();
1520 num = 0;
1521 ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1522 if (ioctl(s, SIOCG80211, &ireq) >= 0)
1523 num = ireq.i_val;
1524 printf("\tssid ");
1525 if (num > 1) {
1526 ireq.i_type = IEEE80211_IOC_SSID;
1527 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1528 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1529 printf(" %d:", ireq.i_val + 1);
1530 print_string(data, ireq.i_len);
1533 } else
1534 print_string(data, ireq.i_len);
1536 ireq.i_type = IEEE80211_IOC_CHANNEL;
1537 if (ioctl(s, SIOCG80211, &ireq) < 0)
1538 goto end;
1539 c = getchaninfo(s, ireq.i_val);
1540 if (ireq.i_val != -1) {
1541 printf(" channel %d", ireq.i_val);
1542 if (verbose)
1543 printf(" (%u)", c->ic_freq);
1544 } else if (verbose)
1545 printf(" channel UNDEF");
1547 ireq.i_type = IEEE80211_IOC_BSSID;
1548 ireq.i_len = IEEE80211_ADDR_LEN;
1549 if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1550 (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1551 printf(" bssid %s", ether_ntoa(ireq.i_data));
1553 ireq.i_type = IEEE80211_IOC_STATIONNAME;
1554 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1555 printf("\n\tstationname ");
1556 print_string(data, ireq.i_len);
1559 spacer = ' '; /* force first break */
1560 LINE_BREAK();
1562 ireq.i_type = IEEE80211_IOC_AUTHMODE;
1563 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1564 switch (ireq.i_val) {
1565 case IEEE80211_AUTH_NONE:
1566 LINE_CHECK("authmode NONE");
1567 break;
1568 case IEEE80211_AUTH_OPEN:
1569 LINE_CHECK("authmode OPEN");
1570 break;
1571 case IEEE80211_AUTH_SHARED:
1572 LINE_CHECK("authmode SHARED");
1573 break;
1574 case IEEE80211_AUTH_8021X:
1575 LINE_CHECK("authmode 802.1x");
1576 break;
1577 case IEEE80211_AUTH_WPA:
1578 ireq.i_type = IEEE80211_IOC_WPA;
1579 if (ioctl(s, SIOCG80211, &ireq) != -1)
1580 wpa = ireq.i_val;
1581 if (!wpa)
1582 wpa = 1; /* default to WPA1 */
1583 switch (wpa) {
1584 case 2:
1585 LINE_CHECK("authmode WPA2/802.11i");
1586 break;
1587 case 3:
1588 LINE_CHECK("authmode WPA1+WPA2/802.11i");
1589 break;
1590 default:
1591 LINE_CHECK("authmode WPA");
1592 break;
1594 break;
1595 case IEEE80211_AUTH_AUTO:
1596 LINE_CHECK("authmode AUTO");
1597 break;
1598 default:
1599 LINE_CHECK("authmode UNKNOWN (0x%x)",
1600 ireq.i_val);
1601 break;
1605 ireq.i_type = IEEE80211_IOC_WEP;
1606 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1607 ireq.i_val != IEEE80211_WEP_NOSUP) {
1608 int firstkey, wepmode;
1610 wepmode = ireq.i_val;
1611 switch (wepmode) {
1612 case IEEE80211_WEP_OFF:
1613 LINE_CHECK("privacy OFF");
1614 break;
1615 case IEEE80211_WEP_ON:
1616 LINE_CHECK("privacy ON");
1617 break;
1618 case IEEE80211_WEP_MIXED:
1619 LINE_CHECK("privacy MIXED");
1620 break;
1621 default:
1622 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1623 break;
1627 * If we get here then we've got WEP support so we need
1628 * to print WEP status.
1631 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1632 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1633 warn("WEP support, but no tx key!");
1634 goto end;
1636 if (ireq.i_val != -1)
1637 LINE_CHECK("deftxkey %d", ireq.i_val+1);
1638 else if (wepmode != IEEE80211_WEP_OFF || verbose)
1639 LINE_CHECK("deftxkey UNDEF");
1641 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1642 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1643 warn("WEP support, but no NUMWEPKEYS support!");
1644 goto end;
1646 num = ireq.i_val;
1648 firstkey = 1;
1649 for (i = 0; i < num; i++) {
1650 struct ieee80211req_key ik;
1652 memset(&ik, 0, sizeof(ik));
1653 ik.ik_keyix = i;
1654 ireq.i_type = IEEE80211_IOC_WPAKEY;
1655 ireq.i_data = &ik;
1656 ireq.i_len = sizeof(ik);
1657 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1658 warn("WEP support, but can get keys!");
1659 goto end;
1661 if (ik.ik_keylen != 0) {
1662 if (verbose)
1663 LINE_BREAK();
1664 printkey(&ik);
1665 firstkey = 0;
1670 ireq.i_type = IEEE80211_IOC_POWERSAVE;
1671 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1672 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1673 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1674 switch (ireq.i_val) {
1675 case IEEE80211_POWERSAVE_OFF:
1676 LINE_CHECK("powersavemode OFF");
1677 break;
1678 case IEEE80211_POWERSAVE_CAM:
1679 LINE_CHECK("powersavemode CAM");
1680 break;
1681 case IEEE80211_POWERSAVE_PSP:
1682 LINE_CHECK("powersavemode PSP");
1683 break;
1684 case IEEE80211_POWERSAVE_PSP_CAM:
1685 LINE_CHECK("powersavemode PSP-CAM");
1686 break;
1688 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1689 if (ioctl(s, SIOCG80211, &ireq) != -1)
1690 LINE_CHECK("powersavesleep %d", ireq.i_val);
1694 ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1695 if (ioctl(s, SIOCG80211, &ireq) != -1)
1696 LINE_CHECK("txpowmax %d", ireq.i_val);
1698 if (verbose) {
1699 ireq.i_type = IEEE80211_IOC_TXPOWER;
1700 if (ioctl(s, SIOCG80211, &ireq) != -1)
1701 LINE_CHECK("txpower %d", ireq.i_val);
1704 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1705 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1706 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1707 LINE_CHECK("rtsthreshold %d", ireq.i_val);
1710 ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1711 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1712 if (ireq.i_val != 2*1 || verbose) {
1713 if (ireq.i_val == 11)
1714 LINE_CHECK("mcastrate 5.5");
1715 else
1716 LINE_CHECK("mcastrate %d", ireq.i_val/2);
1720 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1721 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1722 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1723 LINE_CHECK("fragthreshold %d", ireq.i_val);
1726 ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
1727 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1728 if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
1729 LINE_CHECK("bmiss %d", ireq.i_val);
1732 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1733 ireq.i_type = IEEE80211_IOC_PUREG;
1734 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1735 if (ireq.i_val)
1736 LINE_CHECK("pureg");
1737 else if (verbose)
1738 LINE_CHECK("-pureg");
1740 ireq.i_type = IEEE80211_IOC_PROTMODE;
1741 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1742 switch (ireq.i_val) {
1743 case IEEE80211_PROTMODE_OFF:
1744 LINE_CHECK("protmode OFF");
1745 break;
1746 case IEEE80211_PROTMODE_CTS:
1747 LINE_CHECK("protmode CTS");
1748 break;
1749 case IEEE80211_PROTMODE_RTSCTS:
1750 LINE_CHECK("protmode RTSCTS");
1751 break;
1752 default:
1753 LINE_CHECK("protmode UNKNOWN (0x%x)",
1754 ireq.i_val);
1755 break;
1760 ireq.i_type = IEEE80211_IOC_WME;
1761 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1762 wme = ireq.i_val;
1763 if (wme)
1764 LINE_CHECK("wme");
1765 else if (verbose)
1766 LINE_CHECK("-wme");
1767 } else
1768 wme = 0;
1770 ireq.i_type = IEEE80211_IOC_BURST;
1771 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1772 if (ireq.i_val)
1773 LINE_CHECK("burst");
1774 else if (verbose)
1775 LINE_CHECK("-burst");
1778 if (opmode == IEEE80211_M_HOSTAP) {
1779 ireq.i_type = IEEE80211_IOC_HIDESSID;
1780 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1781 if (ireq.i_val)
1782 LINE_CHECK("ssid HIDE");
1783 else if (verbose)
1784 LINE_CHECK("ssid SHOW");
1787 ireq.i_type = IEEE80211_IOC_APBRIDGE;
1788 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1789 if (!ireq.i_val)
1790 LINE_CHECK("-apbridge");
1791 else if (verbose)
1792 LINE_CHECK("apbridge");
1795 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1796 if (ioctl(s, SIOCG80211, &ireq) != -1)
1797 LINE_CHECK("dtimperiod %u", ireq.i_val);
1798 } else {
1799 ireq.i_type = IEEE80211_IOC_ROAMING;
1800 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1801 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1802 switch (ireq.i_val) {
1803 case IEEE80211_ROAMING_DEVICE:
1804 LINE_CHECK("roaming DEVICE");
1805 break;
1806 case IEEE80211_ROAMING_AUTO:
1807 LINE_CHECK("roaming AUTO");
1808 break;
1809 case IEEE80211_ROAMING_MANUAL:
1810 LINE_CHECK("roaming MANUAL");
1811 break;
1812 default:
1813 LINE_CHECK("roaming UNKNOWN (0x%x)",
1814 ireq.i_val);
1815 break;
1820 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1821 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1822 if (ireq.i_val)
1823 LINE_CHECK("bintval %u", ireq.i_val);
1824 else if (verbose)
1825 LINE_CHECK("bintval %u", ireq.i_val);
1828 if (wme && verbose) {
1829 LINE_BREAK();
1830 list_wme(s);
1833 if (wpa) {
1834 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1835 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1836 if (ireq.i_val)
1837 LINE_CHECK("countermeasures");
1838 else if (verbose)
1839 LINE_CHECK("-countermeasures");
1841 #if 0
1842 /* XXX not interesting with WPA done in user space */
1843 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1844 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1847 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1848 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1849 LINE_CHECK("mcastcipher ");
1850 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1851 spacer = ' ';
1854 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1855 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1856 LINE_CHECK("ucastcipher ");
1857 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1860 if (wpa & 2) {
1861 ireq.i_type = IEEE80211_IOC_RSNCAPS;
1862 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1863 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1864 spacer = ' ';
1868 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1869 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1871 #endif
1872 LINE_BREAK();
1874 LINE_BREAK();
1876 end:
1877 return;
1880 static void
1881 set80211(int s, int type, int val, int len, u_int8_t *data)
1883 struct ieee80211req ireq;
1885 (void) memset(&ireq, 0, sizeof(ireq));
1886 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1887 ireq.i_type = type;
1888 ireq.i_val = val;
1889 ireq.i_len = len;
1890 ireq.i_data = data;
1891 if (ioctl(s, SIOCS80211, &ireq) < 0)
1892 err(1, "SIOCS80211");
1895 static const char *
1896 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1898 int len;
1899 int hexstr;
1900 u_int8_t *p;
1902 len = *lenp;
1903 p = buf;
1904 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1905 if (hexstr)
1906 val += 2;
1907 for (;;) {
1908 if (*val == '\0')
1909 break;
1910 if (sep != NULL && strchr(sep, *val) != NULL) {
1911 val++;
1912 break;
1914 if (hexstr) {
1915 if (!isxdigit((u_char)val[0])) {
1916 warnx("bad hexadecimal digits");
1917 return NULL;
1919 if (!isxdigit((u_char)val[1])) {
1920 warnx("odd count hexadecimal digits");
1921 return NULL;
1924 if (p >= buf + len) {
1925 if (hexstr)
1926 warnx("hexadecimal digits too long");
1927 else
1928 warnx("string too long");
1929 return NULL;
1931 if (hexstr) {
1932 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1933 *p++ = (tohex((u_char)val[0]) << 4) |
1934 tohex((u_char)val[1]);
1935 #undef tohex
1936 val += 2;
1937 } else
1938 *p++ = *val++;
1940 len = p - buf;
1941 if (len < *lenp)
1942 memset(p, 0, *lenp - len);
1943 /* The string "-" is treated as the empty string. */
1944 if (!hexstr && len == 1 && buf[0] == '-')
1945 len = 0;
1946 *lenp = len;
1947 return val;
1950 static void
1951 print_string(const u_int8_t *buf, int len)
1953 int i;
1954 int hasspc;
1956 i = 0;
1957 hasspc = 0;
1958 for (; i < len; i++) {
1959 if (!isprint(buf[i]) && buf[i] != '\0')
1960 break;
1961 if (isspace(buf[i]))
1962 hasspc++;
1964 if (i == len) {
1965 if (hasspc || len == 0 || buf[0] == '\0')
1966 printf("\"%.*s\"", len, buf);
1967 else
1968 printf("%.*s", len, buf);
1969 } else {
1970 printf("0x");
1971 for (i = 0; i < len; i++)
1972 printf("%02x", buf[i]);
1976 static struct cmd ieee80211_cmds[] = {
1977 DEF_CMD_ARG("ssid", set80211ssid),
1978 DEF_CMD_ARG("nwid", set80211ssid),
1979 DEF_CMD_ARG("stationname", set80211stationname),
1980 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
1981 DEF_CMD_ARG("channel", set80211channel),
1982 DEF_CMD_ARG("authmode", set80211authmode),
1983 DEF_CMD_ARG("powersavemode", set80211powersavemode),
1984 DEF_CMD("powersave", 1, set80211powersave),
1985 DEF_CMD("-powersave", 0, set80211powersave),
1986 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
1987 DEF_CMD_ARG("wepmode", set80211wepmode),
1988 DEF_CMD("wep", 1, set80211wep),
1989 DEF_CMD("-wep", 0, set80211wep),
1990 DEF_CMD_ARG("deftxkey", set80211weptxkey),
1991 DEF_CMD_ARG("weptxkey", set80211weptxkey),
1992 DEF_CMD_ARG("wepkey", set80211wepkey),
1993 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
1994 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
1995 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
1996 DEF_CMD_ARG("protmode", set80211protmode),
1997 DEF_CMD_ARG("txpower", set80211txpower),
1998 DEF_CMD_ARG("roaming", set80211roaming),
1999 DEF_CMD("wme", 1, set80211wme),
2000 DEF_CMD("-wme", 0, set80211wme),
2001 DEF_CMD("hidessid", 1, set80211hidessid),
2002 DEF_CMD("-hidessid", 0, set80211hidessid),
2003 DEF_CMD("apbridge", 1, set80211apbridge),
2004 DEF_CMD("-apbridge", 0, set80211apbridge),
2005 DEF_CMD_ARG("chanlist", set80211chanlist),
2006 DEF_CMD_ARG("bssid", set80211bssid),
2007 DEF_CMD_ARG("ap", set80211bssid),
2008 DEF_CMD("scan", 0, set80211scan),
2009 DEF_CMD_ARG("list", set80211list),
2010 DEF_CMD_ARG2("cwmin", set80211cwmin),
2011 DEF_CMD_ARG2("cwmax", set80211cwmax),
2012 DEF_CMD_ARG2("aifs", set80211aifs),
2013 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
2014 DEF_CMD_ARG("acm", set80211acm),
2015 DEF_CMD_ARG("-acm", set80211noacm),
2016 DEF_CMD_ARG("ack", set80211ackpolicy),
2017 DEF_CMD_ARG("-ack", set80211noackpolicy),
2018 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
2019 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
2020 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
2021 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
2022 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
2023 DEF_CMD_ARG("bintval", set80211bintval),
2024 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
2025 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
2026 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
2027 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
2028 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
2029 DEF_CMD_ARG("mac:add", set80211addmac),
2030 DEF_CMD_ARG("mac:del", set80211delmac),
2031 DEF_CMD_ARG("mac:kick", set80211kickmac),
2032 DEF_CMD("pureg", 1, set80211pureg),
2033 DEF_CMD("-pureg", 0, set80211pureg),
2034 DEF_CMD_ARG("mcastrate", set80211mcastrate),
2035 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
2036 DEF_CMD("burst", 1, set80211burst),
2037 DEF_CMD("-burst", 0, set80211burst),
2038 DEF_CMD_ARG("ratectl", set80211ratectl),
2039 DEF_CMD_ARG("bmiss", set80211bmissthreshold),
2040 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold)
2042 static struct afswtch af_ieee80211 = {
2043 .af_name = "af_ieee80211",
2044 .af_af = AF_UNSPEC,
2045 .af_other_status = ieee80211_status,
2048 static __constructor void
2049 ieee80211_ctor(void)
2051 #define N(a) (sizeof(a) / sizeof(a[0]))
2052 int i;
2054 for (i = 0; i < N(ieee80211_cmds); i++)
2055 cmd_register(&ieee80211_cmds[i]);
2056 af_register(&af_ieee80211);
2057 #undef N