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