1 /* 2 * wpa_supplicant/hostapd / Debug prints 3 * Copyright (c) 2002-2007, Jouni Malinen <j (at) 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 22 static int wpa_debug_syslog = 0; 23 #endif /* CONFIG_DEBUG_SYSLOG */ 24 25 26 int wpa_debug_level = MSG_INFO; 27 int wpa_debug_show_keys = 0; 28 int 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 38 39 void 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 62 static FILE *out_file = NULL; 63 #endif /* CONFIG_DEBUG_FILE */ 64 65 66 void 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 89 void wpa_debug_open_syslog(void) 90 { 91 openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD); 92 wpa_debug_syslog++; 93 } 94 95 96 void wpa_debug_close_syslog(void) 97 { 98 if (wpa_debug_syslog) 99 closelog(); 100 } 101 102 103 static 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 */ 132 void 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 163 static 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 200 void 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 206 void 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 212 static 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 297 void 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 303 void 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 311 static char *last_path = NULL; 312 #endif /* CONFIG_DEBUG_FILE */ 313 314 int 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 335 int 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 361 void 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 378 static wpa_msg_cb_func wpa_msg_cb = NULL; 379 380 void wpa_msg_register_cb(wpa_msg_cb_func func) 381 { 382 wpa_msg_cb = func; 383 } 384 385 386 static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL; 387 388 void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func) 389 { 390 wpa_msg_ifname_cb = func; 391 } 392 393 394 void 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 428 void 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 454 static hostapd_logger_cb_func hostapd_logger_cb = NULL; 455 456 void hostapd_logger_register_cb(hostapd_logger_cb_func func) 457 { 458 hostapd_logger_cb = func; 459 } 460 461 462 void 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