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