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