ifieee80211.c revision 120178
1247841Sbapt/*
2247841Sbapt * Copyright 2001 The Aerospace Corporation.  All rights reserved.
3247841Sbapt *
4247841Sbapt * Redistribution and use in source and binary forms, with or without
5247841Sbapt * modification, are permitted provided that the following conditions
6247841Sbapt * are met:
7247841Sbapt * 1. Redistributions of source code must retain the above copyright
8247841Sbapt *    notice, this list of conditions and the following disclaimer.
9247841Sbapt * 2. Redistributions in binary form must reproduce the above copyright
10247841Sbapt *    notice, this list of conditions and the following disclaimer in the
11247841Sbapt *    documentation and/or other materials provided with the distribution.
12247841Sbapt * 3. The name of The Aerospace Corporation may not be used to endorse or
13247841Sbapt *    promote products derived from this software.
14247841Sbapt *
15247841Sbapt * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
16247841Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17247841Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18247841Sbapt * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
19247841Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20247841Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21247841Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22247841Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23247841Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24247841Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25247841Sbapt * SUCH DAMAGE.
26247841Sbapt *
27247841Sbapt * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 120178 2003-09-17 19:27:43Z sam $
28247841Sbapt */
29247841Sbapt
30247841Sbapt/*-
31247841Sbapt * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
32247841Sbapt * All rights reserved.
33247841Sbapt *
34247841Sbapt * This code is derived from software contributed to The NetBSD Foundation
35247841Sbapt * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
36247841Sbapt * NASA Ames Research Center.
37247841Sbapt *
38247841Sbapt * Redistribution and use in source and binary forms, with or without
39247841Sbapt * modification, are permitted provided that the following conditions
40247841Sbapt * are met:
41247841Sbapt * 1. Redistributions of source code must retain the above copyright
42247841Sbapt *    notice, this list of conditions and the following disclaimer.
43247841Sbapt * 2. Redistributions in binary form must reproduce the above copyright
44247841Sbapt *    notice, this list of conditions and the following disclaimer in the
45247841Sbapt *    documentation and/or other materials provided with the distribution.
46247841Sbapt * 3. All advertising materials mentioning features or use of this software
47247841Sbapt *    must display the following acknowledgement:
48247841Sbapt *	This product includes software developed by the NetBSD
49247841Sbapt *	Foundation, Inc. and its contributors.
50247841Sbapt * 4. Neither the name of The NetBSD Foundation nor the names of its
51247841Sbapt *    contributors may be used to endorse or promote products derived
52247841Sbapt *    from this software without specific prior written permission.
53247841Sbapt *
54247841Sbapt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
55247841Sbapt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56247841Sbapt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57247841Sbapt * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
58247841Sbapt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59247841Sbapt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60247841Sbapt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61247841Sbapt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62247841Sbapt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63247841Sbapt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64247841Sbapt * POSSIBILITY OF SUCH DAMAGE.
65247841Sbapt */
66247841Sbapt
67247841Sbapt#include <sys/param.h>
68247841Sbapt#include <sys/ioctl.h>
69247841Sbapt#include <sys/socket.h>
70247841Sbapt#include <sys/sysctl.h>
71247841Sbapt#include <sys/time.h>
72247841Sbapt
73247841Sbapt#include <net/ethernet.h>
74247841Sbapt#include <net/if.h>
75247841Sbapt#include <net/if_dl.h>
76247841Sbapt#include <net/if_types.h>
77247841Sbapt#include <net/route.h>
78247841Sbapt#include <net80211/ieee80211.h>
79247841Sbapt#include <net80211/ieee80211_crypto.h>
80247841Sbapt#include <net80211/ieee80211_ioctl.h>
81247841Sbapt
82247841Sbapt#include <ctype.h>
83247841Sbapt#include <err.h>
84247841Sbapt#include <errno.h>
85247841Sbapt#include <fcntl.h>
86247841Sbapt#include <stdio.h>
87247841Sbapt#include <stdlib.h>
88247841Sbapt#include <string.h>
89247841Sbapt#include <unistd.h>
90247841Sbapt
91247841Sbapt#include "ifconfig.h"
92247841Sbapt
93247841Sbaptstatic void set80211(int s, int type, int val, int len, u_int8_t *data);
94247841Sbaptstatic const char *get_string(const char *val, const char *sep,
95247841Sbapt    u_int8_t *buf, int *lenp);
96247841Sbaptstatic void print_string(const u_int8_t *buf, int len);
97247841Sbapt
98247841Sbaptvoid
99247841Sbaptset80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
100247841Sbapt{
101247841Sbapt	int		ssid;
102247841Sbapt	int		len;
103247841Sbapt	u_int8_t	data[33];
104247841Sbapt
105247841Sbapt	ssid = 0;
106247841Sbapt	len = sizeof(val);
107247841Sbapt	if (len > 2 && isdigit(val[0]) && val[1] == ':') {
108247841Sbapt		ssid = atoi(val)-1;
109247841Sbapt		val += 2;
110247841Sbapt	}
111247841Sbapt
112247841Sbapt	bzero(data, sizeof(data));
113247841Sbapt	len = sizeof(data);
114247841Sbapt	get_string(val, NULL, data, &len);
115247841Sbapt
116247841Sbapt	set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
117247841Sbapt}
118247841Sbapt
119247841Sbaptvoid
120247841Sbaptset80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
121247841Sbapt{
122247841Sbapt	int			len;
123247841Sbapt	u_int8_t		data[33];
124247841Sbapt
125247841Sbapt	bzero(data, sizeof(data));
126247841Sbapt	len = sizeof(data);
127247841Sbapt	get_string(val, NULL, data, &len);
128247841Sbapt
129247841Sbapt	set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
130247841Sbapt}
131247841Sbapt
132247841Sbaptvoid
133247841Sbaptset80211channel(const char *val, int d, int s, const struct afswtch *rafp)
134247841Sbapt{
135247841Sbapt	if (strcmp(val, "-") == 0)
136247841Sbapt		set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
137247841Sbapt	else
138247841Sbapt		set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
139247841Sbapt}
140247841Sbapt
141247841Sbaptvoid
142247841Sbaptset80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
143247841Sbapt{
144247841Sbapt	int	mode;
145247841Sbapt
146247841Sbapt	if (strcasecmp(val, "none") == 0) {
147247841Sbapt		mode = IEEE80211_AUTH_NONE;
148247841Sbapt	} else if (strcasecmp(val, "open") == 0) {
149247841Sbapt		mode = IEEE80211_AUTH_OPEN;
150247841Sbapt	} else if (strcasecmp(val, "shared") == 0) {
151247841Sbapt		mode = IEEE80211_AUTH_SHARED;
152247841Sbapt	} else {
153247841Sbapt		err(1, "unknown authmode");
154247841Sbapt	}
155247841Sbapt
156247841Sbapt	set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
157247841Sbapt}
158247841Sbapt
159247841Sbaptvoid
160247841Sbaptset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
161247841Sbapt{
162247841Sbapt	int	mode;
163247841Sbapt
164247841Sbapt	if (strcasecmp(val, "off") == 0) {
165247841Sbapt		mode = IEEE80211_POWERSAVE_OFF;
166247841Sbapt	} else if (strcasecmp(val, "on") == 0) {
167247841Sbapt		mode = IEEE80211_POWERSAVE_ON;
168247841Sbapt	} else if (strcasecmp(val, "cam") == 0) {
169247841Sbapt		mode = IEEE80211_POWERSAVE_CAM;
170247841Sbapt	} else if (strcasecmp(val, "psp") == 0) {
171247841Sbapt		mode = IEEE80211_POWERSAVE_PSP;
172247841Sbapt	} else if (strcasecmp(val, "psp-cam") == 0) {
173247841Sbapt		mode = IEEE80211_POWERSAVE_PSP_CAM;
174247841Sbapt	} else {
175247841Sbapt		err(1, "unknown powersavemode");
176247841Sbapt	}
177247841Sbapt
178247841Sbapt	set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
179247841Sbapt}
180247841Sbapt
181247841Sbaptvoid
182247841Sbaptset80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
183247841Sbapt{
184247841Sbapt	if (d == 0)
185247841Sbapt		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
186247841Sbapt		    0, NULL);
187247841Sbapt	else
188247841Sbapt		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
189247841Sbapt		    0, NULL);
190247841Sbapt}
191247841Sbapt
192247841Sbaptvoid
193247841Sbaptset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
194247841Sbapt{
195247841Sbapt	set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
196247841Sbapt}
197247841Sbapt
198247841Sbaptvoid
199247841Sbaptset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
200247841Sbapt{
201247841Sbapt	int	mode;
202247841Sbapt
203247841Sbapt	if (strcasecmp(val, "off") == 0) {
204247841Sbapt		mode = IEEE80211_WEP_OFF;
205247841Sbapt	} else if (strcasecmp(val, "on") == 0) {
206247841Sbapt		mode = IEEE80211_WEP_ON;
207247841Sbapt	} else if (strcasecmp(val, "mixed") == 0) {
208247841Sbapt		mode = IEEE80211_WEP_MIXED;
209247841Sbapt	} else {
210247841Sbapt		err(1, "unknown wep mode");
211247841Sbapt	}
212247841Sbapt
213247841Sbapt	set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
214247841Sbapt}
215247841Sbapt
216247841Sbaptvoid
217247841Sbaptset80211wep(const char *val, int d, int s, const struct afswtch *rafp)
218247841Sbapt{
219247841Sbapt	set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
220247841Sbapt}
221247841Sbapt
222247841Sbaptvoid
223247841Sbaptset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
224247841Sbapt{
225247841Sbapt	set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
226247841Sbapt}
227247841Sbapt
228247841Sbaptvoid
229247841Sbaptset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
230247841Sbapt{
231247841Sbapt	int		key = 0;
232247841Sbapt	int		len;
233247841Sbapt	u_int8_t	data[IEEE80211_KEYBUF_SIZE];
234247841Sbapt
235247841Sbapt	if (isdigit(val[0]) && val[1] == ':') {
236247841Sbapt		key = atoi(val)-1;
237247841Sbapt		val += 2;
238247841Sbapt	}
239247841Sbapt
240247841Sbapt	bzero(data, sizeof(data));
241247841Sbapt	len = sizeof(data);
242247841Sbapt	get_string(val, NULL, data, &len);
243247841Sbapt
244247841Sbapt	set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
245247841Sbapt}
246247841Sbapt
247247841Sbapt/*
248247841Sbapt * This function is purly a NetBSD compatability interface.  The NetBSD
249247841Sbapt * iterface is too inflexable, but it's there so we'll support it since
250247841Sbapt * it's not all that hard.
251247841Sbapt */
252247841Sbaptvoid
253247841Sbaptset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
254247841Sbapt{
255247841Sbapt	int		txkey;
256247841Sbapt	int		i, len;
257247841Sbapt	u_int8_t	data[IEEE80211_KEYBUF_SIZE];
258247841Sbapt
259247841Sbapt	set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
260247841Sbapt
261247841Sbapt	if (isdigit(val[0]) && val[1] == ':') {
262247841Sbapt		txkey = val[0]-'0'-1;
263247841Sbapt		val += 2;
264247841Sbapt
265247841Sbapt		for (i = 0; i < 4; i++) {
266247841Sbapt			bzero(data, sizeof(data));
267247841Sbapt			len = sizeof(data);
268247841Sbapt			val = get_string(val, ",", data, &len);
269247841Sbapt
270247841Sbapt			set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
271247841Sbapt		}
272247841Sbapt	} else {
273247841Sbapt		bzero(data, sizeof(data));
274247841Sbapt		len = sizeof(data);
275247841Sbapt		get_string(val, NULL, data, &len);
276247841Sbapt		txkey = 0;
277247841Sbapt
278247841Sbapt		set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
279247841Sbapt
280247841Sbapt		bzero(data, sizeof(data));
281247841Sbapt		for (i = 1; i < 4; i++)
282247841Sbapt			set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
283247841Sbapt	}
284247841Sbapt
285247841Sbapt	set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
286247841Sbapt}
287247841Sbapt
288247841Sbaptvoid
289247841Sbaptieee80211_status (int s, struct rt_addrinfo *info __unused)
290247841Sbapt{
291247841Sbapt	int			i;
292247841Sbapt	int			num;
293247841Sbapt	struct ieee80211req	ireq;
294247841Sbapt	u_int8_t		data[32];
295247841Sbapt	char			spacer;
296247841Sbapt
297247841Sbapt	(void) memset(&ireq, 0, sizeof(ireq));
298247841Sbapt	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
299247841Sbapt	ireq.i_data = &data;
300247841Sbapt
301247841Sbapt	ireq.i_type = IEEE80211_IOC_SSID;
302247841Sbapt	ireq.i_val = -1;
303247841Sbapt	if (ioctl(s, SIOCG80211, &ireq) < 0) {
304247841Sbapt		/* If we can't get the SSID, the this isn't an 802.11 device. */
305247841Sbapt		return;
306247841Sbapt	}
307247841Sbapt	printf("\tssid ");
308247841Sbapt	print_string(data, ireq.i_len);
309247841Sbapt	num = 0;
310247841Sbapt	ireq.i_type = IEEE80211_IOC_NUMSSIDS;
311247841Sbapt	if (ioctl(s, SIOCG80211, &ireq) >= 0) {
312247841Sbapt		num = ireq.i_val;
313247841Sbapt	}
314247841Sbapt	ireq.i_type = IEEE80211_IOC_SSID;
315247841Sbapt	for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
316247841Sbapt		if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
317247841Sbapt			printf(" %d:", ireq.i_val + 1);
318247841Sbapt			print_string(data, ireq.i_len);
319247841Sbapt		}
320247841Sbapt	}
321247841Sbapt	printf("\n");
322247841Sbapt
323247841Sbapt	ireq.i_type = IEEE80211_IOC_STATIONNAME;
324247841Sbapt	if (ioctl(s, SIOCG80211, &ireq) != -1) {
325247841Sbapt		printf("\tstationname ");
326247841Sbapt		print_string(data, ireq.i_len);
327247841Sbapt		printf("\n");
328247841Sbapt	}
329247841Sbapt
330247841Sbapt	ireq.i_type = IEEE80211_IOC_CHANNEL;
331247841Sbapt	if (ioctl(s, SIOCG80211, &ireq) < 0) {
332247841Sbapt		goto end;
333247841Sbapt	}
334247841Sbapt	printf("\tchannel %d", ireq.i_val);
335247841Sbapt
336247841Sbapt	ireq.i_type = IEEE80211_IOC_AUTHMODE;
337247841Sbapt	if (ioctl(s, SIOCG80211, &ireq) != -1) {
338247841Sbapt		printf(" authmode");
339247841Sbapt		switch (ireq.i_val) {
340247841Sbapt			case IEEE80211_AUTH_NONE:
341247841Sbapt				printf(" NONE");
342247841Sbapt				break;
343247841Sbapt			case IEEE80211_AUTH_OPEN:
344247841Sbapt				printf(" OPEN");
345247841Sbapt				break;
346247841Sbapt			case IEEE80211_AUTH_SHARED:
347247841Sbapt				printf(" SHARED");
348247841Sbapt				break;
349247841Sbapt			default:
350247841Sbapt				printf(" UNKNOWN");
351247841Sbapt				break;
352247841Sbapt		}
353247841Sbapt	}
354247841Sbapt
355247841Sbapt	ireq.i_type = IEEE80211_IOC_POWERSAVE;
356247841Sbapt	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
357247841Sbapt	    ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
358247841Sbapt		printf(" powersavemode");
359247841Sbapt		switch (ireq.i_val) {
360247841Sbapt			case IEEE80211_POWERSAVE_OFF:
361247841Sbapt				printf(" OFF");
362247841Sbapt				break;
363247841Sbapt			case IEEE80211_POWERSAVE_CAM:
364247841Sbapt				printf(" CAM");
365247841Sbapt				break;
366247841Sbapt			case IEEE80211_POWERSAVE_PSP:
367247841Sbapt				printf(" PSP");
368247841Sbapt				break;
369247841Sbapt			case IEEE80211_POWERSAVE_PSP_CAM:
370247841Sbapt				printf(" PSP-CAM");
371247841Sbapt				break;
372247841Sbapt		}
373247841Sbapt
374247841Sbapt		ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
375247841Sbapt		if (ioctl(s, SIOCG80211, &ireq) != -1) {
376247841Sbapt			if (ireq.i_val)
377247841Sbapt				printf(" powersavesleep %d", ireq.i_val);
378247841Sbapt		}
379247843Sbapt	}
380247841Sbapt
381247841Sbapt	printf("\n");
382247841Sbapt
383247841Sbapt	ireq.i_type = IEEE80211_IOC_WEP;
384247841Sbapt	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
385247841Sbapt	    ireq.i_val != IEEE80211_WEP_NOSUP) {
386247841Sbapt		printf("\twepmode");
387247841Sbapt		switch (ireq.i_val) {
388247841Sbapt			case IEEE80211_WEP_OFF:
389247841Sbapt				printf(" OFF");
390247841Sbapt				break;
391247841Sbapt			case IEEE80211_WEP_ON:
392247841Sbapt				printf(" ON");
393247841Sbapt				break;
394247841Sbapt			case IEEE80211_WEP_MIXED:
395247841Sbapt				printf(" MIXED");
396247841Sbapt				break;
397247841Sbapt			default:
398247841Sbapt				printf(" UNKNOWN");
399247841Sbapt				break;
400247841Sbapt		}
401247841Sbapt
402247841Sbapt		/*
403247841Sbapt		 * If we get here then we've got WEP support so we need
404247841Sbapt		 * to print WEP status.
405247841Sbapt		 */
406247841Sbapt
407247841Sbapt		ireq.i_type = IEEE80211_IOC_WEPTXKEY;
408247841Sbapt		if (ioctl(s, SIOCG80211, &ireq) < 0) {
409247841Sbapt			warn("WEP support, but no tx key!");
410247841Sbapt			goto end;
411247841Sbapt		}
412247841Sbapt		printf(" weptxkey %d", ireq.i_val+1);
413247841Sbapt
414247841Sbapt		ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
415247841Sbapt		if (ioctl(s, SIOCG80211, &ireq) < 0) {
416247841Sbapt			warn("WEP support, but no NUMWEPKEYS support!");
417247841Sbapt			goto end;
418247841Sbapt		}
419247841Sbapt		num = ireq.i_val;
420247841Sbapt
421247841Sbapt		printf("\n");
422247841Sbapt
423247841Sbapt		ireq.i_type = IEEE80211_IOC_WEPKEY;
424247841Sbapt		spacer = '\t';
425247841Sbapt		for (i = 0; i < num; i++) {
426247841Sbapt			ireq.i_val = i;
427247841Sbapt			if (ioctl(s, SIOCG80211, &ireq) < 0) {
428247841Sbapt				warn("WEP support, but can get keys!");
429				goto end;
430			}
431			if (ireq.i_len == 0 ||
432			    ireq.i_len > IEEE80211_KEYBUF_SIZE)
433				continue;
434			printf("%cwepkey %d:%s", spacer, i+1,
435			    ireq.i_len <= 5 ? "40-bit" :
436			    ireq.i_len <= 13 ? "104-bit" : "128-bit");
437			if (spacer == '\t')
438				spacer = ' ';
439		}
440		if (spacer == ' ')
441			printf("\n");
442	}
443
444end:
445	return;
446}
447
448static void
449set80211(int s, int type, int val, int len, u_int8_t *data)
450{
451	struct ieee80211req	ireq;
452
453	(void) memset(&ireq, 0, sizeof(ireq));
454	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
455	ireq.i_type = type;
456	ireq.i_val = val;
457	ireq.i_len = len;
458	ireq.i_data = data;
459	if (ioctl(s, SIOCS80211, &ireq) < 0)
460		err(1, "SIOCS80211");
461}
462
463static const char *
464get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
465{
466	int len;
467	int hexstr;
468	u_int8_t *p;
469
470	len = *lenp;
471	p = buf;
472	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
473	if (hexstr)
474		val += 2;
475	for (;;) {
476		if (*val == '\0')
477			break;
478		if (sep != NULL && strchr(sep, *val) != NULL) {
479			val++;
480			break;
481		}
482		if (hexstr) {
483			if (!isxdigit((u_char)val[0]) ||
484			    !isxdigit((u_char)val[1])) {
485				warnx("bad hexadecimal digits");
486				return NULL;
487			}
488		}
489		if (p > buf + len) {
490			if (hexstr)
491				warnx("hexadecimal digits too long");
492			else
493				warnx("strings too long");
494			return NULL;
495		}
496		if (hexstr) {
497#define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
498			*p++ = (tohex((u_char)val[0]) << 4) |
499			    tohex((u_char)val[1]);
500#undef tohex
501			val += 2;
502		} else
503			*p++ = *val++;
504	}
505	len = p - buf;
506	/* The string "-" is treated as the empty string. */
507	if (!hexstr && len == 1 && buf[0] == '-')
508		len = 0;
509	if (len < *lenp)
510		memset(p, 0, *lenp - len);
511	*lenp = len;
512	return val;
513}
514
515static void
516print_string(const u_int8_t *buf, int len)
517{
518	int i;
519	int hasspc;
520
521	i = 0;
522	hasspc = 0;
523	for (; i < len; i++) {
524		if (!isprint(buf[i]) && buf[i] != '\0')
525			break;
526		if (isspace(buf[i]))
527			hasspc++;
528	}
529	if (i == len) {
530		if (hasspc || len == 0 || buf[0] == '\0')
531			printf("\"%.*s\"", len, buf);
532		else
533			printf("%.*s", len, buf);
534	} else {
535		printf("0x");
536		for (i = 0; i < len; i++)
537			printf("%02x", buf[i]);
538	}
539}
540
541