Upgrade to OpenSSH 4.6p1.
[dragonfly.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: 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 $
29  */
30
31 /*-
32  * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
33  * All rights reserved.
34  *
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.
38  *
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.
54  *
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.
66  */
67
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>
73
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>
80
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>
85
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>
96
97 #include "ifconfig.h"
98
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);
103
104 static int
105 isanyarg(const char *arg)
106 {
107         return (strcmp(arg, "-") == 0 ||
108             strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
109 }
110
111 static void
112 set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
113 {
114         int             ssid;
115         int             len;
116         u_int8_t        data[IEEE80211_NWID_LEN];
117
118         ssid = 0;
119         len = strlen(val);
120         if (len > 2 && isdigit(val[0]) && val[1] == ':') {
121                 ssid = atoi(val)-1;
122                 val += 2;
123         }
124
125         bzero(data, sizeof(data));
126         len = sizeof(data);
127         if (get_string(val, NULL, data, &len) == NULL)
128                 exit(1);
129
130         set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
131 }
132
133 static void
134 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
135 {
136         int                     len;
137         u_int8_t                data[33];
138
139         bzero(data, sizeof(data));
140         len = sizeof(data);
141         get_string(val, NULL, data, &len);
142
143         set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
144 }
145
146 /*
147  * Convert IEEE channel number to MHz frequency.
148  */
149 static u_int
150 ieee80211_ieee2mhz(u_int chan)
151 {
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);
159 }
160
161 /*
162  * Convert MHz frequency to IEEE channel number.
163  */
164 static u_int
165 ieee80211_mhz2ieee(u_int freq)
166 {
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;
174 }
175
176 static void
177 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
178 {
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);
186 }
187
188 static void
189 set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
190 {
191         int     mode;
192
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");
205         }
206
207         set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
208 }
209
210 static void
211 set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
212 {
213         int     mode;
214
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");
227         }
228
229         set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
230 }
231
232 static void
233 set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
234 {
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);
241 }
242
243 static void
244 set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
245 {
246         set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
247 }
248
249 static void
250 set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
251 {
252         int     mode;
253
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");
262         }
263
264         set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
265 }
266
267 static void
268 set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
269 {
270         set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
271 }
272
273 static int
274 isundefarg(const char *arg)
275 {
276         return (strcmp(arg, "-") == 0 || strncasecmp(arg, "undef", 5) == 0);
277 }
278
279 static void
280 set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
281 {
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);
286 }
287
288 static void
289 set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
290 {
291         int             key = 0;
292         int             len;
293         u_int8_t        data[IEEE80211_KEYBUF_SIZE];
294
295         if (isdigit(val[0]) && val[1] == ':') {
296                 key = atoi(val)-1;
297                 val += 2;
298         }
299
300         bzero(data, sizeof(data));
301         len = sizeof(data);
302         get_string(val, NULL, data, &len);
303
304         set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
305 }
306
307 /*
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.
311  */
312 static void
313 set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
314 {
315         int             txkey;
316         int             i, len;
317         u_int8_t        data[IEEE80211_KEYBUF_SIZE];
318
319         set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
320
321         if (isdigit(val[0]) && val[1] == ':') {
322                 txkey = val[0]-'0'-1;
323                 val += 2;
324
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);
331
332                         set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
333                 }
334         } else {
335                 bzero(data, sizeof(data));
336                 len = sizeof(data);
337                 get_string(val, NULL, data, &len);
338                 txkey = 0;
339
340                 set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
341
342                 bzero(data, sizeof(data));
343                 for (i = 1; i < 4; i++)
344                         set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
345         }
346
347         set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
348 }
349
350 static void
351 set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
352 {
353         set80211(s, IEEE80211_IOC_RTSTHRESHOLD,
354                 isundefarg(val) ? IEEE80211_RTS_MAX : atoi(val), 0, NULL);
355 }
356
357 static void
358 set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
359 {
360         int     mode;
361
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");
370         }
371
372         set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
373 }
374
375 static void
376 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
377 {
378         set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
379 }
380
381 #define IEEE80211_ROAMING_DEVICE        0
382 #define IEEE80211_ROAMING_AUTO          1
383 #define IEEE80211_ROAMING_MANUAL        2
384
385 static void
386 set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
387 {
388         int mode;
389
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");
398         }
399         set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
400 }
401
402 static void
403 set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
404 {
405         set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
406 }
407
408 static void
409 set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
410 {
411         set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
412 }
413
414 static void
415 set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
416 {
417         set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
418 }
419
420 static void
421 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
422 {
423         struct ieee80211req_chanlist chanlist;
424 #define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
425         char *temp, *cp, *tp;
426
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;
435
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;
459                 }
460                 if (tp == NULL)
461                         break;
462                 while (isspace(*tp))
463                         tp++;
464                 if (!isdigit(*tp))
465                         break;
466                 cp = tp;
467         }
468         set80211(s, IEEE80211_IOC_CHANLIST, 0,
469                 sizeof(chanlist), (uint8_t *) &chanlist);
470 #undef MAXCHAN
471 }
472
473 static void
474 set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
475 {
476
477         if (!isanyarg(val)) {
478                 char *temp;
479                 struct sockaddr_dl sdl;
480
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);
498         }
499 }
500
501 static int
502 getac(const char *ac)
503 {
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);
513 }
514
515 static
516 DECL_CMD_FUNC2(set80211cwmin, ac, val)
517 {
518         set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
519 }
520
521 static
522 DECL_CMD_FUNC2(set80211cwmax, ac, val)
523 {
524         set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
525 }
526
527 static
528 DECL_CMD_FUNC2(set80211aifs, ac, val)
529 {
530         set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
531 }
532
533 static
534 DECL_CMD_FUNC2(set80211txoplimit, ac, val)
535 {
536         set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
537 }
538
539 static
540 DECL_CMD_FUNC(set80211acm, ac, d)
541 {
542         set80211(s, IEEE80211_IOC_WME_ACM, 1, getac(ac), NULL);
543 }
544 static
545 DECL_CMD_FUNC(set80211noacm, ac, d)
546 {
547         set80211(s, IEEE80211_IOC_WME_ACM, 0, getac(ac), NULL);
548 }
549
550 static
551 DECL_CMD_FUNC(set80211ackpolicy, ac, d)
552 {
553         set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 1, getac(ac), NULL);
554 }
555 static
556 DECL_CMD_FUNC(set80211noackpolicy, ac, d)
557 {
558         set80211(s, IEEE80211_IOC_WME_ACKPOLICY, 0, getac(ac), NULL);
559 }
560
561 static
562 DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
563 {
564         set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
565                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
566 }
567
568 static
569 DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
570 {
571         set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
572                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
573 }
574
575 static
576 DECL_CMD_FUNC2(set80211bssaifs, ac, val)
577 {
578         set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
579                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
580 }
581
582 static
583 DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
584 {
585         set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
586                 getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
587 }
588
589 static
590 DECL_CMD_FUNC(set80211dtimperiod, val, d)
591 {
592         set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
593 }
594
595 static
596 DECL_CMD_FUNC(set80211bintval, val, d)
597 {
598         set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
599 }
600
601 static void
602 set80211macmac(int s, int op, const char *val)
603 {
604         char *temp;
605         struct sockaddr_dl sdl;
606
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));
618 }
619
620 static
621 DECL_CMD_FUNC(set80211addmac, val, d)
622 {
623         set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
624 }
625
626 static
627 DECL_CMD_FUNC(set80211delmac, val, d)
628 {
629         set80211macmac(s, IEEE80211_IOC_DELMAC, val);
630 }
631
632 static
633 DECL_CMD_FUNC(set80211kickmac, val, d)
634 {
635         char *temp;
636         struct sockaddr_dl sdl;
637         struct ieee80211req_mlme mlme;
638
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);
654 }
655
656 static
657 DECL_CMD_FUNC(set80211maccmd, val, d)
658 {
659         set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
660 }
661
662 static void
663 set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
664 {
665         set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
666 }
667
668 static void
669 set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
670 {
671         set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
672 }
673
674 static void
675 set80211ratectl(const char *val, int d, int s, const struct afswtch *rafp)
676 {
677         int ratectl = 0;
678
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");
685
686         set80211(s, IEEE80211_IOC_RATECTL, ratectl, 0, NULL);
687 }
688
689 static
690 DECL_CMD_FUNC(set80211mcastrate, val, d)
691 {
692         set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
693 }
694
695 static
696 DECL_CMD_FUNC(set80211fragthreshold, val, d)
697 {
698         set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
699                 isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
700 }
701
702 static
703 DECL_CMD_FUNC(set80211bmissthreshold, val, d)
704 {
705         set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
706                 isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
707 }
708
709 static int
710 getmaxrate(uint8_t rates[15], uint8_t nrates)
711 {
712         int i, maxrate = -1;
713
714         for (i = 0; i < nrates; i++) {
715                 int rate = rates[i] & IEEE80211_RATE_VAL;
716                 if (rate > maxrate)
717                         maxrate = rate;
718         }
719         return maxrate / 2;
720 }
721
722 static const char *
723 getcaps(int capinfo)
724 {
725         static char capstring[32];
726         char *cp = capstring;
727
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;
752 }
753
754 static void
755 printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
756 {
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);
767                 }
768                 if (ielen != 0)
769                         printf("-");
770                 printf(">");
771         }
772 }
773
774 /*
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 "...".
779  */
780 static int
781 copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
782 {
783         const u_int8_t *p; 
784         size_t maxlen;
785         int i;
786
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;
795         }
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;
805                 }
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);
812         }
813         return maxlen;
814 }
815
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)))
823
824 static int __inline
825 iswpaoui(const u_int8_t *frm)
826 {
827         return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
828 }
829
830 static int __inline
831 iswmeoui(const u_int8_t *frm)
832 {
833         return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
834 }
835
836 static int __inline
837 isatherosoui(const u_int8_t *frm)
838 {
839         return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
840 }
841
842 static void
843 printies(const u_int8_t *vp, int ielen, int maxcols)
844 {
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;
863                 }
864                 ielen -= 2+vp[1];
865                 vp += 2+vp[1];
866         }
867 }
868
869 static void
870 list_scan(int s)
871 {
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;
877
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;
888
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"
898         );
899         cp = buf;
900         do {
901                 struct ieee80211req_scan_result *sr;
902                 uint8_t *vp;
903
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)
916                 );
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));
921 }
922
923 #include <netproto/802_11/ieee80211_dragonfly.h>
924
925 static void
926 scan_and_wait(int s)
927 {
928         struct ieee80211req ireq;
929         int sroute;
930
931         sroute = socket(PF_ROUTE, SOCK_RAW, 0);
932         if (sroute < 0) {
933                 perror("socket(PF_ROUTE,SOCK_RAW)");
934                 return;
935         }
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;
944
945                 do {
946                         if (read(sroute, buf, sizeof(buf)) < 0) {
947                                 perror("read(PF_ROUTE)");
948                                 break;
949                         }
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);
956         }
957         close(sroute);
958 }
959
960 static
961 DECL_CMD_FUNC(set80211scan, val, d)
962 {
963         scan_and_wait(s);
964         list_scan(s);
965 }
966
967 static enum ieee80211_opmode get80211opmode(int s);
968
969 static void
970 list_stations(int s)
971 {
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;
980
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) {
986                 /*
987                  * Get information about the associated AP.
988                  */
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);
993         }
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;
1002
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"
1014         );
1015         cp = (uint8_t *) u.req.info;
1016         do {
1017                 struct ieee80211req_sta_info *si;
1018                 uint8_t *vp;
1019
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
1035                 );
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));
1040 }
1041
1042 static void
1043 print_chaninfo(const struct ieee80211_channel *c)
1044 {
1045 #define IEEE80211_IS_CHAN_PASSIVE(_c) \
1046         (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
1047         char buf[14];
1048
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
1066 }
1067
1068 static void
1069 list_channels(int s, int allchans)
1070 {
1071         struct ieee80211req ireq;
1072         struct ieee80211req_chaninfo chans;
1073         struct ieee80211req_chaninfo achans;
1074         const struct ieee80211_channel *c;
1075         int i, half;
1076
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;
1086
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;
1097                 }
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");
1107         }
1108         if (achans.ic_nchans % 2) {
1109                 print_chaninfo(&achans.ic_chans[i]);
1110                 printf("\n");
1111         }
1112 }
1113
1114 static void
1115 list_keys(int s)
1116 {
1117 }
1118
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"
1123
1124 #define IEEE80211_CEXT_BITS     "\020\1PBCC"
1125
1126 static void
1127 list_capabilities(int s)
1128 {
1129         struct ieee80211req ireq;
1130         uint32_t caps, caps_ext;
1131
1132         memset(&ireq, 0, sizeof(ireq));
1133         caps_ext = 0;
1134
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');
1146 }
1147
1148 static void
1149 list_wme(int s)
1150 {
1151         static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
1152         struct ieee80211req ireq;
1153         int ac;
1154
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]);
1164
1165                 ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
1166
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");
1186                 }
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");
1195                         }
1196                 }
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;
1203         }
1204 }
1205
1206 static void
1207 list_mac(int s)
1208 {
1209         struct ieee80211req ireq;
1210         struct ieee80211req_maclist *acllist;
1211         int i, nacls, policy;
1212         char c;
1213
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;
1222                 }
1223                 err(1, "unable to get mac policy");
1224         }
1225         policy = ireq.i_val;
1226
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;
1233
1234         ireq.i_data = malloc(ireq.i_len);
1235         if (ireq.i_data == NULL)
1236                 err(1, "out of memory for acl list");
1237
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 = '?';
1255         }
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));
1261 }
1262
1263 static
1264 DECL_CMD_FUNC(set80211list, arg, d)
1265 {
1266 #define iseq(a,b)       (strncasecmp(a,b,sizeof(b)-1) == 0)
1267
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
1287 }
1288
1289 static enum ieee80211_opmode
1290 get80211opmode(int s)
1291 {
1292         struct ifmediareq ifmr;
1293
1294         (void) memset(&ifmr, 0, sizeof(ifmr));
1295         (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1296
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;
1304         }
1305         return IEEE80211_M_STA;
1306 }
1307
1308 static const struct ieee80211_channel *
1309 getchaninfo(int s, int chan)
1310 {
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;
1316
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;
1329         }
1330         return &undef;
1331 }
1332
1333 #if 0
1334 static void
1335 printcipher(int s, struct ieee80211req *ireq, int keylenop)
1336 {
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;
1365         }
1366 }
1367 #endif
1368
1369 #define MAXCOL  78
1370 static  int col;
1371 static  char spacer;
1372
1373 static void
1374 LINE_BREAK(void)
1375 {
1376         if (spacer != '\t') {
1377                 printf("\n");
1378                 spacer = '\t';
1379         }
1380         col = 8;        /* 8-col tab */
1381 }
1382
1383 static void
1384 LINE_CHECK(const char *fmt, ...)
1385 {
1386         char buf[80];
1387         va_list ap;
1388         int n;
1389
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;
1397         }
1398         buf[0] = spacer;
1399         printf("%s", buf);
1400         spacer = ' ';
1401 }
1402
1403 static void
1404 printkey(const struct ieee80211req_key *ik)
1405 {
1406         static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
1407         int keylen = ik->ik_keylen;
1408         int printcontents;
1409
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;
1442         }
1443         if (printcontents) {
1444                 int i;
1445
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 = " ";
1458
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 = "+";
1465                 }
1466                 LINE_BREAK();
1467         }
1468 }
1469
1470 static void
1471 ieee80211_status(int s)
1472 {
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;
1479
1480         (void) memset(&ireq, 0, sizeof(ireq));
1481         (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
1482         ireq.i_data = &data;
1483
1484         wpa = 0;                /* unknown/not set */
1485
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;
1491         }
1492
1493         ireq.i_type = IEEE80211_IOC_RATECTL;
1494         if (ioctl(s, SIOCG80211, &ireq) != -1) {
1495                 int lineb = 1;
1496
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;
1510                 }
1511                 if (lineb)
1512                         LINE_BREAK();
1513         }
1514
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);
1526                         }
1527                 }
1528         } else
1529                 print_string(data, ireq.i_len);
1530
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");
1541
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));
1547
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);
1552         }
1553
1554         spacer = ' ';           /* force first break */
1555         LINE_BREAK();
1556
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;
1588                                 }
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;
1597                 }
1598         }
1599
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;
1604
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;
1619                 }
1620
1621                 /*
1622                  * If we get here then we've got WEP support so we need
1623                  * to print WEP status.
1624                  */
1625
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;
1630                 }
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");
1635
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;
1640                 }
1641                 num = ireq.i_val;
1642
1643                 firstkey = 1;
1644                 for (i = 0; i < num; i++) {
1645                         struct ieee80211req_key ik;
1646
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;
1655                         }
1656                         if (ik.ik_keylen != 0) {
1657                                 if (verbose)
1658                                         LINE_BREAK();
1659                                 printkey(&ik);
1660                                 firstkey = 0;
1661                         }
1662                 }
1663         }
1664
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;
1682                         }
1683                         ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
1684                         if (ioctl(s, SIOCG80211, &ireq) != -1)
1685                                 LINE_CHECK("powersavesleep %d", ireq.i_val);
1686                 }
1687         }
1688
1689         ireq.i_type = IEEE80211_IOC_TXPOWMAX;
1690         if (ioctl(s, SIOCG80211, &ireq) != -1)
1691                 LINE_CHECK("txpowmax %d", ireq.i_val);
1692
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);
1697         }
1698
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);
1703         }
1704
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);
1712                 }
1713         }
1714
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);
1719         }
1720
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);
1725         }
1726
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");
1734                 }
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;
1751                         }
1752                 }
1753         }
1754
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;
1764
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");
1771         }
1772
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");
1780                 }
1781
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");
1788                 }
1789
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;
1811                                 }
1812                         }
1813                 }
1814         }
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);
1821         }
1822
1823         if (wme && verbose) {
1824                 LINE_BREAK();
1825                 list_wme(s);
1826         }
1827
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");
1835                 }
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) {
1840                 }
1841
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 = ' ';
1847                 }
1848
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);
1853                 }
1854
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 = ' ';
1860                         }
1861                 }
1862
1863                 ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
1864                 if (ioctl(s, SIOCG80211, &ireq) != -1) {
1865                 }
1866 #endif
1867                 LINE_BREAK();
1868         }
1869         LINE_BREAK();
1870
1871 end:
1872         return;
1873 }
1874
1875 static void
1876 set80211(int s, int type, int val, int len, u_int8_t *data)
1877 {
1878         struct ieee80211req     ireq;
1879
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");
1888 }
1889
1890 static const char *
1891 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1892 {
1893         int len;
1894         int hexstr;
1895         u_int8_t *p;
1896
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;
1908                 }
1909                 if (hexstr) {
1910                         if (!isxdigit((u_char)val[0])) {
1911                                 warnx("bad hexadecimal digits");
1912                                 return NULL;
1913                         }
1914                         if (!isxdigit((u_char)val[1])) {
1915                                 warnx("odd count hexadecimal digits");
1916                                 return NULL;
1917                         }
1918                 }
1919                 if (p >= buf + len) {
1920                         if (hexstr)
1921                                 warnx("hexadecimal digits too long");
1922                         else
1923                                 warnx("string too long");
1924                         return NULL;
1925                 }
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++;
1934         }
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;
1943 }
1944
1945 static void
1946 print_string(const u_int8_t *buf, int len)
1947 {
1948         int i;
1949         int hasspc;
1950
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++;
1958         }
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]);
1968         }
1969 }
1970
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)
2036 };
2037 static struct afswtch af_ieee80211 = {
2038         .af_name        = "af_ieee80211",
2039         .af_af          = AF_UNSPEC,
2040         .af_other_status = ieee80211_status,
2041 };
2042
2043 static __constructor void
2044 ieee80211_ctor(void)
2045 {
2046 #define N(a)    (sizeof(a) / sizeof(a[0]))
2047         int i;
2048
2049         for (i = 0; i < N(ieee80211_cmds);  i++)
2050                 cmd_register(&ieee80211_cmds[i]);
2051         af_register(&af_ieee80211);
2052 #undef N
2053 }