]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/hostapd/common.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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_level = MSG_INFO;
24 int wpa_debug_show_keys = 0;
25 int wpa_debug_timestamp = 0;
26
27
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
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  */
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  */
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  */
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
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
144
145 #ifndef CONFIG_NO_STDOUT_DEBUG
146
147 void wpa_debug_print_timestamp(void)
148 {
149         struct os_time tv;
150
151         if (!wpa_debug_timestamp)
152                 return;
153
154         os_get_time(&tv);
155 #ifdef CONFIG_DEBUG_FILE
156         if (out_file) {
157                 fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
158                         (unsigned int) tv.usec);
159         } else
160 #endif /* CONFIG_DEBUG_FILE */
161         printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
162 }
163
164
165 /**
166  * wpa_printf - conditional printf
167  * @level: priority level (MSG_*) of the message
168  * @fmt: printf format string, followed by optional arguments
169  *
170  * This function is used to print conditional debugging and error messages. The
171  * output may be directed to stdout, stderr, and/or syslog based on
172  * configuration.
173  *
174  * Note: New line '\n' is added to the end of the text when printing to stdout.
175  */
176 void wpa_printf(int level, char *fmt, ...)
177 {
178         va_list ap;
179
180         va_start(ap, fmt);
181         if (level >= wpa_debug_level) {
182                 wpa_debug_print_timestamp();
183 #ifdef CONFIG_DEBUG_FILE
184                 if (out_file) {
185                         vfprintf(out_file, fmt, ap);
186                         fprintf(out_file, "\n");
187                 } else {
188 #endif /* CONFIG_DEBUG_FILE */
189                 vprintf(fmt, ap);
190                 printf("\n");
191 #ifdef CONFIG_DEBUG_FILE
192                 }
193 #endif /* CONFIG_DEBUG_FILE */
194         }
195         va_end(ap);
196 }
197
198
199 static void _wpa_hexdump(int level, const char *title, const u8 *buf,
200                          size_t len, int show)
201 {
202         size_t i;
203         if (level < wpa_debug_level)
204                 return;
205         wpa_debug_print_timestamp();
206 #ifdef CONFIG_DEBUG_FILE
207         if (out_file) {
208                 fprintf(out_file, "%s - hexdump(len=%lu):",
209                         title, (unsigned long) len);
210                 if (buf == NULL) {
211                         fprintf(out_file, " [NULL]");
212                 } else if (show) {
213                         for (i = 0; i < len; i++)
214                                 fprintf(out_file, " %02x", buf[i]);
215                 } else {
216                         fprintf(out_file, " [REMOVED]");
217                 }
218                 fprintf(out_file, "\n");
219         } else {
220 #endif /* CONFIG_DEBUG_FILE */
221         printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
222         if (buf == NULL) {
223                 printf(" [NULL]");
224         } else if (show) {
225                 for (i = 0; i < len; i++)
226                         printf(" %02x", buf[i]);
227         } else {
228                 printf(" [REMOVED]");
229         }
230         printf("\n");
231 #ifdef CONFIG_DEBUG_FILE
232         }
233 #endif /* CONFIG_DEBUG_FILE */
234 }
235
236 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
237 {
238         _wpa_hexdump(level, title, buf, len, 1);
239 }
240
241
242 void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
243 {
244         _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
245 }
246
247
248 static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
249                                size_t len, int show)
250 {
251         size_t i, llen;
252         const u8 *pos = buf;
253         const size_t line_len = 16;
254
255         if (level < wpa_debug_level)
256                 return;
257         wpa_debug_print_timestamp();
258 #ifdef CONFIG_DEBUG_FILE
259         if (out_file) {
260                 if (!show) {
261                         fprintf(out_file,
262                                 "%s - hexdump_ascii(len=%lu): [REMOVED]\n",
263                                 title, (unsigned long) len);
264                         return;
265                 }
266                 if (buf == NULL) {
267                         fprintf(out_file,
268                                 "%s - hexdump_ascii(len=%lu): [NULL]\n",
269                                 title, (unsigned long) len);
270                         return;
271                 }
272                 fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
273                         title, (unsigned long) len);
274                 while (len) {
275                         llen = len > line_len ? line_len : len;
276                         fprintf(out_file, "    ");
277                         for (i = 0; i < llen; i++)
278                                 fprintf(out_file, " %02x", pos[i]);
279                         for (i = llen; i < line_len; i++)
280                                 fprintf(out_file, "   ");
281                         fprintf(out_file, "   ");
282                         for (i = 0; i < llen; i++) {
283                                 if (isprint(pos[i]))
284                                         fprintf(out_file, "%c", pos[i]);
285                                 else
286                                         fprintf(out_file, "_");
287                         }
288                         for (i = llen; i < line_len; i++)
289                                 fprintf(out_file, " ");
290                         fprintf(out_file, "\n");
291                         pos += llen;
292                         len -= llen;
293                 }
294         } else {
295 #endif /* CONFIG_DEBUG_FILE */
296         if (!show) {
297                 printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
298                        title, (unsigned long) len);
299                 return;
300         }
301         if (buf == NULL) {
302                 printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
303                        title, (unsigned long) len);
304                 return;
305         }
306         printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
307         while (len) {
308                 llen = len > line_len ? line_len : len;
309                 printf("    ");
310                 for (i = 0; i < llen; i++)
311                         printf(" %02x", pos[i]);
312                 for (i = llen; i < line_len; i++)
313                         printf("   ");
314                 printf("   ");
315                 for (i = 0; i < llen; i++) {
316                         if (isprint(pos[i]))
317                                 printf("%c", pos[i]);
318                         else
319                                 printf("_");
320                 }
321                 for (i = llen; i < line_len; i++)
322                         printf(" ");
323                 printf("\n");
324                 pos += llen;
325                 len -= llen;
326         }
327 #ifdef CONFIG_DEBUG_FILE
328         }
329 #endif /* CONFIG_DEBUG_FILE */
330 }
331
332
333 void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
334 {
335         _wpa_hexdump_ascii(level, title, buf, len, 1);
336 }
337
338
339 void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
340                            size_t len)
341 {
342         _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
343 }
344
345
346 int wpa_debug_open_file(const char *path)
347 {
348 #ifdef CONFIG_DEBUG_FILE
349         if (!path)
350                 return 0;
351         out_file = fopen(path, "a");
352         if (out_file == NULL) {
353                 wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
354                            "output file, using standard output");
355                 return -1;
356         }
357 #ifndef _WIN32
358         setvbuf(out_file, NULL, _IOLBF, 0);
359 #endif /* _WIN32 */
360 #endif /* CONFIG_DEBUG_FILE */
361         return 0;
362 }
363
364
365 void wpa_debug_close_file(void)
366 {
367 #ifdef CONFIG_DEBUG_FILE
368         if (!out_file)
369                 return;
370         fclose(out_file);
371         out_file = NULL;
372 #endif /* CONFIG_DEBUG_FILE */
373 }
374
375 #endif /* CONFIG_NO_STDOUT_DEBUG */
376
377
378 #ifndef CONFIG_NO_WPA_MSG
379 static wpa_msg_cb_func wpa_msg_cb = NULL;
380
381 void wpa_msg_register_cb(wpa_msg_cb_func func)
382 {
383         wpa_msg_cb = func;
384 }
385
386
387 void wpa_msg(void *ctx, int level, char *fmt, ...)
388 {
389         va_list ap;
390         char *buf;
391         const int buflen = 2048;
392         int len;
393
394         buf = os_malloc(buflen);
395         if (buf == NULL) {
396                 wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
397                            "buffer");
398                 return;
399         }
400         va_start(ap, fmt);
401         len = vsnprintf(buf, buflen, fmt, ap);
402         va_end(ap);
403         wpa_printf(level, "%s", buf);
404         if (wpa_msg_cb)
405                 wpa_msg_cb(ctx, level, buf, len);
406         os_free(buf);
407 }
408 #endif /* CONFIG_NO_WPA_MSG */
409
410
411 static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
412                                     size_t len, int uppercase)
413 {
414         size_t i;
415         char *pos = buf, *end = buf + buf_size;
416         int ret;
417         if (buf_size == 0)
418                 return 0;
419         for (i = 0; i < len; i++) {
420                 ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
421                                   data[i]);
422                 if (ret < 0 || ret >= end - pos) {
423                         end[-1] = '\0';
424                         return pos - buf;
425                 }
426                 pos += ret;
427         }
428         end[-1] = '\0';
429         return pos - buf;
430 }
431
432 /**
433  * wpa_snprintf_hex - Print data as a hex string into a buffer
434  * @buf: Memory area to use as the output buffer
435  * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
436  * @data: Data to be printed
437  * @len: Length of data in bytes
438  * Returns: Number of bytes written
439  */
440 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
441 {
442         return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
443 }
444
445
446 /**
447  * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
448  * @buf: Memory area to use as the output buffer
449  * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
450  * @data: Data to be printed
451  * @len: Length of data in bytes
452  * Returns: Number of bytes written
453  */
454 int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
455                                size_t len)
456 {
457         return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
458 }
459
460
461 #ifdef CONFIG_ANSI_C_EXTRA
462
463 #ifdef _WIN32_WCE
464 void perror(const char *s)
465 {
466         wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
467                    s, (int) GetLastError());
468 }
469 #endif /* _WIN32_WCE */
470
471
472 int optind = 1;
473 int optopt;
474 char *optarg;
475
476 int getopt(int argc, char *const argv[], const char *optstring)
477 {
478         static int optchr = 1;
479         char *cp;
480
481         if (optchr == 1) {
482                 if (optind >= argc) {
483                         /* all arguments processed */
484                         return EOF;
485                 }
486
487                 if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
488                         /* no option characters */
489                         return EOF;
490                 }
491         }
492
493         if (os_strcmp(argv[optind], "--") == 0) {
494                 /* no more options */
495                 optind++;
496                 return EOF;
497         }
498
499         optopt = argv[optind][optchr];
500         cp = os_strchr(optstring, optopt);
501         if (cp == NULL || optopt == ':') {
502                 if (argv[optind][++optchr] == '\0') {
503                         optchr = 1;
504                         optind++;
505                 }
506                 return '?';
507         }
508
509         if (cp[1] == ':') {
510                 /* Argument required */
511                 optchr = 1;
512                 if (argv[optind][optchr + 1]) {
513                         /* No space between option and argument */
514                         optarg = &argv[optind++][optchr + 1];
515                 } else if (++optind >= argc) {
516                         /* option requires an argument */
517                         return '?';
518                 } else {
519                         /* Argument in the next argv */
520                         optarg = argv[optind++];
521                 }
522         } else {
523                 /* No argument */
524                 if (argv[optind][++optchr] == '\0') {
525                         optchr = 1;
526                         optind++;
527                 }
528                 optarg = NULL;
529         }
530         return *cp;
531 }
532 #endif /* CONFIG_ANSI_C_EXTRA */
533
534
535 #ifdef CONFIG_NATIVE_WINDOWS
536 /**
537  * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
538  * @str: Pointer to string to convert
539  *
540  * This function converts a unicode string to ASCII using the same
541  * buffer for output. If UNICODE is not set, the buffer is not
542  * modified.
543  */
544 void wpa_unicode2ascii_inplace(TCHAR *str)
545 {
546 #ifdef UNICODE
547         char *dst = (char *) str;
548         while (*str)
549                 *dst++ = (char) *str++;
550         *dst = '\0';
551 #endif /* UNICODE */
552 }
553
554
555 TCHAR * wpa_strdup_tchar(const char *str)
556 {
557 #ifdef UNICODE
558         TCHAR *buf;
559         buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
560         if (buf == NULL)
561                 return NULL;
562         wsprintf(buf, L"%S", str);
563         return buf;
564 #else /* UNICODE */
565         return os_strdup(str);
566 #endif /* UNICODE */
567 }
568 #endif /* CONFIG_NATIVE_WINDOWS */
569
570
571 /**
572  * wpa_ssid_txt - Convert SSID to a printable string
573  * @ssid: SSID (32-octet string)
574  * @ssid_len: Length of ssid in octets
575  * Returns: Pointer to a printable string
576  *
577  * This function can be used to convert SSIDs into printable form. In most
578  * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
579  * does not limit the used character set, so anything could be used in an SSID.
580  *
581  * This function uses a static buffer, so only one call can be used at the
582  * time, i.e., this is not re-entrant and the returned buffer must be used
583  * before calling this again.
584  */
585 const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
586 {
587         static char ssid_txt[33];
588         char *pos;
589
590         if (ssid_len > 32)
591                 ssid_len = 32;
592         os_memcpy(ssid_txt, ssid, ssid_len);
593         ssid_txt[ssid_len] = '\0';
594         for (pos = ssid_txt; *pos != '\0'; pos++) {
595                 if ((u8) *pos < 32 || (u8) *pos >= 127)
596                         *pos = '_';
597         }
598         return ssid_txt;
599 }