common.c revision 337817
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 */ 89337817Scy if (*r == '\0' || isspace((unsigned char) *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: 501337817Scy if (data[i] >= 32 && data[i] <= 126) { 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 700337817Scyint has_ctrl_char(const u8 *data, size_t len) 701337817Scy{ 702337817Scy size_t i; 703337817Scy 704337817Scy for (i = 0; i < len; i++) { 705337817Scy if (data[i] < 32 || data[i] == 127) 706337817Scy return 1; 707337817Scy } 708337817Scy return 0; 709337817Scy} 710337817Scy 711337817Scy 712337817Scyint has_newline(const char *str) 713337817Scy{ 714337817Scy while (*str) { 715337817Scy if (*str == '\n' || *str == '\r') 716337817Scy return 1; 717337817Scy str++; 718337817Scy } 719337817Scy return 0; 720337817Scy} 721337817Scy 722337817Scy 723252726Srpaulosize_t merge_byte_arrays(u8 *res, size_t res_len, 724252726Srpaulo const u8 *src1, size_t src1_len, 725252726Srpaulo const u8 *src2, size_t src2_len) 726252726Srpaulo{ 727252726Srpaulo size_t len = 0; 728252726Srpaulo 729252726Srpaulo os_memset(res, 0, res_len); 730252726Srpaulo 731252726Srpaulo if (src1) { 732252726Srpaulo if (src1_len >= res_len) { 733252726Srpaulo os_memcpy(res, src1, res_len); 734252726Srpaulo return res_len; 735252726Srpaulo } 736252726Srpaulo 737252726Srpaulo os_memcpy(res, src1, src1_len); 738252726Srpaulo len += src1_len; 739252726Srpaulo } 740252726Srpaulo 741252726Srpaulo if (src2) { 742252726Srpaulo if (len + src2_len >= res_len) { 743252726Srpaulo os_memcpy(res + len, src2, res_len - len); 744252726Srpaulo return res_len; 745252726Srpaulo } 746252726Srpaulo 747252726Srpaulo os_memcpy(res + len, src2, src2_len); 748252726Srpaulo len += src2_len; 749252726Srpaulo } 750252726Srpaulo 751252726Srpaulo return len; 752252726Srpaulo} 753281806Srpaulo 754281806Srpaulo 755281806Srpaulochar * dup_binstr(const void *src, size_t len) 756281806Srpaulo{ 757281806Srpaulo char *res; 758281806Srpaulo 759281806Srpaulo if (src == NULL) 760281806Srpaulo return NULL; 761281806Srpaulo res = os_malloc(len + 1); 762281806Srpaulo if (res == NULL) 763281806Srpaulo return NULL; 764281806Srpaulo os_memcpy(res, src, len); 765281806Srpaulo res[len] = '\0'; 766281806Srpaulo 767281806Srpaulo return res; 768281806Srpaulo} 769281806Srpaulo 770281806Srpaulo 771281806Srpauloint freq_range_list_parse(struct wpa_freq_range_list *res, const char *value) 772281806Srpaulo{ 773281806Srpaulo struct wpa_freq_range *freq = NULL, *n; 774281806Srpaulo unsigned int count = 0; 775281806Srpaulo const char *pos, *pos2, *pos3; 776281806Srpaulo 777281806Srpaulo /* 778281806Srpaulo * Comma separated list of frequency ranges. 779281806Srpaulo * For example: 2412-2432,2462,5000-6000 780281806Srpaulo */ 781281806Srpaulo pos = value; 782281806Srpaulo while (pos && pos[0]) { 783281806Srpaulo n = os_realloc_array(freq, count + 1, 784281806Srpaulo sizeof(struct wpa_freq_range)); 785281806Srpaulo if (n == NULL) { 786281806Srpaulo os_free(freq); 787281806Srpaulo return -1; 788281806Srpaulo } 789281806Srpaulo freq = n; 790281806Srpaulo freq[count].min = atoi(pos); 791281806Srpaulo pos2 = os_strchr(pos, '-'); 792281806Srpaulo pos3 = os_strchr(pos, ','); 793281806Srpaulo if (pos2 && (!pos3 || pos2 < pos3)) { 794281806Srpaulo pos2++; 795281806Srpaulo freq[count].max = atoi(pos2); 796281806Srpaulo } else 797281806Srpaulo freq[count].max = freq[count].min; 798281806Srpaulo pos = pos3; 799281806Srpaulo if (pos) 800281806Srpaulo pos++; 801281806Srpaulo count++; 802281806Srpaulo } 803281806Srpaulo 804281806Srpaulo os_free(res->range); 805281806Srpaulo res->range = freq; 806281806Srpaulo res->num = count; 807281806Srpaulo 808281806Srpaulo return 0; 809281806Srpaulo} 810281806Srpaulo 811281806Srpaulo 812281806Srpauloint freq_range_list_includes(const struct wpa_freq_range_list *list, 813281806Srpaulo unsigned int freq) 814281806Srpaulo{ 815281806Srpaulo unsigned int i; 816281806Srpaulo 817281806Srpaulo if (list == NULL) 818281806Srpaulo return 0; 819281806Srpaulo 820281806Srpaulo for (i = 0; i < list->num; i++) { 821281806Srpaulo if (freq >= list->range[i].min && freq <= list->range[i].max) 822281806Srpaulo return 1; 823281806Srpaulo } 824281806Srpaulo 825281806Srpaulo return 0; 826281806Srpaulo} 827281806Srpaulo 828281806Srpaulo 829281806Srpaulochar * freq_range_list_str(const struct wpa_freq_range_list *list) 830281806Srpaulo{ 831281806Srpaulo char *buf, *pos, *end; 832281806Srpaulo size_t maxlen; 833281806Srpaulo unsigned int i; 834281806Srpaulo int res; 835281806Srpaulo 836281806Srpaulo if (list->num == 0) 837281806Srpaulo return NULL; 838281806Srpaulo 839281806Srpaulo maxlen = list->num * 30; 840281806Srpaulo buf = os_malloc(maxlen); 841281806Srpaulo if (buf == NULL) 842281806Srpaulo return NULL; 843281806Srpaulo pos = buf; 844281806Srpaulo end = buf + maxlen; 845281806Srpaulo 846281806Srpaulo for (i = 0; i < list->num; i++) { 847281806Srpaulo struct wpa_freq_range *range = &list->range[i]; 848281806Srpaulo 849281806Srpaulo if (range->min == range->max) 850281806Srpaulo res = os_snprintf(pos, end - pos, "%s%u", 851281806Srpaulo i == 0 ? "" : ",", range->min); 852281806Srpaulo else 853281806Srpaulo res = os_snprintf(pos, end - pos, "%s%u-%u", 854281806Srpaulo i == 0 ? "" : ",", 855281806Srpaulo range->min, range->max); 856281806Srpaulo if (os_snprintf_error(end - pos, res)) { 857281806Srpaulo os_free(buf); 858281806Srpaulo return NULL; 859281806Srpaulo } 860281806Srpaulo pos += res; 861281806Srpaulo } 862281806Srpaulo 863281806Srpaulo return buf; 864281806Srpaulo} 865281806Srpaulo 866281806Srpaulo 867281806Srpauloint int_array_len(const int *a) 868281806Srpaulo{ 869281806Srpaulo int i; 870281806Srpaulo for (i = 0; a && a[i]; i++) 871281806Srpaulo ; 872281806Srpaulo return i; 873281806Srpaulo} 874281806Srpaulo 875281806Srpaulo 876281806Srpaulovoid int_array_concat(int **res, const int *a) 877281806Srpaulo{ 878281806Srpaulo int reslen, alen, i; 879281806Srpaulo int *n; 880281806Srpaulo 881281806Srpaulo reslen = int_array_len(*res); 882281806Srpaulo alen = int_array_len(a); 883281806Srpaulo 884281806Srpaulo n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); 885281806Srpaulo if (n == NULL) { 886281806Srpaulo os_free(*res); 887281806Srpaulo *res = NULL; 888281806Srpaulo return; 889281806Srpaulo } 890281806Srpaulo for (i = 0; i <= alen; i++) 891281806Srpaulo n[reslen + i] = a[i]; 892281806Srpaulo *res = n; 893281806Srpaulo} 894281806Srpaulo 895281806Srpaulo 896281806Srpaulostatic int freq_cmp(const void *a, const void *b) 897281806Srpaulo{ 898281806Srpaulo int _a = *(int *) a; 899281806Srpaulo int _b = *(int *) b; 900281806Srpaulo 901281806Srpaulo if (_a == 0) 902281806Srpaulo return 1; 903281806Srpaulo if (_b == 0) 904281806Srpaulo return -1; 905281806Srpaulo return _a - _b; 906281806Srpaulo} 907281806Srpaulo 908281806Srpaulo 909281806Srpaulovoid int_array_sort_unique(int *a) 910281806Srpaulo{ 911281806Srpaulo int alen; 912281806Srpaulo int i, j; 913281806Srpaulo 914281806Srpaulo if (a == NULL) 915281806Srpaulo return; 916281806Srpaulo 917281806Srpaulo alen = int_array_len(a); 918281806Srpaulo qsort(a, alen, sizeof(int), freq_cmp); 919281806Srpaulo 920281806Srpaulo i = 0; 921281806Srpaulo j = 1; 922281806Srpaulo while (a[i] && a[j]) { 923281806Srpaulo if (a[i] == a[j]) { 924281806Srpaulo j++; 925281806Srpaulo continue; 926281806Srpaulo } 927281806Srpaulo a[++i] = a[j++]; 928281806Srpaulo } 929281806Srpaulo if (a[i]) 930281806Srpaulo i++; 931281806Srpaulo a[i] = 0; 932281806Srpaulo} 933281806Srpaulo 934281806Srpaulo 935281806Srpaulovoid int_array_add_unique(int **res, int a) 936281806Srpaulo{ 937281806Srpaulo int reslen; 938281806Srpaulo int *n; 939281806Srpaulo 940281806Srpaulo for (reslen = 0; *res && (*res)[reslen]; reslen++) { 941281806Srpaulo if ((*res)[reslen] == a) 942281806Srpaulo return; /* already in the list */ 943281806Srpaulo } 944281806Srpaulo 945281806Srpaulo n = os_realloc_array(*res, reslen + 2, sizeof(int)); 946281806Srpaulo if (n == NULL) { 947281806Srpaulo os_free(*res); 948281806Srpaulo *res = NULL; 949281806Srpaulo return; 950281806Srpaulo } 951281806Srpaulo 952281806Srpaulo n[reslen] = a; 953281806Srpaulo n[reslen + 1] = 0; 954281806Srpaulo 955281806Srpaulo *res = n; 956281806Srpaulo} 957281806Srpaulo 958281806Srpaulo 959281806Srpaulovoid str_clear_free(char *str) 960281806Srpaulo{ 961281806Srpaulo if (str) { 962281806Srpaulo size_t len = os_strlen(str); 963281806Srpaulo os_memset(str, 0, len); 964281806Srpaulo os_free(str); 965281806Srpaulo } 966281806Srpaulo} 967281806Srpaulo 968281806Srpaulo 969281806Srpaulovoid bin_clear_free(void *bin, size_t len) 970281806Srpaulo{ 971281806Srpaulo if (bin) { 972281806Srpaulo os_memset(bin, 0, len); 973281806Srpaulo os_free(bin); 974281806Srpaulo } 975281806Srpaulo} 976281806Srpaulo 977281806Srpaulo 978281806Srpauloint random_mac_addr(u8 *addr) 979281806Srpaulo{ 980281806Srpaulo if (os_get_random(addr, ETH_ALEN) < 0) 981281806Srpaulo return -1; 982281806Srpaulo addr[0] &= 0xfe; /* unicast */ 983281806Srpaulo addr[0] |= 0x02; /* locally administered */ 984281806Srpaulo return 0; 985281806Srpaulo} 986281806Srpaulo 987281806Srpaulo 988281806Srpauloint random_mac_addr_keep_oui(u8 *addr) 989281806Srpaulo{ 990281806Srpaulo if (os_get_random(addr + 3, 3) < 0) 991281806Srpaulo return -1; 992281806Srpaulo addr[0] &= 0xfe; /* unicast */ 993281806Srpaulo addr[0] |= 0x02; /* locally administered */ 994281806Srpaulo return 0; 995281806Srpaulo} 996281806Srpaulo 997281806Srpaulo 998281806Srpaulo/** 999289549Srpaulo * cstr_token - Get next token from const char string 1000289549Srpaulo * @str: a constant string to tokenize 1001289549Srpaulo * @delim: a string of delimiters 1002289549Srpaulo * @last: a pointer to a character following the returned token 1003289549Srpaulo * It has to be set to NULL for the first call and passed for any 1004337817Scy * further call. 1005289549Srpaulo * Returns: a pointer to token position in str or NULL 1006289549Srpaulo * 1007289549Srpaulo * This function is similar to str_token, but it can be used with both 1008289549Srpaulo * char and const char strings. Differences: 1009289549Srpaulo * - The str buffer remains unmodified 1010289549Srpaulo * - The returned token is not a NULL terminated string, but a token 1011289549Srpaulo * position in str buffer. If a return value is not NULL a size 1012289549Srpaulo * of the returned token could be calculated as (last - token). 1013289549Srpaulo */ 1014289549Srpauloconst char * cstr_token(const char *str, const char *delim, const char **last) 1015289549Srpaulo{ 1016289549Srpaulo const char *end, *token = str; 1017289549Srpaulo 1018289549Srpaulo if (!str || !delim || !last) 1019289549Srpaulo return NULL; 1020289549Srpaulo 1021289549Srpaulo if (*last) 1022289549Srpaulo token = *last; 1023289549Srpaulo 1024289549Srpaulo while (*token && os_strchr(delim, *token)) 1025289549Srpaulo token++; 1026289549Srpaulo 1027289549Srpaulo if (!*token) 1028289549Srpaulo return NULL; 1029289549Srpaulo 1030289549Srpaulo end = token + 1; 1031289549Srpaulo 1032289549Srpaulo while (*end && !os_strchr(delim, *end)) 1033289549Srpaulo end++; 1034289549Srpaulo 1035289549Srpaulo *last = end; 1036289549Srpaulo return token; 1037289549Srpaulo} 1038289549Srpaulo 1039289549Srpaulo 1040289549Srpaulo/** 1041281806Srpaulo * str_token - Get next token from a string 1042281806Srpaulo * @buf: String to tokenize. Note that the string might be modified. 1043281806Srpaulo * @delim: String of delimiters 1044281806Srpaulo * @context: Pointer to save our context. Should be initialized with 1045281806Srpaulo * NULL on the first call, and passed for any further call. 1046281806Srpaulo * Returns: The next token, NULL if there are no more valid tokens. 1047281806Srpaulo */ 1048281806Srpaulochar * str_token(char *str, const char *delim, char **context) 1049281806Srpaulo{ 1050289549Srpaulo char *token = (char *) cstr_token(str, delim, (const char **) context); 1051281806Srpaulo 1052289549Srpaulo if (token && **context) 1053289549Srpaulo *(*context)++ = '\0'; 1054281806Srpaulo 1055289549Srpaulo return token; 1056281806Srpaulo} 1057281806Srpaulo 1058281806Srpaulo 1059281806Srpaulosize_t utf8_unescape(const char *inp, size_t in_size, 1060281806Srpaulo char *outp, size_t out_size) 1061281806Srpaulo{ 1062281806Srpaulo size_t res_size = 0; 1063281806Srpaulo 1064281806Srpaulo if (!inp || !outp) 1065281806Srpaulo return 0; 1066281806Srpaulo 1067281806Srpaulo if (!in_size) 1068281806Srpaulo in_size = os_strlen(inp); 1069281806Srpaulo 1070281806Srpaulo /* Advance past leading single quote */ 1071281806Srpaulo if (*inp == '\'' && in_size) { 1072281806Srpaulo inp++; 1073281806Srpaulo in_size--; 1074281806Srpaulo } 1075281806Srpaulo 1076281806Srpaulo while (in_size--) { 1077281806Srpaulo if (res_size >= out_size) 1078281806Srpaulo return 0; 1079281806Srpaulo 1080281806Srpaulo switch (*inp) { 1081281806Srpaulo case '\'': 1082281806Srpaulo /* Terminate on bare single quote */ 1083281806Srpaulo *outp = '\0'; 1084281806Srpaulo return res_size; 1085281806Srpaulo 1086281806Srpaulo case '\\': 1087281806Srpaulo if (!in_size--) 1088281806Srpaulo return 0; 1089281806Srpaulo inp++; 1090281806Srpaulo /* fall through */ 1091281806Srpaulo 1092281806Srpaulo default: 1093281806Srpaulo *outp++ = *inp++; 1094281806Srpaulo res_size++; 1095281806Srpaulo } 1096281806Srpaulo } 1097281806Srpaulo 1098281806Srpaulo /* NUL terminate if space allows */ 1099281806Srpaulo if (res_size < out_size) 1100281806Srpaulo *outp = '\0'; 1101281806Srpaulo 1102281806Srpaulo return res_size; 1103281806Srpaulo} 1104281806Srpaulo 1105281806Srpaulo 1106281806Srpaulosize_t utf8_escape(const char *inp, size_t in_size, 1107281806Srpaulo char *outp, size_t out_size) 1108281806Srpaulo{ 1109281806Srpaulo size_t res_size = 0; 1110281806Srpaulo 1111281806Srpaulo if (!inp || !outp) 1112281806Srpaulo return 0; 1113281806Srpaulo 1114281806Srpaulo /* inp may or may not be NUL terminated, but must be if 0 size 1115281806Srpaulo * is specified */ 1116281806Srpaulo if (!in_size) 1117281806Srpaulo in_size = os_strlen(inp); 1118281806Srpaulo 1119281806Srpaulo while (in_size--) { 1120281806Srpaulo if (res_size++ >= out_size) 1121281806Srpaulo return 0; 1122281806Srpaulo 1123281806Srpaulo switch (*inp) { 1124281806Srpaulo case '\\': 1125281806Srpaulo case '\'': 1126281806Srpaulo if (res_size++ >= out_size) 1127281806Srpaulo return 0; 1128281806Srpaulo *outp++ = '\\'; 1129281806Srpaulo /* fall through */ 1130281806Srpaulo 1131281806Srpaulo default: 1132281806Srpaulo *outp++ = *inp++; 1133281806Srpaulo break; 1134281806Srpaulo } 1135281806Srpaulo } 1136281806Srpaulo 1137281806Srpaulo /* NUL terminate if space allows */ 1138281806Srpaulo if (res_size < out_size) 1139281806Srpaulo *outp = '\0'; 1140281806Srpaulo 1141281806Srpaulo return res_size; 1142281806Srpaulo} 1143289549Srpaulo 1144289549Srpaulo 1145289549Srpauloint is_ctrl_char(char c) 1146289549Srpaulo{ 1147289549Srpaulo return c > 0 && c < 32; 1148289549Srpaulo} 1149337817Scy 1150337817Scy 1151337817Scy/** 1152337817Scy * ssid_parse - Parse a string that contains SSID in hex or text format 1153337817Scy * @buf: Input NULL terminated string that contains the SSID 1154337817Scy * @ssid: Output SSID 1155337817Scy * Returns: 0 on success, -1 otherwise 1156337817Scy * 1157337817Scy * The SSID has to be enclosed in double quotes for the text format or space 1158337817Scy * or NULL terminated string of hex digits for the hex format. buf can include 1159337817Scy * additional arguments after the SSID. 1160337817Scy */ 1161337817Scyint ssid_parse(const char *buf, struct wpa_ssid_value *ssid) 1162337817Scy{ 1163337817Scy char *tmp, *res, *end; 1164337817Scy size_t len; 1165337817Scy 1166337817Scy ssid->ssid_len = 0; 1167337817Scy 1168337817Scy tmp = os_strdup(buf); 1169337817Scy if (!tmp) 1170337817Scy return -1; 1171337817Scy 1172337817Scy if (*tmp != '"') { 1173337817Scy end = os_strchr(tmp, ' '); 1174337817Scy if (end) 1175337817Scy *end = '\0'; 1176337817Scy } else { 1177337817Scy end = os_strchr(tmp + 1, '"'); 1178337817Scy if (!end) { 1179337817Scy os_free(tmp); 1180337817Scy return -1; 1181337817Scy } 1182337817Scy 1183337817Scy end[1] = '\0'; 1184337817Scy } 1185337817Scy 1186337817Scy res = wpa_config_parse_string(tmp, &len); 1187337817Scy if (res && len <= SSID_MAX_LEN) { 1188337817Scy ssid->ssid_len = len; 1189337817Scy os_memcpy(ssid->ssid, res, len); 1190337817Scy } 1191337817Scy 1192337817Scy os_free(tmp); 1193337817Scy os_free(res); 1194337817Scy 1195337817Scy return ssid->ssid_len ? 0 : -1; 1196337817Scy} 1197337817Scy 1198337817Scy 1199337817Scyint str_starts(const char *str, const char *start) 1200337817Scy{ 1201337817Scy return os_strncmp(str, start, os_strlen(start)) == 0; 1202337817Scy} 1203