]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * wpa_supplicant/hostapd / common helper functions, etc. | |
3 | * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> | |
4 | * | |
0f3d578e JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
6fc6879b JM |
7 | */ |
8 | ||
9 | #include "includes.h" | |
10 | ||
11 | #include "common.h" | |
12 | ||
13 | ||
14 | static int hex2num(char c) | |
15 | { | |
16 | if (c >= '0' && c <= '9') | |
17 | return c - '0'; | |
18 | if (c >= 'a' && c <= 'f') | |
19 | return c - 'a' + 10; | |
20 | if (c >= 'A' && c <= 'F') | |
21 | return c - 'A' + 10; | |
22 | return -1; | |
23 | } | |
24 | ||
25 | ||
b3a6d9d4 | 26 | int hex2byte(const char *hex) |
6fc6879b JM |
27 | { |
28 | int a, b; | |
29 | a = hex2num(*hex++); | |
30 | if (a < 0) | |
31 | return -1; | |
32 | b = hex2num(*hex++); | |
33 | if (b < 0) | |
34 | return -1; | |
35 | return (a << 4) | b; | |
36 | } | |
37 | ||
38 | ||
79cd993a ST |
39 | static const char * hwaddr_parse(const char *txt, u8 *addr) |
40 | { | |
41 | size_t i; | |
42 | ||
43 | for (i = 0; i < ETH_ALEN; i++) { | |
44 | int a; | |
45 | ||
46 | a = hex2byte(txt); | |
47 | if (a < 0) | |
48 | return NULL; | |
49 | txt += 2; | |
50 | addr[i] = a; | |
51 | if (i < ETH_ALEN - 1 && *txt++ != ':') | |
52 | return NULL; | |
53 | } | |
54 | return txt; | |
55 | } | |
56 | ||
57 | ||
6fc6879b | 58 | /** |
448a0a19 | 59 | * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format) |
6fc6879b JM |
60 | * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") |
61 | * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) | |
62 | * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) | |
63 | */ | |
64 | int hwaddr_aton(const char *txt, u8 *addr) | |
65 | { | |
79cd993a ST |
66 | return hwaddr_parse(txt, addr) ? 0 : -1; |
67 | } | |
6fc6879b | 68 | |
6fc6879b | 69 | |
79cd993a ST |
70 | /** |
71 | * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format) | |
72 | * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00") | |
73 | * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) | |
74 | * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes) | |
75 | * @maskable: Flag to indicate whether a mask is allowed | |
76 | * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) | |
77 | */ | |
78 | int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable) | |
79 | { | |
80 | const char *r; | |
81 | ||
82 | /* parse address part */ | |
83 | r = hwaddr_parse(txt, addr); | |
84 | if (!r) | |
85 | return -1; | |
86 | ||
87 | /* check for optional mask */ | |
88 | if (*r == '\0' || isspace(*r)) { | |
89 | /* no mask specified, assume default */ | |
90 | os_memset(mask, 0xff, ETH_ALEN); | |
91 | } else if (maskable && *r == '/') { | |
92 | /* mask specified and allowed */ | |
93 | r = hwaddr_parse(r + 1, mask); | |
94 | /* parser error? */ | |
95 | if (!r) | |
6fc6879b | 96 | return -1; |
79cd993a ST |
97 | } else { |
98 | /* mask specified but not allowed or trailing garbage */ | |
99 | return -1; | |
6fc6879b JM |
100 | } |
101 | ||
102 | return 0; | |
103 | } | |
104 | ||
79cd993a | 105 | |
0c11c633 JB |
106 | /** |
107 | * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format) | |
108 | * @txt: MAC address as a string (e.g., "001122334455") | |
109 | * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) | |
110 | * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) | |
111 | */ | |
112 | int hwaddr_compact_aton(const char *txt, u8 *addr) | |
113 | { | |
114 | int i; | |
115 | ||
116 | for (i = 0; i < 6; i++) { | |
117 | int a, b; | |
118 | ||
119 | a = hex2num(*txt++); | |
120 | if (a < 0) | |
121 | return -1; | |
122 | b = hex2num(*txt++); | |
123 | if (b < 0) | |
124 | return -1; | |
125 | *addr++ = (a << 4) | b; | |
126 | } | |
127 | ||
128 | return 0; | |
129 | } | |
6fc6879b | 130 | |
448a0a19 JM |
131 | /** |
132 | * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format) | |
133 | * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455) | |
134 | * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) | |
135 | * Returns: Characters used (> 0) on success, -1 on failure | |
136 | */ | |
137 | int hwaddr_aton2(const char *txt, u8 *addr) | |
138 | { | |
139 | int i; | |
140 | const char *pos = txt; | |
141 | ||
142 | for (i = 0; i < 6; i++) { | |
143 | int a, b; | |
144 | ||
145 | while (*pos == ':' || *pos == '.' || *pos == '-') | |
146 | pos++; | |
147 | ||
148 | a = hex2num(*pos++); | |
149 | if (a < 0) | |
150 | return -1; | |
151 | b = hex2num(*pos++); | |
152 | if (b < 0) | |
153 | return -1; | |
154 | *addr++ = (a << 4) | b; | |
155 | } | |
156 | ||
157 | return pos - txt; | |
158 | } | |
159 | ||
160 | ||
6fc6879b JM |
161 | /** |
162 | * hexstr2bin - Convert ASCII hex string into binary data | |
163 | * @hex: ASCII hex string (e.g., "01ab") | |
164 | * @buf: Buffer for the binary data | |
165 | * @len: Length of the text to convert in bytes (of buf); hex will be double | |
166 | * this size | |
167 | * Returns: 0 on success, -1 on failure (invalid hex string) | |
168 | */ | |
169 | int hexstr2bin(const char *hex, u8 *buf, size_t len) | |
170 | { | |
171 | size_t i; | |
172 | int a; | |
173 | const char *ipos = hex; | |
174 | u8 *opos = buf; | |
175 | ||
176 | for (i = 0; i < len; i++) { | |
177 | a = hex2byte(ipos); | |
178 | if (a < 0) | |
179 | return -1; | |
180 | *opos++ = a; | |
181 | ipos += 2; | |
182 | } | |
183 | return 0; | |
184 | } | |
185 | ||
186 | ||
79cd993a ST |
187 | int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask) |
188 | { | |
189 | size_t i; | |
190 | int print_mask = 0; | |
191 | int res; | |
192 | ||
193 | for (i = 0; i < ETH_ALEN; i++) { | |
194 | if (mask[i] != 0xff) { | |
195 | print_mask = 1; | |
196 | break; | |
197 | } | |
198 | } | |
199 | ||
200 | if (print_mask) | |
201 | res = os_snprintf(buf, len, MACSTR "/" MACSTR, | |
202 | MAC2STR(addr), MAC2STR(mask)); | |
203 | else | |
204 | res = os_snprintf(buf, len, MACSTR, MAC2STR(addr)); | |
205 | if (os_snprintf_error(len, res)) | |
206 | return -1; | |
207 | return res; | |
208 | } | |
209 | ||
210 | ||
6fc6879b JM |
211 | /** |
212 | * inc_byte_array - Increment arbitrary length byte array by one | |
213 | * @counter: Pointer to byte array | |
214 | * @len: Length of the counter in bytes | |
215 | * | |
216 | * This function increments the last byte of the counter by one and continues | |
217 | * rolling over to more significant bytes if the byte was incremented from | |
218 | * 0xff to 0x00. | |
219 | */ | |
220 | void inc_byte_array(u8 *counter, size_t len) | |
221 | { | |
222 | int pos = len - 1; | |
223 | while (pos >= 0) { | |
224 | counter[pos]++; | |
225 | if (counter[pos] != 0) | |
226 | break; | |
227 | pos--; | |
228 | } | |
229 | } | |
230 | ||
231 | ||
232 | void wpa_get_ntp_timestamp(u8 *buf) | |
233 | { | |
234 | struct os_time now; | |
235 | u32 sec, usec; | |
236 | be32 tmp; | |
237 | ||
238 | /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ | |
239 | os_get_time(&now); | |
240 | sec = now.sec + 2208988800U; /* Epoch to 1900 */ | |
241 | /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ | |
242 | usec = now.usec; | |
243 | usec = 4295 * usec - (usec >> 5) - (usec >> 9); | |
244 | tmp = host_to_be32(sec); | |
245 | os_memcpy(buf, (u8 *) &tmp, 4); | |
246 | tmp = host_to_be32(usec); | |
247 | os_memcpy(buf + 4, (u8 *) &tmp, 4); | |
248 | } | |
249 | ||
71d263ea MB |
250 | /** |
251 | * wpa_scnprintf - Simpler-to-use snprintf function | |
252 | * @buf: Output buffer | |
253 | * @size: Buffer size | |
254 | * @fmt: format | |
255 | * | |
256 | * Simpler snprintf version that doesn't require further error checks - the | |
257 | * return value only indicates how many bytes were actually written, excluding | |
258 | * the NULL byte (i.e., 0 on error, size-1 if buffer is not big enough). | |
259 | */ | |
260 | int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...) | |
261 | { | |
262 | va_list ap; | |
263 | int ret; | |
264 | ||
265 | if (!size) | |
266 | return 0; | |
267 | ||
268 | va_start(ap, fmt); | |
269 | ret = vsnprintf(buf, size, fmt, ap); | |
270 | va_end(ap); | |
271 | ||
272 | if (ret < 0) | |
273 | return 0; | |
274 | if ((size_t) ret >= size) | |
275 | return size - 1; | |
276 | ||
277 | return ret; | |
278 | } | |
6fc6879b | 279 | |
2c1cf903 JM |
280 | |
281 | int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, | |
282 | char sep) | |
283 | { | |
284 | size_t i; | |
285 | char *pos = buf, *end = buf + buf_size; | |
286 | int ret; | |
287 | ||
288 | if (buf_size == 0) | |
289 | return 0; | |
290 | ||
291 | for (i = 0; i < len; i++) { | |
292 | ret = os_snprintf(pos, end - pos, "%02x%c", | |
293 | data[i], sep); | |
294 | if (os_snprintf_error(end - pos, ret)) { | |
295 | end[-1] = '\0'; | |
296 | return pos - buf; | |
297 | } | |
298 | pos += ret; | |
299 | } | |
300 | pos[-1] = '\0'; | |
301 | return pos - buf; | |
302 | } | |
303 | ||
304 | ||
6fc6879b JM |
305 | static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, |
306 | size_t len, int uppercase) | |
307 | { | |
308 | size_t i; | |
309 | char *pos = buf, *end = buf + buf_size; | |
310 | int ret; | |
311 | if (buf_size == 0) | |
312 | return 0; | |
313 | for (i = 0; i < len; i++) { | |
314 | ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", | |
315 | data[i]); | |
d85e1fc8 | 316 | if (os_snprintf_error(end - pos, ret)) { |
6fc6879b JM |
317 | end[-1] = '\0'; |
318 | return pos - buf; | |
319 | } | |
320 | pos += ret; | |
321 | } | |
322 | end[-1] = '\0'; | |
323 | return pos - buf; | |
324 | } | |
325 | ||
326 | /** | |
327 | * wpa_snprintf_hex - Print data as a hex string into a buffer | |
328 | * @buf: Memory area to use as the output buffer | |
329 | * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) | |
330 | * @data: Data to be printed | |
331 | * @len: Length of data in bytes | |
332 | * Returns: Number of bytes written | |
333 | */ | |
334 | int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) | |
335 | { | |
336 | return _wpa_snprintf_hex(buf, buf_size, data, len, 0); | |
337 | } | |
338 | ||
339 | ||
340 | /** | |
341 | * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf | |
342 | * @buf: Memory area to use as the output buffer | |
343 | * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) | |
344 | * @data: Data to be printed | |
345 | * @len: Length of data in bytes | |
346 | * Returns: Number of bytes written | |
347 | */ | |
348 | int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, | |
349 | size_t len) | |
350 | { | |
351 | return _wpa_snprintf_hex(buf, buf_size, data, len, 1); | |
352 | } | |
353 | ||
354 | ||
355 | #ifdef CONFIG_ANSI_C_EXTRA | |
356 | ||
357 | #ifdef _WIN32_WCE | |
358 | void perror(const char *s) | |
359 | { | |
360 | wpa_printf(MSG_ERROR, "%s: GetLastError: %d", | |
361 | s, (int) GetLastError()); | |
362 | } | |
363 | #endif /* _WIN32_WCE */ | |
364 | ||
365 | ||
366 | int optind = 1; | |
367 | int optopt; | |
368 | char *optarg; | |
369 | ||
370 | int getopt(int argc, char *const argv[], const char *optstring) | |
371 | { | |
372 | static int optchr = 1; | |
373 | char *cp; | |
374 | ||
375 | if (optchr == 1) { | |
376 | if (optind >= argc) { | |
377 | /* all arguments processed */ | |
378 | return EOF; | |
379 | } | |
380 | ||
381 | if (argv[optind][0] != '-' || argv[optind][1] == '\0') { | |
382 | /* no option characters */ | |
383 | return EOF; | |
384 | } | |
385 | } | |
386 | ||
387 | if (os_strcmp(argv[optind], "--") == 0) { | |
388 | /* no more options */ | |
389 | optind++; | |
390 | return EOF; | |
391 | } | |
392 | ||
393 | optopt = argv[optind][optchr]; | |
394 | cp = os_strchr(optstring, optopt); | |
395 | if (cp == NULL || optopt == ':') { | |
396 | if (argv[optind][++optchr] == '\0') { | |
397 | optchr = 1; | |
398 | optind++; | |
399 | } | |
400 | return '?'; | |
401 | } | |
402 | ||
403 | if (cp[1] == ':') { | |
404 | /* Argument required */ | |
405 | optchr = 1; | |
406 | if (argv[optind][optchr + 1]) { | |
407 | /* No space between option and argument */ | |
408 | optarg = &argv[optind++][optchr + 1]; | |
409 | } else if (++optind >= argc) { | |
410 | /* option requires an argument */ | |
411 | return '?'; | |
412 | } else { | |
413 | /* Argument in the next argv */ | |
414 | optarg = argv[optind++]; | |
415 | } | |
416 | } else { | |
417 | /* No argument */ | |
418 | if (argv[optind][++optchr] == '\0') { | |
419 | optchr = 1; | |
420 | optind++; | |
421 | } | |
422 | optarg = NULL; | |
423 | } | |
424 | return *cp; | |
425 | } | |
426 | #endif /* CONFIG_ANSI_C_EXTRA */ | |
427 | ||
428 | ||
429 | #ifdef CONFIG_NATIVE_WINDOWS | |
430 | /** | |
431 | * wpa_unicode2ascii_inplace - Convert unicode string into ASCII | |
432 | * @str: Pointer to string to convert | |
433 | * | |
434 | * This function converts a unicode string to ASCII using the same | |
435 | * buffer for output. If UNICODE is not set, the buffer is not | |
436 | * modified. | |
437 | */ | |
438 | void wpa_unicode2ascii_inplace(TCHAR *str) | |
439 | { | |
440 | #ifdef UNICODE | |
441 | char *dst = (char *) str; | |
442 | while (*str) | |
443 | *dst++ = (char) *str++; | |
444 | *dst = '\0'; | |
445 | #endif /* UNICODE */ | |
446 | } | |
447 | ||
448 | ||
449 | TCHAR * wpa_strdup_tchar(const char *str) | |
450 | { | |
451 | #ifdef UNICODE | |
452 | TCHAR *buf; | |
453 | buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR)); | |
454 | if (buf == NULL) | |
455 | return NULL; | |
456 | wsprintf(buf, L"%S", str); | |
457 | return buf; | |
458 | #else /* UNICODE */ | |
459 | return os_strdup(str); | |
460 | #endif /* UNICODE */ | |
461 | } | |
462 | #endif /* CONFIG_NATIVE_WINDOWS */ | |
463 | ||
464 | ||
0d7773b6 JM |
465 | void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) |
466 | { | |
467 | char *end = txt + maxlen; | |
468 | size_t i; | |
469 | ||
470 | for (i = 0; i < len; i++) { | |
5dff6dff | 471 | if (txt + 4 >= end) |
0d7773b6 JM |
472 | break; |
473 | ||
474 | switch (data[i]) { | |
475 | case '\"': | |
476 | *txt++ = '\\'; | |
477 | *txt++ = '\"'; | |
478 | break; | |
479 | case '\\': | |
480 | *txt++ = '\\'; | |
481 | *txt++ = '\\'; | |
482 | break; | |
a8833b84 | 483 | case '\033': |
0d7773b6 JM |
484 | *txt++ = '\\'; |
485 | *txt++ = 'e'; | |
486 | break; | |
487 | case '\n': | |
488 | *txt++ = '\\'; | |
489 | *txt++ = 'n'; | |
490 | break; | |
491 | case '\r': | |
492 | *txt++ = '\\'; | |
493 | *txt++ = 'r'; | |
494 | break; | |
495 | case '\t': | |
496 | *txt++ = '\\'; | |
497 | *txt++ = 't'; | |
498 | break; | |
499 | default: | |
500 | if (data[i] >= 32 && data[i] <= 127) { | |
501 | *txt++ = data[i]; | |
502 | } else { | |
503 | txt += os_snprintf(txt, end - txt, "\\x%02x", | |
504 | data[i]); | |
505 | } | |
506 | break; | |
507 | } | |
508 | } | |
509 | ||
510 | *txt = '\0'; | |
511 | } | |
512 | ||
513 | ||
514 | size_t printf_decode(u8 *buf, size_t maxlen, const char *str) | |
515 | { | |
516 | const char *pos = str; | |
517 | size_t len = 0; | |
518 | int val; | |
519 | ||
520 | while (*pos) { | |
913c19c6 | 521 | if (len + 1 >= maxlen) |
0d7773b6 JM |
522 | break; |
523 | switch (*pos) { | |
524 | case '\\': | |
525 | pos++; | |
526 | switch (*pos) { | |
527 | case '\\': | |
528 | buf[len++] = '\\'; | |
529 | pos++; | |
530 | break; | |
531 | case '"': | |
532 | buf[len++] = '"'; | |
533 | pos++; | |
534 | break; | |
535 | case 'n': | |
536 | buf[len++] = '\n'; | |
537 | pos++; | |
538 | break; | |
539 | case 'r': | |
540 | buf[len++] = '\r'; | |
541 | pos++; | |
542 | break; | |
543 | case 't': | |
544 | buf[len++] = '\t'; | |
545 | pos++; | |
546 | break; | |
547 | case 'e': | |
a8833b84 | 548 | buf[len++] = '\033'; |
0d7773b6 JM |
549 | pos++; |
550 | break; | |
551 | case 'x': | |
552 | pos++; | |
553 | val = hex2byte(pos); | |
554 | if (val < 0) { | |
555 | val = hex2num(*pos); | |
556 | if (val < 0) | |
557 | break; | |
558 | buf[len++] = val; | |
559 | pos++; | |
560 | } else { | |
561 | buf[len++] = val; | |
562 | pos += 2; | |
563 | } | |
564 | break; | |
565 | case '0': | |
566 | case '1': | |
567 | case '2': | |
568 | case '3': | |
569 | case '4': | |
570 | case '5': | |
571 | case '6': | |
572 | case '7': | |
573 | val = *pos++ - '0'; | |
574 | if (*pos >= '0' && *pos <= '7') | |
575 | val = val * 8 + (*pos++ - '0'); | |
576 | if (*pos >= '0' && *pos <= '7') | |
577 | val = val * 8 + (*pos++ - '0'); | |
578 | buf[len++] = val; | |
579 | break; | |
580 | default: | |
581 | break; | |
582 | } | |
583 | break; | |
584 | default: | |
585 | buf[len++] = *pos++; | |
586 | break; | |
587 | } | |
588 | } | |
913c19c6 KP |
589 | if (maxlen > len) |
590 | buf[len] = '\0'; | |
0d7773b6 JM |
591 | |
592 | return len; | |
593 | } | |
594 | ||
595 | ||
6fc6879b JM |
596 | /** |
597 | * wpa_ssid_txt - Convert SSID to a printable string | |
598 | * @ssid: SSID (32-octet string) | |
599 | * @ssid_len: Length of ssid in octets | |
600 | * Returns: Pointer to a printable string | |
601 | * | |
602 | * This function can be used to convert SSIDs into printable form. In most | |
603 | * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard | |
604 | * does not limit the used character set, so anything could be used in an SSID. | |
605 | * | |
606 | * This function uses a static buffer, so only one call can be used at the | |
607 | * time, i.e., this is not re-entrant and the returned buffer must be used | |
608 | * before calling this again. | |
609 | */ | |
610 | const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len) | |
611 | { | |
6bc1f956 JM |
612 | static char ssid_txt[32 * 4 + 1]; |
613 | ||
614 | if (ssid == NULL) { | |
615 | ssid_txt[0] = '\0'; | |
616 | return ssid_txt; | |
6fc6879b | 617 | } |
6bc1f956 JM |
618 | |
619 | printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len); | |
6fc6879b JM |
620 | return ssid_txt; |
621 | } | |
0ae7b086 JM |
622 | |
623 | ||
624 | void * __hide_aliasing_typecast(void *foo) | |
625 | { | |
626 | return foo; | |
627 | } | |
b87d70c8 JM |
628 | |
629 | ||
630 | char * wpa_config_parse_string(const char *value, size_t *len) | |
631 | { | |
632 | if (*value == '"') { | |
633 | const char *pos; | |
634 | char *str; | |
635 | value++; | |
636 | pos = os_strrchr(value, '"'); | |
637 | if (pos == NULL || pos[1] != '\0') | |
638 | return NULL; | |
639 | *len = pos - value; | |
5e24dc8a | 640 | str = dup_binstr(value, *len); |
b87d70c8 JM |
641 | if (str == NULL) |
642 | return NULL; | |
b87d70c8 JM |
643 | return str; |
644 | } else if (*value == 'P' && value[1] == '"') { | |
645 | const char *pos; | |
646 | char *tstr, *str; | |
647 | size_t tlen; | |
648 | value += 2; | |
649 | pos = os_strrchr(value, '"'); | |
650 | if (pos == NULL || pos[1] != '\0') | |
651 | return NULL; | |
652 | tlen = pos - value; | |
5e24dc8a | 653 | tstr = dup_binstr(value, tlen); |
b87d70c8 JM |
654 | if (tstr == NULL) |
655 | return NULL; | |
b87d70c8 JM |
656 | |
657 | str = os_malloc(tlen + 1); | |
658 | if (str == NULL) { | |
659 | os_free(tstr); | |
660 | return NULL; | |
661 | } | |
662 | ||
663 | *len = printf_decode((u8 *) str, tlen + 1, tstr); | |
664 | os_free(tstr); | |
665 | ||
666 | return str; | |
667 | } else { | |
668 | u8 *str; | |
669 | size_t tlen, hlen = os_strlen(value); | |
670 | if (hlen & 1) | |
671 | return NULL; | |
672 | tlen = hlen / 2; | |
673 | str = os_malloc(tlen + 1); | |
674 | if (str == NULL) | |
675 | return NULL; | |
676 | if (hexstr2bin(value, str, tlen)) { | |
677 | os_free(str); | |
678 | return NULL; | |
679 | } | |
680 | str[tlen] = '\0'; | |
681 | *len = tlen; | |
682 | return (char *) str; | |
683 | } | |
684 | } | |
e122bb70 JM |
685 | |
686 | ||
687 | int is_hex(const u8 *data, size_t len) | |
688 | { | |
689 | size_t i; | |
690 | ||
691 | for (i = 0; i < len; i++) { | |
692 | if (data[i] < 32 || data[i] >= 127) | |
693 | return 1; | |
694 | } | |
695 | return 0; | |
696 | } | |
3489cfb0 JM |
697 | |
698 | ||
699 | size_t merge_byte_arrays(u8 *res, size_t res_len, | |
700 | const u8 *src1, size_t src1_len, | |
701 | const u8 *src2, size_t src2_len) | |
702 | { | |
703 | size_t len = 0; | |
704 | ||
705 | os_memset(res, 0, res_len); | |
706 | ||
707 | if (src1) { | |
708 | if (src1_len >= res_len) { | |
709 | os_memcpy(res, src1, res_len); | |
710 | return res_len; | |
711 | } | |
712 | ||
713 | os_memcpy(res, src1, src1_len); | |
714 | len += src1_len; | |
715 | } | |
716 | ||
717 | if (src2) { | |
718 | if (len + src2_len >= res_len) { | |
719 | os_memcpy(res + len, src2, res_len - len); | |
720 | return res_len; | |
721 | } | |
722 | ||
723 | os_memcpy(res + len, src2, src2_len); | |
724 | len += src2_len; | |
725 | } | |
726 | ||
727 | return len; | |
728 | } | |
5e24dc8a JM |
729 | |
730 | ||
731 | char * dup_binstr(const void *src, size_t len) | |
732 | { | |
733 | char *res; | |
734 | ||
735 | if (src == NULL) | |
736 | return NULL; | |
737 | res = os_malloc(len + 1); | |
738 | if (res == NULL) | |
739 | return NULL; | |
740 | os_memcpy(res, src, len); | |
741 | res[len] = '\0'; | |
742 | ||
743 | return res; | |
744 | } | |
af8a827b JM |
745 | |
746 | ||
747 | int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value) | |
748 | { | |
749 | struct wpa_freq_range *freq = NULL, *n; | |
750 | unsigned int count = 0; | |
751 | const char *pos, *pos2, *pos3; | |
752 | ||
753 | /* | |
754 | * Comma separated list of frequency ranges. | |
755 | * For example: 2412-2432,2462,5000-6000 | |
756 | */ | |
757 | pos = value; | |
758 | while (pos && pos[0]) { | |
759 | n = os_realloc_array(freq, count + 1, | |
760 | sizeof(struct wpa_freq_range)); | |
761 | if (n == NULL) { | |
762 | os_free(freq); | |
763 | return -1; | |
764 | } | |
765 | freq = n; | |
766 | freq[count].min = atoi(pos); | |
767 | pos2 = os_strchr(pos, '-'); | |
768 | pos3 = os_strchr(pos, ','); | |
769 | if (pos2 && (!pos3 || pos2 < pos3)) { | |
770 | pos2++; | |
771 | freq[count].max = atoi(pos2); | |
772 | } else | |
773 | freq[count].max = freq[count].min; | |
774 | pos = pos3; | |
775 | if (pos) | |
776 | pos++; | |
777 | count++; | |
778 | } | |
779 | ||
780 | os_free(res->range); | |
781 | res->range = freq; | |
782 | res->num = count; | |
783 | ||
784 | return 0; | |
785 | } | |
786 | ||
787 | ||
788 | int freq_range_list_includes(const struct wpa_freq_range_list *list, | |
789 | unsigned int freq) | |
790 | { | |
791 | unsigned int i; | |
792 | ||
793 | if (list == NULL) | |
794 | return 0; | |
795 | ||
796 | for (i = 0; i < list->num; i++) { | |
797 | if (freq >= list->range[i].min && freq <= list->range[i].max) | |
798 | return 1; | |
799 | } | |
800 | ||
801 | return 0; | |
802 | } | |
803 | ||
804 | ||
805 | char * freq_range_list_str(const struct wpa_freq_range_list *list) | |
806 | { | |
807 | char *buf, *pos, *end; | |
808 | size_t maxlen; | |
809 | unsigned int i; | |
810 | int res; | |
811 | ||
812 | if (list->num == 0) | |
813 | return NULL; | |
814 | ||
815 | maxlen = list->num * 30; | |
816 | buf = os_malloc(maxlen); | |
817 | if (buf == NULL) | |
818 | return NULL; | |
819 | pos = buf; | |
820 | end = buf + maxlen; | |
821 | ||
822 | for (i = 0; i < list->num; i++) { | |
823 | struct wpa_freq_range *range = &list->range[i]; | |
824 | ||
825 | if (range->min == range->max) | |
826 | res = os_snprintf(pos, end - pos, "%s%u", | |
827 | i == 0 ? "" : ",", range->min); | |
828 | else | |
829 | res = os_snprintf(pos, end - pos, "%s%u-%u", | |
830 | i == 0 ? "" : ",", | |
831 | range->min, range->max); | |
7bdd8981 | 832 | if (os_snprintf_error(end - pos, res)) { |
af8a827b JM |
833 | os_free(buf); |
834 | return NULL; | |
835 | } | |
836 | pos += res; | |
837 | } | |
838 | ||
839 | return buf; | |
840 | } | |
98eda9c2 JM |
841 | |
842 | ||
843 | int int_array_len(const int *a) | |
844 | { | |
845 | int i; | |
846 | for (i = 0; a && a[i]; i++) | |
847 | ; | |
848 | return i; | |
849 | } | |
850 | ||
851 | ||
852 | void int_array_concat(int **res, const int *a) | |
853 | { | |
854 | int reslen, alen, i; | |
855 | int *n; | |
856 | ||
857 | reslen = int_array_len(*res); | |
858 | alen = int_array_len(a); | |
859 | ||
860 | n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); | |
861 | if (n == NULL) { | |
862 | os_free(*res); | |
863 | *res = NULL; | |
864 | return; | |
865 | } | |
866 | for (i = 0; i <= alen; i++) | |
867 | n[reslen + i] = a[i]; | |
868 | *res = n; | |
869 | } | |
870 | ||
871 | ||
872 | static int freq_cmp(const void *a, const void *b) | |
873 | { | |
874 | int _a = *(int *) a; | |
875 | int _b = *(int *) b; | |
876 | ||
877 | if (_a == 0) | |
878 | return 1; | |
879 | if (_b == 0) | |
880 | return -1; | |
881 | return _a - _b; | |
882 | } | |
883 | ||
884 | ||
885 | void int_array_sort_unique(int *a) | |
886 | { | |
887 | int alen; | |
888 | int i, j; | |
889 | ||
890 | if (a == NULL) | |
891 | return; | |
892 | ||
893 | alen = int_array_len(a); | |
894 | qsort(a, alen, sizeof(int), freq_cmp); | |
895 | ||
896 | i = 0; | |
897 | j = 1; | |
898 | while (a[i] && a[j]) { | |
899 | if (a[i] == a[j]) { | |
900 | j++; | |
901 | continue; | |
902 | } | |
903 | a[++i] = a[j++]; | |
904 | } | |
905 | if (a[i]) | |
906 | i++; | |
907 | a[i] = 0; | |
908 | } | |
909 | ||
910 | ||
911 | void int_array_add_unique(int **res, int a) | |
912 | { | |
913 | int reslen; | |
914 | int *n; | |
915 | ||
916 | for (reslen = 0; *res && (*res)[reslen]; reslen++) { | |
917 | if ((*res)[reslen] == a) | |
918 | return; /* already in the list */ | |
919 | } | |
920 | ||
921 | n = os_realloc_array(*res, reslen + 2, sizeof(int)); | |
922 | if (n == NULL) { | |
923 | os_free(*res); | |
924 | *res = NULL; | |
925 | return; | |
926 | } | |
927 | ||
928 | n[reslen] = a; | |
929 | n[reslen + 1] = 0; | |
930 | ||
931 | *res = n; | |
932 | } | |
19c48da0 JM |
933 | |
934 | ||
935 | void str_clear_free(char *str) | |
936 | { | |
937 | if (str) { | |
938 | size_t len = os_strlen(str); | |
939 | os_memset(str, 0, len); | |
940 | os_free(str); | |
941 | } | |
942 | } | |
943 | ||
944 | ||
945 | void bin_clear_free(void *bin, size_t len) | |
946 | { | |
947 | if (bin) { | |
948 | os_memset(bin, 0, len); | |
949 | os_free(bin); | |
950 | } | |
951 | } | |
4d8fb637 JM |
952 | |
953 | ||
954 | int random_mac_addr(u8 *addr) | |
955 | { | |
956 | if (os_get_random(addr, ETH_ALEN) < 0) | |
957 | return -1; | |
958 | addr[0] &= 0xfe; /* unicast */ | |
959 | addr[0] |= 0x02; /* locally administered */ | |
960 | return 0; | |
961 | } | |
1cbdb9d1 JM |
962 | |
963 | ||
964 | int random_mac_addr_keep_oui(u8 *addr) | |
965 | { | |
966 | if (os_get_random(addr + 3, 3) < 0) | |
967 | return -1; | |
968 | addr[0] &= 0xfe; /* unicast */ | |
969 | addr[0] |= 0x02; /* locally administered */ | |
970 | return 0; | |
971 | } | |
1b640fd2 EP |
972 | |
973 | ||
974 | /** | |
975 | * str_token - Get next token from a string | |
976 | * @buf: String to tokenize. Note that the string might be modified. | |
977 | * @delim: String of delimiters | |
978 | * @context: Pointer to save our context. Should be initialized with | |
979 | * NULL on the first call, and passed for any further call. | |
980 | * Returns: The next token, NULL if there are no more valid tokens. | |
981 | */ | |
982 | char * str_token(char *str, const char *delim, char **context) | |
983 | { | |
984 | char *end, *pos = str; | |
985 | ||
986 | if (*context) | |
987 | pos = *context; | |
988 | ||
989 | while (*pos && os_strchr(delim, *pos)) | |
990 | pos++; | |
991 | if (!*pos) | |
992 | return NULL; | |
993 | ||
994 | end = pos + 1; | |
995 | while (*end && !os_strchr(delim, *end)) | |
996 | end++; | |
997 | ||
998 | if (*end) | |
999 | *end++ = '\0'; | |
1000 | ||
1001 | *context = end; | |
1002 | return pos; | |
1003 | } | |
c3d6c717 BG |
1004 | |
1005 | ||
1006 | size_t utf8_unescape(const char *inp, size_t in_size, | |
1007 | char *outp, size_t out_size) | |
1008 | { | |
1009 | size_t res_size = 0; | |
1010 | ||
1011 | if (!inp || !outp) | |
1012 | return 0; | |
1013 | ||
1014 | if (!in_size) | |
1015 | in_size = os_strlen(inp); | |
1016 | ||
1017 | /* Advance past leading single quote */ | |
1018 | if (*inp == '\'' && in_size) { | |
1019 | inp++; | |
1020 | in_size--; | |
1021 | } | |
1022 | ||
1023 | while (in_size--) { | |
1024 | if (res_size >= out_size) | |
1025 | return 0; | |
1026 | ||
1027 | switch (*inp) { | |
1028 | case '\'': | |
1029 | /* Terminate on bare single quote */ | |
1030 | *outp = '\0'; | |
1031 | return res_size; | |
1032 | ||
1033 | case '\\': | |
1034 | if (!in_size--) | |
1035 | return 0; | |
1036 | inp++; | |
1037 | /* fall through */ | |
1038 | ||
1039 | default: | |
1040 | *outp++ = *inp++; | |
1041 | res_size++; | |
1042 | } | |
1043 | } | |
1044 | ||
1045 | /* NUL terminate if space allows */ | |
1046 | if (res_size < out_size) | |
1047 | *outp = '\0'; | |
1048 | ||
1049 | return res_size; | |
1050 | } | |
1051 | ||
1052 | ||
1053 | size_t utf8_escape(const char *inp, size_t in_size, | |
1054 | char *outp, size_t out_size) | |
1055 | { | |
1056 | size_t res_size = 0; | |
1057 | ||
1058 | if (!inp || !outp) | |
1059 | return 0; | |
1060 | ||
1061 | /* inp may or may not be NUL terminated, but must be if 0 size | |
1062 | * is specified */ | |
1063 | if (!in_size) | |
1064 | in_size = os_strlen(inp); | |
1065 | ||
1066 | while (in_size--) { | |
1067 | if (res_size++ >= out_size) | |
1068 | return 0; | |
1069 | ||
1070 | switch (*inp) { | |
1071 | case '\\': | |
1072 | case '\'': | |
1073 | if (res_size++ >= out_size) | |
1074 | return 0; | |
1075 | *outp++ = '\\'; | |
1076 | /* fall through */ | |
1077 | ||
1078 | default: | |
1079 | *outp++ = *inp++; | |
1080 | break; | |
1081 | } | |
1082 | } | |
1083 | ||
1084 | /* NUL terminate if space allows */ | |
1085 | if (res_size < out_size) | |
1086 | *outp = '\0'; | |
1087 | ||
1088 | return res_size; | |
1089 | } |