common.c revision 289549
1189251Ssam/* 2189251Ssam * wpa_supplicant/hostapd / common helper functions, etc. 3189251Ssam * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11289549Srpaulo#include "common/ieee802_11_defs.h" 12189251Ssam#include "common.h" 13189251Ssam 14189251Ssam 15189251Ssamstatic int hex2num(char c) 16189251Ssam{ 17189251Ssam if (c >= '0' && c <= '9') 18189251Ssam return c - '0'; 19189251Ssam if (c >= 'a' && c <= 'f') 20189251Ssam return c - 'a' + 10; 21189251Ssam if (c >= 'A' && c <= 'F') 22189251Ssam return c - 'A' + 10; 23189251Ssam return -1; 24189251Ssam} 25189251Ssam 26189251Ssam 27252726Srpauloint hex2byte(const char *hex) 28189251Ssam{ 29189251Ssam int a, b; 30189251Ssam a = hex2num(*hex++); 31189251Ssam if (a < 0) 32189251Ssam return -1; 33189251Ssam b = hex2num(*hex++); 34189251Ssam if (b < 0) 35189251Ssam return -1; 36189251Ssam return (a << 4) | b; 37189251Ssam} 38189251Ssam 39189251Ssam 40281806Srpaulostatic const char * hwaddr_parse(const char *txt, u8 *addr) 41281806Srpaulo{ 42281806Srpaulo size_t i; 43281806Srpaulo 44281806Srpaulo for (i = 0; i < ETH_ALEN; i++) { 45281806Srpaulo int a; 46281806Srpaulo 47281806Srpaulo a = hex2byte(txt); 48281806Srpaulo if (a < 0) 49281806Srpaulo return NULL; 50281806Srpaulo txt += 2; 51281806Srpaulo addr[i] = a; 52281806Srpaulo if (i < ETH_ALEN - 1 && *txt++ != ':') 53281806Srpaulo return NULL; 54281806Srpaulo } 55281806Srpaulo return txt; 56281806Srpaulo} 57281806Srpaulo 58281806Srpaulo 59189251Ssam/** 60214734Srpaulo * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format) 61189251Ssam * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") 62189251Ssam * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) 63189251Ssam * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) 64189251Ssam */ 65189251Ssamint hwaddr_aton(const char *txt, u8 *addr) 66189251Ssam{ 67281806Srpaulo return hwaddr_parse(txt, addr) ? 0 : -1; 68281806Srpaulo} 69189251Ssam 70189251Ssam 71281806Srpaulo/** 72281806Srpaulo * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format) 73281806Srpaulo * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00") 74281806Srpaulo * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) 75281806Srpaulo * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes) 76281806Srpaulo * @maskable: Flag to indicate whether a mask is allowed 77281806Srpaulo * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) 78281806Srpaulo */ 79281806Srpauloint hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable) 80281806Srpaulo{ 81281806Srpaulo const char *r; 82281806Srpaulo 83281806Srpaulo /* parse address part */ 84281806Srpaulo r = hwaddr_parse(txt, addr); 85281806Srpaulo if (!r) 86281806Srpaulo return -1; 87281806Srpaulo 88281806Srpaulo /* check for optional mask */ 89281806Srpaulo if (*r == '\0' || isspace(*r)) { 90281806Srpaulo /* no mask specified, assume default */ 91281806Srpaulo os_memset(mask, 0xff, ETH_ALEN); 92281806Srpaulo } else if (maskable && *r == '/') { 93281806Srpaulo /* mask specified and allowed */ 94281806Srpaulo r = hwaddr_parse(r + 1, mask); 95281806Srpaulo /* parser error? */ 96281806Srpaulo if (!r) 97189251Ssam return -1; 98281806Srpaulo } else { 99281806Srpaulo /* mask specified but not allowed or trailing garbage */ 100281806Srpaulo return -1; 101189251Ssam } 102189251Ssam 103189251Ssam return 0; 104189251Ssam} 105189251Ssam 106281806Srpaulo 107252726Srpaulo/** 108252726Srpaulo * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format) 109252726Srpaulo * @txt: MAC address as a string (e.g., "001122334455") 110252726Srpaulo * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) 111252726Srpaulo * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) 112252726Srpaulo */ 113252726Srpauloint hwaddr_compact_aton(const char *txt, u8 *addr) 114252726Srpaulo{ 115252726Srpaulo int i; 116189251Ssam 117252726Srpaulo for (i = 0; i < 6; i++) { 118252726Srpaulo int a, b; 119252726Srpaulo 120252726Srpaulo a = hex2num(*txt++); 121252726Srpaulo if (a < 0) 122252726Srpaulo return -1; 123252726Srpaulo b = hex2num(*txt++); 124252726Srpaulo if (b < 0) 125252726Srpaulo return -1; 126252726Srpaulo *addr++ = (a << 4) | b; 127252726Srpaulo } 128252726Srpaulo 129252726Srpaulo return 0; 130252726Srpaulo} 131252726Srpaulo 132189251Ssam/** 133214734Srpaulo * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format) 134214734Srpaulo * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455) 135214734Srpaulo * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) 136214734Srpaulo * Returns: Characters used (> 0) on success, -1 on failure 137214734Srpaulo */ 138214734Srpauloint hwaddr_aton2(const char *txt, u8 *addr) 139214734Srpaulo{ 140214734Srpaulo int i; 141214734Srpaulo const char *pos = txt; 142214734Srpaulo 143214734Srpaulo for (i = 0; i < 6; i++) { 144214734Srpaulo int a, b; 145214734Srpaulo 146214734Srpaulo while (*pos == ':' || *pos == '.' || *pos == '-') 147214734Srpaulo pos++; 148214734Srpaulo 149214734Srpaulo a = hex2num(*pos++); 150214734Srpaulo if (a < 0) 151214734Srpaulo return -1; 152214734Srpaulo b = hex2num(*pos++); 153214734Srpaulo if (b < 0) 154214734Srpaulo return -1; 155214734Srpaulo *addr++ = (a << 4) | b; 156214734Srpaulo } 157214734Srpaulo 158214734Srpaulo return pos - txt; 159214734Srpaulo} 160214734Srpaulo 161214734Srpaulo 162214734Srpaulo/** 163189251Ssam * hexstr2bin - Convert ASCII hex string into binary data 164189251Ssam * @hex: ASCII hex string (e.g., "01ab") 165189251Ssam * @buf: Buffer for the binary data 166189251Ssam * @len: Length of the text to convert in bytes (of buf); hex will be double 167189251Ssam * this size 168189251Ssam * Returns: 0 on success, -1 on failure (invalid hex string) 169189251Ssam */ 170189251Ssamint hexstr2bin(const char *hex, u8 *buf, size_t len) 171189251Ssam{ 172189251Ssam size_t i; 173189251Ssam int a; 174189251Ssam const char *ipos = hex; 175189251Ssam u8 *opos = buf; 176189251Ssam 177189251Ssam for (i = 0; i < len; i++) { 178189251Ssam a = hex2byte(ipos); 179189251Ssam if (a < 0) 180189251Ssam return -1; 181189251Ssam *opos++ = a; 182189251Ssam ipos += 2; 183189251Ssam } 184189251Ssam return 0; 185189251Ssam} 186189251Ssam 187189251Ssam 188281806Srpauloint hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask) 189281806Srpaulo{ 190281806Srpaulo size_t i; 191281806Srpaulo int print_mask = 0; 192281806Srpaulo int res; 193281806Srpaulo 194281806Srpaulo for (i = 0; i < ETH_ALEN; i++) { 195281806Srpaulo if (mask[i] != 0xff) { 196281806Srpaulo print_mask = 1; 197281806Srpaulo break; 198281806Srpaulo } 199281806Srpaulo } 200281806Srpaulo 201281806Srpaulo if (print_mask) 202281806Srpaulo res = os_snprintf(buf, len, MACSTR "/" MACSTR, 203281806Srpaulo MAC2STR(addr), MAC2STR(mask)); 204281806Srpaulo else 205281806Srpaulo res = os_snprintf(buf, len, MACSTR, MAC2STR(addr)); 206281806Srpaulo if (os_snprintf_error(len, res)) 207281806Srpaulo return -1; 208281806Srpaulo return res; 209281806Srpaulo} 210281806Srpaulo 211281806Srpaulo 212189251Ssam/** 213189251Ssam * inc_byte_array - Increment arbitrary length byte array by one 214189251Ssam * @counter: Pointer to byte array 215189251Ssam * @len: Length of the counter in bytes 216189251Ssam * 217189251Ssam * This function increments the last byte of the counter by one and continues 218189251Ssam * rolling over to more significant bytes if the byte was incremented from 219189251Ssam * 0xff to 0x00. 220189251Ssam */ 221189251Ssamvoid inc_byte_array(u8 *counter, size_t len) 222189251Ssam{ 223189251Ssam int pos = len - 1; 224189251Ssam while (pos >= 0) { 225189251Ssam counter[pos]++; 226189251Ssam if (counter[pos] != 0) 227189251Ssam break; 228189251Ssam pos--; 229189251Ssam } 230189251Ssam} 231189251Ssam 232189251Ssam 233189251Ssamvoid wpa_get_ntp_timestamp(u8 *buf) 234189251Ssam{ 235189251Ssam struct os_time now; 236189251Ssam u32 sec, usec; 237189251Ssam be32 tmp; 238189251Ssam 239189251Ssam /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ 240189251Ssam os_get_time(&now); 241189251Ssam sec = now.sec + 2208988800U; /* Epoch to 1900 */ 242189251Ssam /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ 243189251Ssam usec = now.usec; 244189251Ssam usec = 4295 * usec - (usec >> 5) - (usec >> 9); 245189251Ssam tmp = host_to_be32(sec); 246189251Ssam os_memcpy(buf, (u8 *) &tmp, 4); 247189251Ssam tmp = host_to_be32(usec); 248189251Ssam os_memcpy(buf + 4, (u8 *) &tmp, 4); 249189251Ssam} 250189251Ssam 251281806Srpaulo/** 252281806Srpaulo * wpa_scnprintf - Simpler-to-use snprintf function 253281806Srpaulo * @buf: Output buffer 254281806Srpaulo * @size: Buffer size 255281806Srpaulo * @fmt: format 256281806Srpaulo * 257281806Srpaulo * Simpler snprintf version that doesn't require further error checks - the 258281806Srpaulo * return value only indicates how many bytes were actually written, excluding 259281806Srpaulo * the NULL byte (i.e., 0 on error, size-1 if buffer is not big enough). 260281806Srpaulo */ 261281806Srpauloint wpa_scnprintf(char *buf, size_t size, const char *fmt, ...) 262281806Srpaulo{ 263281806Srpaulo va_list ap; 264281806Srpaulo int ret; 265189251Ssam 266281806Srpaulo if (!size) 267281806Srpaulo return 0; 268281806Srpaulo 269281806Srpaulo va_start(ap, fmt); 270281806Srpaulo ret = vsnprintf(buf, size, fmt, ap); 271281806Srpaulo va_end(ap); 272281806Srpaulo 273281806Srpaulo if (ret < 0) 274281806Srpaulo return 0; 275281806Srpaulo if ((size_t) ret >= size) 276281806Srpaulo return size - 1; 277281806Srpaulo 278281806Srpaulo return ret; 279281806Srpaulo} 280281806Srpaulo 281289549Srpaulo 282289549Srpauloint wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, 283289549Srpaulo char sep) 284289549Srpaulo{ 285289549Srpaulo size_t i; 286289549Srpaulo char *pos = buf, *end = buf + buf_size; 287289549Srpaulo int ret; 288289549Srpaulo 289289549Srpaulo if (buf_size == 0) 290289549Srpaulo return 0; 291289549Srpaulo 292289549Srpaulo for (i = 0; i < len; i++) { 293289549Srpaulo ret = os_snprintf(pos, end - pos, "%02x%c", 294289549Srpaulo data[i], sep); 295289549Srpaulo if (os_snprintf_error(end - pos, ret)) { 296289549Srpaulo end[-1] = '\0'; 297289549Srpaulo return pos - buf; 298289549Srpaulo } 299289549Srpaulo pos += ret; 300289549Srpaulo } 301289549Srpaulo pos[-1] = '\0'; 302289549Srpaulo return pos - buf; 303289549Srpaulo} 304289549Srpaulo 305289549Srpaulo 306189251Ssamstatic inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, 307189251Ssam size_t len, int uppercase) 308189251Ssam{ 309189251Ssam size_t i; 310189251Ssam char *pos = buf, *end = buf + buf_size; 311189251Ssam int ret; 312189251Ssam if (buf_size == 0) 313189251Ssam return 0; 314189251Ssam for (i = 0; i < len; i++) { 315189251Ssam ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", 316189251Ssam data[i]); 317281806Srpaulo if (os_snprintf_error(end - pos, ret)) { 318189251Ssam end[-1] = '\0'; 319189251Ssam return pos - buf; 320189251Ssam } 321189251Ssam pos += ret; 322189251Ssam } 323189251Ssam end[-1] = '\0'; 324189251Ssam return pos - buf; 325189251Ssam} 326189251Ssam 327189251Ssam/** 328189251Ssam * wpa_snprintf_hex - Print data as a hex string into a buffer 329189251Ssam * @buf: Memory area to use as the output buffer 330189251Ssam * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) 331189251Ssam * @data: Data to be printed 332189251Ssam * @len: Length of data in bytes 333189251Ssam * Returns: Number of bytes written 334189251Ssam */ 335189251Ssamint wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) 336189251Ssam{ 337189251Ssam return _wpa_snprintf_hex(buf, buf_size, data, len, 0); 338189251Ssam} 339189251Ssam 340189251Ssam 341189251Ssam/** 342189251Ssam * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf 343189251Ssam * @buf: Memory area to use as the output buffer 344189251Ssam * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) 345189251Ssam * @data: Data to be printed 346189251Ssam * @len: Length of data in bytes 347189251Ssam * Returns: Number of bytes written 348189251Ssam */ 349189251Ssamint wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, 350189251Ssam size_t len) 351189251Ssam{ 352189251Ssam return _wpa_snprintf_hex(buf, buf_size, data, len, 1); 353189251Ssam} 354189251Ssam 355189251Ssam 356189251Ssam#ifdef CONFIG_ANSI_C_EXTRA 357189251Ssam 358189251Ssam#ifdef _WIN32_WCE 359189251Ssamvoid perror(const char *s) 360189251Ssam{ 361189251Ssam wpa_printf(MSG_ERROR, "%s: GetLastError: %d", 362189251Ssam s, (int) GetLastError()); 363189251Ssam} 364189251Ssam#endif /* _WIN32_WCE */ 365189251Ssam 366189251Ssam 367189251Ssamint optind = 1; 368189251Ssamint optopt; 369189251Ssamchar *optarg; 370189251Ssam 371189251Ssamint getopt(int argc, char *const argv[], const char *optstring) 372189251Ssam{ 373189251Ssam static int optchr = 1; 374189251Ssam char *cp; 375189251Ssam 376189251Ssam if (optchr == 1) { 377189251Ssam if (optind >= argc) { 378189251Ssam /* all arguments processed */ 379189251Ssam return EOF; 380189251Ssam } 381189251Ssam 382189251Ssam if (argv[optind][0] != '-' || argv[optind][1] == '\0') { 383189251Ssam /* no option characters */ 384189251Ssam return EOF; 385189251Ssam } 386189251Ssam } 387189251Ssam 388189251Ssam if (os_strcmp(argv[optind], "--") == 0) { 389189251Ssam /* no more options */ 390189251Ssam optind++; 391189251Ssam return EOF; 392189251Ssam } 393189251Ssam 394189251Ssam optopt = argv[optind][optchr]; 395189251Ssam cp = os_strchr(optstring, optopt); 396189251Ssam if (cp == NULL || optopt == ':') { 397189251Ssam if (argv[optind][++optchr] == '\0') { 398189251Ssam optchr = 1; 399189251Ssam optind++; 400189251Ssam } 401189251Ssam return '?'; 402189251Ssam } 403189251Ssam 404189251Ssam if (cp[1] == ':') { 405189251Ssam /* Argument required */ 406189251Ssam optchr = 1; 407189251Ssam if (argv[optind][optchr + 1]) { 408189251Ssam /* No space between option and argument */ 409189251Ssam optarg = &argv[optind++][optchr + 1]; 410189251Ssam } else if (++optind >= argc) { 411189251Ssam /* option requires an argument */ 412189251Ssam return '?'; 413189251Ssam } else { 414189251Ssam /* Argument in the next argv */ 415189251Ssam optarg = argv[optind++]; 416189251Ssam } 417189251Ssam } else { 418189251Ssam /* No argument */ 419189251Ssam if (argv[optind][++optchr] == '\0') { 420189251Ssam optchr = 1; 421189251Ssam optind++; 422189251Ssam } 423189251Ssam optarg = NULL; 424189251Ssam } 425189251Ssam return *cp; 426189251Ssam} 427189251Ssam#endif /* CONFIG_ANSI_C_EXTRA */ 428189251Ssam 429189251Ssam 430189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 431189251Ssam/** 432189251Ssam * wpa_unicode2ascii_inplace - Convert unicode string into ASCII 433189251Ssam * @str: Pointer to string to convert 434189251Ssam * 435189251Ssam * This function converts a unicode string to ASCII using the same 436189251Ssam * buffer for output. If UNICODE is not set, the buffer is not 437189251Ssam * modified. 438189251Ssam */ 439189251Ssamvoid wpa_unicode2ascii_inplace(TCHAR *str) 440189251Ssam{ 441189251Ssam#ifdef UNICODE 442189251Ssam char *dst = (char *) str; 443189251Ssam while (*str) 444189251Ssam *dst++ = (char) *str++; 445189251Ssam *dst = '\0'; 446189251Ssam#endif /* UNICODE */ 447189251Ssam} 448189251Ssam 449189251Ssam 450189251SsamTCHAR * wpa_strdup_tchar(const char *str) 451189251Ssam{ 452189251Ssam#ifdef UNICODE 453189251Ssam TCHAR *buf; 454189251Ssam buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR)); 455189251Ssam if (buf == NULL) 456189251Ssam return NULL; 457189251Ssam wsprintf(buf, L"%S", str); 458189251Ssam return buf; 459189251Ssam#else /* UNICODE */ 460189251Ssam return os_strdup(str); 461189251Ssam#endif /* UNICODE */ 462189251Ssam} 463189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 464189251Ssam 465189251Ssam 466252726Srpaulovoid printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) 467252726Srpaulo{ 468252726Srpaulo char *end = txt + maxlen; 469252726Srpaulo size_t i; 470252726Srpaulo 471252726Srpaulo for (i = 0; i < len; i++) { 472281806Srpaulo if (txt + 4 >= end) 473252726Srpaulo break; 474252726Srpaulo 475252726Srpaulo switch (data[i]) { 476252726Srpaulo case '\"': 477252726Srpaulo *txt++ = '\\'; 478252726Srpaulo *txt++ = '\"'; 479252726Srpaulo break; 480252726Srpaulo case '\\': 481252726Srpaulo *txt++ = '\\'; 482252726Srpaulo *txt++ = '\\'; 483252726Srpaulo break; 484281806Srpaulo case '\033': 485252726Srpaulo *txt++ = '\\'; 486252726Srpaulo *txt++ = 'e'; 487252726Srpaulo break; 488252726Srpaulo case '\n': 489252726Srpaulo *txt++ = '\\'; 490252726Srpaulo *txt++ = 'n'; 491252726Srpaulo break; 492252726Srpaulo case '\r': 493252726Srpaulo *txt++ = '\\'; 494252726Srpaulo *txt++ = 'r'; 495252726Srpaulo break; 496252726Srpaulo case '\t': 497252726Srpaulo *txt++ = '\\'; 498252726Srpaulo *txt++ = 't'; 499252726Srpaulo break; 500252726Srpaulo default: 501252726Srpaulo if (data[i] >= 32 && data[i] <= 127) { 502252726Srpaulo *txt++ = data[i]; 503252726Srpaulo } else { 504252726Srpaulo txt += os_snprintf(txt, end - txt, "\\x%02x", 505252726Srpaulo data[i]); 506252726Srpaulo } 507252726Srpaulo break; 508252726Srpaulo } 509252726Srpaulo } 510252726Srpaulo 511252726Srpaulo *txt = '\0'; 512252726Srpaulo} 513252726Srpaulo 514252726Srpaulo 515252726Srpaulosize_t printf_decode(u8 *buf, size_t maxlen, const char *str) 516252726Srpaulo{ 517252726Srpaulo const char *pos = str; 518252726Srpaulo size_t len = 0; 519252726Srpaulo int val; 520252726Srpaulo 521252726Srpaulo while (*pos) { 522281806Srpaulo if (len + 1 >= maxlen) 523252726Srpaulo break; 524252726Srpaulo switch (*pos) { 525252726Srpaulo case '\\': 526252726Srpaulo pos++; 527252726Srpaulo switch (*pos) { 528252726Srpaulo case '\\': 529252726Srpaulo buf[len++] = '\\'; 530252726Srpaulo pos++; 531252726Srpaulo break; 532252726Srpaulo case '"': 533252726Srpaulo buf[len++] = '"'; 534252726Srpaulo pos++; 535252726Srpaulo break; 536252726Srpaulo case 'n': 537252726Srpaulo buf[len++] = '\n'; 538252726Srpaulo pos++; 539252726Srpaulo break; 540252726Srpaulo case 'r': 541252726Srpaulo buf[len++] = '\r'; 542252726Srpaulo pos++; 543252726Srpaulo break; 544252726Srpaulo case 't': 545252726Srpaulo buf[len++] = '\t'; 546252726Srpaulo pos++; 547252726Srpaulo break; 548252726Srpaulo case 'e': 549281806Srpaulo buf[len++] = '\033'; 550252726Srpaulo pos++; 551252726Srpaulo break; 552252726Srpaulo case 'x': 553252726Srpaulo pos++; 554252726Srpaulo val = hex2byte(pos); 555252726Srpaulo if (val < 0) { 556252726Srpaulo val = hex2num(*pos); 557252726Srpaulo if (val < 0) 558252726Srpaulo break; 559252726Srpaulo buf[len++] = val; 560252726Srpaulo pos++; 561252726Srpaulo } else { 562252726Srpaulo buf[len++] = val; 563252726Srpaulo pos += 2; 564252726Srpaulo } 565252726Srpaulo break; 566252726Srpaulo case '0': 567252726Srpaulo case '1': 568252726Srpaulo case '2': 569252726Srpaulo case '3': 570252726Srpaulo case '4': 571252726Srpaulo case '5': 572252726Srpaulo case '6': 573252726Srpaulo case '7': 574252726Srpaulo val = *pos++ - '0'; 575252726Srpaulo if (*pos >= '0' && *pos <= '7') 576252726Srpaulo val = val * 8 + (*pos++ - '0'); 577252726Srpaulo if (*pos >= '0' && *pos <= '7') 578252726Srpaulo val = val * 8 + (*pos++ - '0'); 579252726Srpaulo buf[len++] = val; 580252726Srpaulo break; 581252726Srpaulo default: 582252726Srpaulo break; 583252726Srpaulo } 584252726Srpaulo break; 585252726Srpaulo default: 586252726Srpaulo buf[len++] = *pos++; 587252726Srpaulo break; 588252726Srpaulo } 589252726Srpaulo } 590281806Srpaulo if (maxlen > len) 591281806Srpaulo buf[len] = '\0'; 592252726Srpaulo 593252726Srpaulo return len; 594252726Srpaulo} 595252726Srpaulo 596252726Srpaulo 597189251Ssam/** 598189251Ssam * wpa_ssid_txt - Convert SSID to a printable string 599189251Ssam * @ssid: SSID (32-octet string) 600189251Ssam * @ssid_len: Length of ssid in octets 601189251Ssam * Returns: Pointer to a printable string 602189251Ssam * 603189251Ssam * This function can be used to convert SSIDs into printable form. In most 604189251Ssam * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard 605189251Ssam * does not limit the used character set, so anything could be used in an SSID. 606189251Ssam * 607189251Ssam * This function uses a static buffer, so only one call can be used at the 608189251Ssam * time, i.e., this is not re-entrant and the returned buffer must be used 609189251Ssam * before calling this again. 610189251Ssam */ 611189251Ssamconst char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len) 612189251Ssam{ 613289549Srpaulo static char ssid_txt[SSID_MAX_LEN * 4 + 1]; 614189251Ssam 615252726Srpaulo if (ssid == NULL) { 616252726Srpaulo ssid_txt[0] = '\0'; 617252726Srpaulo return ssid_txt; 618189251Ssam } 619252726Srpaulo 620252726Srpaulo printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len); 621189251Ssam return ssid_txt; 622189251Ssam} 623209158Srpaulo 624209158Srpaulo 625209158Srpaulovoid * __hide_aliasing_typecast(void *foo) 626209158Srpaulo{ 627209158Srpaulo return foo; 628209158Srpaulo} 629252726Srpaulo 630252726Srpaulo 631252726Srpaulochar * wpa_config_parse_string(const char *value, size_t *len) 632252726Srpaulo{ 633252726Srpaulo if (*value == '"') { 634252726Srpaulo const char *pos; 635252726Srpaulo char *str; 636252726Srpaulo value++; 637252726Srpaulo pos = os_strrchr(value, '"'); 638252726Srpaulo if (pos == NULL || pos[1] != '\0') 639252726Srpaulo return NULL; 640252726Srpaulo *len = pos - value; 641281806Srpaulo str = dup_binstr(value, *len); 642252726Srpaulo if (str == NULL) 643252726Srpaulo return NULL; 644252726Srpaulo return str; 645252726Srpaulo } else if (*value == 'P' && value[1] == '"') { 646252726Srpaulo const char *pos; 647252726Srpaulo char *tstr, *str; 648252726Srpaulo size_t tlen; 649252726Srpaulo value += 2; 650252726Srpaulo pos = os_strrchr(value, '"'); 651252726Srpaulo if (pos == NULL || pos[1] != '\0') 652252726Srpaulo return NULL; 653252726Srpaulo tlen = pos - value; 654281806Srpaulo tstr = dup_binstr(value, tlen); 655252726Srpaulo if (tstr == NULL) 656252726Srpaulo return NULL; 657252726Srpaulo 658252726Srpaulo str = os_malloc(tlen + 1); 659252726Srpaulo if (str == NULL) { 660252726Srpaulo os_free(tstr); 661252726Srpaulo return NULL; 662252726Srpaulo } 663252726Srpaulo 664252726Srpaulo *len = printf_decode((u8 *) str, tlen + 1, tstr); 665252726Srpaulo os_free(tstr); 666252726Srpaulo 667252726Srpaulo return str; 668252726Srpaulo } else { 669252726Srpaulo u8 *str; 670252726Srpaulo size_t tlen, hlen = os_strlen(value); 671252726Srpaulo if (hlen & 1) 672252726Srpaulo return NULL; 673252726Srpaulo tlen = hlen / 2; 674252726Srpaulo str = os_malloc(tlen + 1); 675252726Srpaulo if (str == NULL) 676252726Srpaulo return NULL; 677252726Srpaulo if (hexstr2bin(value, str, tlen)) { 678252726Srpaulo os_free(str); 679252726Srpaulo return NULL; 680252726Srpaulo } 681252726Srpaulo str[tlen] = '\0'; 682252726Srpaulo *len = tlen; 683252726Srpaulo return (char *) str; 684252726Srpaulo } 685252726Srpaulo} 686252726Srpaulo 687252726Srpaulo 688252726Srpauloint is_hex(const u8 *data, size_t len) 689252726Srpaulo{ 690252726Srpaulo size_t i; 691252726Srpaulo 692252726Srpaulo for (i = 0; i < len; i++) { 693252726Srpaulo if (data[i] < 32 || data[i] >= 127) 694252726Srpaulo return 1; 695252726Srpaulo } 696252726Srpaulo return 0; 697252726Srpaulo} 698252726Srpaulo 699252726Srpaulo 700252726Srpaulosize_t merge_byte_arrays(u8 *res, size_t res_len, 701252726Srpaulo const u8 *src1, size_t src1_len, 702252726Srpaulo const u8 *src2, size_t src2_len) 703252726Srpaulo{ 704252726Srpaulo size_t len = 0; 705252726Srpaulo 706252726Srpaulo os_memset(res, 0, res_len); 707252726Srpaulo 708252726Srpaulo if (src1) { 709252726Srpaulo if (src1_len >= res_len) { 710252726Srpaulo os_memcpy(res, src1, res_len); 711252726Srpaulo return res_len; 712252726Srpaulo } 713252726Srpaulo 714252726Srpaulo os_memcpy(res, src1, src1_len); 715252726Srpaulo len += src1_len; 716252726Srpaulo } 717252726Srpaulo 718252726Srpaulo if (src2) { 719252726Srpaulo if (len + src2_len >= res_len) { 720252726Srpaulo os_memcpy(res + len, src2, res_len - len); 721252726Srpaulo return res_len; 722252726Srpaulo } 723252726Srpaulo 724252726Srpaulo os_memcpy(res + len, src2, src2_len); 725252726Srpaulo len += src2_len; 726252726Srpaulo } 727252726Srpaulo 728252726Srpaulo return len; 729252726Srpaulo} 730281806Srpaulo 731281806Srpaulo 732281806Srpaulochar * dup_binstr(const void *src, size_t len) 733281806Srpaulo{ 734281806Srpaulo char *res; 735281806Srpaulo 736281806Srpaulo if (src == NULL) 737281806Srpaulo return NULL; 738281806Srpaulo res = os_malloc(len + 1); 739281806Srpaulo if (res == NULL) 740281806Srpaulo return NULL; 741281806Srpaulo os_memcpy(res, src, len); 742281806Srpaulo res[len] = '\0'; 743281806Srpaulo 744281806Srpaulo return res; 745281806Srpaulo} 746281806Srpaulo 747281806Srpaulo 748281806Srpauloint freq_range_list_parse(struct wpa_freq_range_list *res, const char *value) 749281806Srpaulo{ 750281806Srpaulo struct wpa_freq_range *freq = NULL, *n; 751281806Srpaulo unsigned int count = 0; 752281806Srpaulo const char *pos, *pos2, *pos3; 753281806Srpaulo 754281806Srpaulo /* 755281806Srpaulo * Comma separated list of frequency ranges. 756281806Srpaulo * For example: 2412-2432,2462,5000-6000 757281806Srpaulo */ 758281806Srpaulo pos = value; 759281806Srpaulo while (pos && pos[0]) { 760281806Srpaulo n = os_realloc_array(freq, count + 1, 761281806Srpaulo sizeof(struct wpa_freq_range)); 762281806Srpaulo if (n == NULL) { 763281806Srpaulo os_free(freq); 764281806Srpaulo return -1; 765281806Srpaulo } 766281806Srpaulo freq = n; 767281806Srpaulo freq[count].min = atoi(pos); 768281806Srpaulo pos2 = os_strchr(pos, '-'); 769281806Srpaulo pos3 = os_strchr(pos, ','); 770281806Srpaulo if (pos2 && (!pos3 || pos2 < pos3)) { 771281806Srpaulo pos2++; 772281806Srpaulo freq[count].max = atoi(pos2); 773281806Srpaulo } else 774281806Srpaulo freq[count].max = freq[count].min; 775281806Srpaulo pos = pos3; 776281806Srpaulo if (pos) 777281806Srpaulo pos++; 778281806Srpaulo count++; 779281806Srpaulo } 780281806Srpaulo 781281806Srpaulo os_free(res->range); 782281806Srpaulo res->range = freq; 783281806Srpaulo res->num = count; 784281806Srpaulo 785281806Srpaulo return 0; 786281806Srpaulo} 787281806Srpaulo 788281806Srpaulo 789281806Srpauloint freq_range_list_includes(const struct wpa_freq_range_list *list, 790281806Srpaulo unsigned int freq) 791281806Srpaulo{ 792281806Srpaulo unsigned int i; 793281806Srpaulo 794281806Srpaulo if (list == NULL) 795281806Srpaulo return 0; 796281806Srpaulo 797281806Srpaulo for (i = 0; i < list->num; i++) { 798281806Srpaulo if (freq >= list->range[i].min && freq <= list->range[i].max) 799281806Srpaulo return 1; 800281806Srpaulo } 801281806Srpaulo 802281806Srpaulo return 0; 803281806Srpaulo} 804281806Srpaulo 805281806Srpaulo 806281806Srpaulochar * freq_range_list_str(const struct wpa_freq_range_list *list) 807281806Srpaulo{ 808281806Srpaulo char *buf, *pos, *end; 809281806Srpaulo size_t maxlen; 810281806Srpaulo unsigned int i; 811281806Srpaulo int res; 812281806Srpaulo 813281806Srpaulo if (list->num == 0) 814281806Srpaulo return NULL; 815281806Srpaulo 816281806Srpaulo maxlen = list->num * 30; 817281806Srpaulo buf = os_malloc(maxlen); 818281806Srpaulo if (buf == NULL) 819281806Srpaulo return NULL; 820281806Srpaulo pos = buf; 821281806Srpaulo end = buf + maxlen; 822281806Srpaulo 823281806Srpaulo for (i = 0; i < list->num; i++) { 824281806Srpaulo struct wpa_freq_range *range = &list->range[i]; 825281806Srpaulo 826281806Srpaulo if (range->min == range->max) 827281806Srpaulo res = os_snprintf(pos, end - pos, "%s%u", 828281806Srpaulo i == 0 ? "" : ",", range->min); 829281806Srpaulo else 830281806Srpaulo res = os_snprintf(pos, end - pos, "%s%u-%u", 831281806Srpaulo i == 0 ? "" : ",", 832281806Srpaulo range->min, range->max); 833281806Srpaulo if (os_snprintf_error(end - pos, res)) { 834281806Srpaulo os_free(buf); 835281806Srpaulo return NULL; 836281806Srpaulo } 837281806Srpaulo pos += res; 838281806Srpaulo } 839281806Srpaulo 840281806Srpaulo return buf; 841281806Srpaulo} 842281806Srpaulo 843281806Srpaulo 844281806Srpauloint int_array_len(const int *a) 845281806Srpaulo{ 846281806Srpaulo int i; 847281806Srpaulo for (i = 0; a && a[i]; i++) 848281806Srpaulo ; 849281806Srpaulo return i; 850281806Srpaulo} 851281806Srpaulo 852281806Srpaulo 853281806Srpaulovoid int_array_concat(int **res, const int *a) 854281806Srpaulo{ 855281806Srpaulo int reslen, alen, i; 856281806Srpaulo int *n; 857281806Srpaulo 858281806Srpaulo reslen = int_array_len(*res); 859281806Srpaulo alen = int_array_len(a); 860281806Srpaulo 861281806Srpaulo n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); 862281806Srpaulo if (n == NULL) { 863281806Srpaulo os_free(*res); 864281806Srpaulo *res = NULL; 865281806Srpaulo return; 866281806Srpaulo } 867281806Srpaulo for (i = 0; i <= alen; i++) 868281806Srpaulo n[reslen + i] = a[i]; 869281806Srpaulo *res = n; 870281806Srpaulo} 871281806Srpaulo 872281806Srpaulo 873281806Srpaulostatic int freq_cmp(const void *a, const void *b) 874281806Srpaulo{ 875281806Srpaulo int _a = *(int *) a; 876281806Srpaulo int _b = *(int *) b; 877281806Srpaulo 878281806Srpaulo if (_a == 0) 879281806Srpaulo return 1; 880281806Srpaulo if (_b == 0) 881281806Srpaulo return -1; 882281806Srpaulo return _a - _b; 883281806Srpaulo} 884281806Srpaulo 885281806Srpaulo 886281806Srpaulovoid int_array_sort_unique(int *a) 887281806Srpaulo{ 888281806Srpaulo int alen; 889281806Srpaulo int i, j; 890281806Srpaulo 891281806Srpaulo if (a == NULL) 892281806Srpaulo return; 893281806Srpaulo 894281806Srpaulo alen = int_array_len(a); 895281806Srpaulo qsort(a, alen, sizeof(int), freq_cmp); 896281806Srpaulo 897281806Srpaulo i = 0; 898281806Srpaulo j = 1; 899281806Srpaulo while (a[i] && a[j]) { 900281806Srpaulo if (a[i] == a[j]) { 901281806Srpaulo j++; 902281806Srpaulo continue; 903281806Srpaulo } 904281806Srpaulo a[++i] = a[j++]; 905281806Srpaulo } 906281806Srpaulo if (a[i]) 907281806Srpaulo i++; 908281806Srpaulo a[i] = 0; 909281806Srpaulo} 910281806Srpaulo 911281806Srpaulo 912281806Srpaulovoid int_array_add_unique(int **res, int a) 913281806Srpaulo{ 914281806Srpaulo int reslen; 915281806Srpaulo int *n; 916281806Srpaulo 917281806Srpaulo for (reslen = 0; *res && (*res)[reslen]; reslen++) { 918281806Srpaulo if ((*res)[reslen] == a) 919281806Srpaulo return; /* already in the list */ 920281806Srpaulo } 921281806Srpaulo 922281806Srpaulo n = os_realloc_array(*res, reslen + 2, sizeof(int)); 923281806Srpaulo if (n == NULL) { 924281806Srpaulo os_free(*res); 925281806Srpaulo *res = NULL; 926281806Srpaulo return; 927281806Srpaulo } 928281806Srpaulo 929281806Srpaulo n[reslen] = a; 930281806Srpaulo n[reslen + 1] = 0; 931281806Srpaulo 932281806Srpaulo *res = n; 933281806Srpaulo} 934281806Srpaulo 935281806Srpaulo 936281806Srpaulovoid str_clear_free(char *str) 937281806Srpaulo{ 938281806Srpaulo if (str) { 939281806Srpaulo size_t len = os_strlen(str); 940281806Srpaulo os_memset(str, 0, len); 941281806Srpaulo os_free(str); 942281806Srpaulo } 943281806Srpaulo} 944281806Srpaulo 945281806Srpaulo 946281806Srpaulovoid bin_clear_free(void *bin, size_t len) 947281806Srpaulo{ 948281806Srpaulo if (bin) { 949281806Srpaulo os_memset(bin, 0, len); 950281806Srpaulo os_free(bin); 951281806Srpaulo } 952281806Srpaulo} 953281806Srpaulo 954281806Srpaulo 955281806Srpauloint random_mac_addr(u8 *addr) 956281806Srpaulo{ 957281806Srpaulo if (os_get_random(addr, ETH_ALEN) < 0) 958281806Srpaulo return -1; 959281806Srpaulo addr[0] &= 0xfe; /* unicast */ 960281806Srpaulo addr[0] |= 0x02; /* locally administered */ 961281806Srpaulo return 0; 962281806Srpaulo} 963281806Srpaulo 964281806Srpaulo 965281806Srpauloint random_mac_addr_keep_oui(u8 *addr) 966281806Srpaulo{ 967281806Srpaulo if (os_get_random(addr + 3, 3) < 0) 968281806Srpaulo return -1; 969281806Srpaulo addr[0] &= 0xfe; /* unicast */ 970281806Srpaulo addr[0] |= 0x02; /* locally administered */ 971281806Srpaulo return 0; 972281806Srpaulo} 973281806Srpaulo 974281806Srpaulo 975281806Srpaulo/** 976289549Srpaulo * cstr_token - Get next token from const char string 977289549Srpaulo * @str: a constant string to tokenize 978289549Srpaulo * @delim: a string of delimiters 979289549Srpaulo * @last: a pointer to a character following the returned token 980289549Srpaulo * It has to be set to NULL for the first call and passed for any 981289549Srpaulo * futher call. 982289549Srpaulo * Returns: a pointer to token position in str or NULL 983289549Srpaulo * 984289549Srpaulo * This function is similar to str_token, but it can be used with both 985289549Srpaulo * char and const char strings. Differences: 986289549Srpaulo * - The str buffer remains unmodified 987289549Srpaulo * - The returned token is not a NULL terminated string, but a token 988289549Srpaulo * position in str buffer. If a return value is not NULL a size 989289549Srpaulo * of the returned token could be calculated as (last - token). 990289549Srpaulo */ 991289549Srpauloconst char * cstr_token(const char *str, const char *delim, const char **last) 992289549Srpaulo{ 993289549Srpaulo const char *end, *token = str; 994289549Srpaulo 995289549Srpaulo if (!str || !delim || !last) 996289549Srpaulo return NULL; 997289549Srpaulo 998289549Srpaulo if (*last) 999289549Srpaulo token = *last; 1000289549Srpaulo 1001289549Srpaulo while (*token && os_strchr(delim, *token)) 1002289549Srpaulo token++; 1003289549Srpaulo 1004289549Srpaulo if (!*token) 1005289549Srpaulo return NULL; 1006289549Srpaulo 1007289549Srpaulo end = token + 1; 1008289549Srpaulo 1009289549Srpaulo while (*end && !os_strchr(delim, *end)) 1010289549Srpaulo end++; 1011289549Srpaulo 1012289549Srpaulo *last = end; 1013289549Srpaulo return token; 1014289549Srpaulo} 1015289549Srpaulo 1016289549Srpaulo 1017289549Srpaulo/** 1018281806Srpaulo * str_token - Get next token from a string 1019281806Srpaulo * @buf: String to tokenize. Note that the string might be modified. 1020281806Srpaulo * @delim: String of delimiters 1021281806Srpaulo * @context: Pointer to save our context. Should be initialized with 1022281806Srpaulo * NULL on the first call, and passed for any further call. 1023281806Srpaulo * Returns: The next token, NULL if there are no more valid tokens. 1024281806Srpaulo */ 1025281806Srpaulochar * str_token(char *str, const char *delim, char **context) 1026281806Srpaulo{ 1027289549Srpaulo char *token = (char *) cstr_token(str, delim, (const char **) context); 1028281806Srpaulo 1029289549Srpaulo if (token && **context) 1030289549Srpaulo *(*context)++ = '\0'; 1031281806Srpaulo 1032289549Srpaulo return token; 1033281806Srpaulo} 1034281806Srpaulo 1035281806Srpaulo 1036281806Srpaulosize_t utf8_unescape(const char *inp, size_t in_size, 1037281806Srpaulo char *outp, size_t out_size) 1038281806Srpaulo{ 1039281806Srpaulo size_t res_size = 0; 1040281806Srpaulo 1041281806Srpaulo if (!inp || !outp) 1042281806Srpaulo return 0; 1043281806Srpaulo 1044281806Srpaulo if (!in_size) 1045281806Srpaulo in_size = os_strlen(inp); 1046281806Srpaulo 1047281806Srpaulo /* Advance past leading single quote */ 1048281806Srpaulo if (*inp == '\'' && in_size) { 1049281806Srpaulo inp++; 1050281806Srpaulo in_size--; 1051281806Srpaulo } 1052281806Srpaulo 1053281806Srpaulo while (in_size--) { 1054281806Srpaulo if (res_size >= out_size) 1055281806Srpaulo return 0; 1056281806Srpaulo 1057281806Srpaulo switch (*inp) { 1058281806Srpaulo case '\'': 1059281806Srpaulo /* Terminate on bare single quote */ 1060281806Srpaulo *outp = '\0'; 1061281806Srpaulo return res_size; 1062281806Srpaulo 1063281806Srpaulo case '\\': 1064281806Srpaulo if (!in_size--) 1065281806Srpaulo return 0; 1066281806Srpaulo inp++; 1067281806Srpaulo /* fall through */ 1068281806Srpaulo 1069281806Srpaulo default: 1070281806Srpaulo *outp++ = *inp++; 1071281806Srpaulo res_size++; 1072281806Srpaulo } 1073281806Srpaulo } 1074281806Srpaulo 1075281806Srpaulo /* NUL terminate if space allows */ 1076281806Srpaulo if (res_size < out_size) 1077281806Srpaulo *outp = '\0'; 1078281806Srpaulo 1079281806Srpaulo return res_size; 1080281806Srpaulo} 1081281806Srpaulo 1082281806Srpaulo 1083281806Srpaulosize_t utf8_escape(const char *inp, size_t in_size, 1084281806Srpaulo char *outp, size_t out_size) 1085281806Srpaulo{ 1086281806Srpaulo size_t res_size = 0; 1087281806Srpaulo 1088281806Srpaulo if (!inp || !outp) 1089281806Srpaulo return 0; 1090281806Srpaulo 1091281806Srpaulo /* inp may or may not be NUL terminated, but must be if 0 size 1092281806Srpaulo * is specified */ 1093281806Srpaulo if (!in_size) 1094281806Srpaulo in_size = os_strlen(inp); 1095281806Srpaulo 1096281806Srpaulo while (in_size--) { 1097281806Srpaulo if (res_size++ >= out_size) 1098281806Srpaulo return 0; 1099281806Srpaulo 1100281806Srpaulo switch (*inp) { 1101281806Srpaulo case '\\': 1102281806Srpaulo case '\'': 1103281806Srpaulo if (res_size++ >= out_size) 1104281806Srpaulo return 0; 1105281806Srpaulo *outp++ = '\\'; 1106281806Srpaulo /* fall through */ 1107281806Srpaulo 1108281806Srpaulo default: 1109281806Srpaulo *outp++ = *inp++; 1110281806Srpaulo break; 1111281806Srpaulo } 1112281806Srpaulo } 1113281806Srpaulo 1114281806Srpaulo /* NUL terminate if space allows */ 1115281806Srpaulo if (res_size < out_size) 1116281806Srpaulo *outp = '\0'; 1117281806Srpaulo 1118281806Srpaulo return res_size; 1119281806Srpaulo} 1120289549Srpaulo 1121289549Srpaulo 1122289549Srpauloint is_ctrl_char(char c) 1123289549Srpaulo{ 1124289549Srpaulo return c > 0 && c < 32; 1125289549Srpaulo} 1126