ifieee80211.c revision 95005
177218Sphk/*
277218Sphk * Copyright 2001 The Aerospace Corporation.  All rights reserved.
377218Sphk *
477218Sphk * Redistribution and use in source and binary forms, with or without
577218Sphk * modification, are permitted provided that the following conditions
677218Sphk * are met:
777218Sphk * 1. Redistributions of source code must retain the above copyright
877218Sphk *    notice, this list of conditions and the following disclaimer.
977218Sphk * 2. Redistributions in binary form must reproduce the above copyright
1077218Sphk *    notice, this list of conditions and the following disclaimer in the
1177218Sphk *    documentation and/or other materials provided with the distribution.
1291454Sbrooks * 3. The name of The Aerospace Corporation may not be used to endorse or
1391454Sbrooks *    promote products derived from this software.
1477218Sphk *
1577218Sphk * THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION ``AS IS'' AND
1677218Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1777218Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1877218Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
1977218Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2077218Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2177218Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2277218Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2377218Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2477218Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2577218Sphk * SUCH DAMAGE.
2677218Sphk *
2777218Sphk * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 95005 2002-04-18 17:14:09Z imp $
2877218Sphk */
2977218Sphk
3077218Sphk/*-
3177218Sphk * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
3277218Sphk * All rights reserved.
3377218Sphk *
3477218Sphk * This code is derived from software contributed to The NetBSD Foundation
3577218Sphk * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
3677218Sphk * NASA Ames Research Center.
3777218Sphk *
3877218Sphk * Redistribution and use in source and binary forms, with or without
3977218Sphk * modification, are permitted provided that the following conditions
4077218Sphk * are met:
4177218Sphk * 1. Redistributions of source code must retain the above copyright
4277218Sphk *    notice, this list of conditions and the following disclaimer.
4377218Sphk * 2. Redistributions in binary form must reproduce the above copyright
4477218Sphk *    notice, this list of conditions and the following disclaimer in the
4577218Sphk *    documentation and/or other materials provided with the distribution.
4677218Sphk * 3. All advertising materials mentioning features or use of this software
4777218Sphk *    must display the following acknowledgement:
4877218Sphk *	This product includes software developed by the NetBSD
4977218Sphk *	Foundation, Inc. and its contributors.
5077218Sphk * 4. Neither the name of The NetBSD Foundation nor the names of its
5177218Sphk *    contributors may be used to endorse or promote products derived
5277218Sphk *    from this software without specific prior written permission.
5377218Sphk *
5477218Sphk * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
5577218Sphk * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
5677218Sphk * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
5777218Sphk * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
5877218Sphk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5977218Sphk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
6077218Sphk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
6177218Sphk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
6277218Sphk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
6377218Sphk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
6477218Sphk * POSSIBILITY OF SUCH DAMAGE.
6577218Sphk */
6677218Sphk
6777218Sphk#include <sys/param.h>
6877218Sphk#include <sys/ioctl.h>
6977218Sphk#include <sys/socket.h>
7077218Sphk#include <sys/sysctl.h>
7177218Sphk#include <sys/time.h>
7277218Sphk
7377218Sphk#include <net/ethernet.h>
7477218Sphk#include <net/if.h>
7577218Sphk#include <net/if_dl.h>
7677218Sphk#include <net/if_types.h>
7777218Sphk#include <net/route.h>
7877218Sphk#include <net/if_ieee80211.h>
7977218Sphk
8077218Sphk#include <ctype.h>
8177218Sphk#include <err.h>
8277218Sphk#include <errno.h>
8377218Sphk#include <fcntl.h>
8477218Sphk#include <stdio.h>
8577218Sphk#include <stdlib.h>
8677218Sphk#include <string.h>
8777218Sphk#include <unistd.h>
8877218Sphk
8977218Sphk#include "ifconfig.h"
9077218Sphk
9177218Sphkstatic void set80211(int s, int type, int val, int len, u_int8_t *data);
9277218Sphkstatic const char *get_string(const char *val, const char *sep,
9377218Sphk    u_int8_t *buf, int *lenp);
9477218Sphkstatic void print_string(const u_int8_t *buf, int len);
9577218Sphk
9677218Sphkvoid
9777218Sphkset80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
9877218Sphk{
9977218Sphk	int		ssid;
10077218Sphk	int		len;
10177218Sphk	u_int8_t	data[33];
10277218Sphk
10377218Sphk	ssid = 0;
10488748Sambrisko	len = sizeof(val);
10588748Sambrisko	if (len > 2 && isdigit(val[0]) && val[1] == ':') {
10688748Sambrisko		ssid = atoi(val)-1;
10788748Sambrisko		val += 2;
10888748Sambrisko	}
10977218Sphk
11077218Sphk	bzero(data, sizeof(data));
11177218Sphk	len = sizeof(data);
11277218Sphk	get_string(val, NULL, data, &len);
11377218Sphk
11477218Sphk	set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
11577218Sphk}
11677218Sphk
11777218Sphkvoid
11877218Sphkset80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
11977218Sphk{
12077218Sphk	int			len;
12177218Sphk	u_int8_t		data[33];
12277218Sphk
12377218Sphk	bzero(data, sizeof(data));
12477218Sphk	len = sizeof(data);
12577218Sphk	get_string(val, NULL, data, &len);
12677218Sphk
12777218Sphk	set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
12877218Sphk}
12977218Sphk
13077218Sphkvoid
13177218Sphkset80211channel(const char *val, int d, int s, const struct afswtch *rafp)
13277218Sphk{
13377218Sphk	set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
13477218Sphk}
13577218Sphk
13677218Sphkvoid
13777218Sphkset80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
13877218Sphk{
13977218Sphk	int	mode;
14077218Sphk
14191454Sbrooks	if (strcasecmp(val, "none") == 0) {
14277218Sphk		mode = IEEE80211_AUTH_NONE;
14391454Sbrooks	} else if (strcasecmp(val, "open") == 0) {
14477218Sphk		mode = IEEE80211_AUTH_OPEN;
14591454Sbrooks	} else if (strcasecmp(val, "shared") == 0) {
14677218Sphk		mode = IEEE80211_AUTH_SHARED;
14777218Sphk	} else {
14877218Sphk		err(1, "unknown authmode");
14977218Sphk	}
15077218Sphk
15177218Sphk	set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
15277218Sphk}
15377218Sphk
15477218Sphkvoid
15577218Sphkset80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
15677218Sphk{
15777218Sphk	int	mode;
15877218Sphk
15991454Sbrooks	if (strcasecmp(val, "off") == 0) {
16077218Sphk		mode = IEEE80211_POWERSAVE_OFF;
16191454Sbrooks	} else if (strcasecmp(val, "on") == 0) {
16277218Sphk		mode = IEEE80211_POWERSAVE_ON;
16391454Sbrooks	} else if (strcasecmp(val, "cam") == 0) {
16477218Sphk		mode = IEEE80211_POWERSAVE_CAM;
16591454Sbrooks	} else if (strcasecmp(val, "psp") == 0) {
16677218Sphk		mode = IEEE80211_POWERSAVE_PSP;
16791454Sbrooks	} else if (strcasecmp(val, "psp-cam") == 0) {
16877218Sphk		mode = IEEE80211_POWERSAVE_PSP_CAM;
16977218Sphk	} else {
17077218Sphk		err(1, "unknown powersavemode");
17177218Sphk	}
17277218Sphk
17377218Sphk	set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
17477218Sphk}
17577218Sphk
17677218Sphkvoid
17777218Sphkset80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
17877218Sphk{
17977218Sphk	if (d == 0)
18077218Sphk		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_OFF,
18177218Sphk		    0, NULL);
18277218Sphk	else
18377218Sphk		set80211(s, IEEE80211_IOC_POWERSAVE, IEEE80211_POWERSAVE_ON,
18477218Sphk		    0, NULL);
18577218Sphk}
18677218Sphk
18777218Sphkvoid
18877218Sphkset80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
18977218Sphk{
19077218Sphk	set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
19177218Sphk}
19277218Sphk
19377218Sphkvoid
19477218Sphkset80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
19577218Sphk{
19677218Sphk	int	mode;
19777218Sphk
19891454Sbrooks	if (strcasecmp(val, "off") == 0) {
19977218Sphk		mode = IEEE80211_WEP_OFF;
20091454Sbrooks	} else if (strcasecmp(val, "on") == 0) {
20177218Sphk		mode = IEEE80211_WEP_ON;
20291454Sbrooks	} else if (strcasecmp(val, "mixed") == 0) {
20377218Sphk		mode = IEEE80211_WEP_MIXED;
20477218Sphk	} else {
20577218Sphk		err(1, "unknown wep mode");
20677218Sphk	}
20777218Sphk
20877218Sphk	set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
20977218Sphk}
21077218Sphk
21177218Sphkvoid
21277218Sphkset80211wep(const char *val, int d, int s, const struct afswtch *rafp)
21377218Sphk{
21477218Sphk	set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
21577218Sphk}
21677218Sphk
21777218Sphkvoid
21877218Sphkset80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
21977218Sphk{
22077218Sphk	set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
22177218Sphk}
22277218Sphk
22377218Sphkvoid
22477218Sphkset80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
22577218Sphk{
22677218Sphk	int		key = 0;
22777218Sphk	int		len;
22877218Sphk	u_int8_t	data[14];
22977218Sphk
23091454Sbrooks	if (isdigit(val[0]) && val[1] == ':') {
23177218Sphk		key = atoi(val)-1;
23277218Sphk		val += 2;
23377218Sphk	}
23477218Sphk
23577218Sphk	bzero(data, sizeof(data));
23677218Sphk	len = sizeof(data);
23777218Sphk	get_string(val, NULL, data, &len);
23877218Sphk
23977218Sphk	set80211(s, IEEE80211_IOC_WEPKEY, key, len, data);
24077218Sphk}
24177218Sphk
24277218Sphk/*
24377218Sphk * This function is purly a NetBSD compatability interface.  The NetBSD
24477218Sphk * iterface is too inflexable, but it's there so we'll support it since
24577218Sphk * it's not all that hard.
24677218Sphk */
24777218Sphkvoid
24877218Sphkset80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
24977218Sphk{
25077218Sphk	int		txkey;
25177218Sphk	int		i, len;
25277218Sphk	u_int8_t	data[14];
25377218Sphk
25477218Sphk	set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
25577218Sphk
25691454Sbrooks	if (isdigit(val[0]) && val[1] == ':') {
25777218Sphk		txkey = val[0]-'0'-1;
25877218Sphk		val += 2;
25977218Sphk
26091454Sbrooks		for (i = 0; i < 4; i++) {
26177218Sphk			bzero(data, sizeof(data));
26277218Sphk			len = sizeof(data);
26377218Sphk			val = get_string(val, ",", data, &len);
26477218Sphk
26577218Sphk			set80211(s, IEEE80211_IOC_WEPKEY, i, len, data);
26677218Sphk		}
26777218Sphk	} else {
26877218Sphk		bzero(data, sizeof(data));
26977218Sphk		len = sizeof(data);
27077218Sphk		get_string(val, NULL, data, &len);
27177218Sphk		txkey = 0;
27277218Sphk
27377218Sphk		set80211(s, IEEE80211_IOC_WEPKEY, 0, len, data);
27477218Sphk
27577218Sphk		bzero(data, sizeof(data));
27691454Sbrooks		for (i = 1; i < 4; i++)
27777218Sphk			set80211(s, IEEE80211_IOC_WEPKEY, i, 0, data);
27877218Sphk	}
27977218Sphk
28077218Sphk	set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
28177218Sphk}
28277218Sphk
28377218Sphkvoid
28495005Simpieee80211_status (int s, struct rt_addrinfo *info __unused)
28577218Sphk{
28677218Sphk	int			i;
28777218Sphk	int			num;
28877218Sphk	struct ieee80211req	ireq;
28977218Sphk	u_int8_t		data[32];
29077218Sphk	char			spacer;
29177218Sphk
29277218Sphk	(void) memset(&ireq, 0, sizeof(ireq));
29377218Sphk	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
29477218Sphk	ireq.i_data = &data;
29577218Sphk
29677218Sphk	ireq.i_type = IEEE80211_IOC_SSID;
29777218Sphk	ireq.i_val = -1;
29877218Sphk	if (ioctl(s, SIOCG80211, &ireq) < 0) {
29977218Sphk		/* If we can't get the SSID, the this isn't an 802.11 device. */
30077218Sphk		return;
30177218Sphk	}
30277218Sphk	printf("\tssid ");
30377218Sphk	print_string(data, ireq.i_len);
30488748Sambrisko	num = 0;
30588748Sambrisko	ireq.i_type = IEEE80211_IOC_NUMSSIDS;
30688748Sambrisko	if (ioctl(s, SIOCG80211, &ireq) >= 0) {
30788748Sambrisko		num = ireq.i_val;
30888748Sambrisko	}
30988748Sambrisko	ireq.i_type = IEEE80211_IOC_SSID;
31088748Sambrisko	for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
31188748Sambrisko		if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
31288748Sambrisko			printf(" %d:", ireq.i_val + 1);
31388748Sambrisko			print_string(data, ireq.i_len);
31488748Sambrisko		}
31588748Sambrisko	}
31677218Sphk	printf("\n");
31777218Sphk
31877218Sphk	ireq.i_type = IEEE80211_IOC_STATIONNAME;
31977218Sphk	if (ioctl(s, SIOCG80211, &ireq) != -1) {
32077218Sphk		printf("\tstationname ");
32177218Sphk		print_string(data, ireq.i_len);
32277218Sphk		printf("\n");
32377218Sphk	}
32477218Sphk
32577218Sphk	ireq.i_type = IEEE80211_IOC_CHANNEL;
32677218Sphk	if (ioctl(s, SIOCG80211, &ireq) < 0) {
32777218Sphk		goto end;
32877218Sphk	}
32977218Sphk	printf("\tchannel %d", ireq.i_val);
33077218Sphk
33177218Sphk	ireq.i_type = IEEE80211_IOC_AUTHMODE;
33277218Sphk	if (ioctl(s, SIOCG80211, &ireq) != -1) {
33377218Sphk		printf(" authmode");
33477218Sphk		switch (ireq.i_val) {
33577218Sphk			case IEEE80211_AUTH_NONE:
33677218Sphk				printf(" NONE");
33777218Sphk				break;
33877218Sphk			case IEEE80211_AUTH_OPEN:
33977218Sphk				printf(" OPEN");
34077218Sphk				break;
34177218Sphk			case IEEE80211_AUTH_SHARED:
34277218Sphk				printf(" SHARED");
34377218Sphk				break;
34477218Sphk			default:
34577218Sphk				printf(" UNKNOWN");
34677218Sphk				break;
34777218Sphk		}
34877218Sphk	}
34977218Sphk
35077218Sphk	ireq.i_type = IEEE80211_IOC_POWERSAVE;
35177218Sphk	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
35277218Sphk	    ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
35377218Sphk		printf(" powersavemode");
35477218Sphk		switch (ireq.i_val) {
35577218Sphk			case IEEE80211_POWERSAVE_OFF:
35677218Sphk				printf(" OFF");
35777218Sphk				break;
35877218Sphk			case IEEE80211_POWERSAVE_CAM:
35977218Sphk				printf(" CAM");
36077218Sphk				break;
36177218Sphk			case IEEE80211_POWERSAVE_PSP:
36277218Sphk				printf(" PSP");
36377218Sphk				break;
36477218Sphk			case IEEE80211_POWERSAVE_PSP_CAM:
36577218Sphk				printf(" PSP-CAM");
36677218Sphk				break;
36777218Sphk		}
36877218Sphk
36977218Sphk		ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
37077218Sphk		if (ioctl(s, SIOCG80211, &ireq) != -1) {
37191454Sbrooks			if (ireq.i_val)
37277218Sphk				printf(" powersavesleep %d", ireq.i_val);
37377218Sphk		}
37477218Sphk	}
37577218Sphk
37677218Sphk	printf("\n");
37777218Sphk
37877218Sphk	ireq.i_type = IEEE80211_IOC_WEP;
37980315Sbrooks	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
38080315Sbrooks	    ireq.i_val != IEEE80211_WEP_NOSUP) {
38177218Sphk		printf("\twepmode");
38277218Sphk		switch (ireq.i_val) {
38377218Sphk			case IEEE80211_WEP_OFF:
38477218Sphk				printf(" OFF");
38577218Sphk				break;
38677218Sphk			case IEEE80211_WEP_ON:
38777218Sphk				printf(" ON");
38877218Sphk				break;
38977218Sphk			case IEEE80211_WEP_MIXED:
39077218Sphk				printf(" MIXED");
39177218Sphk				break;
39277218Sphk			default:
39377218Sphk				printf(" UNKNOWN");
39477218Sphk				break;
39577218Sphk		}
39677218Sphk
39777218Sphk		/*
39877218Sphk		 * If we get here then we've got WEP support so we need
39977218Sphk		 * to print WEP status.
40091454Sbrooks		 */
40177218Sphk
40277218Sphk		ireq.i_type = IEEE80211_IOC_WEPTXKEY;
40377218Sphk		if (ioctl(s, SIOCG80211, &ireq) < 0) {
40477218Sphk			warn("WEP support, but no tx key!");
40577218Sphk			goto end;
40677218Sphk		}
40777218Sphk		printf(" weptxkey %d", ireq.i_val+1);
40877218Sphk
40977218Sphk		ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
41077218Sphk		if (ioctl(s, SIOCG80211, &ireq) < 0) {
41177218Sphk			warn("WEP support, but no NUMWEPKEYS support!");
41277218Sphk			goto end;
41377218Sphk		}
41477218Sphk		num = ireq.i_val;
41577218Sphk
41677218Sphk		printf("\n");
41777218Sphk
41877218Sphk		ireq.i_type = IEEE80211_IOC_WEPKEY;
41977218Sphk		spacer = '\t';
42091454Sbrooks		for (i = 0; i < num; i++) {
42177218Sphk			ireq.i_val = i;
42277218Sphk			if (ioctl(s, SIOCG80211, &ireq) < 0) {
42377218Sphk				warn("WEP support, but can get keys!");
42477218Sphk				goto end;
42577218Sphk			}
42691454Sbrooks			if (ireq.i_len == 0 || ireq.i_len > 13)
42777218Sphk				continue;
42877218Sphk			printf("%cwepkey %d:%s", spacer, i+1,
42977218Sphk			    ireq.i_len <= 5 ? "64-bit" : "128-bit");
43091454Sbrooks			if (spacer == '\t')
43177218Sphk				spacer = ' ';
43277218Sphk		}
43380315Sbrooks		if (spacer == ' ')
43480315Sbrooks			printf("\n");
43577218Sphk	}
43677218Sphk
43777218Sphkend:
43877218Sphk	return;
43977218Sphk}
44077218Sphk
44177218Sphkstatic void
44277218Sphkset80211(int s, int type, int val, int len, u_int8_t *data)
44377218Sphk{
44477218Sphk	struct ieee80211req	ireq;
44577218Sphk
44677218Sphk	(void) memset(&ireq, 0, sizeof(ireq));
44777218Sphk	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
44877218Sphk	ireq.i_type = type;
44977218Sphk	ireq.i_val = val;
45077218Sphk	ireq.i_len = len;
45177218Sphk	ireq.i_data = data;
45291454Sbrooks	if (ioctl(s, SIOCS80211, &ireq) < 0)
45377218Sphk		err(1, "SIOCS80211");
45477218Sphk}
45577218Sphk
45677218Sphkstatic const char *
45777218Sphkget_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
45877218Sphk{
45977218Sphk	int len;
46077218Sphk	int hexstr;
46177218Sphk	u_int8_t *p;
46277218Sphk
46377218Sphk	len = *lenp;
46477218Sphk	p = buf;
46577218Sphk	hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
46677218Sphk	if (hexstr)
46777218Sphk		val += 2;
46877218Sphk	for (;;) {
46977218Sphk		if (*val == '\0')
47077218Sphk			break;
47177218Sphk		if (sep != NULL && strchr(sep, *val) != NULL) {
47277218Sphk			val++;
47377218Sphk			break;
47477218Sphk		}
47577218Sphk		if (hexstr) {
47677218Sphk			if (!isxdigit((u_char)val[0]) ||
47777218Sphk			    !isxdigit((u_char)val[1])) {
47877218Sphk				warnx("bad hexadecimal digits");
47977218Sphk				return NULL;
48077218Sphk			}
48177218Sphk		}
48277218Sphk		if (p > buf + len) {
48377218Sphk			if (hexstr)
48477218Sphk				warnx("hexadecimal digits too long");
48577218Sphk			else
48677218Sphk				warnx("strings too long");
48777218Sphk			return NULL;
48877218Sphk		}
48977218Sphk		if (hexstr) {
49077218Sphk#define	tohex(x)	(isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
49177218Sphk			*p++ = (tohex((u_char)val[0]) << 4) |
49277218Sphk			    tohex((u_char)val[1]);
49377218Sphk#undef tohex
49477218Sphk			val += 2;
49577218Sphk		} else
49677218Sphk			*p++ = *val++;
49777218Sphk	}
49877218Sphk	len = p - buf;
49977218Sphk	/* The string "-" is treated as the empty string. */
50077218Sphk	if (!hexstr && len == 1 && buf[0] == '-')
50177218Sphk		len = 0;
50277218Sphk	if (len < *lenp)
50377218Sphk		memset(p, 0, *lenp - len);
50477218Sphk	*lenp = len;
50577218Sphk	return val;
50677218Sphk}
50777218Sphk
50877218Sphkstatic void
50977218Sphkprint_string(const u_int8_t *buf, int len)
51077218Sphk{
51177218Sphk	int i;
51277218Sphk	int hasspc;
51377218Sphk
51477218Sphk	i = 0;
51577218Sphk	hasspc = 0;
51691454Sbrooks	for (; i < len; i++) {
51777218Sphk		if (!isprint(buf[i]) && buf[i] != '\0')
51877218Sphk			break;
51977218Sphk		if (isspace(buf[i]))
52077218Sphk			hasspc++;
52177218Sphk	}
52277218Sphk	if (i == len) {
52377218Sphk		if (hasspc || len == 0 || buf[0] == '\0')
52477218Sphk			printf("\"%.*s\"", len, buf);
52577218Sphk		else
52677218Sphk			printf("%.*s", len, buf);
52777218Sphk	} else {
52877218Sphk		printf("0x");
52977218Sphk		for (i = 0; i < len; i++)
53077218Sphk			printf("%02x", buf[i]);
53177218Sphk	}
53277218Sphk}
53377218Sphk
534