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