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