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