1 /* 2 * wpa_supplicant/hostapd / Debug prints 3 * Copyright (c) 2002-2007, Jouni Malinen <j (at) 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 #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 26 static FILE *wpa_debug_tracing_file = NULL; 27 28 #define WPAS_TRACE_PFX "wpas <%d>: " 29 #endif /* CONFIG_DEBUG_LINUX_TRACING */ 30 31 32 int wpa_debug_level = MSG_INFO; 33 int wpa_debug_show_keys = 0; 34 int 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 45 static 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 61 static FILE *out_file = NULL; 62 #endif /* CONFIG_DEBUG_FILE */ 63 64 65 void 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 90 void wpa_debug_open_syslog(void) 91 { 92 openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD); 93 wpa_debug_syslog++; 94 } 95 96 97 void wpa_debug_close_syslog(void) 98 { 99 if (wpa_debug_syslog) 100 closelog(); 101 } 102 103 104 static 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 124 int 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 182 void 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 */ 204 void 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 251 static 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 378 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) 379 { 380 _wpa_hexdump(level, title, buf, len, 1); 381 } 382 383 384 void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) 385 { 386 _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); 387 } 388 389 390 static void _wpa_hexdump_ascii(int level, const char *title, const u8 *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", buf[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 498 void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) 499 { 500 _wpa_hexdump_ascii(level, title, buf, len, 1); 501 } 502 503 504 void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, 505 size_t len) 506 { 507 _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); 508 } 509 510 511 #ifdef CONFIG_DEBUG_FILE 512 static char *last_path = NULL; 513 #endif /* CONFIG_DEBUG_FILE */ 514 515 int wpa_debug_reopen_file(void) 516 { 517 #ifdef CONFIG_DEBUG_FILE 518 int rv; 519 if (last_path) { 520 char *tmp = os_strdup(last_path); 521 wpa_debug_close_file(); 522 rv = wpa_debug_open_file(tmp); 523 os_free(tmp); 524 } else { 525 wpa_printf(MSG_ERROR, "Last-path was not set, cannot " 526 "re-open log file."); 527 rv = -1; 528 } 529 return rv; 530 #else /* CONFIG_DEBUG_FILE */ 531 return 0; 532 #endif /* CONFIG_DEBUG_FILE */ 533 } 534 535 536 int wpa_debug_open_file(const char *path) 537 { 538 #ifdef CONFIG_DEBUG_FILE 539 if (!path) 540 return 0; 541 542 if (last_path == NULL || os_strcmp(last_path, path) != 0) { 543 /* Save our path to enable re-open */ 544 os_free(last_path); 545 last_path = os_strdup(path); 546 } 547 548 out_file = fopen(path, "a"); 549 if (out_file == NULL) { 550 wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " 551 "output file, using standard output"); 552 return -1; 553 } 554 #ifndef _WIN32 555 setvbuf(out_file, NULL, _IOLBF, 0); 556 #endif /* _WIN32 */ 557 #endif /* CONFIG_DEBUG_FILE */ 558 return 0; 559 } 560 561 562 void wpa_debug_close_file(void) 563 { 564 #ifdef CONFIG_DEBUG_FILE 565 if (!out_file) 566 return; 567 fclose(out_file); 568 out_file = NULL; 569 os_free(last_path); 570 last_path = NULL; 571 #endif /* CONFIG_DEBUG_FILE */ 572 } 573 574 #endif /* CONFIG_NO_STDOUT_DEBUG */ 575 576 577 #ifndef CONFIG_NO_WPA_MSG 578 static wpa_msg_cb_func wpa_msg_cb = NULL; 579 580 void wpa_msg_register_cb(wpa_msg_cb_func func) 581 { 582 wpa_msg_cb = func; 583 } 584 585 586 static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL; 587 588 void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func) 589 { 590 wpa_msg_ifname_cb = func; 591 } 592 593 594 void wpa_msg(void *ctx, int level, const char *fmt, ...) 595 { 596 va_list ap; 597 char *buf; 598 const int buflen = 2048; 599 int len; 600 char prefix[130]; 601 602 buf = os_malloc(buflen); 603 if (buf == NULL) { 604 wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message " 605 "buffer"); 606 return; 607 } 608 va_start(ap, fmt); 609 prefix[0] = '\0'; 610 if (wpa_msg_ifname_cb) { 611 const char *ifname = wpa_msg_ifname_cb(ctx); 612 if (ifname) { 613 int res = os_snprintf(prefix, sizeof(prefix), "%s: ", 614 ifname); 615 if (res < 0 || res >= (int) sizeof(prefix)) 616 prefix[0] = '\0'; 617 } 618 } 619 len = vsnprintf(buf, buflen, fmt, ap); 620 va_end(ap); 621 wpa_printf(level, "%s%s", prefix, buf); 622 if (wpa_msg_cb) 623 wpa_msg_cb(ctx, level, buf, len); 624 os_free(buf); 625 } 626 627 628 void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) 629 { 630 va_list ap; 631 char *buf; 632 const int buflen = 2048; 633 int len; 634 635 if (!wpa_msg_cb) 636 return; 637 638 buf = os_malloc(buflen); 639 if (buf == NULL) { 640 wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate " 641 "message buffer"); 642 return; 643 } 644 va_start(ap, fmt); 645 len = vsnprintf(buf, buflen, fmt, ap); 646 va_end(ap); 647 wpa_msg_cb(ctx, level, buf, len); 648 os_free(buf); 649 } 650 #endif /* CONFIG_NO_WPA_MSG */ 651 652 653 #ifndef CONFIG_NO_HOSTAPD_LOGGER 654 static hostapd_logger_cb_func hostapd_logger_cb = NULL; 655 656 void hostapd_logger_register_cb(hostapd_logger_cb_func func) 657 { 658 hostapd_logger_cb = func; 659 } 660 661 662 void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, 663 const char *fmt, ...) 664 { 665 va_list ap; 666 char *buf; 667 const int buflen = 2048; 668 int len; 669 670 buf = os_malloc(buflen); 671 if (buf == NULL) { 672 wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate " 673 "message buffer"); 674 return; 675 } 676 va_start(ap, fmt); 677 len = vsnprintf(buf, buflen, fmt, ap); 678 va_end(ap); 679 if (hostapd_logger_cb) 680 hostapd_logger_cb(ctx, addr, module, level, buf, len); 681 else if (addr) 682 wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", 683 MAC2STR(addr), buf); 684 else 685 wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); 686 os_free(buf); 687 } 688 #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 689