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