xref: /freebsd/contrib/wpa/src/utils/wpa_debug.c (revision 6966ac055c3b7a39266fb982493330df7a097997)
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 
16 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 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <fcntl.h>
64 
65 static FILE *out_file = NULL;
66 #endif /* CONFIG_DEBUG_FILE */
67 
68 
69 void wpa_debug_print_timestamp(void)
70 {
71 #ifndef CONFIG_ANDROID_LOG
72 	struct os_time tv;
73 
74 	if (!wpa_debug_timestamp)
75 		return;
76 
77 	os_get_time(&tv);
78 #ifdef CONFIG_DEBUG_FILE
79 	if (out_file) {
80 		fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
81 			(unsigned int) tv.usec);
82 	} else
83 #endif /* CONFIG_DEBUG_FILE */
84 	printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
85 #endif /* CONFIG_ANDROID_LOG */
86 }
87 
88 
89 #ifdef CONFIG_DEBUG_SYSLOG
90 #ifndef LOG_HOSTAPD
91 #define LOG_HOSTAPD LOG_DAEMON
92 #endif /* LOG_HOSTAPD */
93 
94 void wpa_debug_open_syslog(void)
95 {
96 	openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD);
97 	wpa_debug_syslog++;
98 }
99 
100 
101 void wpa_debug_close_syslog(void)
102 {
103 	if (wpa_debug_syslog)
104 		closelog();
105 }
106 
107 
108 static int syslog_priority(int level)
109 {
110 	switch (level) {
111 	case MSG_MSGDUMP:
112 	case MSG_DEBUG:
113 		return LOG_DEBUG;
114 	case MSG_INFO:
115 		return LOG_NOTICE;
116 	case MSG_WARNING:
117 		return LOG_WARNING;
118 	case MSG_ERROR:
119 		return LOG_ERR;
120 	}
121 	return LOG_INFO;
122 }
123 #endif /* CONFIG_DEBUG_SYSLOG */
124 
125 
126 #ifdef CONFIG_DEBUG_LINUX_TRACING
127 
128 int wpa_debug_open_linux_tracing(void)
129 {
130 	int mounts, trace_fd;
131 	char buf[4096] = {};
132 	ssize_t buflen;
133 	char *line, *tmp1, *path = NULL;
134 
135 	mounts = open("/proc/mounts", O_RDONLY);
136 	if (mounts < 0) {
137 		printf("no /proc/mounts\n");
138 		return -1;
139 	}
140 
141 	buflen = read(mounts, buf, sizeof(buf) - 1);
142 	close(mounts);
143 	if (buflen < 0) {
144 		printf("failed to read /proc/mounts\n");
145 		return -1;
146 	}
147 	buf[buflen] = '\0';
148 
149 	line = strtok_r(buf, "\n", &tmp1);
150 	while (line) {
151 		char *tmp2, *tmp_path, *fstype;
152 		/* "<dev> <mountpoint> <fs type> ..." */
153 		strtok_r(line, " ", &tmp2);
154 		tmp_path = strtok_r(NULL, " ", &tmp2);
155 		fstype = strtok_r(NULL, " ", &tmp2);
156 		if (fstype && strcmp(fstype, "debugfs") == 0) {
157 			path = tmp_path;
158 			break;
159 		}
160 
161 		line = strtok_r(NULL, "\n", &tmp1);
162 	}
163 
164 	if (path == NULL) {
165 		printf("debugfs mountpoint not found\n");
166 		return -1;
167 	}
168 
169 	snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path);
170 
171 	trace_fd = open(buf, O_WRONLY);
172 	if (trace_fd < 0) {
173 		printf("failed to open trace_marker file\n");
174 		return -1;
175 	}
176 	wpa_debug_tracing_file = fdopen(trace_fd, "w");
177 	if (wpa_debug_tracing_file == NULL) {
178 		close(trace_fd);
179 		printf("failed to fdopen()\n");
180 		return -1;
181 	}
182 
183 	return 0;
184 }
185 
186 
187 void wpa_debug_close_linux_tracing(void)
188 {
189 	if (wpa_debug_tracing_file == NULL)
190 		return;
191 	fclose(wpa_debug_tracing_file);
192 	wpa_debug_tracing_file = NULL;
193 }
194 
195 #endif /* CONFIG_DEBUG_LINUX_TRACING */
196 
197 
198 /**
199  * wpa_printf - conditional printf
200  * @level: priority level (MSG_*) of the message
201  * @fmt: printf format string, followed by optional arguments
202  *
203  * This function is used to print conditional debugging and error messages. The
204  * output may be directed to stdout, stderr, and/or syslog based on
205  * configuration.
206  *
207  * Note: New line '\n' is added to the end of the text when printing to stdout.
208  */
209 void wpa_printf(int level, const char *fmt, ...)
210 {
211 	va_list ap;
212 
213 	va_start(ap, fmt);
214 	if (level >= wpa_debug_level) {
215 #ifdef CONFIG_ANDROID_LOG
216 		__android_log_vprint(wpa_to_android_level(level),
217 				     ANDROID_LOG_NAME, fmt, ap);
218 #else /* CONFIG_ANDROID_LOG */
219 #ifdef CONFIG_DEBUG_SYSLOG
220 		if (wpa_debug_syslog) {
221 			vsyslog(syslog_priority(level), fmt, ap);
222 		} else {
223 #endif /* CONFIG_DEBUG_SYSLOG */
224 		wpa_debug_print_timestamp();
225 #ifdef CONFIG_DEBUG_FILE
226 		if (out_file) {
227 			vfprintf(out_file, fmt, ap);
228 			fprintf(out_file, "\n");
229 		} else {
230 #endif /* CONFIG_DEBUG_FILE */
231 		vprintf(fmt, ap);
232 		printf("\n");
233 #ifdef CONFIG_DEBUG_FILE
234 		}
235 #endif /* CONFIG_DEBUG_FILE */
236 #ifdef CONFIG_DEBUG_SYSLOG
237 		}
238 #endif /* CONFIG_DEBUG_SYSLOG */
239 #endif /* CONFIG_ANDROID_LOG */
240 	}
241 	va_end(ap);
242 
243 #ifdef CONFIG_DEBUG_LINUX_TRACING
244 	if (wpa_debug_tracing_file != NULL) {
245 		va_start(ap, fmt);
246 		fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level);
247 		vfprintf(wpa_debug_tracing_file, fmt, ap);
248 		fprintf(wpa_debug_tracing_file, "\n");
249 		fflush(wpa_debug_tracing_file);
250 		va_end(ap);
251 	}
252 #endif /* CONFIG_DEBUG_LINUX_TRACING */
253 }
254 
255 
256 static void _wpa_hexdump(int level, const char *title, const u8 *buf,
257 			 size_t len, int show)
258 {
259 	size_t i;
260 
261 #ifdef CONFIG_DEBUG_LINUX_TRACING
262 	if (wpa_debug_tracing_file != NULL) {
263 		fprintf(wpa_debug_tracing_file,
264 			WPAS_TRACE_PFX "%s - hexdump(len=%lu):",
265 			level, title, (unsigned long) len);
266 		if (buf == NULL) {
267 			fprintf(wpa_debug_tracing_file, " [NULL]\n");
268 		} else if (!show) {
269 			fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
270 		} else {
271 			for (i = 0; i < len; i++)
272 				fprintf(wpa_debug_tracing_file,
273 					" %02x", buf[i]);
274 		}
275 		fflush(wpa_debug_tracing_file);
276 	}
277 #endif /* CONFIG_DEBUG_LINUX_TRACING */
278 
279 	if (level < wpa_debug_level)
280 		return;
281 #ifdef CONFIG_ANDROID_LOG
282 	{
283 		const char *display;
284 		char *strbuf = NULL;
285 		size_t slen = len;
286 		if (buf == NULL) {
287 			display = " [NULL]";
288 		} else if (len == 0) {
289 			display = "";
290 		} else if (show && len) {
291 			/* Limit debug message length for Android log */
292 			if (slen > 32)
293 				slen = 32;
294 			strbuf = os_malloc(1 + 3 * slen);
295 			if (strbuf == NULL) {
296 				wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
297 					   "allocate message buffer");
298 				return;
299 			}
300 
301 			for (i = 0; i < slen; i++)
302 				os_snprintf(&strbuf[i * 3], 4, " %02x",
303 					    buf[i]);
304 
305 			display = strbuf;
306 		} else {
307 			display = " [REMOVED]";
308 		}
309 
310 		__android_log_print(wpa_to_android_level(level),
311 				    ANDROID_LOG_NAME,
312 				    "%s - hexdump(len=%lu):%s%s",
313 				    title, (long unsigned int) len, display,
314 				    len > slen ? " ..." : "");
315 		bin_clear_free(strbuf, 1 + 3 * slen);
316 		return;
317 	}
318 #else /* CONFIG_ANDROID_LOG */
319 #ifdef CONFIG_DEBUG_SYSLOG
320 	if (wpa_debug_syslog) {
321 		const char *display;
322 		char *strbuf = NULL;
323 
324 		if (buf == NULL) {
325 			display = " [NULL]";
326 		} else if (len == 0) {
327 			display = "";
328 		} else if (show && len) {
329 			strbuf = os_malloc(1 + 3 * len);
330 			if (strbuf == NULL) {
331 				wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
332 					   "allocate message buffer");
333 				return;
334 			}
335 
336 			for (i = 0; i < len; i++)
337 				os_snprintf(&strbuf[i * 3], 4, " %02x",
338 					    buf[i]);
339 
340 			display = strbuf;
341 		} else {
342 			display = " [REMOVED]";
343 		}
344 
345 		syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
346 		       title, (unsigned long) len, display);
347 		bin_clear_free(strbuf, 1 + 3 * len);
348 		return;
349 	}
350 #endif /* CONFIG_DEBUG_SYSLOG */
351 	wpa_debug_print_timestamp();
352 #ifdef CONFIG_DEBUG_FILE
353 	if (out_file) {
354 		fprintf(out_file, "%s - hexdump(len=%lu):",
355 			title, (unsigned long) len);
356 		if (buf == NULL) {
357 			fprintf(out_file, " [NULL]");
358 		} else if (show) {
359 			for (i = 0; i < len; i++)
360 				fprintf(out_file, " %02x", buf[i]);
361 		} else {
362 			fprintf(out_file, " [REMOVED]");
363 		}
364 		fprintf(out_file, "\n");
365 	} else {
366 #endif /* CONFIG_DEBUG_FILE */
367 	printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
368 	if (buf == NULL) {
369 		printf(" [NULL]");
370 	} else if (show) {
371 		for (i = 0; i < len; i++)
372 			printf(" %02x", buf[i]);
373 	} else {
374 		printf(" [REMOVED]");
375 	}
376 	printf("\n");
377 #ifdef CONFIG_DEBUG_FILE
378 	}
379 #endif /* CONFIG_DEBUG_FILE */
380 #endif /* CONFIG_ANDROID_LOG */
381 }
382 
383 void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
384 {
385 	_wpa_hexdump(level, title, buf, len, 1);
386 }
387 
388 
389 void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
390 {
391 	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
392 }
393 
394 
395 static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
396 			       size_t len, int show)
397 {
398 	size_t i, llen;
399 	const u8 *pos = buf;
400 	const size_t line_len = 16;
401 
402 #ifdef CONFIG_DEBUG_LINUX_TRACING
403 	if (wpa_debug_tracing_file != NULL) {
404 		fprintf(wpa_debug_tracing_file,
405 			WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):",
406 			level, title, (unsigned long) len);
407 		if (buf == NULL) {
408 			fprintf(wpa_debug_tracing_file, " [NULL]\n");
409 		} else if (!show) {
410 			fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
411 		} else {
412 			/* can do ascii processing in userspace */
413 			for (i = 0; i < len; i++)
414 				fprintf(wpa_debug_tracing_file,
415 					" %02x", pos[i]);
416 		}
417 		fflush(wpa_debug_tracing_file);
418 	}
419 #endif /* CONFIG_DEBUG_LINUX_TRACING */
420 
421 	if (level < wpa_debug_level)
422 		return;
423 #ifdef CONFIG_ANDROID_LOG
424 	_wpa_hexdump(level, title, buf, len, show);
425 #else /* CONFIG_ANDROID_LOG */
426 #ifdef CONFIG_DEBUG_SYSLOG
427 	if (wpa_debug_syslog) {
428 		_wpa_hexdump(level, title, buf, len, show);
429 		return;
430 	}
431 #endif /* CONFIG_DEBUG_SYSLOG */
432 	wpa_debug_print_timestamp();
433 #ifdef CONFIG_DEBUG_FILE
434 	if (out_file) {
435 		if (!show) {
436 			fprintf(out_file,
437 				"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
438 				title, (unsigned long) len);
439 			return;
440 		}
441 		if (buf == NULL) {
442 			fprintf(out_file,
443 				"%s - hexdump_ascii(len=%lu): [NULL]\n",
444 				title, (unsigned long) len);
445 			return;
446 		}
447 		fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
448 			title, (unsigned long) len);
449 		while (len) {
450 			llen = len > line_len ? line_len : len;
451 			fprintf(out_file, "    ");
452 			for (i = 0; i < llen; i++)
453 				fprintf(out_file, " %02x", pos[i]);
454 			for (i = llen; i < line_len; i++)
455 				fprintf(out_file, "   ");
456 			fprintf(out_file, "   ");
457 			for (i = 0; i < llen; i++) {
458 				if (isprint(pos[i]))
459 					fprintf(out_file, "%c", pos[i]);
460 				else
461 					fprintf(out_file, "_");
462 			}
463 			for (i = llen; i < line_len; i++)
464 				fprintf(out_file, " ");
465 			fprintf(out_file, "\n");
466 			pos += llen;
467 			len -= llen;
468 		}
469 	} else {
470 #endif /* CONFIG_DEBUG_FILE */
471 	if (!show) {
472 		printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
473 		       title, (unsigned long) len);
474 		return;
475 	}
476 	if (buf == NULL) {
477 		printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
478 		       title, (unsigned long) len);
479 		return;
480 	}
481 	printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
482 	while (len) {
483 		llen = len > line_len ? line_len : len;
484 		printf("    ");
485 		for (i = 0; i < llen; i++)
486 			printf(" %02x", pos[i]);
487 		for (i = llen; i < line_len; i++)
488 			printf("   ");
489 		printf("   ");
490 		for (i = 0; i < llen; i++) {
491 			if (isprint(pos[i]))
492 				printf("%c", pos[i]);
493 			else
494 				printf("_");
495 		}
496 		for (i = llen; i < line_len; i++)
497 			printf(" ");
498 		printf("\n");
499 		pos += llen;
500 		len -= llen;
501 	}
502 #ifdef CONFIG_DEBUG_FILE
503 	}
504 #endif /* CONFIG_DEBUG_FILE */
505 #endif /* CONFIG_ANDROID_LOG */
506 }
507 
508 
509 void wpa_hexdump_ascii(int level, const char *title, const void *buf,
510 		       size_t len)
511 {
512 	_wpa_hexdump_ascii(level, title, buf, len, 1);
513 }
514 
515 
516 void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
517 			   size_t len)
518 {
519 	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
520 }
521 
522 
523 #ifdef CONFIG_DEBUG_FILE
524 static char *last_path = NULL;
525 #endif /* CONFIG_DEBUG_FILE */
526 
527 int wpa_debug_reopen_file(void)
528 {
529 #ifdef CONFIG_DEBUG_FILE
530 	int rv;
531 	char *tmp;
532 
533 	if (!last_path)
534 		return 0; /* logfile not used */
535 
536 	tmp = os_strdup(last_path);
537 	if (!tmp)
538 		return -1;
539 
540 	wpa_debug_close_file();
541 	rv = wpa_debug_open_file(tmp);
542 	os_free(tmp);
543 	return rv;
544 #else /* CONFIG_DEBUG_FILE */
545 	return 0;
546 #endif /* CONFIG_DEBUG_FILE */
547 }
548 
549 
550 int wpa_debug_open_file(const char *path)
551 {
552 #ifdef CONFIG_DEBUG_FILE
553 	int out_fd;
554 
555 	if (!path)
556 		return 0;
557 
558 	if (last_path == NULL || os_strcmp(last_path, path) != 0) {
559 		/* Save our path to enable re-open */
560 		os_free(last_path);
561 		last_path = os_strdup(path);
562 	}
563 
564 	out_fd = open(path, O_CREAT | O_APPEND | O_WRONLY,
565 		      S_IRUSR | S_IWUSR | S_IRGRP);
566 	if (out_fd < 0) {
567 		wpa_printf(MSG_ERROR,
568 			   "%s: Failed to open output file descriptor, using standard output",
569 			   __func__);
570 		return -1;
571 	}
572 
573 #ifdef __linux__
574 	if (fcntl(out_fd, F_SETFD, FD_CLOEXEC) < 0) {
575 		wpa_printf(MSG_DEBUG,
576 			   "%s: Failed to set FD_CLOEXEC - continue without: %s",
577 			   __func__, strerror(errno));
578 	}
579 #endif /* __linux__ */
580 
581 	out_file = fdopen(out_fd, "a");
582 	if (out_file == NULL) {
583 		wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
584 			   "output file, using standard output");
585 		close(out_fd);
586 		return -1;
587 	}
588 #ifndef _WIN32
589 	setvbuf(out_file, NULL, _IOLBF, 0);
590 #endif /* _WIN32 */
591 #else /* CONFIG_DEBUG_FILE */
592 	(void)path;
593 #endif /* CONFIG_DEBUG_FILE */
594 	return 0;
595 }
596 
597 
598 void wpa_debug_close_file(void)
599 {
600 #ifdef CONFIG_DEBUG_FILE
601 	if (!out_file)
602 		return;
603 	fclose(out_file);
604 	out_file = NULL;
605 	os_free(last_path);
606 	last_path = NULL;
607 #endif /* CONFIG_DEBUG_FILE */
608 }
609 
610 
611 void wpa_debug_setup_stdout(void)
612 {
613 #ifndef _WIN32
614 	setvbuf(stdout, NULL, _IOLBF, 0);
615 #endif /* _WIN32 */
616 }
617 
618 #endif /* CONFIG_NO_STDOUT_DEBUG */
619 
620 
621 #ifndef CONFIG_NO_WPA_MSG
622 static wpa_msg_cb_func wpa_msg_cb = NULL;
623 
624 void wpa_msg_register_cb(wpa_msg_cb_func func)
625 {
626 	wpa_msg_cb = func;
627 }
628 
629 
630 static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
631 
632 void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
633 {
634 	wpa_msg_ifname_cb = func;
635 }
636 
637 
638 void wpa_msg(void *ctx, int level, const char *fmt, ...)
639 {
640 	va_list ap;
641 	char *buf;
642 	int buflen;
643 	int len;
644 	char prefix[130];
645 
646 	va_start(ap, fmt);
647 	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
648 	va_end(ap);
649 
650 	buf = os_malloc(buflen);
651 	if (buf == NULL) {
652 		wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
653 			   "buffer");
654 		return;
655 	}
656 	va_start(ap, fmt);
657 	prefix[0] = '\0';
658 	if (wpa_msg_ifname_cb) {
659 		const char *ifname = wpa_msg_ifname_cb(ctx);
660 		if (ifname) {
661 			int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
662 					      ifname);
663 			if (os_snprintf_error(sizeof(prefix), res))
664 				prefix[0] = '\0';
665 		}
666 	}
667 	len = vsnprintf(buf, buflen, fmt, ap);
668 	va_end(ap);
669 	wpa_printf(level, "%s%s", prefix, buf);
670 	if (wpa_msg_cb)
671 		wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
672 	bin_clear_free(buf, buflen);
673 }
674 
675 
676 void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
677 {
678 	va_list ap;
679 	char *buf;
680 	int buflen;
681 	int len;
682 
683 	if (!wpa_msg_cb)
684 		return;
685 
686 	va_start(ap, fmt);
687 	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
688 	va_end(ap);
689 
690 	buf = os_malloc(buflen);
691 	if (buf == NULL) {
692 		wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
693 			   "message buffer");
694 		return;
695 	}
696 	va_start(ap, fmt);
697 	len = vsnprintf(buf, buflen, fmt, ap);
698 	va_end(ap);
699 	wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
700 	bin_clear_free(buf, buflen);
701 }
702 
703 
704 void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
705 {
706 	va_list ap;
707 	char *buf;
708 	int buflen;
709 	int len;
710 
711 	va_start(ap, fmt);
712 	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
713 	va_end(ap);
714 
715 	buf = os_malloc(buflen);
716 	if (buf == NULL) {
717 		wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate "
718 			   "message buffer");
719 		return;
720 	}
721 	va_start(ap, fmt);
722 	len = vsnprintf(buf, buflen, fmt, ap);
723 	va_end(ap);
724 	wpa_printf(level, "%s", buf);
725 	if (wpa_msg_cb)
726 		wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
727 	bin_clear_free(buf, buflen);
728 }
729 
730 
731 void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
732 {
733 	va_list ap;
734 	char *buf;
735 	int buflen;
736 	int len;
737 
738 	if (!wpa_msg_cb)
739 		return;
740 
741 	va_start(ap, fmt);
742 	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
743 	va_end(ap);
744 
745 	buf = os_malloc(buflen);
746 	if (buf == NULL) {
747 		wpa_printf(MSG_ERROR,
748 			   "wpa_msg_global_ctrl: Failed to allocate message buffer");
749 		return;
750 	}
751 	va_start(ap, fmt);
752 	len = vsnprintf(buf, buflen, fmt, ap);
753 	va_end(ap);
754 	wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
755 	bin_clear_free(buf, buflen);
756 }
757 
758 
759 void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
760 {
761 	va_list ap;
762 	char *buf;
763 	int buflen;
764 	int len;
765 
766 	va_start(ap, fmt);
767 	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
768 	va_end(ap);
769 
770 	buf = os_malloc(buflen);
771 	if (buf == NULL) {
772 		wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate "
773 			   "message buffer");
774 		return;
775 	}
776 	va_start(ap, fmt);
777 	len = vsnprintf(buf, buflen, fmt, ap);
778 	va_end(ap);
779 	wpa_printf(level, "%s", buf);
780 	if (wpa_msg_cb)
781 		wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len);
782 	bin_clear_free(buf, buflen);
783 }
784 
785 
786 void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
787 {
788 	va_list ap;
789 	char *buf;
790 	int buflen;
791 	int len;
792 
793 	va_start(ap, fmt);
794 	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
795 	va_end(ap);
796 
797 	buf = os_malloc(buflen);
798 	if (buf == NULL) {
799 		wpa_printf(MSG_ERROR, "%s: Failed to allocate message buffer",
800 			   __func__);
801 		return;
802 	}
803 	va_start(ap, fmt);
804 	len = vsnprintf(buf, buflen, fmt, ap);
805 	va_end(ap);
806 	wpa_printf(level, "%s", buf);
807 	if (wpa_msg_cb)
808 		wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len);
809 	os_free(buf);
810 }
811 
812 #endif /* CONFIG_NO_WPA_MSG */
813 
814 
815 #ifndef CONFIG_NO_HOSTAPD_LOGGER
816 static hostapd_logger_cb_func hostapd_logger_cb = NULL;
817 
818 void hostapd_logger_register_cb(hostapd_logger_cb_func func)
819 {
820 	hostapd_logger_cb = func;
821 }
822 
823 
824 void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
825 		    const char *fmt, ...)
826 {
827 	va_list ap;
828 	char *buf;
829 	int buflen;
830 	int len;
831 
832 	va_start(ap, fmt);
833 	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
834 	va_end(ap);
835 
836 	buf = os_malloc(buflen);
837 	if (buf == NULL) {
838 		wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
839 			   "message buffer");
840 		return;
841 	}
842 	va_start(ap, fmt);
843 	len = vsnprintf(buf, buflen, fmt, ap);
844 	va_end(ap);
845 	if (hostapd_logger_cb)
846 		hostapd_logger_cb(ctx, addr, module, level, buf, len);
847 	else if (addr)
848 		wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s",
849 			   MAC2STR(addr), buf);
850 	else
851 		wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
852 	bin_clear_free(buf, buflen);
853 }
854 #endif /* CONFIG_NO_HOSTAPD_LOGGER */
855 
856 
857 const char * debug_level_str(int level)
858 {
859 	switch (level) {
860 	case MSG_EXCESSIVE:
861 		return "EXCESSIVE";
862 	case MSG_MSGDUMP:
863 		return "MSGDUMP";
864 	case MSG_DEBUG:
865 		return "DEBUG";
866 	case MSG_INFO:
867 		return "INFO";
868 	case MSG_WARNING:
869 		return "WARNING";
870 	case MSG_ERROR:
871 		return "ERROR";
872 	default:
873 		return "?";
874 	}
875 }
876 
877 
878 int str_to_debug_level(const char *s)
879 {
880 	if (os_strcasecmp(s, "EXCESSIVE") == 0)
881 		return MSG_EXCESSIVE;
882 	if (os_strcasecmp(s, "MSGDUMP") == 0)
883 		return MSG_MSGDUMP;
884 	if (os_strcasecmp(s, "DEBUG") == 0)
885 		return MSG_DEBUG;
886 	if (os_strcasecmp(s, "INFO") == 0)
887 		return MSG_INFO;
888 	if (os_strcasecmp(s, "WARNING") == 0)
889 		return MSG_WARNING;
890 	if (os_strcasecmp(s, "ERROR") == 0)
891 		return MSG_ERROR;
892 	return -1;
893 }
894