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