Fix taskqueues to truely work on SMP systems.
[dragonfly.git] / sbin / ifconfig / ifieee80211.c
blob34f708fc850a2af438e9ce381e316cabda98a881
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.17 2006/12/08 14:25:07 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
684 errx(1, "unknown ratectl");
686 set80211(s, IEEE80211_IOC_RATECTL, ratectl, 0, NULL);
689 static
690 DECL_CMD_FUNC(set80211mcastrate, val, d)
692 set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
695 static
696 DECL_CMD_FUNC(set80211fragthreshold, val, d)
698 set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
699 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
702 static
703 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
705 set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
706 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
709 static int
710 getmaxrate(uint8_t rates[15], uint8_t nrates)
712 int i, maxrate = -1;
714 for (i = 0; i < nrates; i++) {
715 int rate = rates[i] & IEEE80211_RATE_VAL;
716 if (rate > maxrate)
717 maxrate = rate;
719 return maxrate / 2;
722 static const char *
723 getcaps(int capinfo)
725 static char capstring[32];
726 char *cp = capstring;
728 if (capinfo & IEEE80211_CAPINFO_ESS)
729 *cp++ = 'E';
730 if (capinfo & IEEE80211_CAPINFO_IBSS)
731 *cp++ = 'I';
732 if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
733 *cp++ = 'c';
734 if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
735 *cp++ = 'C';
736 if (capinfo & IEEE80211_CAPINFO_PRIVACY)
737 *cp++ = 'P';
738 if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
739 *cp++ = 'S';
740 if (capinfo & IEEE80211_CAPINFO_PBCC)
741 *cp++ = 'B';
742 if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
743 *cp++ = 'A';
744 if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
745 *cp++ = 's';
746 if (capinfo & IEEE80211_CAPINFO_RSN)
747 *cp++ = 'R';
748 if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
749 *cp++ = 'D';
750 *cp = '\0';
751 return capstring;
754 static void
755 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
757 printf("%s", tag);
758 if (verbose) {
759 maxlen -= strlen(tag)+2;
760 if (2*ielen > maxlen)
761 maxlen--;
762 printf("<");
763 for (; ielen > 0; ie++, ielen--) {
764 if (maxlen-- <= 0)
765 break;
766 printf("%02x", *ie);
768 if (ielen != 0)
769 printf("-");
770 printf(">");
775 * Copy the ssid string contents into buf, truncating to fit. If the
776 * ssid is entirely printable then just copy intact. Otherwise convert
777 * to hexadecimal. If the result is truncated then replace the last
778 * three characters with "...".
780 static int
781 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
783 const u_int8_t *p;
784 size_t maxlen;
785 int i;
787 if (essid_len > bufsize)
788 maxlen = bufsize;
789 else
790 maxlen = essid_len;
791 /* determine printable or not */
792 for (i = 0, p = essid; i < maxlen; i++, p++) {
793 if (*p < ' ' || *p > 0x7e)
794 break;
796 if (i != maxlen) { /* not printable, print as hex */
797 if (bufsize < 3)
798 return 0;
799 strlcpy(buf, "0x", bufsize);
800 bufsize -= 2;
801 p = essid;
802 for (i = 0; i < maxlen && bufsize >= 2; i++) {
803 sprintf(&buf[2+2*i], "%02x", p[i]);
804 bufsize -= 2;
806 if (i != essid_len)
807 memcpy(&buf[2+2*i-3], "...", 3);
808 } else { /* printable, truncate as needed */
809 memcpy(buf, essid, maxlen);
810 if (maxlen != essid_len)
811 memcpy(&buf[maxlen-3], "...", 3);
813 return maxlen;
816 /* unaligned little endian access */
817 #define LE_READ_4(p) \
818 ((u_int32_t) \
819 ((((const u_int8_t *)(p))[0] ) | \
820 (((const u_int8_t *)(p))[1] << 8) | \
821 (((const u_int8_t *)(p))[2] << 16) | \
822 (((const u_int8_t *)(p))[3] << 24)))
824 static int __inline
825 iswpaoui(const u_int8_t *frm)
827 return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
830 static int __inline
831 iswmeoui(const u_int8_t *frm)
833 return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
836 static int __inline
837 isatherosoui(const u_int8_t *frm)
839 return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
842 static void
843 printies(const u_int8_t *vp, int ielen, int maxcols)
845 while (ielen > 0) {
846 switch (vp[0]) {
847 case IEEE80211_ELEMID_VENDOR:
848 if (iswpaoui(vp))
849 printie(" WPA", vp, 2+vp[1], maxcols);
850 else if (iswmeoui(vp))
851 printie(" WME", vp, 2+vp[1], maxcols);
852 else if (isatherosoui(vp))
853 printie(" ATH", vp, 2+vp[1], maxcols);
854 else
855 printie(" VEN", vp, 2+vp[1], maxcols);
856 break;
857 case IEEE80211_ELEMID_RSN:
858 printie(" RSN", vp, 2+vp[1], maxcols);
859 break;
860 default:
861 printie(" ???", vp, 2+vp[1], maxcols);
862 break;
864 ielen -= 2+vp[1];
865 vp += 2+vp[1];
869 static void
870 list_scan(int s)
872 uint8_t buf[24*1024];
873 struct ieee80211req ireq;
874 char ssid[IEEE80211_NWID_LEN+1];
875 uint8_t *cp;
876 int len, ssidmax;
878 (void) memset(&ireq, 0, sizeof(ireq));
879 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
880 ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
881 ireq.i_data = buf;
882 ireq.i_len = sizeof(buf);
883 if (ioctl(s, SIOCG80211, &ireq) < 0)
884 errx(1, "unable to get scan results");
885 len = ireq.i_len;
886 if (len < sizeof(struct ieee80211req_scan_result))
887 return;
889 ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
890 printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
891 , ssidmax, ssidmax, "SSID"
892 , "BSSID"
893 , "CHAN"
894 , "RATE"
895 , "S:N"
896 , "INT"
897 , "CAPS"
899 cp = buf;
900 do {
901 struct ieee80211req_scan_result *sr;
902 uint8_t *vp;
904 sr = (struct ieee80211req_scan_result *) cp;
905 vp = (u_int8_t *)(sr+1);
906 printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
907 , ssidmax
908 , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
909 , ssid
910 , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
911 , ieee80211_mhz2ieee(sr->isr_freq)
912 , getmaxrate(sr->isr_rates, sr->isr_nrates)
913 , sr->isr_rssi, sr->isr_noise
914 , sr->isr_intval
915 , getcaps(sr->isr_capinfo)
917 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
918 printf("\n");
919 cp += sr->isr_len, len -= sr->isr_len;
920 } while (len >= sizeof(struct ieee80211req_scan_result));
923 #include <netproto/802_11/ieee80211_dragonfly.h>
925 static void
926 scan_and_wait(int s)
928 struct ieee80211req ireq;
929 int sroute;
931 sroute = socket(PF_ROUTE, SOCK_RAW, 0);
932 if (sroute < 0) {
933 perror("socket(PF_ROUTE,SOCK_RAW)");
934 return;
936 (void) memset(&ireq, 0, sizeof(ireq));
937 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
938 ireq.i_type = IEEE80211_IOC_SCAN_REQ;
939 /* NB: only root can trigger a scan so ignore errors */
940 if (ioctl(s, SIOCS80211, &ireq) >= 0) {
941 char buf[2048];
942 struct if_announcemsghdr *ifan;
943 struct rt_msghdr *rtm;
945 do {
946 if (read(sroute, buf, sizeof(buf)) < 0) {
947 perror("read(PF_ROUTE)");
948 break;
950 rtm = (struct rt_msghdr *) buf;
951 if (rtm->rtm_version != RTM_VERSION)
952 break;
953 ifan = (struct if_announcemsghdr *) rtm;
954 } while (rtm->rtm_type != RTM_IEEE80211 ||
955 ifan->ifan_what != RTM_IEEE80211_SCAN);
957 close(sroute);
960 static
961 DECL_CMD_FUNC(set80211scan, val, d)
963 scan_and_wait(s);
964 list_scan(s);
967 static enum ieee80211_opmode get80211opmode(int s);
969 static void
970 list_stations(int s)
972 union {
973 struct ieee80211req_sta_req req;
974 uint8_t buf[24*1024];
975 } u;
976 enum ieee80211_opmode opmode = get80211opmode(s);
977 struct ieee80211req ireq;
978 uint8_t *cp;
979 int len;
981 (void) memset(&ireq, 0, sizeof(ireq));
982 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
983 /* broadcast address =>'s get all stations */
984 (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
985 if (opmode == IEEE80211_M_STA) {
987 * Get information about the associated AP.
989 ireq.i_type = IEEE80211_IOC_BSSID;
990 ireq.i_data = u.req.is_u.macaddr;
991 ireq.i_len = IEEE80211_ADDR_LEN;
992 (void) ioctl(s, SIOCG80211, &ireq);
994 ireq.i_type = IEEE80211_IOC_STA_INFO;
995 ireq.i_data = &u;
996 ireq.i_len = sizeof(u);
997 if (ioctl(s, SIOCG80211, &ireq) < 0)
998 errx(1, "unable to get station information");
999 len = ireq.i_len;
1000 if (len < sizeof(struct ieee80211req_sta_info))
1001 return;
1003 printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
1004 , "ADDR"
1005 , "AID"
1006 , "CHAN"
1007 , "RATE"
1008 , "RSSI"
1009 , "IDLE"
1010 , "TXSEQ"
1011 , "RXSEQ"
1012 , "CAPS"
1013 , "ERP"
1015 cp = (uint8_t *) u.req.info;
1016 do {
1017 struct ieee80211req_sta_info *si;
1018 uint8_t *vp;
1020 si = (struct ieee80211req_sta_info *) cp;
1021 if (si->isi_len < sizeof(*si))
1022 break;
1023 vp = (u_int8_t *)(si+1);
1024 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
1025 , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1026 , IEEE80211_AID(si->isi_associd)
1027 , ieee80211_mhz2ieee(si->isi_freq)
1028 , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
1029 , si->isi_rssi
1030 , si->isi_inact
1031 , si->isi_txseqs[0]
1032 , si->isi_rxseqs[0]
1033 , getcaps(si->isi_capinfo)
1034 , si->isi_erp
1036 printies(vp, si->isi_ie_len, 24);
1037 printf("\n");
1038 cp += si->isi_len, len -= si->isi_len;
1039 } while (len >= sizeof(struct ieee80211req_sta_info));
1042 static void
1043 print_chaninfo(const struct ieee80211_channel *c)
1045 #define IEEE80211_IS_CHAN_PASSIVE(_c) \
1046 (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1047 char buf[14];
1049 buf[0] = '\0';
1050 if (IEEE80211_IS_CHAN_FHSS(c))
1051 strlcat(buf, " FHSS", sizeof(buf));
1052 if (IEEE80211_IS_CHAN_A(c))
1053 strlcat(buf, " 11a", sizeof(buf));
1054 /* XXX 11g schizophrenia */
1055 if (IEEE80211_IS_CHAN_G(c) ||
1056 IEEE80211_IS_CHAN_PUREG(c))
1057 strlcat(buf, " 11g", sizeof(buf));
1058 else if (IEEE80211_IS_CHAN_B(c))
1059 strlcat(buf, " 11b", sizeof(buf));
1060 if (IEEE80211_IS_CHAN_T(c))
1061 strlcat(buf, " Turbo", sizeof(buf));
1062 printf("Channel %3u : %u%c Mhz%-14.14s",
1063 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1064 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1065 #undef IEEE80211_IS_CHAN_PASSIVE
1068 static void
1069 list_channels(int s, int allchans)
1071 struct ieee80211req ireq;
1072 struct ieee80211req_chaninfo chans;
1073 struct ieee80211req_chaninfo achans;
1074 const struct ieee80211_channel *c;
1075 int i, half;
1077 (void) memset(&ireq, 0, sizeof(ireq));
1078 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1079 ireq.i_type = IEEE80211_IOC_CHANINFO;
1080 ireq.i_data = &chans;
1081 ireq.i_len = sizeof(chans);
1082 if (ioctl(s, SIOCG80211, &ireq) < 0)
1083 errx(1, "unable to get channel information");
1084 if (!allchans) {
1085 struct ieee80211req_chanlist active;
1087 ireq.i_type = IEEE80211_IOC_CHANLIST;
1088 ireq.i_data = &active;
1089 ireq.i_len = sizeof(active);
1090 if (ioctl(s, SIOCG80211, &ireq) < 0)
1091 errx(1, "unable to get active channel list");
1092 memset(&achans, 0, sizeof(achans));
1093 for (i = 0; i < chans.ic_nchans; i++) {
1094 c = &chans.ic_chans[i];
1095 if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1096 achans.ic_chans[achans.ic_nchans++] = *c;
1098 } else
1099 achans = chans;
1100 half = achans.ic_nchans / 2;
1101 if (achans.ic_nchans % 2)
1102 half++;
1103 for (i = 0; i < achans.ic_nchans / 2; i++) {
1104 print_chaninfo(&achans.ic_chans[i]);
1105 print_chaninfo(&achans.ic_chans[half+i]);
1106 printf("\n");
1108 if (achans.ic_nchans % 2) {
1109 print_chaninfo(&achans.ic_chans[i]);
1110 printf("\n");
1114 static void
1115 list_keys(int s)
1119 #define IEEE80211_C_BITS \
1120 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1121 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1122 "\31WPA2\32BURST\33WME"
1124 #define IEEE80211_CEXT_BITS "\020\1PBCC"
1126 static void
1127 list_capabilities(int s)
1129 struct ieee80211req ireq;
1130 uint32_t caps, caps_ext;
1132 memset(&ireq, 0, sizeof(ireq));
1133 caps_ext = 0;
1135 strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1136 ireq.i_data = &caps_ext;
1137 ireq.i_len = sizeof(caps_ext);
1138 ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1139 if (ioctl(s, SIOCG80211, &ireq) < 0)
1140 errx(1, "unable to get driver capabilities");
1141 caps = (((uint16_t)ireq.i_val) << 16) | ((uint16_t)ireq.i_len);
1142 printb(name, caps, IEEE80211_C_BITS);
1143 if (caps_ext != 0)
1144 printb(", ext", caps_ext, IEEE80211_CEXT_BITS);
1145 putchar('\n');
1148 static void
1149 list_wme(int s)
1151 static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1152 struct ieee80211req ireq;
1153 int ac;
1155 (void) memset(&ireq, 0, sizeof(ireq));
1156 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1157 ireq.i_len = 0;
1158 for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
1159 again:
1160 if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
1161 printf("\t%s", " ");
1162 else
1163 printf("\t%s", acnames[ac]);
1165 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1167 /* show WME BSS parameters */
1168 ireq.i_type = IEEE80211_IOC_WME_CWMIN;
1169 if (ioctl(s, SIOCG80211, &ireq) != -1)
1170 printf(" cwmin %2u", ireq.i_val);
1171 ireq.i_type = IEEE80211_IOC_WME_CWMAX;
1172 if (ioctl(s, SIOCG80211, &ireq) != -1)
1173 printf(" cwmax %2u", ireq.i_val);
1174 ireq.i_type = IEEE80211_IOC_WME_AIFS;
1175 if (ioctl(s, SIOCG80211, &ireq) != -1)
1176 printf(" aifs %2u", ireq.i_val);
1177 ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
1178 if (ioctl(s, SIOCG80211, &ireq) != -1)
1179 printf(" txopLimit %3u", ireq.i_val);
1180 ireq.i_type = IEEE80211_IOC_WME_ACM;
1181 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1182 if (ireq.i_val)
1183 printf(" acm");
1184 else if (verbose)
1185 printf(" -acm");
1187 /* !BSS only */
1188 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1189 ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
1190 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1191 if (!ireq.i_val)
1192 printf(" -ack");
1193 else if (verbose)
1194 printf(" ack");
1197 printf("\n");
1198 if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
1199 ireq.i_len |= IEEE80211_WMEPARAM_BSS;
1200 goto again;
1201 } else
1202 ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
1206 static void
1207 list_mac(int s)
1209 struct ieee80211req ireq;
1210 struct ieee80211req_maclist *acllist;
1211 int i, nacls, policy;
1212 char c;
1214 (void) memset(&ireq, 0, sizeof(ireq));
1215 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* XXX ?? */
1216 ireq.i_type = IEEE80211_IOC_MACCMD;
1217 ireq.i_val = IEEE80211_MACCMD_POLICY;
1218 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1219 if (errno == EINVAL) {
1220 printf("No acl policy loaded\n");
1221 return;
1223 err(1, "unable to get mac policy");
1225 policy = ireq.i_val;
1227 ireq.i_val = IEEE80211_MACCMD_LIST;
1228 ireq.i_len = 0;
1229 if (ioctl(s, SIOCG80211, &ireq) < 0)
1230 err(1, "unable to get mac acl list size");
1231 if (ireq.i_len == 0) /* NB: no acls */
1232 return;
1234 ireq.i_data = malloc(ireq.i_len);
1235 if (ireq.i_data == NULL)
1236 err(1, "out of memory for acl list");
1238 if (ioctl(s, SIOCG80211, &ireq) < 0)
1239 err(1, "unable to get mac acl list");
1240 if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
1241 if (verbose)
1242 printf("policy: open\n");
1243 c = '*';
1244 } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
1245 if (verbose)
1246 printf("policy: allow\n");
1247 c = '+';
1248 } else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
1249 if (verbose)
1250 printf("policy: deny\n");
1251 c = '-';
1252 } else {
1253 printf("policy: unknown (%u)\n", policy);
1254 c = '?';
1256 nacls = ireq.i_len / sizeof(*acllist);
1257 acllist = (struct ieee80211req_maclist *) ireq.i_data;
1258 for (i = 0; i < nacls; i++)
1259 printf("%c%s\n", c, ether_ntoa(
1260 (const struct ether_addr *) acllist[i].ml_macaddr));
1263 static
1264 DECL_CMD_FUNC(set80211list, arg, d)
1266 #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
1268 if (iseq(arg, "sta"))
1269 list_stations(s);
1270 else if (iseq(arg, "scan") || iseq(arg, "ap"))
1271 list_scan(s);
1272 else if (iseq(arg, "chan") || iseq(arg, "freq"))
1273 list_channels(s, 1);
1274 else if (iseq(arg, "active"))
1275 list_channels(s, 0);
1276 else if (iseq(arg, "keys"))
1277 list_keys(s);
1278 else if (iseq(arg, "caps"))
1279 list_capabilities(s);
1280 else if (iseq(arg, "wme"))
1281 list_wme(s);
1282 else if (iseq(arg, "mac"))
1283 list_mac(s);
1284 else
1285 errx(1, "Don't know how to list %s for %s", arg, name);
1286 #undef iseq
1289 static enum ieee80211_opmode
1290 get80211opmode(int s)
1292 struct ifmediareq ifmr;
1294 (void) memset(&ifmr, 0, sizeof(ifmr));
1295 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1297 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
1298 if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
1299 return IEEE80211_M_IBSS; /* XXX ahdemo */
1300 if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
1301 return IEEE80211_M_HOSTAP;
1302 if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
1303 return IEEE80211_M_MONITOR;
1305 return IEEE80211_M_STA;
1308 static const struct ieee80211_channel *
1309 getchaninfo(int s, int chan)
1311 struct ieee80211req ireq;
1312 static struct ieee80211req_chaninfo chans;
1313 static struct ieee80211_channel undef;
1314 const struct ieee80211_channel *c;
1315 int i, freq;
1317 (void) memset(&ireq, 0, sizeof(ireq));
1318 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1319 ireq.i_type = IEEE80211_IOC_CHANINFO;
1320 ireq.i_data = &chans;
1321 ireq.i_len = sizeof(chans);
1322 if (ioctl(s, SIOCG80211, &ireq) < 0)
1323 errx(1, "unable to get channel information");
1324 freq = ieee80211_ieee2mhz(chan);
1325 for (i = 0; i < chans.ic_nchans; i++) {
1326 c = &chans.ic_chans[i];
1327 if (c->ic_freq == freq)
1328 return c;
1330 return &undef;
1333 #if 0
1334 static void
1335 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1337 switch (ireq->i_val) {
1338 case IEEE80211_CIPHER_WEP:
1339 ireq->i_type = keylenop;
1340 if (ioctl(s, SIOCG80211, ireq) != -1)
1341 printf("WEP-%s",
1342 ireq->i_len <= 5 ? "40" :
1343 ireq->i_len <= 13 ? "104" : "128");
1344 else
1345 printf("WEP");
1346 break;
1347 case IEEE80211_CIPHER_TKIP:
1348 printf("TKIP");
1349 break;
1350 case IEEE80211_CIPHER_AES_OCB:
1351 printf("AES-OCB");
1352 break;
1353 case IEEE80211_CIPHER_AES_CCM:
1354 printf("AES-CCM");
1355 break;
1356 case IEEE80211_CIPHER_CKIP:
1357 printf("CKIP");
1358 break;
1359 case IEEE80211_CIPHER_NONE:
1360 printf("NONE");
1361 break;
1362 default:
1363 printf("UNKNOWN (0x%x)", ireq->i_val);
1364 break;
1367 #endif
1369 #define MAXCOL 78
1370 static int col;
1371 static char spacer;
1373 static void
1374 LINE_BREAK(void)
1376 if (spacer != '\t') {
1377 printf("\n");
1378 spacer = '\t';
1380 col = 8; /* 8-col tab */
1383 static void
1384 LINE_CHECK(const char *fmt, ...)
1386 char buf[80];
1387 va_list ap;
1388 int n;
1390 va_start(ap, fmt);
1391 n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
1392 va_end(ap);
1393 col += 1+n;
1394 if (col > MAXCOL) {
1395 LINE_BREAK();
1396 col += n;
1398 buf[0] = spacer;
1399 printf("%s", buf);
1400 spacer = ' ';
1403 static void
1404 printkey(const struct ieee80211req_key *ik)
1406 static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1407 int keylen = ik->ik_keylen;
1408 int printcontents;
1410 printcontents = printkeys &&
1411 (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
1412 if (printcontents)
1413 LINE_BREAK();
1414 switch (ik->ik_type) {
1415 case IEEE80211_CIPHER_WEP:
1416 /* compatibility */
1417 LINE_CHECK("wepkey %u:%s", ik->ik_keyix+1,
1418 keylen <= 5 ? "40-bit" :
1419 keylen <= 13 ? "104-bit" : "128-bit");
1420 break;
1421 case IEEE80211_CIPHER_TKIP:
1422 if (keylen > 128/8)
1423 keylen -= 128/8; /* ignore MIC for now */
1424 LINE_CHECK("TKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1425 break;
1426 case IEEE80211_CIPHER_AES_OCB:
1427 LINE_CHECK("AES-OCB %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1428 break;
1429 case IEEE80211_CIPHER_AES_CCM:
1430 LINE_CHECK("AES-CCM %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1431 break;
1432 case IEEE80211_CIPHER_CKIP:
1433 LINE_CHECK("CKIP %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1434 break;
1435 case IEEE80211_CIPHER_NONE:
1436 LINE_CHECK("NULL %u:%u-bit", ik->ik_keyix+1, 8*keylen);
1437 break;
1438 default:
1439 LINE_CHECK("UNKNOWN (0x%x) %u:%u-bit",
1440 ik->ik_type, ik->ik_keyix+1, 8*keylen);
1441 break;
1443 if (printcontents) {
1444 int i;
1446 printf(" <");
1447 for (i = 0; i < keylen; i++)
1448 printf("%02x", ik->ik_keydata[i]);
1449 printf(">");
1450 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1451 (ik->ik_keyrsc != 0 || verbose))
1452 printf(" rsc %ju", (uintmax_t)ik->ik_keyrsc);
1453 if (ik->ik_type != IEEE80211_CIPHER_WEP &&
1454 (ik->ik_keytsc != 0 || verbose))
1455 printf(" tsc %ju", (uintmax_t)ik->ik_keytsc);
1456 if (ik->ik_flags != 0 && verbose) {
1457 const char *sep = " ";
1459 if (ik->ik_flags & IEEE80211_KEY_XMIT)
1460 printf("%stx", sep), sep = "+";
1461 if (ik->ik_flags & IEEE80211_KEY_RECV)
1462 printf("%srx", sep), sep = "+";
1463 if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
1464 printf("%sdef", sep), sep = "+";
1466 LINE_BREAK();
1470 static void
1471 ieee80211_status(int s)
1473 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
1474 enum ieee80211_opmode opmode = get80211opmode(s);
1475 int i, num, wpa, wme;
1476 struct ieee80211req ireq;
1477 u_int8_t data[32];
1478 const struct ieee80211_channel *c;
1480 (void) memset(&ireq, 0, sizeof(ireq));
1481 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1482 ireq.i_data = &data;
1484 wpa = 0; /* unknown/not set */
1486 ireq.i_type = IEEE80211_IOC_SSID;
1487 ireq.i_val = -1;
1488 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1489 /* If we can't get the SSID, this isn't an 802.11 device. */
1490 return;
1493 ireq.i_type = IEEE80211_IOC_RATECTL;
1494 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1495 int lineb = 1;
1497 switch (ireq.i_val) {
1498 case IEEE80211_RATECTL_ONOE:
1499 printf("\tratectl: onoe");
1500 break;
1501 case IEEE80211_RATECTL_AMRR:
1502 printf("\tratectl: amrr");
1503 break;
1504 default:
1505 if (verbose)
1506 printf("\tratectl: none");
1507 else
1508 lineb = 0;
1509 break;
1511 if (lineb)
1512 LINE_BREAK();
1515 num = 0;
1516 ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1517 if (ioctl(s, SIOCG80211, &ireq) >= 0)
1518 num = ireq.i_val;
1519 printf("\tssid ");
1520 if (num > 1) {
1521 ireq.i_type = IEEE80211_IOC_SSID;
1522 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1523 if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1524 printf(" %d:", ireq.i_val + 1);
1525 print_string(data, ireq.i_len);
1528 } else
1529 print_string(data, ireq.i_len);
1531 ireq.i_type = IEEE80211_IOC_CHANNEL;
1532 if (ioctl(s, SIOCG80211, &ireq) < 0)
1533 goto end;
1534 c = getchaninfo(s, ireq.i_val);
1535 if (ireq.i_val != -1) {
1536 printf(" channel %d", ireq.i_val);
1537 if (verbose)
1538 printf(" (%u)", c->ic_freq);
1539 } else if (verbose)
1540 printf(" channel UNDEF");
1542 ireq.i_type = IEEE80211_IOC_BSSID;
1543 ireq.i_len = IEEE80211_ADDR_LEN;
1544 if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1545 (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1546 printf(" bssid %s", ether_ntoa(ireq.i_data));
1548 ireq.i_type = IEEE80211_IOC_STATIONNAME;
1549 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1550 printf("\n\tstationname ");
1551 print_string(data, ireq.i_len);
1554 spacer = ' '; /* force first break */
1555 LINE_BREAK();
1557 ireq.i_type = IEEE80211_IOC_AUTHMODE;
1558 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1559 switch (ireq.i_val) {
1560 case IEEE80211_AUTH_NONE:
1561 LINE_CHECK("authmode NONE");
1562 break;
1563 case IEEE80211_AUTH_OPEN:
1564 LINE_CHECK("authmode OPEN");
1565 break;
1566 case IEEE80211_AUTH_SHARED:
1567 LINE_CHECK("authmode SHARED");
1568 break;
1569 case IEEE80211_AUTH_8021X:
1570 LINE_CHECK("authmode 802.1x");
1571 break;
1572 case IEEE80211_AUTH_WPA:
1573 ireq.i_type = IEEE80211_IOC_WPA;
1574 if (ioctl(s, SIOCG80211, &ireq) != -1)
1575 wpa = ireq.i_val;
1576 if (!wpa)
1577 wpa = 1; /* default to WPA1 */
1578 switch (wpa) {
1579 case 2:
1580 LINE_CHECK("authmode WPA2/802.11i");
1581 break;
1582 case 3:
1583 LINE_CHECK("authmode WPA1+WPA2/802.11i");
1584 break;
1585 default:
1586 LINE_CHECK("authmode WPA");
1587 break;
1589 break;
1590 case IEEE80211_AUTH_AUTO:
1591 LINE_CHECK("authmode AUTO");
1592 break;
1593 default:
1594 LINE_CHECK("authmode UNKNOWN (0x%x)",
1595 ireq.i_val);
1596 break;
1600 ireq.i_type = IEEE80211_IOC_WEP;
1601 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1602 ireq.i_val != IEEE80211_WEP_NOSUP) {
1603 int firstkey, wepmode;
1605 wepmode = ireq.i_val;
1606 switch (wepmode) {
1607 case IEEE80211_WEP_OFF:
1608 LINE_CHECK("privacy OFF");
1609 break;
1610 case IEEE80211_WEP_ON:
1611 LINE_CHECK("privacy ON");
1612 break;
1613 case IEEE80211_WEP_MIXED:
1614 LINE_CHECK("privacy MIXED");
1615 break;
1616 default:
1617 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1618 break;
1622 * If we get here then we've got WEP support so we need
1623 * to print WEP status.
1626 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1627 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1628 warn("WEP support, but no tx key!");
1629 goto end;
1631 if (ireq.i_val != -1)
1632 LINE_CHECK("deftxkey %d", ireq.i_val+1);
1633 else if (wepmode != IEEE80211_WEP_OFF || verbose)
1634 LINE_CHECK("deftxkey UNDEF");
1636 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1637 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1638 warn("WEP support, but no NUMWEPKEYS support!");
1639 goto end;
1641 num = ireq.i_val;
1643 firstkey = 1;
1644 for (i = 0; i < num; i++) {
1645 struct ieee80211req_key ik;
1647 memset(&ik, 0, sizeof(ik));
1648 ik.ik_keyix = i;
1649 ireq.i_type = IEEE80211_IOC_WPAKEY;
1650 ireq.i_data = &ik;
1651 ireq.i_len = sizeof(ik);
1652 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1653 warn("WEP support, but can get keys!");
1654 goto end;
1656 if (ik.ik_keylen != 0) {
1657 if (verbose)
1658 LINE_BREAK();
1659 printkey(&ik);
1660 firstkey = 0;
1665 ireq.i_type = IEEE80211_IOC_POWERSAVE;
1666 if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1667 ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1668 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1669 switch (ireq.i_val) {
1670 case IEEE80211_POWERSAVE_OFF:
1671 LINE_CHECK("powersavemode OFF");
1672 break;
1673 case IEEE80211_POWERSAVE_CAM:
1674 LINE_CHECK("powersavemode CAM");
1675 break;
1676 case IEEE80211_POWERSAVE_PSP:
1677 LINE_CHECK("powersavemode PSP");
1678 break;
1679 case IEEE80211_POWERSAVE_PSP_CAM:
1680 LINE_CHECK("powersavemode PSP-CAM");
1681 break;
1683 ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1684 if (ioctl(s, SIOCG80211, &ireq) != -1)
1685 LINE_CHECK("powersavesleep %d", ireq.i_val);
1689 ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1690 if (ioctl(s, SIOCG80211, &ireq) != -1)
1691 LINE_CHECK("txpowmax %d", ireq.i_val);
1693 if (verbose) {
1694 ireq.i_type = IEEE80211_IOC_TXPOWER;
1695 if (ioctl(s, SIOCG80211, &ireq) != -1)
1696 LINE_CHECK("txpower %d", ireq.i_val);
1699 ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1700 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1701 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1702 LINE_CHECK("rtsthreshold %d", ireq.i_val);
1705 ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1706 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1707 if (ireq.i_val != 2*1 || verbose) {
1708 if (ireq.i_val == 11)
1709 LINE_CHECK("mcastrate 5.5");
1710 else
1711 LINE_CHECK("mcastrate %d", ireq.i_val/2);
1715 ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1716 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1717 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1718 LINE_CHECK("fragthreshold %d", ireq.i_val);
1721 ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
1722 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1723 if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
1724 LINE_CHECK("bmiss %d", ireq.i_val);
1727 if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1728 ireq.i_type = IEEE80211_IOC_PUREG;
1729 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1730 if (ireq.i_val)
1731 LINE_CHECK("pureg");
1732 else if (verbose)
1733 LINE_CHECK("-pureg");
1735 ireq.i_type = IEEE80211_IOC_PROTMODE;
1736 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1737 switch (ireq.i_val) {
1738 case IEEE80211_PROTMODE_OFF:
1739 LINE_CHECK("protmode OFF");
1740 break;
1741 case IEEE80211_PROTMODE_CTS:
1742 LINE_CHECK("protmode CTS");
1743 break;
1744 case IEEE80211_PROTMODE_RTSCTS:
1745 LINE_CHECK("protmode RTSCTS");
1746 break;
1747 default:
1748 LINE_CHECK("protmode UNKNOWN (0x%x)",
1749 ireq.i_val);
1750 break;
1755 ireq.i_type = IEEE80211_IOC_WME;
1756 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1757 wme = ireq.i_val;
1758 if (wme)
1759 LINE_CHECK("wme");
1760 else if (verbose)
1761 LINE_CHECK("-wme");
1762 } else
1763 wme = 0;
1765 ireq.i_type = IEEE80211_IOC_BURST;
1766 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1767 if (ireq.i_val)
1768 LINE_CHECK("burst");
1769 else if (verbose)
1770 LINE_CHECK("-burst");
1773 if (opmode == IEEE80211_M_HOSTAP) {
1774 ireq.i_type = IEEE80211_IOC_HIDESSID;
1775 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1776 if (ireq.i_val)
1777 LINE_CHECK("ssid HIDE");
1778 else if (verbose)
1779 LINE_CHECK("ssid SHOW");
1782 ireq.i_type = IEEE80211_IOC_APBRIDGE;
1783 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1784 if (!ireq.i_val)
1785 LINE_CHECK("-apbridge");
1786 else if (verbose)
1787 LINE_CHECK("apbridge");
1790 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1791 if (ioctl(s, SIOCG80211, &ireq) != -1)
1792 LINE_CHECK("dtimperiod %u", ireq.i_val);
1793 } else {
1794 ireq.i_type = IEEE80211_IOC_ROAMING;
1795 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1796 if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1797 switch (ireq.i_val) {
1798 case IEEE80211_ROAMING_DEVICE:
1799 LINE_CHECK("roaming DEVICE");
1800 break;
1801 case IEEE80211_ROAMING_AUTO:
1802 LINE_CHECK("roaming AUTO");
1803 break;
1804 case IEEE80211_ROAMING_MANUAL:
1805 LINE_CHECK("roaming MANUAL");
1806 break;
1807 default:
1808 LINE_CHECK("roaming UNKNOWN (0x%x)",
1809 ireq.i_val);
1810 break;
1815 ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1816 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1817 if (ireq.i_val)
1818 LINE_CHECK("bintval %u", ireq.i_val);
1819 else if (verbose)
1820 LINE_CHECK("bintval %u", ireq.i_val);
1823 if (wme && verbose) {
1824 LINE_BREAK();
1825 list_wme(s);
1828 if (wpa) {
1829 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1830 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1831 if (ireq.i_val)
1832 LINE_CHECK("countermeasures");
1833 else if (verbose)
1834 LINE_CHECK("-countermeasures");
1836 #if 0
1837 /* XXX not interesting with WPA done in user space */
1838 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1839 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1842 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1843 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1844 LINE_CHECK("mcastcipher ");
1845 printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1846 spacer = ' ';
1849 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1850 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1851 LINE_CHECK("ucastcipher ");
1852 printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1855 if (wpa & 2) {
1856 ireq.i_type = IEEE80211_IOC_RSNCAPS;
1857 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1858 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1859 spacer = ' ';
1863 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1864 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1866 #endif
1867 LINE_BREAK();
1869 LINE_BREAK();
1871 end:
1872 return;
1875 static void
1876 set80211(int s, int type, int val, int len, u_int8_t *data)
1878 struct ieee80211req ireq;
1880 (void) memset(&ireq, 0, sizeof(ireq));
1881 (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1882 ireq.i_type = type;
1883 ireq.i_val = val;
1884 ireq.i_len = len;
1885 ireq.i_data = data;
1886 if (ioctl(s, SIOCS80211, &ireq) < 0)
1887 err(1, "SIOCS80211");
1890 static const char *
1891 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1893 int len;
1894 int hexstr;
1895 u_int8_t *p;
1897 len = *lenp;
1898 p = buf;
1899 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1900 if (hexstr)
1901 val += 2;
1902 for (;;) {
1903 if (*val == '\0')
1904 break;
1905 if (sep != NULL && strchr(sep, *val) != NULL) {
1906 val++;
1907 break;
1909 if (hexstr) {
1910 if (!isxdigit((u_char)val[0])) {
1911 warnx("bad hexadecimal digits");
1912 return NULL;
1914 if (!isxdigit((u_char)val[1])) {
1915 warnx("odd count hexadecimal digits");
1916 return NULL;
1919 if (p >= buf + len) {
1920 if (hexstr)
1921 warnx("hexadecimal digits too long");
1922 else
1923 warnx("string too long");
1924 return NULL;
1926 if (hexstr) {
1927 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1928 *p++ = (tohex((u_char)val[0]) << 4) |
1929 tohex((u_char)val[1]);
1930 #undef tohex
1931 val += 2;
1932 } else
1933 *p++ = *val++;
1935 len = p - buf;
1936 if (len < *lenp)
1937 memset(p, 0, *lenp - len);
1938 /* The string "-" is treated as the empty string. */
1939 if (!hexstr && len == 1 && buf[0] == '-')
1940 len = 0;
1941 *lenp = len;
1942 return val;
1945 static void
1946 print_string(const u_int8_t *buf, int len)
1948 int i;
1949 int hasspc;
1951 i = 0;
1952 hasspc = 0;
1953 for (; i < len; i++) {
1954 if (!isprint(buf[i]) && buf[i] != '\0')
1955 break;
1956 if (isspace(buf[i]))
1957 hasspc++;
1959 if (i == len) {
1960 if (hasspc || len == 0 || buf[0] == '\0')
1961 printf("\"%.*s\"", len, buf);
1962 else
1963 printf("%.*s", len, buf);
1964 } else {
1965 printf("0x");
1966 for (i = 0; i < len; i++)
1967 printf("%02x", buf[i]);
1971 static struct cmd ieee80211_cmds[] = {
1972 DEF_CMD_ARG("ssid", set80211ssid),
1973 DEF_CMD_ARG("nwid", set80211ssid),
1974 DEF_CMD_ARG("stationname", set80211stationname),
1975 DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
1976 DEF_CMD_ARG("channel", set80211channel),
1977 DEF_CMD_ARG("authmode", set80211authmode),
1978 DEF_CMD_ARG("powersavemode", set80211powersavemode),
1979 DEF_CMD("powersave", 1, set80211powersave),
1980 DEF_CMD("-powersave", 0, set80211powersave),
1981 DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
1982 DEF_CMD_ARG("wepmode", set80211wepmode),
1983 DEF_CMD("wep", 1, set80211wep),
1984 DEF_CMD("-wep", 0, set80211wep),
1985 DEF_CMD_ARG("deftxkey", set80211weptxkey),
1986 DEF_CMD_ARG("weptxkey", set80211weptxkey),
1987 DEF_CMD_ARG("wepkey", set80211wepkey),
1988 DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
1989 DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
1990 DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
1991 DEF_CMD_ARG("protmode", set80211protmode),
1992 DEF_CMD_ARG("txpower", set80211txpower),
1993 DEF_CMD_ARG("roaming", set80211roaming),
1994 DEF_CMD("wme", 1, set80211wme),
1995 DEF_CMD("-wme", 0, set80211wme),
1996 DEF_CMD("hidessid", 1, set80211hidessid),
1997 DEF_CMD("-hidessid", 0, set80211hidessid),
1998 DEF_CMD("apbridge", 1, set80211apbridge),
1999 DEF_CMD("-apbridge", 0, set80211apbridge),
2000 DEF_CMD_ARG("chanlist", set80211chanlist),
2001 DEF_CMD_ARG("bssid", set80211bssid),
2002 DEF_CMD_ARG("ap", set80211bssid),
2003 DEF_CMD("scan", 0, set80211scan),
2004 DEF_CMD_ARG("list", set80211list),
2005 DEF_CMD_ARG2("cwmin", set80211cwmin),
2006 DEF_CMD_ARG2("cwmax", set80211cwmax),
2007 DEF_CMD_ARG2("aifs", set80211aifs),
2008 DEF_CMD_ARG2("txoplimit", set80211txoplimit),
2009 DEF_CMD_ARG("acm", set80211acm),
2010 DEF_CMD_ARG("-acm", set80211noacm),
2011 DEF_CMD_ARG("ack", set80211ackpolicy),
2012 DEF_CMD_ARG("-ack", set80211noackpolicy),
2013 DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
2014 DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
2015 DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
2016 DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
2017 DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
2018 DEF_CMD_ARG("bintval", set80211bintval),
2019 DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
2020 DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
2021 DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
2022 DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
2023 DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
2024 DEF_CMD_ARG("mac:add", set80211addmac),
2025 DEF_CMD_ARG("mac:del", set80211delmac),
2026 DEF_CMD_ARG("mac:kick", set80211kickmac),
2027 DEF_CMD("pureg", 1, set80211pureg),
2028 DEF_CMD("-pureg", 0, set80211pureg),
2029 DEF_CMD_ARG("mcastrate", set80211mcastrate),
2030 DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
2031 DEF_CMD("burst", 1, set80211burst),
2032 DEF_CMD("-burst", 0, set80211burst),
2033 DEF_CMD_ARG("ratectl", set80211ratectl),
2034 DEF_CMD_ARG("bmiss", set80211bmissthreshold),
2035 DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold)
2037 static struct afswtch af_ieee80211 = {
2038 .af_name = "af_ieee80211",
2039 .af_af = AF_UNSPEC,
2040 .af_other_status = ieee80211_status,
2043 static __constructor void
2044 ieee80211_ctor(void)
2046 #define N(a) (sizeof(a) / sizeof(a[0]))
2047 int i;
2049 for (i = 0; i < N(ieee80211_cmds); i++)
2050 cmd_register(&ieee80211_cmds[i]);
2051 af_register(&af_ieee80211);
2052 #undef N