1 /*
2 * wpa_supplicant/hostapd / common helper functions, etc.
3 * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "includes.h"
16
17 #include "common.h"
18
19
20 #ifdef CONFIG_DEBUG_FILE
21 static FILE *out_file = NULL;
22 #endif /* CONFIG_DEBUG_FILE */
23 int wpa_debug_level = MSG_INFO;
24 int wpa_debug_show_keys = 0;
25 int wpa_debug_timestamp = 0;
26
27
hex2num(char c)28 static int hex2num(char c)
29 {
30 if (c >= '0' && c <= '9')
31 return c - '0';
32 if (c >= 'a' && c <= 'f')
33 return c - 'a' + 10;
34 if (c >= 'A' && c <= 'F')
35 return c - 'A' + 10;
36 return -1;
37 }
38
39
hex2byte(const char * hex)40 static int hex2byte(const char *hex)
41 {
42 int a, b;
43 a = hex2num(*hex++);
44 if (a < 0)
45 return -1;
46 b = hex2num(*hex++);
47 if (b < 0)
48 return -1;
49 return (a << 4) | b;
50 }
51
52
53 /**
54 * hwaddr_aton - Convert ASCII string to MAC address
55 * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
56 * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
57 * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
58 */
hwaddr_aton(const char * txt,u8 * addr)59 int hwaddr_aton(const char *txt, u8 *addr)
60 {
61 int i;
62
63 for (i = 0; i < 6; i++) {
64 int a, b;
65
66 a = hex2num(*txt++);
67 if (a < 0)
68 return -1;
69 b = hex2num(*txt++);
70 if (b < 0)
71 return -1;
72 *addr++ = (a << 4) | b;
73 if (i < 5 && *txt++ != ':')
74 return -1;
75 }
76
77 return 0;
78 }
79
80
81 /**
82 * hexstr2bin - Convert ASCII hex string into binary data
83 * @hex: ASCII hex string (e.g., "01ab")
84 * @buf: Buffer for the binary data
85 * @len: Length of the text to convert in bytes (of buf); hex will be double
86 * this size
87 * Returns: 0 on success, -1 on failure (invalid hex string)
88 */
hexstr2bin(const char * hex,u8 * buf,size_t len)89 int hexstr2bin(const char *hex, u8 *buf, size_t len)
90 {
91 size_t i;
92 int a;
93 const char *ipos = hex;
94 u8 *opos = buf;
95
96 for (i = 0; i < len; i++) {
97 a = hex2byte(ipos);
98 if (a < 0)
99 return -1;
100 *opos++ = a;
101 ipos += 2;
102 }
103 return 0;
104 }
105
106
107 /**
108 * inc_byte_array - Increment arbitrary length byte array by one
109 * @counter: Pointer to byte array
110 * @len: Length of the counter in bytes
111 *
112 * This function increments the last byte of the counter by one and continues
113 * rolling over to more significant bytes if the byte was incremented from
114 * 0xff to 0x00.
115 */
inc_byte_array(u8 * counter,size_t len)116 void inc_byte_array(u8 *counter, size_t len)
117 {
118 int pos = len - 1;
119 while (pos >= 0) {
120 counter[pos]++;
121 if (counter[pos] != 0)
122 break;
123 pos--;
124 }
125 }
126
127
wpa_get_ntp_timestamp(u8 * buf)128 void wpa_get_ntp_timestamp(u8 *buf)
129 {
130 struct os_time now;
131 u32 sec, usec;
132
133 /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
134 os_get_time(&now);
135 sec = host_to_be32(now.sec + 2208988800U); /* Epoch to 1900 */
136 /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
137 usec = now.usec;
138 usec = host_to_be32(4295 * usec - (usec >> 5) - (usec >> 9));
139 os_memcpy(buf, (u8 *) &sec, 4);
140 os_memcpy(buf + 4, (u8 *) &usec, 4);
141 }
142
143 #ifdef ANDROID
144
145 #include <android/log.h>
146
android_printf(int level,char * format,...)147 void android_printf(int level, char *format, ...)
148 {
149 if (level >= wpa_debug_level) {
150 va_list ap;
151 if (level == MSG_ERROR) {
152 level = ANDROID_LOG_ERROR;
153 } else if (level == MSG_WARNING) {
154 level = ANDROID_LOG_WARN;
155 } else if (level == MSG_INFO) {
156 level = ANDROID_LOG_INFO;
157 } else {
158 level = ANDROID_LOG_DEBUG;
159 }
160 va_start(ap, format);
161 __android_log_vprint(level, "wpa_supplicant", format, ap);
162 va_end(ap);
163 }
164 }
165
166 #else /* ANDROID */
167
168 #ifndef CONFIG_NO_STDOUT_DEBUG
169
wpa_debug_print_timestamp(void)170 void wpa_debug_print_timestamp(void)
171 {
172 struct os_time tv;
173
174 if (!wpa_debug_timestamp)
175 return;
176
177 os_get_time(&tv);
178 #ifdef CONFIG_DEBUG_FILE
179 if (out_file) {
180 fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
181 (unsigned int) tv.usec);
182 } else
183 #endif /* CONFIG_DEBUG_FILE */
184 printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
185 }
186
187
188 /**
189 * wpa_printf - conditional printf
190 * @level: priority level (MSG_*) of the message
191 * @fmt: printf format string, followed by optional arguments
192 *
193 * This function is used to print conditional debugging and error messages. The
194 * output may be directed to stdout, stderr, and/or syslog based on
195 * configuration.
196 *
197 * Note: New line '\n' is added to the end of the text when printing to stdout.
198 */
wpa_printf(int level,char * fmt,...)199 void wpa_printf(int level, char *fmt, ...)
200 {
201 va_list ap;
202
203 va_start(ap, fmt);
204 if (level >= wpa_debug_level) {
205 wpa_debug_print_timestamp();
206 #ifdef CONFIG_DEBUG_FILE
207 if (out_file) {
208 vfprintf(out_file, fmt, ap);
209 fprintf(out_file, "\n");
210 } else {
211 #endif /* CONFIG_DEBUG_FILE */
212 vprintf(fmt, ap);
213 printf("\n");
214 #ifdef CONFIG_DEBUG_FILE
215 }
216 #endif /* CONFIG_DEBUG_FILE */
217 }
218 va_end(ap);
219 }
220
221
_wpa_hexdump(int level,const char * title,const u8 * buf,size_t len,int show)222 static void _wpa_hexdump(int level, const char *title, const u8 *buf,
223 size_t len, int show)
224 {
225 size_t i;
226 if (level < wpa_debug_level)
227 return;
228 wpa_debug_print_timestamp();
229 #ifdef CONFIG_DEBUG_FILE
230 if (out_file) {
231 fprintf(out_file, "%s - hexdump(len=%lu):",
232 title, (unsigned long) len);
233 if (buf == NULL) {
234 fprintf(out_file, " [NULL]");
235 } else if (show) {
236 for (i = 0; i < len; i++)
237 fprintf(out_file, " %02x", buf[i]);
238 } else {
239 fprintf(out_file, " [REMOVED]");
240 }
241 fprintf(out_file, "\n");
242 } else {
243 #endif /* CONFIG_DEBUG_FILE */
244 printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
245 if (buf == NULL) {
246 printf(" [NULL]");
247 } else if (show) {
248 for (i = 0; i < len; i++)
249 printf(" %02x", buf[i]);
250 } else {
251 printf(" [REMOVED]");
252 }
253 printf("\n");
254 #ifdef CONFIG_DEBUG_FILE
255 }
256 #endif /* CONFIG_DEBUG_FILE */
257 }
258
wpa_hexdump(int level,const char * title,const u8 * buf,size_t len)259 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
260 {
261 _wpa_hexdump(level, title, buf, len, 1);
262 }
263
264
wpa_hexdump_key(int level,const char * title,const u8 * buf,size_t len)265 void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
266 {
267 _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
268 }
269
270
_wpa_hexdump_ascii(int level,const char * title,const u8 * buf,size_t len,int show)271 static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
272 size_t len, int show)
273 {
274 size_t i, llen;
275 const u8 *pos = buf;
276 const size_t line_len = 16;
277
278 if (level < wpa_debug_level)
279 return;
280 wpa_debug_print_timestamp();
281 #ifdef CONFIG_DEBUG_FILE
282 if (out_file) {
283 if (!show) {
284 fprintf(out_file,
285 "%s - hexdump_ascii(len=%lu): [REMOVED]\n",
286 title, (unsigned long) len);
287 return;
288 }
289 if (buf == NULL) {
290 fprintf(out_file,
291 "%s - hexdump_ascii(len=%lu): [NULL]\n",
292 title, (unsigned long) len);
293 return;
294 }
295 fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
296 title, (unsigned long) len);
297 while (len) {
298 llen = len > line_len ? line_len : len;
299 fprintf(out_file, " ");
300 for (i = 0; i < llen; i++)
301 fprintf(out_file, " %02x", pos[i]);
302 for (i = llen; i < line_len; i++)
303 fprintf(out_file, " ");
304 fprintf(out_file, " ");
305 for (i = 0; i < llen; i++) {
306 if (isprint(pos[i]))
307 fprintf(out_file, "%c", pos[i]);
308 else
309 fprintf(out_file, "_");
310 }
311 for (i = llen; i < line_len; i++)
312 fprintf(out_file, " ");
313 fprintf(out_file, "\n");
314 pos += llen;
315 len -= llen;
316 }
317 } else {
318 #endif /* CONFIG_DEBUG_FILE */
319 if (!show) {
320 printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
321 title, (unsigned long) len);
322 return;
323 }
324 if (buf == NULL) {
325 printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
326 title, (unsigned long) len);
327 return;
328 }
329 printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
330 while (len) {
331 llen = len > line_len ? line_len : len;
332 printf(" ");
333 for (i = 0; i < llen; i++)
334 printf(" %02x", pos[i]);
335 for (i = llen; i < line_len; i++)
336 printf(" ");
337 printf(" ");
338 for (i = 0; i < llen; i++) {
339 if (isprint(pos[i]))
340 printf("%c", pos[i]);
341 else
342 printf("_");
343 }
344 for (i = llen; i < line_len; i++)
345 printf(" ");
346 printf("\n");
347 pos += llen;
348 len -= llen;
349 }
350 #ifdef CONFIG_DEBUG_FILE
351 }
352 #endif /* CONFIG_DEBUG_FILE */
353 }
354
355
wpa_hexdump_ascii(int level,const char * title,const u8 * buf,size_t len)356 void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
357 {
358 _wpa_hexdump_ascii(level, title, buf, len, 1);
359 }
360
361
wpa_hexdump_ascii_key(int level,const char * title,const u8 * buf,size_t len)362 void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
363 size_t len)
364 {
365 _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
366 }
367
368
wpa_debug_open_file(const char * path)369 int wpa_debug_open_file(const char *path)
370 {
371 #ifdef CONFIG_DEBUG_FILE
372 if (!path)
373 return 0;
374 out_file = fopen(path, "a");
375 if (out_file == NULL) {
376 wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
377 "output file, using standard output");
378 return -1;
379 }
380 #ifndef _WIN32
381 setvbuf(out_file, NULL, _IOLBF, 0);
382 #endif /* _WIN32 */
383 #endif /* CONFIG_DEBUG_FILE */
384 return 0;
385 }
386
387
wpa_debug_close_file(void)388 void wpa_debug_close_file(void)
389 {
390 #ifdef CONFIG_DEBUG_FILE
391 if (!out_file)
392 return;
393 fclose(out_file);
394 out_file = NULL;
395 #endif /* CONFIG_DEBUG_FILE */
396 }
397
398 #endif /* CONFIG_NO_STDOUT_DEBUG */
399
400 #endif /* ANDROID */
401
402 #ifndef CONFIG_NO_WPA_MSG
403 static wpa_msg_cb_func wpa_msg_cb = NULL;
404
wpa_msg_register_cb(wpa_msg_cb_func func)405 void wpa_msg_register_cb(wpa_msg_cb_func func)
406 {
407 wpa_msg_cb = func;
408 }
409
410
wpa_msg(void * ctx,int level,char * fmt,...)411 void wpa_msg(void *ctx, int level, char *fmt, ...)
412 {
413 va_list ap;
414 char *buf;
415 const int buflen = 2048;
416 int len;
417
418 buf = os_malloc(buflen);
419 if (buf == NULL) {
420 wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
421 "buffer");
422 return;
423 }
424 va_start(ap, fmt);
425 len = vsnprintf(buf, buflen, fmt, ap);
426 va_end(ap);
427 wpa_printf(level, "%s", buf);
428 if (wpa_msg_cb)
429 wpa_msg_cb(ctx, level, buf, len);
430 os_free(buf);
431 }
432 #endif /* CONFIG_NO_WPA_MSG */
433
434
_wpa_snprintf_hex(char * buf,size_t buf_size,const u8 * data,size_t len,int uppercase)435 static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
436 size_t len, int uppercase)
437 {
438 size_t i;
439 char *pos = buf, *end = buf + buf_size;
440 int ret;
441 if (buf_size == 0)
442 return 0;
443 for (i = 0; i < len; i++) {
444 ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
445 data[i]);
446 if (ret < 0 || ret >= end - pos) {
447 end[-1] = '\0';
448 return pos - buf;
449 }
450 pos += ret;
451 }
452 end[-1] = '\0';
453 return pos - buf;
454 }
455
456 /**
457 * wpa_snprintf_hex - Print data as a hex string into a buffer
458 * @buf: Memory area to use as the output buffer
459 * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
460 * @data: Data to be printed
461 * @len: Length of data in bytes
462 * Returns: Number of bytes written
463 */
wpa_snprintf_hex(char * buf,size_t buf_size,const u8 * data,size_t len)464 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
465 {
466 return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
467 }
468
469
470 /**
471 * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
472 * @buf: Memory area to use as the output buffer
473 * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
474 * @data: Data to be printed
475 * @len: Length of data in bytes
476 * Returns: Number of bytes written
477 */
wpa_snprintf_hex_uppercase(char * buf,size_t buf_size,const u8 * data,size_t len)478 int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
479 size_t len)
480 {
481 return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
482 }
483
484
485 #ifdef CONFIG_ANSI_C_EXTRA
486
487 #ifdef _WIN32_WCE
perror(const char * s)488 void perror(const char *s)
489 {
490 wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
491 s, (int) GetLastError());
492 }
493 #endif /* _WIN32_WCE */
494
495
496 int optind = 1;
497 int optopt;
498 char *optarg;
499
getopt(int argc,char * const argv[],const char * optstring)500 int getopt(int argc, char *const argv[], const char *optstring)
501 {
502 static int optchr = 1;
503 char *cp;
504
505 if (optchr == 1) {
506 if (optind >= argc) {
507 /* all arguments processed */
508 return EOF;
509 }
510
511 if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
512 /* no option characters */
513 return EOF;
514 }
515 }
516
517 if (os_strcmp(argv[optind], "--") == 0) {
518 /* no more options */
519 optind++;
520 return EOF;
521 }
522
523 optopt = argv[optind][optchr];
524 cp = os_strchr(optstring, optopt);
525 if (cp == NULL || optopt == ':') {
526 if (argv[optind][++optchr] == '\0') {
527 optchr = 1;
528 optind++;
529 }
530 return '?';
531 }
532
533 if (cp[1] == ':') {
534 /* Argument required */
535 optchr = 1;
536 if (argv[optind][optchr + 1]) {
537 /* No space between option and argument */
538 optarg = &argv[optind++][optchr + 1];
539 } else if (++optind >= argc) {
540 /* option requires an argument */
541 return '?';
542 } else {
543 /* Argument in the next argv */
544 optarg = argv[optind++];
545 }
546 } else {
547 /* No argument */
548 if (argv[optind][++optchr] == '\0') {
549 optchr = 1;
550 optind++;
551 }
552 optarg = NULL;
553 }
554 return *cp;
555 }
556 #endif /* CONFIG_ANSI_C_EXTRA */
557
558
559 #ifdef CONFIG_NATIVE_WINDOWS
560 /**
561 * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
562 * @str: Pointer to string to convert
563 *
564 * This function converts a unicode string to ASCII using the same
565 * buffer for output. If UNICODE is not set, the buffer is not
566 * modified.
567 */
wpa_unicode2ascii_inplace(TCHAR * str)568 void wpa_unicode2ascii_inplace(TCHAR *str)
569 {
570 #ifdef UNICODE
571 char *dst = (char *) str;
572 while (*str)
573 *dst++ = (char) *str++;
574 *dst = '\0';
575 #endif /* UNICODE */
576 }
577
578
wpa_strdup_tchar(const char * str)579 TCHAR * wpa_strdup_tchar(const char *str)
580 {
581 #ifdef UNICODE
582 TCHAR *buf;
583 buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
584 if (buf == NULL)
585 return NULL;
586 wsprintf(buf, L"%S", str);
587 return buf;
588 #else /* UNICODE */
589 return os_strdup(str);
590 #endif /* UNICODE */
591 }
592 #endif /* CONFIG_NATIVE_WINDOWS */
593
594
595 /**
596 * wpa_ssid_txt - Convert SSID to a printable string
597 * @ssid: SSID (32-octet string)
598 * @ssid_len: Length of ssid in octets
599 * Returns: Pointer to a printable string
600 *
601 * This function can be used to convert SSIDs into printable form. In most
602 * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
603 * does not limit the used character set, so anything could be used in an SSID.
604 *
605 * This function uses a static buffer, so only one call can be used at the
606 * time, i.e., this is not re-entrant and the returned buffer must be used
607 * before calling this again.
608 */
wpa_ssid_txt(u8 * ssid,size_t ssid_len)609 const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
610 {
611 static char ssid_txt[33];
612 char *pos;
613
614 if (ssid_len > 32)
615 ssid_len = 32;
616 os_memcpy(ssid_txt, ssid, ssid_len);
617 ssid_txt[ssid_len] = '\0';
618 for (pos = ssid_txt; *pos != '\0'; pos++) {
619 if ((u8) *pos < 32 || (u8) *pos >= 127)
620 *pos = '_';
621 }
622 return ssid_txt;
623 }
624