wpa_debug.c revision fb79edc9df1f20461e90e478363d207348213d35
1/* 2 * wpa_supplicant/hostapd / Debug prints 3 * Copyright (c) 2002-2013, 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 16static int wpa_debug_syslog = 0; 17#endif /* CONFIG_DEBUG_SYSLOG */ 18 19#ifdef CONFIG_DEBUG_LINUX_TRACING 20#include <sys/types.h> 21#include <sys/stat.h> 22#include <fcntl.h> 23#include <string.h> 24#include <stdio.h> 25 26static FILE *wpa_debug_tracing_file = NULL; 27 28#define WPAS_TRACE_PFX "wpas <%d>: " 29#endif /* CONFIG_DEBUG_LINUX_TRACING */ 30 31 32int wpa_debug_level = MSG_INFO; 33int wpa_debug_show_keys = 0; 34int wpa_debug_timestamp = 0; 35 36 37#ifdef CONFIG_ANDROID_LOG 38 39#include <android/log.h> 40 41#ifndef ANDROID_LOG_NAME 42#define ANDROID_LOG_NAME "wpa_supplicant" 43#endif /* ANDROID_LOG_NAME */ 44 45static int wpa_to_android_level(int level) 46{ 47 if (level == MSG_ERROR) 48 return ANDROID_LOG_ERROR; 49 if (level == MSG_WARNING) 50 return ANDROID_LOG_WARN; 51 if (level == MSG_INFO) 52 return ANDROID_LOG_INFO; 53 return ANDROID_LOG_DEBUG; 54} 55 56#endif /* CONFIG_ANDROID_LOG */ 57 58#ifndef CONFIG_NO_STDOUT_DEBUG 59 60#ifdef CONFIG_DEBUG_FILE 61static FILE *out_file = NULL; 62#endif /* CONFIG_DEBUG_FILE */ 63 64 65void wpa_debug_print_timestamp(void) 66{ 67#ifndef CONFIG_ANDROID_LOG 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#endif /* CONFIG_ANDROID_LOG */ 82} 83 84 85#ifdef CONFIG_DEBUG_SYSLOG 86#ifndef LOG_HOSTAPD 87#define LOG_HOSTAPD LOG_DAEMON 88#endif /* LOG_HOSTAPD */ 89 90void wpa_debug_open_syslog(void) 91{ 92 openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD); 93 wpa_debug_syslog++; 94} 95 96 97void wpa_debug_close_syslog(void) 98{ 99 if (wpa_debug_syslog) 100 closelog(); 101} 102 103 104static int syslog_priority(int level) 105{ 106 switch (level) { 107 case MSG_MSGDUMP: 108 case MSG_DEBUG: 109 return LOG_DEBUG; 110 case MSG_INFO: 111 return LOG_NOTICE; 112 case MSG_WARNING: 113 return LOG_WARNING; 114 case MSG_ERROR: 115 return LOG_ERR; 116 } 117 return LOG_INFO; 118} 119#endif /* CONFIG_DEBUG_SYSLOG */ 120 121 122#ifdef CONFIG_DEBUG_LINUX_TRACING 123 124int wpa_debug_open_linux_tracing(void) 125{ 126 int mounts, trace_fd; 127 char buf[4096] = {}; 128 ssize_t buflen; 129 char *line, *tmp1, *path = NULL; 130 131 mounts = open("/proc/mounts", O_RDONLY); 132 if (mounts < 0) { 133 printf("no /proc/mounts\n"); 134 return -1; 135 } 136 137 buflen = read(mounts, buf, sizeof(buf) - 1); 138 close(mounts); 139 if (buflen < 0) { 140 printf("failed to read /proc/mounts\n"); 141 return -1; 142 } 143 144 line = strtok_r(buf, "\n", &tmp1); 145 while (line) { 146 char *tmp2, *tmp_path, *fstype; 147 /* "<dev> <mountpoint> <fs type> ..." */ 148 strtok_r(line, " ", &tmp2); 149 tmp_path = strtok_r(NULL, " ", &tmp2); 150 fstype = strtok_r(NULL, " ", &tmp2); 151 if (strcmp(fstype, "debugfs") == 0) { 152 path = tmp_path; 153 break; 154 } 155 156 line = strtok_r(NULL, "\n", &tmp1); 157 } 158 159 if (path == NULL) { 160 printf("debugfs mountpoint not found\n"); 161 return -1; 162 } 163 164 snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path); 165 166 trace_fd = open(buf, O_WRONLY); 167 if (trace_fd < 0) { 168 printf("failed to open trace_marker file\n"); 169 return -1; 170 } 171 wpa_debug_tracing_file = fdopen(trace_fd, "w"); 172 if (wpa_debug_tracing_file == NULL) { 173 close(trace_fd); 174 printf("failed to fdopen()\n"); 175 return -1; 176 } 177 178 return 0; 179} 180 181 182void wpa_debug_close_linux_tracing(void) 183{ 184 if (wpa_debug_tracing_file == NULL) 185 return; 186 fclose(wpa_debug_tracing_file); 187 wpa_debug_tracing_file = NULL; 188} 189 190#endif /* CONFIG_DEBUG_LINUX_TRACING */ 191 192 193/** 194 * wpa_printf - conditional printf 195 * @level: priority level (MSG_*) of the message 196 * @fmt: printf format string, followed by optional arguments 197 * 198 * This function is used to print conditional debugging and error messages. The 199 * output may be directed to stdout, stderr, and/or syslog based on 200 * configuration. 201 * 202 * Note: New line '\n' is added to the end of the text when printing to stdout. 203 */ 204void wpa_printf(int level, const char *fmt, ...) 205{ 206 va_list ap; 207 208 va_start(ap, fmt); 209 if (level >= wpa_debug_level) { 210#ifdef CONFIG_ANDROID_LOG 211 __android_log_vprint(wpa_to_android_level(level), 212 ANDROID_LOG_NAME, fmt, ap); 213#else /* CONFIG_ANDROID_LOG */ 214#ifdef CONFIG_DEBUG_SYSLOG 215 if (wpa_debug_syslog) { 216 vsyslog(syslog_priority(level), fmt, ap); 217 } else { 218#endif /* CONFIG_DEBUG_SYSLOG */ 219 wpa_debug_print_timestamp(); 220#ifdef CONFIG_DEBUG_FILE 221 if (out_file) { 222 vfprintf(out_file, fmt, ap); 223 fprintf(out_file, "\n"); 224 } else { 225#endif /* CONFIG_DEBUG_FILE */ 226 vprintf(fmt, ap); 227 printf("\n"); 228#ifdef CONFIG_DEBUG_FILE 229 } 230#endif /* CONFIG_DEBUG_FILE */ 231#ifdef CONFIG_DEBUG_SYSLOG 232 } 233#endif /* CONFIG_DEBUG_SYSLOG */ 234#endif /* CONFIG_ANDROID_LOG */ 235 } 236 va_end(ap); 237 238#ifdef CONFIG_DEBUG_LINUX_TRACING 239 if (wpa_debug_tracing_file != NULL) { 240 va_start(ap, fmt); 241 fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level); 242 vfprintf(wpa_debug_tracing_file, fmt, ap); 243 fprintf(wpa_debug_tracing_file, "\n"); 244 fflush(wpa_debug_tracing_file); 245 va_end(ap); 246 } 247#endif /* CONFIG_DEBUG_LINUX_TRACING */ 248} 249 250 251static void _wpa_hexdump(int level, const char *title, const u8 *buf, 252 size_t len, int show) 253{ 254 size_t i; 255 256#ifdef CONFIG_DEBUG_LINUX_TRACING 257 if (wpa_debug_tracing_file != NULL) { 258 fprintf(wpa_debug_tracing_file, 259 WPAS_TRACE_PFX "%s - hexdump(len=%lu):", 260 level, title, (unsigned long) len); 261 if (buf == NULL) { 262 fprintf(wpa_debug_tracing_file, " [NULL]\n"); 263 } else if (!show) { 264 fprintf(wpa_debug_tracing_file, " [REMOVED]\n"); 265 } else { 266 for (i = 0; i < len; i++) 267 fprintf(wpa_debug_tracing_file, 268 " %02x", buf[i]); 269 } 270 fflush(wpa_debug_tracing_file); 271 } 272#endif /* CONFIG_DEBUG_LINUX_TRACING */ 273 274 if (level < wpa_debug_level) 275 return; 276#ifdef CONFIG_ANDROID_LOG 277 { 278 const char *display; 279 char *strbuf = NULL; 280 size_t slen = len; 281 if (buf == NULL) { 282 display = " [NULL]"; 283 } else if (len == 0) { 284 display = ""; 285 } else if (show && len) { 286 /* Limit debug message length for Android log */ 287 if (slen > 32) 288 slen = 32; 289 strbuf = os_malloc(1 + 3 * slen); 290 if (strbuf == NULL) { 291 wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to " 292 "allocate message buffer"); 293 return; 294 } 295 296 for (i = 0; i < slen; i++) 297 os_snprintf(&strbuf[i * 3], 4, " %02x", 298 buf[i]); 299 300 display = strbuf; 301 } else { 302 display = " [REMOVED]"; 303 } 304 305 __android_log_print(wpa_to_android_level(level), 306 ANDROID_LOG_NAME, 307 "%s - hexdump(len=%lu):%s%s", 308 title, (long unsigned int) len, display, 309 len > slen ? " ..." : ""); 310 os_free(strbuf); 311 return; 312 } 313#else /* CONFIG_ANDROID_LOG */ 314#ifdef CONFIG_DEBUG_SYSLOG 315 if (wpa_debug_syslog) { 316 const char *display; 317 char *strbuf = NULL; 318 319 if (buf == NULL) { 320 display = " [NULL]"; 321 } else if (len == 0) { 322 display = ""; 323 } else if (show && len) { 324 strbuf = os_malloc(1 + 3 * len); 325 if (strbuf == NULL) { 326 wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to " 327 "allocate message buffer"); 328 return; 329 } 330 331 for (i = 0; i < len; i++) 332 os_snprintf(&strbuf[i * 3], 4, " %02x", 333 buf[i]); 334 335 display = strbuf; 336 } else { 337 display = " [REMOVED]"; 338 } 339 340 syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s", 341 title, (unsigned long) len, display); 342 os_free(strbuf); 343 return; 344 } 345#endif /* CONFIG_DEBUG_SYSLOG */ 346 wpa_debug_print_timestamp(); 347#ifdef CONFIG_DEBUG_FILE 348 if (out_file) { 349 fprintf(out_file, "%s - hexdump(len=%lu):", 350 title, (unsigned long) len); 351 if (buf == NULL) { 352 fprintf(out_file, " [NULL]"); 353 } else if (show) { 354 for (i = 0; i < len; i++) 355 fprintf(out_file, " %02x", buf[i]); 356 } else { 357 fprintf(out_file, " [REMOVED]"); 358 } 359 fprintf(out_file, "\n"); 360 } else { 361#endif /* CONFIG_DEBUG_FILE */ 362 printf("%s - hexdump(len=%lu):", title, (unsigned long) len); 363 if (buf == NULL) { 364 printf(" [NULL]"); 365 } else if (show) { 366 for (i = 0; i < len; i++) 367 printf(" %02x", buf[i]); 368 } else { 369 printf(" [REMOVED]"); 370 } 371 printf("\n"); 372#ifdef CONFIG_DEBUG_FILE 373 } 374#endif /* CONFIG_DEBUG_FILE */ 375#endif /* CONFIG_ANDROID_LOG */ 376} 377 378void wpa_hexdump(int level, const char *title, const void *buf, size_t len) 379{ 380 _wpa_hexdump(level, title, buf, len, 1); 381} 382 383 384void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len) 385{ 386 _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); 387} 388 389 390static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, 391 size_t len, int show) 392{ 393 size_t i, llen; 394 const u8 *pos = buf; 395 const size_t line_len = 16; 396 397#ifdef CONFIG_DEBUG_LINUX_TRACING 398 if (wpa_debug_tracing_file != NULL) { 399 fprintf(wpa_debug_tracing_file, 400 WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):", 401 level, title, (unsigned long) len); 402 if (buf == NULL) { 403 fprintf(wpa_debug_tracing_file, " [NULL]\n"); 404 } else if (!show) { 405 fprintf(wpa_debug_tracing_file, " [REMOVED]\n"); 406 } else { 407 /* can do ascii processing in userspace */ 408 for (i = 0; i < len; i++) 409 fprintf(wpa_debug_tracing_file, 410 " %02x", pos[i]); 411 } 412 fflush(wpa_debug_tracing_file); 413 } 414#endif /* CONFIG_DEBUG_LINUX_TRACING */ 415 416 if (level < wpa_debug_level) 417 return; 418#ifdef CONFIG_ANDROID_LOG 419 _wpa_hexdump(level, title, buf, len, show); 420#else /* CONFIG_ANDROID_LOG */ 421 wpa_debug_print_timestamp(); 422#ifdef CONFIG_DEBUG_FILE 423 if (out_file) { 424 if (!show) { 425 fprintf(out_file, 426 "%s - hexdump_ascii(len=%lu): [REMOVED]\n", 427 title, (unsigned long) len); 428 return; 429 } 430 if (buf == NULL) { 431 fprintf(out_file, 432 "%s - hexdump_ascii(len=%lu): [NULL]\n", 433 title, (unsigned long) len); 434 return; 435 } 436 fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n", 437 title, (unsigned long) len); 438 while (len) { 439 llen = len > line_len ? line_len : len; 440 fprintf(out_file, " "); 441 for (i = 0; i < llen; i++) 442 fprintf(out_file, " %02x", pos[i]); 443 for (i = llen; i < line_len; i++) 444 fprintf(out_file, " "); 445 fprintf(out_file, " "); 446 for (i = 0; i < llen; i++) { 447 if (isprint(pos[i])) 448 fprintf(out_file, "%c", pos[i]); 449 else 450 fprintf(out_file, "_"); 451 } 452 for (i = llen; i < line_len; i++) 453 fprintf(out_file, " "); 454 fprintf(out_file, "\n"); 455 pos += llen; 456 len -= llen; 457 } 458 } else { 459#endif /* CONFIG_DEBUG_FILE */ 460 if (!show) { 461 printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", 462 title, (unsigned long) len); 463 return; 464 } 465 if (buf == NULL) { 466 printf("%s - hexdump_ascii(len=%lu): [NULL]\n", 467 title, (unsigned long) len); 468 return; 469 } 470 printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); 471 while (len) { 472 llen = len > line_len ? line_len : len; 473 printf(" "); 474 for (i = 0; i < llen; i++) 475 printf(" %02x", pos[i]); 476 for (i = llen; i < line_len; i++) 477 printf(" "); 478 printf(" "); 479 for (i = 0; i < llen; i++) { 480 if (isprint(pos[i])) 481 printf("%c", pos[i]); 482 else 483 printf("_"); 484 } 485 for (i = llen; i < line_len; i++) 486 printf(" "); 487 printf("\n"); 488 pos += llen; 489 len -= llen; 490 } 491#ifdef CONFIG_DEBUG_FILE 492 } 493#endif /* CONFIG_DEBUG_FILE */ 494#endif /* CONFIG_ANDROID_LOG */ 495} 496 497 498void wpa_hexdump_ascii(int level, const char *title, const void *buf, 499 size_t len) 500{ 501 _wpa_hexdump_ascii(level, title, buf, len, 1); 502} 503 504 505void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, 506 size_t len) 507{ 508 _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); 509} 510 511 512#ifdef CONFIG_DEBUG_FILE 513static char *last_path = NULL; 514#endif /* CONFIG_DEBUG_FILE */ 515 516int wpa_debug_reopen_file(void) 517{ 518#ifdef CONFIG_DEBUG_FILE 519 int rv; 520 if (last_path) { 521 char *tmp = os_strdup(last_path); 522 wpa_debug_close_file(); 523 rv = wpa_debug_open_file(tmp); 524 os_free(tmp); 525 } else { 526 wpa_printf(MSG_ERROR, "Last-path was not set, cannot " 527 "re-open log file."); 528 rv = -1; 529 } 530 return rv; 531#else /* CONFIG_DEBUG_FILE */ 532 return 0; 533#endif /* CONFIG_DEBUG_FILE */ 534} 535 536 537int wpa_debug_open_file(const char *path) 538{ 539#ifdef CONFIG_DEBUG_FILE 540 if (!path) 541 return 0; 542 543 if (last_path == NULL || os_strcmp(last_path, path) != 0) { 544 /* Save our path to enable re-open */ 545 os_free(last_path); 546 last_path = os_strdup(path); 547 } 548 549 out_file = fopen(path, "a"); 550 if (out_file == NULL) { 551 wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " 552 "output file, using standard output"); 553 return -1; 554 } 555#ifndef _WIN32 556 setvbuf(out_file, NULL, _IOLBF, 0); 557#endif /* _WIN32 */ 558#endif /* CONFIG_DEBUG_FILE */ 559 return 0; 560} 561 562 563void wpa_debug_close_file(void) 564{ 565#ifdef CONFIG_DEBUG_FILE 566 if (!out_file) 567 return; 568 fclose(out_file); 569 out_file = NULL; 570 os_free(last_path); 571 last_path = NULL; 572#endif /* CONFIG_DEBUG_FILE */ 573} 574 575#endif /* CONFIG_NO_STDOUT_DEBUG */ 576 577 578#ifndef CONFIG_NO_WPA_MSG 579static wpa_msg_cb_func wpa_msg_cb = NULL; 580 581void wpa_msg_register_cb(wpa_msg_cb_func func) 582{ 583 wpa_msg_cb = func; 584} 585 586 587static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL; 588 589void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func) 590{ 591 wpa_msg_ifname_cb = func; 592} 593 594 595void wpa_msg(void *ctx, int level, const char *fmt, ...) 596{ 597 va_list ap; 598 char *buf; 599 const int buflen = 2048; 600 int len; 601 char prefix[130]; 602 603 buf = os_malloc(buflen); 604 if (buf == NULL) { 605 wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message " 606 "buffer"); 607 return; 608 } 609 va_start(ap, fmt); 610 prefix[0] = '\0'; 611 if (wpa_msg_ifname_cb) { 612 const char *ifname = wpa_msg_ifname_cb(ctx); 613 if (ifname) { 614 int res = os_snprintf(prefix, sizeof(prefix), "%s: ", 615 ifname); 616 if (res < 0 || res >= (int) sizeof(prefix)) 617 prefix[0] = '\0'; 618 } 619 } 620 len = vsnprintf(buf, buflen, fmt, ap); 621 va_end(ap); 622 wpa_printf(level, "%s%s", prefix, buf); 623 if (wpa_msg_cb) 624 wpa_msg_cb(ctx, level, 0, buf, len); 625 os_free(buf); 626} 627 628 629void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) 630{ 631 va_list ap; 632 char *buf; 633 const int buflen = 2048; 634 int len; 635 636 if (!wpa_msg_cb) 637 return; 638 639 buf = os_malloc(buflen); 640 if (buf == NULL) { 641 wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate " 642 "message buffer"); 643 return; 644 } 645 va_start(ap, fmt); 646 len = vsnprintf(buf, buflen, fmt, ap); 647 va_end(ap); 648 wpa_msg_cb(ctx, level, 0, buf, len); 649 os_free(buf); 650} 651 652 653void wpa_msg_global(void *ctx, int level, const char *fmt, ...) 654{ 655 va_list ap; 656 char *buf; 657 const int buflen = 2048; 658 int len; 659 660 buf = os_malloc(buflen); 661 if (buf == NULL) { 662 wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate " 663 "message buffer"); 664 return; 665 } 666 va_start(ap, fmt); 667 len = vsnprintf(buf, buflen, fmt, ap); 668 va_end(ap); 669 wpa_printf(level, "%s", buf); 670 if (wpa_msg_cb) 671 wpa_msg_cb(ctx, level, 1, buf, len); 672 os_free(buf); 673} 674 675 676void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) 677{ 678 va_list ap; 679 char *buf; 680 const int buflen = 2048; 681 int len; 682 683 buf = os_malloc(buflen); 684 if (buf == NULL) { 685 wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate " 686 "message buffer"); 687 return; 688 } 689 va_start(ap, fmt); 690 len = vsnprintf(buf, buflen, fmt, ap); 691 va_end(ap); 692 wpa_printf(level, "%s", buf); 693 if (wpa_msg_cb) 694 wpa_msg_cb(ctx, level, 2, buf, len); 695 os_free(buf); 696} 697 698#endif /* CONFIG_NO_WPA_MSG */ 699 700 701#ifndef CONFIG_NO_HOSTAPD_LOGGER 702static hostapd_logger_cb_func hostapd_logger_cb = NULL; 703 704void hostapd_logger_register_cb(hostapd_logger_cb_func func) 705{ 706 hostapd_logger_cb = func; 707} 708 709 710void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, 711 const char *fmt, ...) 712{ 713 va_list ap; 714 char *buf; 715 const int buflen = 2048; 716 int len; 717 718 buf = os_malloc(buflen); 719 if (buf == NULL) { 720 wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate " 721 "message buffer"); 722 return; 723 } 724 va_start(ap, fmt); 725 len = vsnprintf(buf, buflen, fmt, ap); 726 va_end(ap); 727 if (hostapd_logger_cb) 728 hostapd_logger_cb(ctx, addr, module, level, buf, len); 729 else if (addr) 730 wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", 731 MAC2STR(addr), buf); 732 else 733 wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); 734 os_free(buf); 735} 736#endif /* CONFIG_NO_HOSTAPD_LOGGER */ 737