| /* |
| * wpa_supplicant/hostapd / Debug prints |
| * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * Alternatively, this software may be distributed under the terms of BSD |
| * license. |
| * |
| * See README and COPYING for more details. |
| */ |
| |
| #include "includes.h" |
| |
| #include "common.h" |
| |
| #ifdef CONFIG_DEBUG_SYSLOG |
| #include <syslog.h> |
| |
| static int wpa_debug_syslog = 0; |
| #endif /* CONFIG_DEBUG_SYSLOG */ |
| |
| |
| #ifdef CONFIG_DEBUG_FILE |
| static FILE *out_file = NULL; |
| #endif /* CONFIG_DEBUG_FILE */ |
| int wpa_debug_level = MSG_INFO; |
| int wpa_debug_show_keys = 0; |
| int wpa_debug_timestamp = 0; |
| |
| |
| #ifndef CONFIG_NO_STDOUT_DEBUG |
| |
| void wpa_debug_print_timestamp(void) |
| { |
| struct os_time tv; |
| |
| if (!wpa_debug_timestamp) |
| return; |
| |
| os_get_time(&tv); |
| #ifdef CONFIG_DEBUG_FILE |
| if (out_file) { |
| fprintf(out_file, "%ld.%06u: ", (long) tv.sec, |
| (unsigned int) tv.usec); |
| } else |
| #endif /* CONFIG_DEBUG_FILE */ |
| printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); |
| } |
| |
| |
| #ifdef CONFIG_DEBUG_SYSLOG |
| void wpa_debug_open_syslog(void) |
| { |
| openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD); |
| wpa_debug_syslog++; |
| } |
| |
| |
| void wpa_debug_close_syslog(void) |
| { |
| if (wpa_debug_syslog) |
| closelog(); |
| } |
| |
| |
| static int syslog_priority(int level) |
| { |
| switch (level) { |
| case MSG_MSGDUMP: |
| case MSG_DEBUG: |
| return LOG_DEBUG; |
| case MSG_INFO: |
| return LOG_NOTICE; |
| case MSG_WARNING: |
| return LOG_WARNING; |
| case MSG_ERROR: |
| return LOG_ERR; |
| } |
| return LOG_INFO; |
| } |
| #endif /* CONFIG_DEBUG_SYSLOG */ |
| |
| |
| /** |
| * wpa_printf - conditional printf |
| * @level: priority level (MSG_*) of the message |
| * @fmt: printf format string, followed by optional arguments |
| * |
| * This function is used to print conditional debugging and error messages. The |
| * output may be directed to stdout, stderr, and/or syslog based on |
| * configuration. |
| * |
| * Note: New line '\n' is added to the end of the text when printing to stdout. |
| */ |
| void wpa_printf(int level, const char *fmt, ...) |
| { |
| va_list ap; |
| |
| va_start(ap, fmt); |
| if (level >= wpa_debug_level) { |
| #ifdef CONFIG_DEBUG_SYSLOG |
| if (wpa_debug_syslog) { |
| vsyslog(syslog_priority(level), fmt, ap); |
| } else { |
| #endif /* CONFIG_DEBUG_SYSLOG */ |
| wpa_debug_print_timestamp(); |
| #ifdef CONFIG_DEBUG_FILE |
| if (out_file) { |
| vfprintf(out_file, fmt, ap); |
| fprintf(out_file, "\n"); |
| } else { |
| #endif /* CONFIG_DEBUG_FILE */ |
| vprintf(fmt, ap); |
| printf("\n"); |
| #ifdef CONFIG_DEBUG_FILE |
| } |
| #endif /* CONFIG_DEBUG_FILE */ |
| #ifdef CONFIG_DEBUG_SYSLOG |
| } |
| #endif /* CONFIG_DEBUG_SYSLOG */ |
| } |
| va_end(ap); |
| } |
| |
| |
| static void _wpa_hexdump(int level, const char *title, const u8 *buf, |
| size_t len, int show) |
| { |
| size_t i; |
| if (level < wpa_debug_level) |
| return; |
| wpa_debug_print_timestamp(); |
| #ifdef CONFIG_DEBUG_FILE |
| if (out_file) { |
| fprintf(out_file, "%s - hexdump(len=%lu):", |
| title, (unsigned long) len); |
| if (buf == NULL) { |
| fprintf(out_file, " [NULL]"); |
| } else if (show) { |
| for (i = 0; i < len; i++) |
| fprintf(out_file, " %02x", buf[i]); |
| } else { |
| fprintf(out_file, " [REMOVED]"); |
| } |
| fprintf(out_file, "\n"); |
| } else { |
| #endif /* CONFIG_DEBUG_FILE */ |
| printf("%s - hexdump(len=%lu):", title, (unsigned long) len); |
| if (buf == NULL) { |
| printf(" [NULL]"); |
| } else if (show) { |
| for (i = 0; i < len; i++) |
| printf(" %02x", buf[i]); |
| } else { |
| printf(" [REMOVED]"); |
| } |
| printf("\n"); |
| #ifdef CONFIG_DEBUG_FILE |
| } |
| #endif /* CONFIG_DEBUG_FILE */ |
| } |
| |
| void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) |
| { |
| _wpa_hexdump(level, title, buf, len, 1); |
| } |
| |
| |
| void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) |
| { |
| _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); |
| } |
| |
| |
| static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, |
| size_t len, int show) |
| { |
| size_t i, llen; |
| const u8 *pos = buf; |
| const size_t line_len = 16; |
| |
| if (level < wpa_debug_level) |
| return; |
| wpa_debug_print_timestamp(); |
| #ifdef CONFIG_DEBUG_FILE |
| if (out_file) { |
| if (!show) { |
| fprintf(out_file, |
| "%s - hexdump_ascii(len=%lu): [REMOVED]\n", |
| title, (unsigned long) len); |
| return; |
| } |
| if (buf == NULL) { |
| fprintf(out_file, |
| "%s - hexdump_ascii(len=%lu): [NULL]\n", |
| title, (unsigned long) len); |
| return; |
| } |
| fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n", |
| title, (unsigned long) len); |
| while (len) { |
| llen = len > line_len ? line_len : len; |
| fprintf(out_file, " "); |
| for (i = 0; i < llen; i++) |
| fprintf(out_file, " %02x", pos[i]); |
| for (i = llen; i < line_len; i++) |
| fprintf(out_file, " "); |
| fprintf(out_file, " "); |
| for (i = 0; i < llen; i++) { |
| if (isprint(pos[i])) |
| fprintf(out_file, "%c", pos[i]); |
| else |
| fprintf(out_file, "_"); |
| } |
| for (i = llen; i < line_len; i++) |
| fprintf(out_file, " "); |
| fprintf(out_file, "\n"); |
| pos += llen; |
| len -= llen; |
| } |
| } else { |
| #endif /* CONFIG_DEBUG_FILE */ |
| if (!show) { |
| printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", |
| title, (unsigned long) len); |
| return; |
| } |
| if (buf == NULL) { |
| printf("%s - hexdump_ascii(len=%lu): [NULL]\n", |
| title, (unsigned long) len); |
| return; |
| } |
| printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); |
| while (len) { |
| llen = len > line_len ? line_len : len; |
| printf(" "); |
| for (i = 0; i < llen; i++) |
| printf(" %02x", pos[i]); |
| for (i = llen; i < line_len; i++) |
| printf(" "); |
| printf(" "); |
| for (i = 0; i < llen; i++) { |
| if (isprint(pos[i])) |
| printf("%c", pos[i]); |
| else |
| printf("_"); |
| } |
| for (i = llen; i < line_len; i++) |
| printf(" "); |
| printf("\n"); |
| pos += llen; |
| len -= llen; |
| } |
| #ifdef CONFIG_DEBUG_FILE |
| } |
| #endif /* CONFIG_DEBUG_FILE */ |
| } |
| |
| |
| void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) |
| { |
| _wpa_hexdump_ascii(level, title, buf, len, 1); |
| } |
| |
| |
| void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, |
| size_t len) |
| { |
| _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); |
| } |
| |
| |
| int wpa_debug_open_file(const char *path) |
| { |
| #ifdef CONFIG_DEBUG_FILE |
| if (!path) |
| return 0; |
| out_file = fopen(path, "a"); |
| if (out_file == NULL) { |
| wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " |
| "output file, using standard output"); |
| return -1; |
| } |
| #ifndef _WIN32 |
| setvbuf(out_file, NULL, _IOLBF, 0); |
| #endif /* _WIN32 */ |
| #endif /* CONFIG_DEBUG_FILE */ |
| return 0; |
| } |
| |
| |
| void wpa_debug_close_file(void) |
| { |
| #ifdef CONFIG_DEBUG_FILE |
| if (!out_file) |
| return; |
| fclose(out_file); |
| out_file = NULL; |
| #endif /* CONFIG_DEBUG_FILE */ |
| } |
| |
| #endif /* CONFIG_NO_STDOUT_DEBUG */ |
| |
| |
| #ifndef CONFIG_NO_WPA_MSG |
| static wpa_msg_cb_func wpa_msg_cb = NULL; |
| |
| void wpa_msg_register_cb(wpa_msg_cb_func func) |
| { |
| wpa_msg_cb = func; |
| } |
| |
| |
| void wpa_msg(void *ctx, int level, const char *fmt, ...) |
| { |
| va_list ap; |
| char *buf; |
| const int buflen = 2048; |
| int len; |
| |
| buf = os_malloc(buflen); |
| if (buf == NULL) { |
| wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message " |
| "buffer"); |
| return; |
| } |
| va_start(ap, fmt); |
| len = vsnprintf(buf, buflen, fmt, ap); |
| va_end(ap); |
| wpa_printf(level, "%s", buf); |
| if (wpa_msg_cb) |
| wpa_msg_cb(ctx, level, buf, len); |
| os_free(buf); |
| } |
| |
| |
| void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) |
| { |
| va_list ap; |
| char *buf; |
| const int buflen = 2048; |
| int len; |
| |
| if (!wpa_msg_cb) |
| return; |
| |
| buf = os_malloc(buflen); |
| if (buf == NULL) { |
| wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate " |
| "message buffer"); |
| return; |
| } |
| va_start(ap, fmt); |
| len = vsnprintf(buf, buflen, fmt, ap); |
| va_end(ap); |
| wpa_msg_cb(ctx, level, buf, len); |
| os_free(buf); |
| } |
| #endif /* CONFIG_NO_WPA_MSG */ |
| |
| |
| #ifndef CONFIG_NO_HOSTAPD_LOGGER |
| static hostapd_logger_cb_func hostapd_logger_cb = NULL; |
| |
| void hostapd_logger_register_cb(hostapd_logger_cb_func func) |
| { |
| hostapd_logger_cb = func; |
| } |
| |
| |
| void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, |
| const char *fmt, ...) |
| { |
| va_list ap; |
| char *buf; |
| const int buflen = 2048; |
| int len; |
| |
| buf = os_malloc(buflen); |
| if (buf == NULL) { |
| wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate " |
| "message buffer"); |
| return; |
| } |
| va_start(ap, fmt); |
| len = vsnprintf(buf, buflen, fmt, ap); |
| va_end(ap); |
| if (hostapd_logger_cb) |
| hostapd_logger_cb(ctx, addr, module, level, buf, len); |
| else if (addr) |
| wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", |
| MAC2STR(addr), buf); |
| else |
| wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); |
| os_free(buf); |
| } |
| #endif /* CONFIG_NO_HOSTAPD_LOGGER */ |