ifieee80211.c revision 77218
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 *
13 * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 77218 2001-05-26 09:28:43Z phk $
26 */
27
28/*-
29 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
30 * All rights reserved.
31 *
32 * This code is derived from software contributed to The NetBSD Foundation
33 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
34 * NASA Ames Research Center.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 *    must display the following acknowledgement:
46 *	This product includes software developed by the NetBSD
47 *	Foundation, Inc. and its contributors.
48 * 4. Neither the name of The NetBSD Foundation nor the names of its
49 *    contributors may be used to endorse or promote products derived
50 *    from this software without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
53 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
54 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
56 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
57 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
58 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
59 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
60 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
61 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
62 * POSSIBILITY OF SUCH DAMAGE.
63 */
64
65#include <sys/param.h>
66#include <sys/ioctl.h>
67#include <sys/socket.h>
68#include <sys/sysctl.h>
69#include <sys/time.h>
70
71#include <net/ethernet.h>
72#include <net/if.h>
73#include <net/if_dl.h>
74#include <net/if_types.h>
75#include <net/route.h>
76#include <net/if_ieee80211.h>
77
78#include <ctype.h>
79#include <err.h>
80#include <errno.h>
81#include <fcntl.h>
82#include <stdio.h>
83#include <stdlib.h>
84#include <string.h>
85#include <unistd.h>
86
87#include "ifconfig.h"
88
89static void set80211(int s, int type, int val, int len, u_int8_t *data);
90static const char *get_string(const char *val, const char *sep,
91    u_int8_t *buf, int *lenp);
92static void print_string(const u_int8_t *buf, int len);
93
94void
95set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
96{
97	int		ssid;
98	int		len;
99	u_int8_t	data[33];
100
101	ssid = 0;
102
103	bzero(data, sizeof(data));
104	len = sizeof(data);
105	get_string(val, NULL, data, &len);
106
107	set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
108}
109
110void
111set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
112{
113	int			len;
114	u_int8_t		data[33];
115
116	bzero(data, sizeof(data));
117	len = sizeof(data);
118	get_string(val, NULL, data, &len);
119
120	set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
121}
122
123void
124set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
125{
126	set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
127}
128
129void
130set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
131{
132	int	mode;
133
134	if(strcasecmp(val, "none") == 0) {
135		mode = IEEE80211_AUTH_NONE;
136	} else if(strcasecmp(val, "open") == 0) {
137		mode = IEEE80211_AUTH_OPEN;
138	} else if(strcasecmp(val, "shared") == 0) {
139		mode = IEEE80211_AUTH_SHARED;
140	} else {
141		err(1, "unknown authmode");
142	}
143
144	set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
145}
146
147void
148set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
149{
150	int	mode;
151
152	if(strcasecmp(val, "off") == 0) {
153		mode = IEEE80211_POWERSAVE_OFF;
154	} else if(strcasecmp(val, "on") == 0) {
155		mode = IEEE80211_POWERSAVE_ON;
156	} else if(strcasecmp(val, "cam") == 0) {
157		mode = IEEE80211_POWERSAVE_CAM;
158	} else if(strcasecmp(val, "psp") == 0) {
159		mode = IEEE80211_POWERSAVE_PSP;
160	} else if(strcasecmp(val, "psp-cam") == 0) {
161		mode = IEEE80211_POWERSAVE_PSP_CAM;
162	} else {
163		err(1, "unknown powersavemode");
164	}
165
166	set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
167}
168
169void
170set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
171{
172	if (d == 0)
173		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
174		    0, NULL);
175	else
176		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
177		    0, NULL);
178}
179
180void
181set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
182{
183	set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
184}
185
186void
187set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
188{
189	int	mode;
190
191	if(strcasecmp(val, "off") == 0) {
192		mode = IEEE80211_WEP_OFF;
193	} else if(strcasecmp(val, "on") == 0) {
194		mode = IEEE80211_WEP_ON;
195	} else if(strcasecmp(val, "mixed") == 0) {
196		mode = IEEE80211_WEP_MIXED;
197	} else {
198		err(1, "unknown wep mode");
199	}
200
201	set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
202}
203
204void
205set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
206{
207	set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
208}
209
210void
211set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
212{
213	set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
214}
215
216void
217set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
218{
219	int		key = 0;
220	int		len;
221	u_int8_t	data[14];
222
223	if(isdigit(val[0]) && val[1] == ':') {
224		key = atoi(val)-1;
225		val += 2;
226	}
227
228	bzero(data, sizeof(data));
229	len = sizeof(data);
230	get_string(val, NULL, data, &len);
231
232	set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
233}
234
235/*
236 * This function is purly a NetBSD compatability interface.  The NetBSD
237 * iterface is too inflexable, but it's there so we'll support it since
238 * it's not all that hard.
239 */
240void
241set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
242{
243	int		txkey;
244	int		i, len;
245	u_int8_t	data[14];
246
247	set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
248
249	if(isdigit(val[0]) && val[1] == ':') {
250		txkey = val[0]-'0'-1;
251		val += 2;
252
253		for(i = 0; i < 4; i++) {
254			bzero(data, sizeof(data));
255			len = sizeof(data);
256			val = get_string(val, ",", data, &len);
257
258			set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
259		}
260	} else {
261		bzero(data, sizeof(data));
262		len = sizeof(data);
263		get_string(val, NULL, data, &len);
264		txkey = 0;
265
266		set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
267
268		bzero(data, sizeof(data));
269		for(i = 1; i < 4; i++)
270			set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
271	}
272
273	set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
274}
275
276void
277ieee80211_status (s, info)
278	int s;
279	struct rt_addrinfo *info __unused;
280{
281	int			i;
282	int			num;
283	struct ieee80211req	ireq;
284	u_int8_t		data[32];
285	char			spacer;
286
287	(void) memset(&ireq, 0, sizeof(ireq));
288	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
289	ireq.i_data = &data;
290
291	ireq.i_type = IEEE80211_IOC_SSID;
292	ireq.i_val = -1;
293	if (ioctl(s, SIOCG80211, &ireq) < 0) {
294		/* If we can't get the SSID, the this isn't an 802.11 device. */
295		return;
296	}
297	printf("\tssid ");
298	print_string(data, ireq.i_len);
299	printf("\n");
300
301	ireq.i_type = IEEE80211_IOC_STATIONNAME;
302	if (ioctl(s, SIOCG80211, &ireq) != -1) {
303		printf("\tstationname ");
304		print_string(data, ireq.i_len);
305		printf("\n");
306	}
307
308	ireq.i_type = IEEE80211_IOC_CHANNEL;
309	if (ioctl(s, SIOCG80211, &ireq) < 0) {
310		goto end;
311	}
312	printf("\tchannel %d", ireq.i_val);
313
314	ireq.i_type = IEEE80211_IOC_AUTHMODE;
315	if (ioctl(s, SIOCG80211, &ireq) != -1) {
316		printf(" authmode");
317		switch (ireq.i_val) {
318			case IEEE80211_AUTH_NONE:
319				printf(" NONE");
320				break;
321			case IEEE80211_AUTH_OPEN:
322				printf(" OPEN");
323				break;
324			case IEEE80211_AUTH_SHARED:
325				printf(" SHARED");
326				break;
327			default:
328				printf(" UNKNOWN");
329				break;
330		}
331	}
332
333	ireq.i_type = IEEE80211_IOC_POWERSAVE;
334	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
335	    ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
336		printf(" powersavemode");
337		switch (ireq.i_val) {
338			case IEEE80211_POWERSAVE_OFF:
339				printf(" OFF");
340				break;
341			case IEEE80211_POWERSAVE_CAM:
342				printf(" CAM");
343				break;
344			case IEEE80211_POWERSAVE_PSP:
345				printf(" PSP");
346				break;
347			case IEEE80211_POWERSAVE_PSP_CAM:
348				printf(" PSP-CAM");
349				break;
350		}
351
352		ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
353		if (ioctl(s, SIOCG80211, &ireq) != -1) {
354			if(ireq.i_val)
355				printf(" powersavesleep %d", ireq.i_val);
356		}
357	}
358
359	printf("\n");
360
361	ireq.i_type = IEEE80211_IOC_WEP;
362	if (ioctl(s, SIOCG80211, &ireq) < 0 ||
363	    ireq.i_val == IEEE80211_WEP_NOSUP)
364		goto nowep;
365	else {
366		printf("\twepmode");
367		switch (ireq.i_val) {
368			case IEEE80211_WEP_OFF:
369				printf(" OFF");
370				break;
371			case IEEE80211_WEP_ON:
372				printf(" ON");
373				break;
374			case IEEE80211_WEP_MIXED:
375				printf(" MIXED");
376				break;
377			default:
378				printf(" UNKNOWN");
379				break;
380		}
381
382		/*
383		 * If we get here then we've got WEP support so we need
384		 * to print WEP status.
385		 */
386
387		ireq.i_type = IEEE80211_IOC_WEPTXKEY;
388		if (ioctl(s, SIOCG80211, &ireq) < 0) {
389			warn("WEP support, but no tx key!");
390			goto end;
391		}
392		printf(" weptxkey %d", ireq.i_val+1);
393
394		ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
395		if (ioctl(s, SIOCG80211, &ireq) < 0) {
396			warn("WEP support, but no NUMWEPKEYS support!");
397			goto end;
398		}
399		num = ireq.i_val;
400
401		printf("\n");
402
403		ireq.i_type = IEEE80211_IOC_WEPKEY;
404		spacer = '\t';
405		for(i = 0; i < num; i++) {
406			ireq.i_val = i;
407			if (ioctl(s, SIOCG80211, &ireq) < 0) {
408				warn("WEP support, but can get keys!");
409				goto end;
410			}
411			if(ireq.i_len == 0 || ireq.i_len > 13)
412				continue;
413			printf("%cwepkey %d:%s", spacer, i+1,
414			    ireq.i_len <= 5 ? "64-bit" : "128-bit");
415			if(spacer == '\t')
416				spacer = ' ';
417		}
418
419		printf("\n");
420	}
421nowep:
422
423
424end:
425	return;
426}
427
428static void
429set80211(int s, int type, int val, int len, u_int8_t *data)
430{
431	struct ieee80211req	ireq;
432
433	(void) memset(&ireq, 0, sizeof(ireq));
434	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
435	ireq.i_type = type;
436	ireq.i_val = val;
437	ireq.i_len = len;
438	ireq.i_data = data;
439	if(ioctl(s, SIOCS80211, &ireq) < 0)
440		err(1, "SIOCS80211");
441}
442
443static const char *
444get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
445{
446	int len;
447	int hexstr;
448	u_int8_t *p;
449
450	len = *lenp;
451	p = buf;
452	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
453	if (hexstr)
454		val += 2;
455	for (;;) {
456		if (*val == '\0')
457			break;
458		if (sep != NULL && strchr(sep, *val) != NULL) {
459			val++;
460			break;
461		}
462		if (hexstr) {
463			if (!isxdigit((u_char)val[0]) ||
464			    !isxdigit((u_char)val[1])) {
465				warnx("bad hexadecimal digits");
466				return NULL;
467			}
468		}
469		if (p > buf + len) {
470			if (hexstr)
471				warnx("hexadecimal digits too long");
472			else
473				warnx("strings too long");
474			return NULL;
475		}
476		if (hexstr) {
477#define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
478			*p++ = (tohex((u_char)val[0]) << 4) |
479			    tohex((u_char)val[1]);
480#undef tohex
481			val += 2;
482		} else
483			*p++ = *val++;
484	}
485	len = p - buf;
486	/* The string "-" is treated as the empty string. */
487	if (!hexstr && len == 1 && buf[0] == '-')
488		len = 0;
489	if (len < *lenp)
490		memset(p, 0, *lenp - len);
491	*lenp = len;
492	return val;
493}
494
495static void
496print_string(const u_int8_t *buf, int len)
497{
498	int i;
499	int hasspc;
500
501	i = 0;
502	hasspc = 0;
503	for(; i < len; i++) {
504		if (!isprint(buf[i]) && buf[i] != '\0')
505			break;
506		if (isspace(buf[i]))
507			hasspc++;
508	}
509	if (i == len) {
510		if (hasspc || len == 0 || buf[0] == '\0')
511			printf("\"%.*s\"", len, buf);
512		else
513			printf("%.*s", len, buf);
514	} else {
515		printf("0x");
516		for (i = 0; i < len; i++)
517			printf("%02x", buf[i]);
518	}
519}
520
521