xref: /netbsd-src/external/bsd/wpa/dist/src/utils/wpa_debug.c (revision ba65fde2d7fefa7d39838fa5fa855e62bd606b5e)
1 /*
2  * wpa_supplicant/hostapd / Debug prints
3  * Copyright (c) 2002-2007, Jouni Malinen <j@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 /* ANDROID_LOG_NAME */
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 #ifdef CONFIG_DEBUG_SYSLOG
170 	if (wpa_debug_syslog) {
171 		const char *display;
172 		char *strbuf = NULL;
173 
174 		if (buf == NULL) {
175 			display = " [NULL]";
176 		} else if (len == 0) {
177 			display = "";
178 		} else if (show && len) {
179 			strbuf = os_malloc(1 + 3 * len);
180 			if (strbuf == NULL) {
181 				wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
182 					   "allocate message buffer");
183 				return;
184 			}
185 
186 			for (i = 0; i < len; i++)
187 				os_snprintf(&strbuf[i * 3], 4, " %02x",
188 					    buf[i]);
189 
190 			display = strbuf;
191 		} else {
192 			display = " [REMOVED]";
193 		}
194 
195 		syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
196 		       title, len, display);
197 		os_free(strbuf);
198 		return;
199 	}
200 #endif /* CONFIG_DEBUG_SYSLOG */
201 	wpa_debug_print_timestamp();
202 #ifdef CONFIG_DEBUG_FILE
203 	if (out_file) {
204 		fprintf(out_file, "%s - hexdump(len=%lu):",
205 			title, (unsigned long) len);
206 		if (buf == NULL) {
207 			fprintf(out_file, " [NULL]");
208 		} else if (show) {
209 			for (i = 0; i < len; i++)
210 				fprintf(out_file, " %02x", buf[i]);
211 		} else {
212 			fprintf(out_file, " [REMOVED]");
213 		}
214 		fprintf(out_file, "\n");
215 	} else {
216 #endif /* CONFIG_DEBUG_FILE */
217 	printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
218 	if (buf == NULL) {
219 		printf(" [NULL]");
220 	} else if (show) {
221 		for (i = 0; i < len; i++)
222 			printf(" %02x", buf[i]);
223 	} else {
224 		printf(" [REMOVED]");
225 	}
226 	printf("\n");
227 #ifdef CONFIG_DEBUG_FILE
228 	}
229 #endif /* CONFIG_DEBUG_FILE */
230 }
231 
232 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
233 {
234 	_wpa_hexdump(level, title, buf, len, 1);
235 }
236 
237 
238 void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
239 {
240 	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
241 }
242 
243 
244 static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
245 			       size_t len, int show)
246 {
247 	size_t i, llen;
248 	const u8 *pos = buf;
249 	const size_t line_len = 16;
250 
251 	if (level < wpa_debug_level)
252 		return;
253 	wpa_debug_print_timestamp();
254 #ifdef CONFIG_DEBUG_FILE
255 	if (out_file) {
256 		if (!show) {
257 			fprintf(out_file,
258 				"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
259 				title, (unsigned long) len);
260 			return;
261 		}
262 		if (buf == NULL) {
263 			fprintf(out_file,
264 				"%s - hexdump_ascii(len=%lu): [NULL]\n",
265 				title, (unsigned long) len);
266 			return;
267 		}
268 		fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
269 			title, (unsigned long) len);
270 		while (len) {
271 			llen = len > line_len ? line_len : len;
272 			fprintf(out_file, "    ");
273 			for (i = 0; i < llen; i++)
274 				fprintf(out_file, " %02x", pos[i]);
275 			for (i = llen; i < line_len; i++)
276 				fprintf(out_file, "   ");
277 			fprintf(out_file, "   ");
278 			for (i = 0; i < llen; i++) {
279 				if (isprint(pos[i]))
280 					fprintf(out_file, "%c", pos[i]);
281 				else
282 					fprintf(out_file, "_");
283 			}
284 			for (i = llen; i < line_len; i++)
285 				fprintf(out_file, " ");
286 			fprintf(out_file, "\n");
287 			pos += llen;
288 			len -= llen;
289 		}
290 	} else {
291 #endif /* CONFIG_DEBUG_FILE */
292 	if (!show) {
293 		printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
294 		       title, (unsigned long) len);
295 		return;
296 	}
297 	if (buf == NULL) {
298 		printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
299 		       title, (unsigned long) len);
300 		return;
301 	}
302 	printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
303 	while (len) {
304 		llen = len > line_len ? line_len : len;
305 		printf("    ");
306 		for (i = 0; i < llen; i++)
307 			printf(" %02x", pos[i]);
308 		for (i = llen; i < line_len; i++)
309 			printf("   ");
310 		printf("   ");
311 		for (i = 0; i < llen; i++) {
312 			if (isprint(pos[i]))
313 				printf("%c", pos[i]);
314 			else
315 				printf("_");
316 		}
317 		for (i = llen; i < line_len; i++)
318 			printf(" ");
319 		printf("\n");
320 		pos += llen;
321 		len -= llen;
322 	}
323 #ifdef CONFIG_DEBUG_FILE
324 	}
325 #endif /* CONFIG_DEBUG_FILE */
326 }
327 
328 
329 void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
330 {
331 	_wpa_hexdump_ascii(level, title, buf, len, 1);
332 }
333 
334 
335 void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
336 			   size_t len)
337 {
338 	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
339 }
340 
341 
342 #ifdef CONFIG_DEBUG_FILE
343 static char *last_path = NULL;
344 #endif /* CONFIG_DEBUG_FILE */
345 
346 int wpa_debug_reopen_file(void)
347 {
348 #ifdef CONFIG_DEBUG_FILE
349 	int rv;
350 	if (last_path) {
351 		char *tmp = os_strdup(last_path);
352 		wpa_debug_close_file();
353 		rv = wpa_debug_open_file(tmp);
354 		os_free(tmp);
355 	} else {
356 		wpa_printf(MSG_ERROR, "Last-path was not set, cannot "
357 			   "re-open log file.");
358 		rv = -1;
359 	}
360 	return rv;
361 #else /* CONFIG_DEBUG_FILE */
362 	return 0;
363 #endif /* CONFIG_DEBUG_FILE */
364 }
365 
366 
367 int wpa_debug_open_file(const char *path)
368 {
369 #ifdef CONFIG_DEBUG_FILE
370 	if (!path)
371 		return 0;
372 
373 	if (last_path == NULL || os_strcmp(last_path, path) != 0) {
374 		/* Save our path to enable re-open */
375 		os_free(last_path);
376 		last_path = os_strdup(path);
377 	}
378 
379 	out_file = fopen(path, "a");
380 	if (out_file == NULL) {
381 		wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
382 			   "output file, using standard output");
383 		return -1;
384 	}
385 #ifndef _WIN32
386 	setvbuf(out_file, NULL, _IOLBF, 0);
387 #endif /* _WIN32 */
388 #endif /* CONFIG_DEBUG_FILE */
389 	return 0;
390 }
391 
392 
393 void wpa_debug_close_file(void)
394 {
395 #ifdef CONFIG_DEBUG_FILE
396 	if (!out_file)
397 		return;
398 	fclose(out_file);
399 	out_file = NULL;
400 	os_free(last_path);
401 	last_path = NULL;
402 #endif /* CONFIG_DEBUG_FILE */
403 }
404 
405 #endif /* CONFIG_NO_STDOUT_DEBUG */
406 
407 #endif /* CONFIG_ANDROID_LOG */
408 
409 #ifndef CONFIG_NO_WPA_MSG
410 static wpa_msg_cb_func wpa_msg_cb = NULL;
411 
412 void wpa_msg_register_cb(wpa_msg_cb_func func)
413 {
414 	wpa_msg_cb = func;
415 }
416 
417 
418 static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
419 
420 void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
421 {
422 	wpa_msg_ifname_cb = func;
423 }
424 
425 
426 void wpa_msg(void *ctx, int level, const char *fmt, ...)
427 {
428 	va_list ap;
429 	char *buf;
430 	const int buflen = 2048;
431 	int len;
432 	char prefix[130];
433 
434 	buf = os_malloc(buflen);
435 	if (buf == NULL) {
436 		wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
437 			   "buffer");
438 		return;
439 	}
440 	va_start(ap, fmt);
441 	prefix[0] = '\0';
442 	if (wpa_msg_ifname_cb) {
443 		const char *ifname = wpa_msg_ifname_cb(ctx);
444 		if (ifname) {
445 			int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
446 					      ifname);
447 			if (res < 0 || res >= (int) sizeof(prefix))
448 				prefix[0] = '\0';
449 		}
450 	}
451 	len = vsnprintf(buf, buflen, fmt, ap);
452 	va_end(ap);
453 	wpa_printf(level, "%s%s", prefix, buf);
454 	if (wpa_msg_cb)
455 		wpa_msg_cb(ctx, level, buf, len);
456 	os_free(buf);
457 }
458 
459 
460 void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
461 {
462 	va_list ap;
463 	char *buf;
464 	const int buflen = 2048;
465 	int len;
466 
467 	if (!wpa_msg_cb)
468 		return;
469 
470 	buf = os_malloc(buflen);
471 	if (buf == NULL) {
472 		wpa_printf(MSG_ERROR, "wpa_msg_ctrl: 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 	wpa_msg_cb(ctx, level, buf, len);
480 	os_free(buf);
481 }
482 #endif /* CONFIG_NO_WPA_MSG */
483 
484 
485 #ifndef CONFIG_NO_HOSTAPD_LOGGER
486 static hostapd_logger_cb_func hostapd_logger_cb = NULL;
487 
488 void hostapd_logger_register_cb(hostapd_logger_cb_func func)
489 {
490 	hostapd_logger_cb = func;
491 }
492 
493 
494 void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
495 		    const char *fmt, ...)
496 {
497 	va_list ap;
498 	char *buf;
499 	const int buflen = 2048;
500 	int len;
501 
502 	buf = os_malloc(buflen);
503 	if (buf == NULL) {
504 		wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
505 			   "message buffer");
506 		return;
507 	}
508 	va_start(ap, fmt);
509 	len = vsnprintf(buf, buflen, fmt, ap);
510 	va_end(ap);
511 	if (hostapd_logger_cb)
512 		hostapd_logger_cb(ctx, addr, module, level, buf, len);
513 	else if (addr)
514 		wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s",
515 			   MAC2STR(addr), buf);
516 	else
517 		wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
518 	os_free(buf);
519 }
520 #endif /* CONFIG_NO_HOSTAPD_LOGGER */
521