]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ifconfig/ifieee80211.c
This commit was generated by cvs2svn to compensate for changes in r161764,
[FreeBSD/FreeBSD.git] / sbin / ifconfig / ifieee80211.c
1 /*
2  * Copyright 2001 The Aerospace Corporation.  All rights reserved.
3  *
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.
14  *
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.
26  *
27  * $FreeBSD$
28  */
29
30 /*-
31  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
32  * All rights reserved.
33  *
34  * This code is derived from software contributed to The NetBSD Foundation
35  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36  * NASA Ames Research Center.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *      This product includes software developed by the NetBSD
49  *      Foundation, Inc. and its contributors.
50  * 4. Neither the name of The NetBSD Foundation nor the names of its
51  *    contributors may be used to endorse or promote products derived
52  *    from this software without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
55  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
58  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64  * POSSIBILITY OF SUCH DAMAGE.
65  */
66
67 #include <sys/param.h>
68 #include <sys/ioctl.h>
69 #include <sys/socket.h>
70 #include <sys/sysctl.h>
71 #include <sys/time.h>
72
73 #include <net/ethernet.h>
74 #include <net/if.h>
75 #include <net/if_dl.h>
76 #include <net/if_types.h>
77 #include <net/if_media.h>
78 #include <net/route.h>
79
80 #include <net80211/ieee80211.h>
81 #include <net80211/ieee80211_crypto.h>
82 #include <net80211/ieee80211_ioctl.h>
83
84 #include <ctype.h>
85 #include <err.h>
86 #include <errno.h>
87 #include <fcntl.h>
88 #include <inttypes.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <unistd.h>
93 #include <stdarg.h>
94
95 #include "ifconfig.h"
96
97 static void set80211(int s, int type, int val, int len, u_int8_t *data);
98 static const char *get_string(const char *val, const char *sep,
99     u_int8_t *buf, int *lenp);
100 static void print_string(const u_int8_t *buf, int len);
101
102 static int
103 isanyarg(const char *arg)
104 {
105         return (strcmp(arg, "-") == 0 ||
106             strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
107 }
108
109 static void
110 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
111 {
112         int             ssid;
113         int             len;
114         u_int8_t        data[IEEE80211_NWID_LEN];
115
116         ssid = 0;
117         len = strlen(val);
118         if (len > 2 && isdigit(val[0]) && val[1] == ':') {
119                 ssid = atoi(val)-1;
120                 val += 2;
121         }
122
123         bzero(data, sizeof(data));
124         len = sizeof(data);
125         if (get_string(val, NULL, data, &len) == NULL)
126                 exit(1);
127
128         set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
129 }
130
131 static void
132 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
133 {
134         int                     len;
135         u_int8_t                data[33];
136
137         bzero(data, sizeof(data));
138         len = sizeof(data);
139         get_string(val, NULL, data, &len);
140
141         set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
142 }
143
144 /*
145  * Convert IEEE channel number to MHz frequency.
146  */
147 static u_int
148 ieee80211_ieee2mhz(u_int chan)
149 {
150         if (chan == 14)
151                 return 2484;
152         if (chan < 14)                  /* 0-13 */
153                 return 2407 + chan*5;
154         if (chan < 27)                  /* 15-26 */
155                 return 2512 + ((chan-15)*20);
156         return 5000 + (chan*5);
157 }
158
159 /*
160  * Convert MHz frequency to IEEE channel number.
161  */
162 static u_int
163 ieee80211_mhz2ieee(u_int freq)
164 {
165         if (freq == 2484)
166                 return 14;
167         if (freq < 2484)
168                 return (freq - 2407) / 5;
169         if (freq < 5000)
170                 return 15 + ((freq - 2512) / 20);
171         return (freq - 5000) / 5;
172 }
173
174 static void
175 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
176 {
177         if (!isanyarg(val)) {
178                 int v = atoi(val);
179                 if (v > 255)            /* treat as frequency */
180                         v = ieee80211_mhz2ieee(v);
181                 set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
182         } else
183                 set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
184 }
185
186 static void
187 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
188 {
189         int     mode;
190
191         if (strcasecmp(val, "none") == 0) {
192                 mode = IEEE80211_AUTH_NONE;
193         } else if (strcasecmp(val, "open") == 0) {
194                 mode = IEEE80211_AUTH_OPEN;
195         } else if (strcasecmp(val, "shared") == 0) {
196                 mode = IEEE80211_AUTH_SHARED;
197         } else if (strcasecmp(val, "8021x") == 0) {
198                 mode = IEEE80211_AUTH_8021X;
199         } else if (strcasecmp(val, "wpa") == 0) {
200                 mode = IEEE80211_AUTH_WPA;
201         } else {
202                 errx(1, "unknown authmode");
203         }
204
205         set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
206 }
207
208 static void
209 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
210 {
211         int     mode;
212
213         if (strcasecmp(val, "off") == 0) {
214                 mode = IEEE80211_POWERSAVE_OFF;
215         } else if (strcasecmp(val, "on") == 0) {
216                 mode = IEEE80211_POWERSAVE_ON;
217         } else if (strcasecmp(val, "cam") == 0) {
218                 mode = IEEE80211_POWERSAVE_CAM;
219         } else if (strcasecmp(val, "psp") == 0) {
220                 mode = IEEE80211_POWERSAVE_PSP;
221         } else if (strcasecmp(val, "psp-cam") == 0) {
222                 mode = IEEE80211_POWERSAVE_PSP_CAM;
223         } else {
224                 errx(1, "unknown powersavemode");
225         }
226
227         set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
228 }
229
230 static void
231 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
232 {
233         if (d == 0)
234                 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
235                     0, NULL);
236         else
237                 set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
238                     0, NULL);
239 }
240
241 static void
242 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
243 {
244         set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
245 }
246
247 static void
248 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
249 {
250         int     mode;
251
252         if (strcasecmp(val, "off") == 0) {
253                 mode = IEEE80211_WEP_OFF;
254         } else if (strcasecmp(val, "on") == 0) {
255                 mode = IEEE80211_WEP_ON;
256         } else if (strcasecmp(val, "mixed") == 0) {
257                 mode = IEEE80211_WEP_MIXED;
258         } else {
259                 errx(1, "unknown wep mode");
260         }
261
262         set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
263 }
264
265 static void
266 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
267 {
268         set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
269 }
270
271 static int
272 isundefarg(const char *arg)
273 {
274         return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
275 }
276
277 static void
278 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
279 {
280         if (isundefarg(val))
281                 set80211(s, IEEE80211_IOC_WEPTXKEY, IEEE80211_KEYIX_NONE, 0, NULL);
282         else
283                 set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
284 }
285
286 static void
287 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
288 {
289         int             key = 0;
290         int             len;
291         u_int8_t        data[IEEE80211_KEYBUF_SIZE];
292
293         if (isdigit(val[0]) && val[1] == ':') {
294                 key = atoi(val)-1;
295                 val += 2;
296         }
297
298         bzero(data, sizeof(data));
299         len = sizeof(data);
300         get_string(val, NULL, data, &len);
301
302         set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
303 }
304
305 /*
306  * This function is purely a NetBSD compatability interface.  The NetBSD
307  * interface is too inflexible, but it's there so we'll support it since
308  * it's not all that hard.
309  */
310 static void
311 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
312 {
313         int             txkey;
314         int             i, len;
315         u_int8_t        data[IEEE80211_KEYBUF_SIZE];
316
317         set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
318
319         if (isdigit(val[0]) && val[1] == ':') {
320                 txkey = val[0]-'0'-1;
321                 val += 2;
322
323                 for (i = 0; i < 4; i++) {
324                         bzero(data, sizeof(data));
325                         len = sizeof(data);
326                         val = get_string(val, ",", data, &len);
327                         if (val == NULL)
328                                 exit(1);
329
330                         set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
331                 }
332         } else {
333                 bzero(data, sizeof(data));
334                 len = sizeof(data);
335                 get_string(val, NULL, data, &len);
336                 txkey = 0;
337
338                 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
339
340                 bzero(data, sizeof(data));
341                 for (i = 1; i < 4; i++)
342                         set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
343         }
344
345         set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
346 }
347
348 static void
349 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
350 {
351         set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
352                 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
353 }
354
355 static void
356 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
357 {
358         int     mode;
359
360         if (strcasecmp(val, "off") == 0) {
361                 mode = IEEE80211_PROTMODE_OFF;
362         } else if (strcasecmp(val, "cts") == 0) {
363                 mode = IEEE80211_PROTMODE_CTS;
364         } else if (strcasecmp(val, "rtscts") == 0) {
365                 mode = IEEE80211_PROTMODE_RTSCTS;
366         } else {
367                 errx(1, "unknown protection mode");
368         }
369
370         set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
371 }
372
373 static void
374 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
375 {
376         set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
377 }
378
379 #define IEEE80211_ROAMING_DEVICE        0
380 #define IEEE80211_ROAMING_AUTO          1
381 #define IEEE80211_ROAMING_MANUAL        2
382
383 static void
384 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
385 {
386         int mode;
387
388         if (strcasecmp(val, "device") == 0) {
389                 mode = IEEE80211_ROAMING_DEVICE;
390         } else if (strcasecmp(val, "auto") == 0) {
391                 mode = IEEE80211_ROAMING_AUTO;
392         } else if (strcasecmp(val, "manual") == 0) {
393                 mode = IEEE80211_ROAMING_MANUAL;
394         } else {
395                 errx(1, "unknown roaming mode");
396         }
397         set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
398 }
399
400 static void
401 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
402 {
403         set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
404 }
405
406 static void
407 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
408 {
409         set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
410 }
411
412 static void
413 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
414 {
415         set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
416 }
417
418 static void
419 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
420 {
421         struct ieee80211req_chanlist chanlist;
422 #define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
423         char *temp, *cp, *tp;
424
425         temp = malloc(strlen(val) + 1);
426         if (temp == NULL)
427                 errx(1, "malloc failed");
428         strcpy(temp, val);
429         memset(&chanlist, 0, sizeof(chanlist));
430         cp = temp;
431         for (;;) {
432                 int first, last, f;
433
434                 tp = strchr(cp, ',');
435                 if (tp != NULL)
436                         *tp++ = '\0';
437                 switch (sscanf(cp, "%u-%u", &first, &last)) {
438                 case 1:
439                         if (first > MAXCHAN)
440                                 errx(-1, "channel %u out of range, max %zu",
441                                         first, MAXCHAN);
442                         setbit(chanlist.ic_channels, first);
443                         break;
444                 case 2:
445                         if (first > MAXCHAN)
446                                 errx(-1, "channel %u out of range, max %zu",
447                                         first, MAXCHAN);
448                         if (last > MAXCHAN)
449                                 errx(-1, "channel %u out of range, max %zu",
450                                         last, MAXCHAN);
451                         if (first > last)
452                                 errx(-1, "void channel range, %u > %u",
453                                         first, last);
454                         for (f = first; f <= last; f++)
455                                 setbit(chanlist.ic_channels, f);
456                         break;
457                 }
458                 if (tp == NULL)
459                         break;
460                 while (isspace(*tp))
461                         tp++;
462                 if (!isdigit(*tp))
463                         break;
464                 cp = tp;
465         }
466         set80211(s, IEEE80211_IOC_CHANLIST, 0,
467                 sizeof(chanlist), (uint8_t *) &chanlist);
468 #undef MAXCHAN
469 }
470
471 static void
472 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
473 {
474
475         if (!isanyarg(val)) {
476                 char *temp;
477                 struct sockaddr_dl sdl;
478
479                 temp = malloc(strlen(val) + 2); /* ':' and '\0' */
480                 if (temp == NULL)
481                         errx(1, "malloc failed");
482                 temp[0] = ':';
483                 strcpy(temp + 1, val);
484                 sdl.sdl_len = sizeof(sdl);
485                 link_addr(temp, &sdl);
486                 free(temp);
487                 if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
488                         errx(1, "malformed link-level address");
489                 set80211(s, IEEE80211_IOC_BSSID, 0,
490                         IEEE80211_ADDR_LEN, LLADDR(&sdl));
491         } else {
492                 uint8_t zerobssid[IEEE80211_ADDR_LEN];
493                 memset(zerobssid, 0, sizeof(zerobssid));
494                 set80211(s, IEEE80211_IOC_BSSID, 0,
495                         IEEE80211_ADDR_LEN, zerobssid);
496         }
497 }
498
499 static int
500 getac(const char *ac)
501 {
502         if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
503                 return WME_AC_BE;
504         if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
505                 return WME_AC_BK;
506         if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
507                 return WME_AC_VI;
508         if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
509                 return WME_AC_VO;
510         errx(1, "unknown wme access class %s", ac);
511 }
512
513 static
514 DECL_CMD_FUNC2(set80211cwmin, ac, val)
515 {
516         set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
517 }
518
519 static
520 DECL_CMD_FUNC2(set80211cwmax, ac, val)
521 {
522         set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
523 }
524
525 static
526 DECL_CMD_FUNC2(set80211aifs, ac, val)
527 {
528         set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
529 }
530
531 static
532 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
533 {
534         set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
535 }
536
537 static
538 DECL_CMD_FUNC(set80211acm, ac, d)
539 {
540         set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
541 }
542 static
543 DECL_CMD_FUNC(set80211noacm, ac, d)
544 {
545         set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
546 }
547
548 static
549 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
550 {
551         set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
552 }
553 static
554 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
555 {
556         set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
557 }
558
559 static
560 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
561 {
562         set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
563                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
564 }
565
566 static
567 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
568 {
569         set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
570                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
571 }
572
573 static
574 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
575 {
576         set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
577                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
578 }
579
580 static
581 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
582 {
583         set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
584                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
585 }
586
587 static
588 DECL_CMD_FUNC(set80211dtimperiod, val, d)
589 {
590         set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
591 }
592
593 static
594 DECL_CMD_FUNC(set80211bintval, val, d)
595 {
596         set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
597 }
598
599 static void
600 set80211macmac(int s, int op, const char *val)
601 {
602         char *temp;
603         struct sockaddr_dl sdl;
604
605         temp = malloc(strlen(val) + 2); /* ':' and '\0' */
606         if (temp == NULL)
607                 errx(1, "malloc failed");
608         temp[0] = ':';
609         strcpy(temp + 1, val);
610         sdl.sdl_len = sizeof(sdl);
611         link_addr(temp, &sdl);
612         free(temp);
613         if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
614                 errx(1, "malformed link-level address");
615         set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
616 }
617
618 static
619 DECL_CMD_FUNC(set80211addmac, val, d)
620 {
621         set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
622 }
623
624 static
625 DECL_CMD_FUNC(set80211delmac, val, d)
626 {
627         set80211macmac(s, IEEE80211_IOC_DELMAC, val);
628 }
629
630 static
631 DECL_CMD_FUNC(set80211kickmac, val, d)
632 {
633         char *temp;
634         struct sockaddr_dl sdl;
635         struct ieee80211req_mlme mlme;
636
637         temp = malloc(strlen(val) + 2); /* ':' and '\0' */
638         if (temp == NULL)
639                 errx(1, "malloc failed");
640         temp[0] = ':';
641         strcpy(temp + 1, val);
642         sdl.sdl_len = sizeof(sdl);
643         link_addr(temp, &sdl);
644         free(temp);
645         if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
646                 errx(1, "malformed link-level address");
647         memset(&mlme, 0, sizeof(mlme));
648         mlme.im_op = IEEE80211_MLME_DEAUTH;
649         mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
650         memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
651         set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
652 }
653
654 static
655 DECL_CMD_FUNC(set80211maccmd, val, d)
656 {
657         set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
658 }
659
660 static void
661 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
662 {
663         set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
664 }
665
666 static void
667 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
668 {
669         set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
670 }
671
672 static
673 DECL_CMD_FUNC(set80211mcastrate, val, d)
674 {
675         set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
676 }
677
678 static
679 DECL_CMD_FUNC(set80211fragthreshold, val, d)
680 {
681         set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
682                 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
683 }
684
685 static
686 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
687 {
688         set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
689                 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
690 }
691
692 static int
693 getmaxrate(uint8_t rates[15], uint8_t nrates)
694 {
695         int i, maxrate = -1;
696
697         for (i = 0; i < nrates; i++) {
698                 int rate = rates[i] & IEEE80211_RATE_VAL;
699                 if (rate > maxrate)
700                         maxrate = rate;
701         }
702         return maxrate / 2;
703 }
704
705 static const char *
706 getcaps(int capinfo)
707 {
708         static char capstring[32];
709         char *cp = capstring;
710
711         if (capinfo & IEEE80211_CAPINFO_ESS)
712                 *cp++ = 'E';
713         if (capinfo & IEEE80211_CAPINFO_IBSS)
714                 *cp++ = 'I';
715         if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
716                 *cp++ = 'c';
717         if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
718                 *cp++ = 'C';
719         if (capinfo & IEEE80211_CAPINFO_PRIVACY)
720                 *cp++ = 'P';
721         if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
722                 *cp++ = 'S';
723         if (capinfo & IEEE80211_CAPINFO_PBCC)
724                 *cp++ = 'B';
725         if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
726                 *cp++ = 'A';
727         if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
728                 *cp++ = 's';
729         if (capinfo & IEEE80211_CAPINFO_RSN)
730                 *cp++ = 'R';
731         if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
732                 *cp++ = 'D';
733         *cp = '\0';
734         return capstring;
735 }
736
737 static const char *
738 getflags(int flags)
739 {
740 /* XXX need these publicly defined or similar */
741 #define IEEE80211_NODE_AUTH     0x0001          /* authorized for data */
742 #define IEEE80211_NODE_QOS      0x0002          /* QoS enabled */
743 #define IEEE80211_NODE_ERP      0x0004          /* ERP enabled */
744 #define IEEE80211_NODE_PWR_MGT  0x0010          /* power save mode enabled */
745         static char flagstring[32];
746         char *cp = flagstring;
747
748         if (flags & IEEE80211_NODE_AUTH)
749                 *cp++ = 'A';
750         if (flags & IEEE80211_NODE_QOS)
751                 *cp++ = 'Q';
752         if (flags & IEEE80211_NODE_ERP)
753                 *cp++ = 'E';
754         if (flags & IEEE80211_NODE_PWR_MGT)
755                 *cp++ = 'P';
756         *cp = '\0';
757         return flagstring;
758 #undef IEEE80211_NODE_AUTH
759 #undef IEEE80211_NODE_QOS
760 #undef IEEE80211_NODE_ERP
761 #undef IEEE80211_NODE_PWR_MGT
762 }
763
764 static void
765 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
766 {
767         printf("%s", tag);
768         if (verbose) {
769                 maxlen -= strlen(tag)+2;
770                 if (2*ielen > maxlen)
771                         maxlen--;
772                 printf("<");
773                 for (; ielen > 0; ie++, ielen--) {
774                         if (maxlen-- <= 0)
775                                 break;
776                         printf("%02x", *ie);
777                 }
778                 if (ielen != 0)
779                         printf("-");
780                 printf(">");
781         }
782 }
783
784 /*
785  * Copy the ssid string contents into buf, truncating to fit.  If the
786  * ssid is entirely printable then just copy intact.  Otherwise convert
787  * to hexadecimal.  If the result is truncated then replace the last
788  * three characters with "...".
789  */
790 static int
791 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
792 {
793         const u_int8_t *p; 
794         size_t maxlen;
795         int i;
796
797         if (essid_len > bufsize)
798                 maxlen = bufsize;
799         else
800                 maxlen = essid_len;
801         /* determine printable or not */
802         for (i = 0, p = essid; i < maxlen; i++, p++) {
803                 if (*p < ' ' || *p > 0x7e)
804                         break;
805         }
806         if (i != maxlen) {              /* not printable, print as hex */
807                 if (bufsize < 3)
808                         return 0;
809                 strlcpy(buf, "0x", bufsize);
810                 bufsize -= 2;
811                 p = essid;
812                 for (i = 0; i < maxlen && bufsize >= 2; i++) {
813                         sprintf(&buf[2+2*i], "%02x", p[i]);
814                         bufsize -= 2;
815                 }
816                 if (i != essid_len)
817                         memcpy(&buf[2+2*i-3], "...", 3);
818         } else {                        /* printable, truncate as needed */
819                 memcpy(buf, essid, maxlen);
820                 if (maxlen != essid_len)
821                         memcpy(&buf[maxlen-3], "...", 3);
822         }
823         return maxlen;
824 }
825
826 /* unaligned little endian access */     
827 #define LE_READ_4(p)                                    \
828         ((u_int32_t)                                    \
829          ((((const u_int8_t *)(p))[0]      ) |          \
830           (((const u_int8_t *)(p))[1] <<  8) |          \
831           (((const u_int8_t *)(p))[2] << 16) |          \
832           (((const u_int8_t *)(p))[3] << 24)))
833
834 static int __inline
835 iswpaoui(const u_int8_t *frm)
836 {
837         return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
838 }
839
840 static int __inline
841 iswmeoui(const u_int8_t *frm)
842 {
843         return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
844 }
845
846 static int __inline
847 isatherosoui(const u_int8_t *frm)
848 {
849         return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
850 }
851
852 static void
853 printies(const u_int8_t *vp, int ielen, int maxcols)
854 {
855         while (ielen > 0) {
856                 switch (vp[0]) {
857                 case IEEE80211_ELEMID_VENDOR:
858                         if (iswpaoui(vp))
859                                 printie(" WPA", vp, 2+vp[1], maxcols);
860                         else if (iswmeoui(vp))
861                                 printie(" WME", vp, 2+vp[1], maxcols);
862                         else if (isatherosoui(vp))
863                                 printie(" ATH", vp, 2+vp[1], maxcols);
864                         else
865                                 printie(" VEN", vp, 2+vp[1], maxcols);
866                         break;
867                 case IEEE80211_ELEMID_RSN:
868                         printie(" RSN", vp, 2+vp[1], maxcols);
869                         break;
870                 default:
871                         printie(" ???", vp, 2+vp[1], maxcols);
872                         break;
873                 }
874                 ielen -= 2+vp[1];
875                 vp += 2+vp[1];
876         }
877 }
878
879 static void
880 list_scan(int s)
881 {
882         uint8_t buf[24*1024];
883         struct ieee80211req ireq;
884         char ssid[IEEE80211_NWID_LEN+1];
885         uint8_t *cp;
886         int len, ssidmax;
887
888         (void) memset(&ireq, 0, sizeof(ireq));
889         (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
890         ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
891         ireq.i_data = buf;
892         ireq.i_len = sizeof(buf);
893         if (ioctl(s, SIOCG80211, &ireq) < 0)
894                 errx(1, "unable to get scan results");
895         len = ireq.i_len;
896         if (len < sizeof(struct ieee80211req_scan_result))
897                 return;
898
899         ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
900         printf("%-*.*s  %-17.17s  %4s %4s  %-5s %3s %4s\n"
901                 , ssidmax, ssidmax, "SSID"
902                 , "BSSID"
903                 , "CHAN"
904                 , "RATE"
905                 , "S:N"
906                 , "INT"
907                 , "CAPS"
908         );
909         cp = buf;
910         do {
911                 struct ieee80211req_scan_result *sr;
912                 uint8_t *vp;
913
914                 sr = (struct ieee80211req_scan_result *) cp;
915                 vp = (u_int8_t *)(sr+1);
916                 printf("%-*.*s  %s  %3d  %3dM %2d:%-2d  %3d %-4.4s"
917                         , ssidmax
918                           , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
919                           , ssid
920                         , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
921                         , ieee80211_mhz2ieee(sr->isr_freq)
922                         , getmaxrate(sr->isr_rates, sr->isr_nrates)
923                         , sr->isr_rssi, sr->isr_noise
924                         , sr->isr_intval
925                         , getcaps(sr->isr_capinfo)
926                 );
927                 printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
928                 printf("\n");
929                 cp += sr->isr_len, len -= sr->isr_len;
930         } while (len >= sizeof(struct ieee80211req_scan_result));
931 }
932
933 #include <net80211/ieee80211_freebsd.h>
934
935 static void
936 scan_and_wait(int s)
937 {
938         struct ieee80211req ireq;
939         int sroute;
940
941         sroute = socket(PF_ROUTE, SOCK_RAW, 0);
942         if (sroute < 0) {
943                 perror("socket(PF_ROUTE,SOCK_RAW)");
944                 return;
945         }
946         (void) memset(&ireq, 0, sizeof(ireq));
947         (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
948         ireq.i_type = IEEE80211_IOC_SCAN_REQ;
949         /* NB: only root can trigger a scan so ignore errors */
950         if (ioctl(s, SIOCS80211, &ireq) >= 0) {
951                 char buf[2048];
952                 struct if_announcemsghdr *ifan;
953                 struct rt_msghdr *rtm;
954
955                 do {
956                         if (read(sroute, buf, sizeof(buf)) < 0) {
957                                 perror("read(PF_ROUTE)");
958                                 break;
959                         }
960                         rtm = (struct rt_msghdr *) buf;
961                         if (rtm->rtm_version != RTM_VERSION)
962                                 break;
963                         ifan = (struct if_announcemsghdr *) rtm;
964                 } while (rtm->rtm_type != RTM_IEEE80211 ||
965                     ifan->ifan_what != RTM_IEEE80211_SCAN);
966         }
967         close(sroute);
968 }
969
970 static
971 DECL_CMD_FUNC(set80211scan, val, d)
972 {
973         scan_and_wait(s);
974         list_scan(s);
975 }
976
977 static enum ieee80211_opmode get80211opmode(int s);
978
979 static void
980 list_stations(int s)
981 {
982         union {
983                 struct ieee80211req_sta_req req;
984                 uint8_t buf[24*1024];
985         } u;
986         enum ieee80211_opmode opmode = get80211opmode(s);
987         struct ieee80211req ireq;
988         uint8_t *cp;
989         int len;
990
991         (void) memset(&ireq, 0, sizeof(ireq));
992         (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
993         /* broadcast address =>'s get all stations */
994         (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
995         if (opmode == IEEE80211_M_STA) {
996                 /*
997                  * Get information about the associated AP.
998                  */
999                 ireq.i_type = IEEE80211_IOC_BSSID;
1000                 ireq.i_data = u.req.is_u.macaddr;
1001                 ireq.i_len = IEEE80211_ADDR_LEN;
1002                 (void) ioctl(s, SIOCG80211, &ireq);
1003         }
1004         ireq.i_type = IEEE80211_IOC_STA_INFO;
1005         ireq.i_data = &u;
1006         ireq.i_len = sizeof(u);
1007         if (ioctl(s, SIOCG80211, &ireq) < 0)
1008                 errx(1, "unable to get station information");
1009         len = ireq.i_len;
1010         if (len < sizeof(struct ieee80211req_sta_info))
1011                 return;
1012
1013         printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
1014                 , "ADDR"
1015                 , "AID"
1016                 , "CHAN"
1017                 , "RATE"
1018                 , "RSSI"
1019                 , "IDLE"
1020                 , "TXSEQ"
1021                 , "RXSEQ"
1022                 , "CAPS"
1023                 , "FLAG"
1024         );
1025         cp = (uint8_t *) u.req.info;
1026         do {
1027                 struct ieee80211req_sta_info *si;
1028                 uint8_t *vp;
1029
1030                 si = (struct ieee80211req_sta_info *) cp;
1031                 if (si->isi_len < sizeof(*si))
1032                         break;
1033                 vp = (u_int8_t *)(si+1);
1034                 printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %-4.4s"
1035                         , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
1036                         , IEEE80211_AID(si->isi_associd)
1037                         , ieee80211_mhz2ieee(si->isi_freq)
1038                         , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
1039                         , si->isi_rssi
1040                         , si->isi_inact
1041                         , si->isi_txseqs[0]
1042                         , si->isi_rxseqs[0]
1043                         , getcaps(si->isi_capinfo)
1044                         , getflags(si->isi_state)
1045                 );
1046                 printies(vp, si->isi_ie_len, 24);
1047                 printf("\n");
1048                 cp += si->isi_len, len -= si->isi_len;
1049         } while (len >= sizeof(struct ieee80211req_sta_info));
1050 }
1051
1052 static void
1053 print_chaninfo(const struct ieee80211_channel *c)
1054 {
1055 #define IEEE80211_IS_CHAN_PASSIVE(_c) \
1056         (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1057         char buf[14];
1058
1059         buf[0] = '\0';
1060         if (IEEE80211_IS_CHAN_FHSS(c))
1061                 strlcat(buf, " FHSS", sizeof(buf));
1062         if (IEEE80211_IS_CHAN_A(c))
1063                 strlcat(buf, " 11a", sizeof(buf));
1064         /* XXX 11g schizophrenia */
1065         if (IEEE80211_IS_CHAN_G(c) ||
1066             IEEE80211_IS_CHAN_PUREG(c))
1067                 strlcat(buf, " 11g", sizeof(buf));
1068         else if (IEEE80211_IS_CHAN_B(c))
1069                 strlcat(buf, " 11b", sizeof(buf));
1070         if (IEEE80211_IS_CHAN_T(c))
1071                 strlcat(buf, " Turbo", sizeof(buf));
1072         printf("Channel %3u : %u%c Mhz%-14.14s",
1073                 ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
1074                 IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
1075 #undef IEEE80211_IS_CHAN_PASSIVE
1076 }
1077
1078 static void
1079 list_channels(int s, int allchans)
1080 {
1081         struct ieee80211req ireq;
1082         struct ieee80211req_chaninfo chans;
1083         struct ieee80211req_chaninfo achans;
1084         const struct ieee80211_channel *c;
1085         int i, half;
1086
1087         (void) memset(&ireq, 0, sizeof(ireq));
1088         (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1089         ireq.i_type = IEEE80211_IOC_CHANINFO;
1090         ireq.i_data = &chans;
1091         ireq.i_len = sizeof(chans);
1092         if (ioctl(s, SIOCG80211, &ireq) < 0)
1093                 errx(1, "unable to get channel information");
1094         if (!allchans) {
1095                 struct ieee80211req_chanlist active;
1096
1097                 ireq.i_type = IEEE80211_IOC_CHANLIST;
1098                 ireq.i_data = &active;
1099                 ireq.i_len = sizeof(active);
1100                 if (ioctl(s, SIOCG80211, &ireq) < 0)
1101                         errx(1, "unable to get active channel list");
1102                 memset(&achans, 0, sizeof(achans));
1103                 for (i = 0; i < chans.ic_nchans; i++) {
1104                         c = &chans.ic_chans[i];
1105                         if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
1106                                 achans.ic_chans[achans.ic_nchans++] = *c;
1107                 }
1108         } else
1109                 achans = chans;
1110         half = achans.ic_nchans / 2;
1111         if (achans.ic_nchans % 2)
1112                 half++;
1113         for (i = 0; i < achans.ic_nchans / 2; i++) {
1114                 print_chaninfo(&achans.ic_chans[i]);
1115                 print_chaninfo(&achans.ic_chans[half+i]);
1116                 printf("\n");
1117         }
1118         if (achans.ic_nchans % 2) {
1119                 print_chaninfo(&achans.ic_chans[i]);
1120                 printf("\n");
1121         }
1122 }
1123
1124 static void
1125 list_keys(int s)
1126 {
1127 }
1128
1129 #define IEEE80211_C_BITS \
1130 "\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
1131 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
1132 "\31WPA2\32BURST\33WME"
1133
1134 static void
1135 list_capabilities(int s)
1136 {
1137         struct ieee80211req ireq;
1138         u_int32_t caps;
1139
1140         (void) memset(&ireq, 0, sizeof(ireq));
1141         (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1142         ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
1143         if (ioctl(s, SIOCG80211, &ireq) < 0)
1144                 errx(1, "unable to get driver capabilities");
1145         caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
1146         printb(name, caps, IEEE80211_C_BITS);
1147         putchar('\n');
1148 }
1149
1150 static void
1151 list_wme(int s)
1152 {
1153         static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1154         struct ieee80211req ireq;
1155         int ac;
1156
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]);
1166
1167                 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1168
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");
1188                 }
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");
1197                         }
1198                 }
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;
1205         }
1206 }
1207
1208 static void
1209 list_mac(int s)
1210 {
1211         struct ieee80211req ireq;
1212         struct ieee80211req_maclist *acllist;
1213         int i, nacls, policy;
1214         char c;
1215
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;
1224                 }
1225                 err(1, "unable to get mac policy");
1226         }
1227         policy = ireq.i_val;
1228
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;
1235
1236         ireq.i_data = malloc(ireq.i_len);
1237         if (ireq.i_data == NULL)
1238                 err(1, "out of memory for acl list");
1239
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 = '?';
1257         }
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));
1263 }
1264
1265 static
1266 DECL_CMD_FUNC(set80211list, arg, d)
1267 {
1268 #define iseq(a,b)       (strncasecmp(a,b,sizeof(b)-1) == 0)
1269
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
1289 }
1290
1291 static enum ieee80211_opmode
1292 get80211opmode(int s)
1293 {
1294         struct ifmediareq ifmr;
1295
1296         (void) memset(&ifmr, 0, sizeof(ifmr));
1297         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1298
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;
1306         }
1307         return IEEE80211_M_STA;
1308 }
1309
1310 static const struct ieee80211_channel *
1311 getchaninfo(int s, int chan)
1312 {
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;
1318
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;
1331         }
1332         return &undef;
1333 }
1334
1335 #if 0
1336 static void
1337 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1338 {
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;
1367         }
1368 }
1369 #endif
1370
1371 #define MAXCOL  78
1372 static  int col;
1373 static  char spacer;
1374
1375 static void
1376 LINE_BREAK(void)
1377 {
1378         if (spacer != '\t') {
1379                 printf("\n");
1380                 spacer = '\t';
1381         }
1382         col = 8;        /* 8-col tab */
1383 }
1384
1385 static void
1386 LINE_CHECK(const char *fmt, ...)
1387 {
1388         char buf[80];
1389         va_list ap;
1390         int n;
1391
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;
1399         }
1400         buf[0] = spacer;
1401         printf("%s", buf);
1402         spacer = ' ';
1403 }
1404
1405 static void
1406 printkey(const struct ieee80211req_key *ik)
1407 {
1408         static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1409         int keylen = ik->ik_keylen;
1410         int printcontents;
1411
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;
1444         }
1445         if (printcontents) {
1446                 int i;
1447
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 = " ";
1460
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 = "+";
1467                 }
1468                 LINE_BREAK();
1469         }
1470 }
1471
1472 static void
1473 ieee80211_status(int s)
1474 {
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;
1481
1482         (void) memset(&ireq, 0, sizeof(ireq));
1483         (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1484         ireq.i_data = &data;
1485
1486         wpa = 0;                /* unknown/not set */
1487
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;
1493         }
1494         num = 0;
1495         ireq.i_type = IEEE80211_IOC_NUMSSIDS;
1496         if (ioctl(s, SIOCG80211, &ireq) >= 0)
1497                 num = ireq.i_val;
1498         printf("\tssid ");
1499         if (num > 1) {
1500                 ireq.i_type = IEEE80211_IOC_SSID;
1501                 for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
1502                         if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
1503                                 printf(" %d:", ireq.i_val + 1);
1504                                 print_string(data, ireq.i_len);
1505                         }
1506                 }
1507         } else
1508                 print_string(data, ireq.i_len);
1509
1510         ireq.i_type = IEEE80211_IOC_CHANNEL;
1511         if (ioctl(s, SIOCG80211, &ireq) < 0)
1512                 goto end;
1513         c = getchaninfo(s, ireq.i_val);
1514         if (ireq.i_val != -1) {
1515                 printf(" channel %d", ireq.i_val);
1516                 if (verbose)
1517                         printf(" (%u)", c->ic_freq);
1518         } else if (verbose)
1519                 printf(" channel UNDEF");
1520
1521         ireq.i_type = IEEE80211_IOC_BSSID;
1522         ireq.i_len = IEEE80211_ADDR_LEN;
1523         if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
1524             (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
1525                 printf(" bssid %s", ether_ntoa(ireq.i_data));
1526
1527         ireq.i_type = IEEE80211_IOC_STATIONNAME;
1528         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1529                 printf("\n\tstationname ");
1530                 print_string(data, ireq.i_len);
1531         }
1532
1533         spacer = ' ';           /* force first break */
1534         LINE_BREAK();
1535
1536         ireq.i_type = IEEE80211_IOC_AUTHMODE;
1537         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1538                 switch (ireq.i_val) {
1539                         case IEEE80211_AUTH_NONE:
1540                                 LINE_CHECK("authmode NONE");
1541                                 break;
1542                         case IEEE80211_AUTH_OPEN:
1543                                 LINE_CHECK("authmode OPEN");
1544                                 break;
1545                         case IEEE80211_AUTH_SHARED:
1546                                 LINE_CHECK("authmode SHARED");
1547                                 break;
1548                         case IEEE80211_AUTH_8021X:
1549                                 LINE_CHECK("authmode 802.1x");
1550                                 break;
1551                         case IEEE80211_AUTH_WPA:
1552                                 ireq.i_type = IEEE80211_IOC_WPA;
1553                                 if (ioctl(s, SIOCG80211, &ireq) != -1)
1554                                         wpa = ireq.i_val;
1555                                 if (!wpa)
1556                                         wpa = 1;        /* default to WPA1 */
1557                                 switch (wpa) {
1558                                 case 2:
1559                                         LINE_CHECK("authmode WPA2/802.11i");
1560                                         break;
1561                                 case 3:
1562                                         LINE_CHECK("authmode WPA1+WPA2/802.11i");
1563                                         break;
1564                                 default:
1565                                         LINE_CHECK("authmode WPA");
1566                                         break;
1567                                 }
1568                                 break;
1569                         case IEEE80211_AUTH_AUTO:
1570                                 LINE_CHECK("authmode AUTO");
1571                                 break;
1572                         default:
1573                                 LINE_CHECK("authmode UNKNOWN (0x%x)",
1574                                         ireq.i_val);
1575                                 break;
1576                 }
1577         }
1578
1579         ireq.i_type = IEEE80211_IOC_WEP;
1580         if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1581             ireq.i_val != IEEE80211_WEP_NOSUP) {
1582                 int firstkey, wepmode;
1583
1584                 wepmode = ireq.i_val;
1585                 switch (wepmode) {
1586                         case IEEE80211_WEP_OFF:
1587                                 LINE_CHECK("privacy OFF");
1588                                 break;
1589                         case IEEE80211_WEP_ON:
1590                                 LINE_CHECK("privacy ON");
1591                                 break;
1592                         case IEEE80211_WEP_MIXED:
1593                                 LINE_CHECK("privacy MIXED");
1594                                 break;
1595                         default:
1596                                 LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
1597                                 break;
1598                 }
1599
1600                 /*
1601                  * If we get here then we've got WEP support so we need
1602                  * to print WEP status.
1603                  */
1604
1605                 ireq.i_type = IEEE80211_IOC_WEPTXKEY;
1606                 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1607                         warn("WEP support, but no tx key!");
1608                         goto end;
1609                 }
1610                 if (ireq.i_val != -1)
1611                         LINE_CHECK("deftxkey %d", ireq.i_val+1);
1612                 else if (wepmode != IEEE80211_WEP_OFF || verbose)
1613                         LINE_CHECK("deftxkey UNDEF");
1614
1615                 ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
1616                 if (ioctl(s, SIOCG80211, &ireq) < 0) {
1617                         warn("WEP support, but no NUMWEPKEYS support!");
1618                         goto end;
1619                 }
1620                 num = ireq.i_val;
1621
1622                 firstkey = 1;
1623                 for (i = 0; i < num; i++) {
1624                         struct ieee80211req_key ik;
1625
1626                         memset(&ik, 0, sizeof(ik));
1627                         ik.ik_keyix = i;
1628                         ireq.i_type = IEEE80211_IOC_WPAKEY;
1629                         ireq.i_data = &ik;
1630                         ireq.i_len = sizeof(ik);
1631                         if (ioctl(s, SIOCG80211, &ireq) < 0) {
1632                                 warn("WEP support, but can get keys!");
1633                                 goto end;
1634                         }
1635                         if (ik.ik_keylen != 0) {
1636                                 if (verbose)
1637                                         LINE_BREAK();
1638                                 printkey(&ik);
1639                                 firstkey = 0;
1640                         }
1641                 }
1642         }
1643
1644         ireq.i_type = IEEE80211_IOC_POWERSAVE;
1645         if (ioctl(s, SIOCG80211, &ireq) != -1 &&
1646             ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
1647                 if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
1648                         switch (ireq.i_val) {
1649                                 case IEEE80211_POWERSAVE_OFF:
1650                                         LINE_CHECK("powersavemode OFF");
1651                                         break;
1652                                 case IEEE80211_POWERSAVE_CAM:
1653                                         LINE_CHECK("powersavemode CAM");
1654                                         break;
1655                                 case IEEE80211_POWERSAVE_PSP:
1656                                         LINE_CHECK("powersavemode PSP");
1657                                         break;
1658                                 case IEEE80211_POWERSAVE_PSP_CAM:
1659                                         LINE_CHECK("powersavemode PSP-CAM");
1660                                         break;
1661                         }
1662                         ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1663                         if (ioctl(s, SIOCG80211, &ireq) != -1)
1664                                 LINE_CHECK("powersavesleep %d", ireq.i_val);
1665                 }
1666         }
1667
1668         ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1669         if (ioctl(s, SIOCG80211, &ireq) != -1)
1670                 LINE_CHECK("txpowmax %d", ireq.i_val);
1671
1672         if (verbose) {
1673                 ireq.i_type = IEEE80211_IOC_TXPOWER;
1674                 if (ioctl(s, SIOCG80211, &ireq) != -1)
1675                         LINE_CHECK("txpower %d", ireq.i_val);
1676         }
1677
1678         ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
1679         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1680                 if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
1681                         LINE_CHECK("rtsthreshold %d", ireq.i_val);
1682         }
1683
1684         ireq.i_type = IEEE80211_IOC_MCAST_RATE;
1685         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1686                 if (ireq.i_val != 2*1 || verbose) {
1687                         if (ireq.i_val == 11)
1688                                 LINE_CHECK("mcastrate 5.5");
1689                         else
1690                                 LINE_CHECK("mcastrate %d", ireq.i_val/2);
1691                 }
1692         }
1693
1694         ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
1695         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1696                 if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
1697                         LINE_CHECK("fragthreshold %d", ireq.i_val);
1698         }
1699
1700         ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
1701         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1702                 if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
1703                         LINE_CHECK("bmiss %d", ireq.i_val);
1704         }
1705
1706         if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
1707                 ireq.i_type = IEEE80211_IOC_PUREG;
1708                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1709                         if (ireq.i_val)
1710                                 LINE_CHECK("pureg");
1711                         else if (verbose)
1712                                 LINE_CHECK("-pureg");
1713                 }
1714                 ireq.i_type = IEEE80211_IOC_PROTMODE;
1715                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1716                         switch (ireq.i_val) {
1717                                 case IEEE80211_PROTMODE_OFF:
1718                                         LINE_CHECK("protmode OFF");
1719                                         break;
1720                                 case IEEE80211_PROTMODE_CTS:
1721                                         LINE_CHECK("protmode CTS");
1722                                         break;
1723                                 case IEEE80211_PROTMODE_RTSCTS:
1724                                         LINE_CHECK("protmode RTSCTS");
1725                                         break;
1726                                 default:
1727                                         LINE_CHECK("protmode UNKNOWN (0x%x)",
1728                                                 ireq.i_val);
1729                                         break;
1730                         }
1731                 }
1732         }
1733
1734         ireq.i_type = IEEE80211_IOC_WME;
1735         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1736                 wme = ireq.i_val;
1737                 if (wme)
1738                         LINE_CHECK("wme");
1739                 else if (verbose)
1740                         LINE_CHECK("-wme");
1741         } else
1742                 wme = 0;
1743
1744         ireq.i_type = IEEE80211_IOC_BURST;
1745         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1746                 if (ireq.i_val)
1747                         LINE_CHECK("burst");
1748                 else if (verbose)
1749                         LINE_CHECK("-burst");
1750         }
1751
1752         if (opmode == IEEE80211_M_HOSTAP) {
1753                 ireq.i_type = IEEE80211_IOC_HIDESSID;
1754                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1755                         if (ireq.i_val)
1756                                 LINE_CHECK("ssid HIDE");
1757                         else if (verbose)
1758                                 LINE_CHECK("ssid SHOW");
1759                 }
1760
1761                 ireq.i_type = IEEE80211_IOC_APBRIDGE;
1762                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1763                         if (!ireq.i_val)
1764                                 LINE_CHECK("-apbridge");
1765                         else if (verbose)
1766                                 LINE_CHECK("apbridge");
1767                 }
1768
1769                 ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
1770                 if (ioctl(s, SIOCG80211, &ireq) != -1)
1771                         LINE_CHECK("dtimperiod %u", ireq.i_val);
1772         } else {
1773                 ireq.i_type = IEEE80211_IOC_ROAMING;
1774                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1775                         if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
1776                                 switch (ireq.i_val) {
1777                                 case IEEE80211_ROAMING_DEVICE:
1778                                         LINE_CHECK("roaming DEVICE");
1779                                         break;
1780                                 case IEEE80211_ROAMING_AUTO:
1781                                         LINE_CHECK("roaming AUTO");
1782                                         break;
1783                                 case IEEE80211_ROAMING_MANUAL:
1784                                         LINE_CHECK("roaming MANUAL");
1785                                         break;
1786                                 default:
1787                                         LINE_CHECK("roaming UNKNOWN (0x%x)",
1788                                                 ireq.i_val);
1789                                         break;
1790                                 }
1791                         }
1792                 }
1793         }
1794         ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
1795         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1796                 if (ireq.i_val)
1797                         LINE_CHECK("bintval %u", ireq.i_val);
1798                 else if (verbose)
1799                         LINE_CHECK("bintval %u", ireq.i_val);
1800         }
1801
1802         if (wme && verbose) {
1803                 LINE_BREAK();
1804                 list_wme(s);
1805         }
1806
1807         if (wpa) {
1808                 ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
1809                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1810                         if (ireq.i_val)
1811                                 LINE_CHECK("countermeasures");
1812                         else if (verbose)
1813                                 LINE_CHECK("-countermeasures");
1814                 }
1815 #if 0
1816                 /* XXX not interesting with WPA done in user space */
1817                 ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
1818                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1819                 }
1820
1821                 ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
1822                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1823                         LINE_CHECK("mcastcipher ");
1824                         printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
1825                         spacer = ' ';
1826                 }
1827
1828                 ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
1829                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1830                         LINE_CHECK("ucastcipher ");
1831                         printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
1832                 }
1833
1834                 if (wpa & 2) {
1835                         ireq.i_type = IEEE80211_IOC_RSNCAPS;
1836                         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1837                                 LINE_CHECK("RSN caps 0x%x", ireq.i_val);
1838                                 spacer = ' ';
1839                         }
1840                 }
1841
1842                 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1843                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1844                 }
1845 #endif
1846                 LINE_BREAK();
1847         }
1848         LINE_BREAK();
1849
1850 end:
1851         return;
1852 }
1853
1854 static void
1855 set80211(int s, int type, int val, int len, u_int8_t *data)
1856 {
1857         struct ieee80211req     ireq;
1858
1859         (void) memset(&ireq, 0, sizeof(ireq));
1860         (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1861         ireq.i_type = type;
1862         ireq.i_val = val;
1863         ireq.i_len = len;
1864         ireq.i_data = data;
1865         if (ioctl(s, SIOCS80211, &ireq) < 0)
1866                 err(1, "SIOCS80211");
1867 }
1868
1869 static const char *
1870 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1871 {
1872         int len;
1873         int hexstr;
1874         u_int8_t *p;
1875
1876         len = *lenp;
1877         p = buf;
1878         hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1879         if (hexstr)
1880                 val += 2;
1881         for (;;) {
1882                 if (*val == '\0')
1883                         break;
1884                 if (sep != NULL && strchr(sep, *val) != NULL) {
1885                         val++;
1886                         break;
1887                 }
1888                 if (hexstr) {
1889                         if (!isxdigit((u_char)val[0])) {
1890                                 warnx("bad hexadecimal digits");
1891                                 return NULL;
1892                         }
1893                         if (!isxdigit((u_char)val[1])) {
1894                                 warnx("odd count hexadecimal digits");
1895                                 return NULL;
1896                         }
1897                 }
1898                 if (p >= buf + len) {
1899                         if (hexstr)
1900                                 warnx("hexadecimal digits too long");
1901                         else
1902                                 warnx("string too long");
1903                         return NULL;
1904                 }
1905                 if (hexstr) {
1906 #define tohex(x)        (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1907                         *p++ = (tohex((u_char)val[0]) << 4) |
1908                             tohex((u_char)val[1]);
1909 #undef tohex
1910                         val += 2;
1911                 } else
1912                         *p++ = *val++;
1913         }
1914         len = p - buf;
1915         /* The string "-" is treated as the empty string. */
1916         if (!hexstr && len == 1 && buf[0] == '-')
1917                 len = 0;
1918         if (len < *lenp)
1919                 memset(p, 0, *lenp - len);
1920         *lenp = len;
1921         return val;
1922 }
1923
1924 static void
1925 print_string(const u_int8_t *buf, int len)
1926 {
1927         int i;
1928         int hasspc;
1929
1930         i = 0;
1931         hasspc = 0;
1932         for (; i < len; i++) {
1933                 if (!isprint(buf[i]) && buf[i] != '\0')
1934                         break;
1935                 if (isspace(buf[i]))
1936                         hasspc++;
1937         }
1938         if (i == len) {
1939                 if (hasspc || len == 0 || buf[0] == '\0')
1940                         printf("\"%.*s\"", len, buf);
1941                 else
1942                         printf("%.*s", len, buf);
1943         } else {
1944                 printf("0x");
1945                 for (i = 0; i < len; i++)
1946                         printf("%02x", buf[i]);
1947         }
1948 }
1949
1950 static struct cmd ieee80211_cmds[] = {
1951         DEF_CMD_ARG("ssid",             set80211ssid),
1952         DEF_CMD_ARG("nwid",             set80211ssid),
1953         DEF_CMD_ARG("stationname",      set80211stationname),
1954         DEF_CMD_ARG("station",          set80211stationname),   /* BSD/OS */
1955         DEF_CMD_ARG("channel",          set80211channel),
1956         DEF_CMD_ARG("authmode",         set80211authmode),
1957         DEF_CMD_ARG("powersavemode",    set80211powersavemode),
1958         DEF_CMD("powersave",    1,      set80211powersave),
1959         DEF_CMD("-powersave",   0,      set80211powersave),
1960         DEF_CMD_ARG("powersavesleep",   set80211powersavesleep),
1961         DEF_CMD_ARG("wepmode",          set80211wepmode),
1962         DEF_CMD("wep",          1,      set80211wep),
1963         DEF_CMD("-wep",         0,      set80211wep),
1964         DEF_CMD_ARG("deftxkey",         set80211weptxkey),
1965         DEF_CMD_ARG("weptxkey",         set80211weptxkey),
1966         DEF_CMD_ARG("wepkey",           set80211wepkey),
1967         DEF_CMD_ARG("nwkey",            set80211nwkey),         /* NetBSD */
1968         DEF_CMD("-nwkey",       0,      set80211wep),           /* NetBSD */
1969         DEF_CMD_ARG("rtsthreshold",     set80211rtsthreshold),
1970         DEF_CMD_ARG("protmode",         set80211protmode),
1971         DEF_CMD_ARG("txpower",          set80211txpower),
1972         DEF_CMD_ARG("roaming",          set80211roaming),
1973         DEF_CMD("wme",          1,      set80211wme),
1974         DEF_CMD("-wme",         0,      set80211wme),
1975         DEF_CMD("hidessid",     1,      set80211hidessid),
1976         DEF_CMD("-hidessid",    0,      set80211hidessid),
1977         DEF_CMD("apbridge",     1,      set80211apbridge),
1978         DEF_CMD("-apbridge",    0,      set80211apbridge),
1979         DEF_CMD_ARG("chanlist",         set80211chanlist),
1980         DEF_CMD_ARG("bssid",            set80211bssid),
1981         DEF_CMD_ARG("ap",               set80211bssid),
1982         DEF_CMD("scan", 0,              set80211scan),
1983         DEF_CMD_ARG("list",             set80211list),
1984         DEF_CMD_ARG2("cwmin",           set80211cwmin),
1985         DEF_CMD_ARG2("cwmax",           set80211cwmax),
1986         DEF_CMD_ARG2("aifs",            set80211aifs),
1987         DEF_CMD_ARG2("txoplimit",       set80211txoplimit),
1988         DEF_CMD_ARG("acm",              set80211acm),
1989         DEF_CMD_ARG("-acm",             set80211noacm),
1990         DEF_CMD_ARG("ack",              set80211ackpolicy),
1991         DEF_CMD_ARG("-ack",             set80211noackpolicy),
1992         DEF_CMD_ARG2("bss:cwmin",       set80211bsscwmin),
1993         DEF_CMD_ARG2("bss:cwmax",       set80211bsscwmax),
1994         DEF_CMD_ARG2("bss:aifs",        set80211bssaifs),
1995         DEF_CMD_ARG2("bss:txoplimit",   set80211bsstxoplimit),
1996         DEF_CMD_ARG("dtimperiod",       set80211dtimperiod),
1997         DEF_CMD_ARG("bintval",          set80211bintval),
1998         DEF_CMD("mac:open",     IEEE80211_MACCMD_POLICY_OPEN,   set80211maccmd),
1999         DEF_CMD("mac:allow",    IEEE80211_MACCMD_POLICY_ALLOW,  set80211maccmd),
2000         DEF_CMD("mac:deny",     IEEE80211_MACCMD_POLICY_DENY,   set80211maccmd),
2001         DEF_CMD("mac:flush",    IEEE80211_MACCMD_FLUSH,         set80211maccmd),
2002         DEF_CMD("mac:detach",   IEEE80211_MACCMD_DETACH,        set80211maccmd),
2003         DEF_CMD_ARG("mac:add",          set80211addmac),
2004         DEF_CMD_ARG("mac:del",          set80211delmac),
2005         DEF_CMD_ARG("mac:kick",         set80211kickmac),
2006         DEF_CMD("pureg",        1,      set80211pureg),
2007         DEF_CMD("-pureg",       0,      set80211pureg),
2008         DEF_CMD_ARG("mcastrate",        set80211mcastrate),
2009         DEF_CMD_ARG("fragthreshold",    set80211fragthreshold),
2010         DEF_CMD("burst",        1,      set80211burst),
2011         DEF_CMD("-burst",       0,      set80211burst),
2012         DEF_CMD_ARG("bmiss",            set80211bmissthreshold),
2013         DEF_CMD_ARG("bmissthreshold",   set80211bmissthreshold),
2014 };
2015 static struct afswtch af_ieee80211 = {
2016         .af_name        = "af_ieee80211",
2017         .af_af          = AF_UNSPEC,
2018         .af_other_status = ieee80211_status,
2019 };
2020
2021 static __constructor void
2022 ieee80211_ctor(void)
2023 {
2024 #define N(a)    (sizeof(a) / sizeof(a[0]))
2025         int i;
2026
2027         for (i = 0; i < N(ieee80211_cmds);  i++)
2028                 cmd_register(&ieee80211_cmds[i]);
2029         af_register(&af_ieee80211);
2030 #undef N
2031 }