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