858a97ceb734b6b614a13796c6297183d5b53bfa
[mech_eap.git] / src / utils / wpa_debug.c
1 /*
2  * wpa_supplicant/hostapd / Debug prints
3  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "includes.h"
10
11 #include "common.h"
12
13 #ifdef CONFIG_DEBUG_SYSLOG
14 #include <syslog.h>
15
16 static int wpa_debug_syslog = 0;
17 #endif /* CONFIG_DEBUG_SYSLOG */
18
19
20 int wpa_debug_level = MSG_INFO;
21 int wpa_debug_show_keys = 0;
22 int wpa_debug_timestamp = 0;
23
24
25 #ifdef CONFIG_ANDROID_LOG
26
27 #include <android/log.h>
28
29 #ifndef ANDROID_LOG_NAME
30 #define ANDROID_LOG_NAME        "wpa_supplicant"
31 #endif /* ANDROID_LOG_NAME */
32
33 static int wpa_to_android_level(int level)
34 {
35         if (level == MSG_ERROR)
36                 return ANDROID_LOG_ERROR;
37         if (level == MSG_WARNING)
38                 return ANDROID_LOG_WARN;
39         if (level == MSG_INFO)
40                 return ANDROID_LOG_INFO;
41         return ANDROID_LOG_DEBUG;
42 }
43
44 #endif /* CONFIG_ANDROID_LOG */
45
46 #ifndef CONFIG_NO_STDOUT_DEBUG
47
48 #ifdef CONFIG_DEBUG_FILE
49 static FILE *out_file = NULL;
50 #endif /* CONFIG_DEBUG_FILE */
51
52
53 void wpa_debug_print_timestamp(void)
54 {
55 #ifndef CONFIG_ANDROID_LOG
56         struct os_time tv;
57
58         if (!wpa_debug_timestamp)
59                 return;
60
61         os_get_time(&tv);
62 #ifdef CONFIG_DEBUG_FILE
63         if (out_file) {
64                 fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
65                         (unsigned int) tv.usec);
66         } else
67 #endif /* CONFIG_DEBUG_FILE */
68         printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
69 #endif /* CONFIG_ANDROID_LOG */
70 }
71
72
73 #ifdef CONFIG_DEBUG_SYSLOG
74 #ifndef LOG_HOSTAPD
75 #define LOG_HOSTAPD LOG_DAEMON
76 #endif /* LOG_HOSTAPD */
77
78 void wpa_debug_open_syslog(void)
79 {
80         openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD);
81         wpa_debug_syslog++;
82 }
83
84
85 void wpa_debug_close_syslog(void)
86 {
87         if (wpa_debug_syslog)
88                 closelog();
89 }
90
91
92 static int syslog_priority(int level)
93 {
94         switch (level) {
95         case MSG_MSGDUMP:
96         case MSG_DEBUG:
97                 return LOG_DEBUG;
98         case MSG_INFO:
99                 return LOG_NOTICE;
100         case MSG_WARNING:
101                 return LOG_WARNING;
102         case MSG_ERROR:
103                 return LOG_ERR;
104         }
105         return LOG_INFO;
106 }
107 #endif /* CONFIG_DEBUG_SYSLOG */
108
109
110 /**
111  * wpa_printf - conditional printf
112  * @level: priority level (MSG_*) of the message
113  * @fmt: printf format string, followed by optional arguments
114  *
115  * This function is used to print conditional debugging and error messages. The
116  * output may be directed to stdout, stderr, and/or syslog based on
117  * configuration.
118  *
119  * Note: New line '\n' is added to the end of the text when printing to stdout.
120  */
121 void wpa_printf(int level, const char *fmt, ...)
122 {
123         va_list ap;
124
125         va_start(ap, fmt);
126         if (level >= wpa_debug_level) {
127 #ifdef CONFIG_ANDROID_LOG
128                 __android_log_vprint(wpa_to_android_level(level),
129                                      ANDROID_LOG_NAME, fmt, ap);
130 #else /* CONFIG_ANDROID_LOG */
131 #ifdef CONFIG_DEBUG_SYSLOG
132                 if (wpa_debug_syslog) {
133                         vsyslog(syslog_priority(level), fmt, ap);
134                 } else {
135 #endif /* CONFIG_DEBUG_SYSLOG */
136                 wpa_debug_print_timestamp();
137 #ifdef CONFIG_DEBUG_FILE
138                 if (out_file) {
139                         vfprintf(out_file, fmt, ap);
140                         fprintf(out_file, "\n");
141                 } else {
142 #endif /* CONFIG_DEBUG_FILE */
143                 vprintf(fmt, ap);
144                 printf("\n");
145 #ifdef CONFIG_DEBUG_FILE
146                 }
147 #endif /* CONFIG_DEBUG_FILE */
148 #ifdef CONFIG_DEBUG_SYSLOG
149                 }
150 #endif /* CONFIG_DEBUG_SYSLOG */
151 #endif /* CONFIG_ANDROID_LOG */
152         }
153         va_end(ap);
154 }
155
156
157 static void _wpa_hexdump(int level, const char *title, const u8 *buf,
158                          size_t len, int show)
159 {
160         size_t i;
161         if (level < wpa_debug_level)
162                 return;
163 #ifdef CONFIG_ANDROID_LOG
164         {
165                 const char *display;
166                 char *strbuf = NULL;
167                 size_t slen = len;
168                 if (buf == NULL) {
169                         display = " [NULL]";
170                 } else if (len == 0) {
171                         display = "";
172                 } else if (show && len) {
173                         /* Limit debug message length for Android log */
174                         if (slen > 32)
175                                 slen = 32;
176                         strbuf = os_malloc(1 + 3 * slen);
177                         if (strbuf == NULL) {
178                                 wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
179                                            "allocate message buffer");
180                                 return;
181                         }
182
183                         for (i = 0; i < slen; i++)
184                                 os_snprintf(&strbuf[i * 3], 4, " %02x",
185                                             buf[i]);
186
187                         display = strbuf;
188                 } else {
189                         display = " [REMOVED]";
190                 }
191
192                 __android_log_print(wpa_to_android_level(level),
193                                     ANDROID_LOG_NAME,
194                                     "%s - hexdump(len=%lu):%s%s",
195                                     title, (long unsigned int) len, display,
196                                     len > slen ? " ..." : "");
197                 os_free(strbuf);
198                 return;
199         }
200 #else /* CONFIG_ANDROID_LOG */
201 #ifdef CONFIG_DEBUG_SYSLOG
202         if (wpa_debug_syslog) {
203                 const char *display;
204                 char *strbuf = NULL;
205
206                 if (buf == NULL) {
207                         display = " [NULL]";
208                 } else if (len == 0) {
209                         display = "";
210                 } else if (show && len) {
211                         strbuf = os_malloc(1 + 3 * len);
212                         if (strbuf == NULL) {
213                                 wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
214                                            "allocate message buffer");
215                                 return;
216                         }
217
218                         for (i = 0; i < len; i++)
219                                 os_snprintf(&strbuf[i * 3], 4, " %02x",
220                                             buf[i]);
221
222                         display = strbuf;
223                 } else {
224                         display = " [REMOVED]";
225                 }
226
227                 syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
228                        title, len, display);
229                 os_free(strbuf);
230                 return;
231         }
232 #endif /* CONFIG_DEBUG_SYSLOG */
233         wpa_debug_print_timestamp();
234 #ifdef CONFIG_DEBUG_FILE
235         if (out_file) {
236                 fprintf(out_file, "%s - hexdump(len=%lu):",
237                         title, (unsigned long) len);
238                 if (buf == NULL) {
239                         fprintf(out_file, " [NULL]");
240                 } else if (show) {
241                         for (i = 0; i < len; i++)
242                                 fprintf(out_file, " %02x", buf[i]);
243                 } else {
244                         fprintf(out_file, " [REMOVED]");
245                 }
246                 fprintf(out_file, "\n");
247         } else {
248 #endif /* CONFIG_DEBUG_FILE */
249         printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
250         if (buf == NULL) {
251                 printf(" [NULL]");
252         } else if (show) {
253                 for (i = 0; i < len; i++)
254                         printf(" %02x", buf[i]);
255         } else {
256                 printf(" [REMOVED]");
257         }
258         printf("\n");
259 #ifdef CONFIG_DEBUG_FILE
260         }
261 #endif /* CONFIG_DEBUG_FILE */
262 #endif /* CONFIG_ANDROID_LOG */
263 }
264
265 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
266 {
267         _wpa_hexdump(level, title, buf, len, 1);
268 }
269
270
271 void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
272 {
273         _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
274 }
275
276
277 static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
278                                size_t len, int show)
279 {
280         size_t i, llen;
281         const u8 *pos = buf;
282         const size_t line_len = 16;
283
284         if (level < wpa_debug_level)
285                 return;
286 #ifdef CONFIG_ANDROID_LOG
287         _wpa_hexdump(level, title, buf, len, show);
288 #else /* CONFIG_ANDROID_LOG */
289         wpa_debug_print_timestamp();
290 #ifdef CONFIG_DEBUG_FILE
291         if (out_file) {
292                 if (!show) {
293                         fprintf(out_file,
294                                 "%s - hexdump_ascii(len=%lu): [REMOVED]\n",
295                                 title, (unsigned long) len);
296                         return;
297                 }
298                 if (buf == NULL) {
299                         fprintf(out_file,
300                                 "%s - hexdump_ascii(len=%lu): [NULL]\n",
301                                 title, (unsigned long) len);
302                         return;
303                 }
304                 fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
305                         title, (unsigned long) len);
306                 while (len) {
307                         llen = len > line_len ? line_len : len;
308                         fprintf(out_file, "    ");
309                         for (i = 0; i < llen; i++)
310                                 fprintf(out_file, " %02x", pos[i]);
311                         for (i = llen; i < line_len; i++)
312                                 fprintf(out_file, "   ");
313                         fprintf(out_file, "   ");
314                         for (i = 0; i < llen; i++) {
315                                 if (isprint(pos[i]))
316                                         fprintf(out_file, "%c", pos[i]);
317                                 else
318                                         fprintf(out_file, "_");
319                         }
320                         for (i = llen; i < line_len; i++)
321                                 fprintf(out_file, " ");
322                         fprintf(out_file, "\n");
323                         pos += llen;
324                         len -= llen;
325                 }
326         } else {
327 #endif /* CONFIG_DEBUG_FILE */
328         if (!show) {
329                 printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
330                        title, (unsigned long) len);
331                 return;
332         }
333         if (buf == NULL) {
334                 printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
335                        title, (unsigned long) len);
336                 return;
337         }
338         printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
339         while (len) {
340                 llen = len > line_len ? line_len : len;
341                 printf("    ");
342                 for (i = 0; i < llen; i++)
343                         printf(" %02x", pos[i]);
344                 for (i = llen; i < line_len; i++)
345                         printf("   ");
346                 printf("   ");
347                 for (i = 0; i < llen; i++) {
348                         if (isprint(pos[i]))
349                                 printf("%c", pos[i]);
350                         else
351                                 printf("_");
352                 }
353                 for (i = llen; i < line_len; i++)
354                         printf(" ");
355                 printf("\n");
356                 pos += llen;
357                 len -= llen;
358         }
359 #ifdef CONFIG_DEBUG_FILE
360         }
361 #endif /* CONFIG_DEBUG_FILE */
362 #endif /* CONFIG_ANDROID_LOG */
363 }
364
365
366 void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
367 {
368         _wpa_hexdump_ascii(level, title, buf, len, 1);
369 }
370
371
372 void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
373                            size_t len)
374 {
375         _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
376 }
377
378
379 #ifdef CONFIG_DEBUG_FILE
380 static char *last_path = NULL;
381 #endif /* CONFIG_DEBUG_FILE */
382
383 int wpa_debug_reopen_file(void)
384 {
385 #ifdef CONFIG_DEBUG_FILE
386         int rv;
387         if (last_path) {
388                 char *tmp = os_strdup(last_path);
389                 wpa_debug_close_file();
390                 rv = wpa_debug_open_file(tmp);
391                 os_free(tmp);
392         } else {
393                 wpa_printf(MSG_ERROR, "Last-path was not set, cannot "
394                            "re-open log file.");
395                 rv = -1;
396         }
397         return rv;
398 #else /* CONFIG_DEBUG_FILE */
399         return 0;
400 #endif /* CONFIG_DEBUG_FILE */
401 }
402
403
404 int wpa_debug_open_file(const char *path)
405 {
406 #ifdef CONFIG_DEBUG_FILE
407         if (!path)
408                 return 0;
409
410         if (last_path == NULL || os_strcmp(last_path, path) != 0) {
411                 /* Save our path to enable re-open */
412                 os_free(last_path);
413                 last_path = os_strdup(path);
414         }
415
416         out_file = fopen(path, "a");
417         if (out_file == NULL) {
418                 wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
419                            "output file, using standard output");
420                 return -1;
421         }
422 #ifndef _WIN32
423         setvbuf(out_file, NULL, _IOLBF, 0);
424 #endif /* _WIN32 */
425 #endif /* CONFIG_DEBUG_FILE */
426         return 0;
427 }
428
429
430 void wpa_debug_close_file(void)
431 {
432 #ifdef CONFIG_DEBUG_FILE
433         if (!out_file)
434                 return;
435         fclose(out_file);
436         out_file = NULL;
437         os_free(last_path);
438         last_path = NULL;
439 #endif /* CONFIG_DEBUG_FILE */
440 }
441
442 #endif /* CONFIG_NO_STDOUT_DEBUG */
443
444
445 #ifndef CONFIG_NO_WPA_MSG
446 static wpa_msg_cb_func wpa_msg_cb = NULL;
447
448 void wpa_msg_register_cb(wpa_msg_cb_func func)
449 {
450         wpa_msg_cb = func;
451 }
452
453
454 static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
455
456 void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
457 {
458         wpa_msg_ifname_cb = func;
459 }
460
461
462 void wpa_msg(void *ctx, int level, const char *fmt, ...)
463 {
464         va_list ap;
465         char *buf;
466         const int buflen = 2048;
467         int len;
468         char prefix[130];
469
470         buf = os_malloc(buflen);
471         if (buf == NULL) {
472                 wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
473                            "buffer");
474                 return;
475         }
476         va_start(ap, fmt);
477         prefix[0] = '\0';
478         if (wpa_msg_ifname_cb) {
479                 const char *ifname = wpa_msg_ifname_cb(ctx);
480                 if (ifname) {
481                         int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
482                                               ifname);
483                         if (res < 0 || res >= (int) sizeof(prefix))
484                                 prefix[0] = '\0';
485                 }
486         }
487         len = vsnprintf(buf, buflen, fmt, ap);
488         va_end(ap);
489         wpa_printf(level, "%s%s", prefix, buf);
490         if (wpa_msg_cb)
491                 wpa_msg_cb(ctx, level, buf, len);
492         os_free(buf);
493 }
494
495
496 void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
497 {
498         va_list ap;
499         char *buf;
500         const int buflen = 2048;
501         int len;
502
503         if (!wpa_msg_cb)
504                 return;
505
506         buf = os_malloc(buflen);
507         if (buf == NULL) {
508                 wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
509                            "message buffer");
510                 return;
511         }
512         va_start(ap, fmt);
513         len = vsnprintf(buf, buflen, fmt, ap);
514         va_end(ap);
515         wpa_msg_cb(ctx, level, buf, len);
516         os_free(buf);
517 }
518 #endif /* CONFIG_NO_WPA_MSG */
519
520
521 #ifndef CONFIG_NO_HOSTAPD_LOGGER
522 static hostapd_logger_cb_func hostapd_logger_cb = NULL;
523
524 void hostapd_logger_register_cb(hostapd_logger_cb_func func)
525 {
526         hostapd_logger_cb = func;
527 }
528
529
530 void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
531                     const char *fmt, ...)
532 {
533         va_list ap;
534         char *buf;
535         const int buflen = 2048;
536         int len;
537
538         buf = os_malloc(buflen);
539         if (buf == NULL) {
540                 wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
541                            "message buffer");
542                 return;
543         }
544         va_start(ap, fmt);
545         len = vsnprintf(buf, buflen, fmt, ap);
546         va_end(ap);
547         if (hostapd_logger_cb)
548                 hostapd_logger_cb(ctx, addr, module, level, buf, len);
549         else if (addr)
550                 wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s",
551                            MAC2STR(addr), buf);
552         else
553                 wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
554         os_free(buf);
555 }
556 #endif /* CONFIG_NO_HOSTAPD_LOGGER */