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