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