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
20#ifdef CONFIG_DEBUG_FILE
21static FILE *out_file = NULL;
22#endif /* CONFIG_DEBUG_FILE */
23#ifdef CONFIG_ANDROID_LOG
24int wpa_debug_level = MSG_WARNING;
25#else
26int wpa_debug_level = MSG_INFO;
27#endif
28int wpa_debug_show_keys = 0;
29int wpa_debug_timestamp = 0;
30
31
32#ifdef CONFIG_ANDROID_LOG
33
34#include <android/log.h>
35
36void android_printf(int level, char *format, ...)
37{
38	if (level >= wpa_debug_level) {
39		va_list ap;
40		if (level == MSG_ERROR) {
41			level = ANDROID_LOG_ERROR;
42		} else if (level == MSG_WARNING) {
43			level = ANDROID_LOG_WARN;
44		} else if (level == MSG_INFO) {
45			level = ANDROID_LOG_INFO;
46		} else {
47			level = ANDROID_LOG_DEBUG;
48		}
49		va_start(ap, format);
50		__android_log_vprint(level, "wpa_supplicant", format, ap);
51		va_end(ap);
52	}
53}
54
55#else /* CONFIG_ANDROID_LOG */
56
57#ifndef CONFIG_NO_STDOUT_DEBUG
58
59void wpa_debug_print_timestamp(void)
60{
61	struct os_time tv;
62
63	if (!wpa_debug_timestamp)
64		return;
65
66	os_get_time(&tv);
67#ifdef CONFIG_DEBUG_FILE
68	if (out_file) {
69		fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
70			(unsigned int) tv.usec);
71	} else
72#endif /* CONFIG_DEBUG_FILE */
73	printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
74}
75
76
77/**
78 * wpa_printf - conditional printf
79 * @level: priority level (MSG_*) of the message
80 * @fmt: printf format string, followed by optional arguments
81 *
82 * This function is used to print conditional debugging and error messages. The
83 * output may be directed to stdout, stderr, and/or syslog based on
84 * configuration.
85 *
86 * Note: New line '\n' is added to the end of the text when printing to stdout.
87 */
88void wpa_printf(int level, const char *fmt, ...)
89{
90	va_list ap;
91
92	va_start(ap, fmt);
93	if (level >= wpa_debug_level) {
94		wpa_debug_print_timestamp();
95#ifdef CONFIG_DEBUG_FILE
96		if (out_file) {
97			vfprintf(out_file, fmt, ap);
98			fprintf(out_file, "\n");
99		} else {
100#endif /* CONFIG_DEBUG_FILE */
101		vprintf(fmt, ap);
102		printf("\n");
103#ifdef CONFIG_DEBUG_FILE
104		}
105#endif /* CONFIG_DEBUG_FILE */
106	}
107	va_end(ap);
108}
109
110
111static void _wpa_hexdump(int level, const char *title, const u8 *buf,
112			 size_t len, int show)
113{
114	size_t i;
115	if (level < wpa_debug_level)
116		return;
117	wpa_debug_print_timestamp();
118#ifdef CONFIG_DEBUG_FILE
119	if (out_file) {
120		fprintf(out_file, "%s - hexdump(len=%lu):",
121			title, (unsigned long) len);
122		if (buf == NULL) {
123			fprintf(out_file, " [NULL]");
124		} else if (show) {
125			for (i = 0; i < len; i++)
126				fprintf(out_file, " %02x", buf[i]);
127		} else {
128			fprintf(out_file, " [REMOVED]");
129		}
130		fprintf(out_file, "\n");
131	} else {
132#endif /* CONFIG_DEBUG_FILE */
133	printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
134	if (buf == NULL) {
135		printf(" [NULL]");
136	} else if (show) {
137		for (i = 0; i < len; i++)
138			printf(" %02x", buf[i]);
139	} else {
140		printf(" [REMOVED]");
141	}
142	printf("\n");
143#ifdef CONFIG_DEBUG_FILE
144	}
145#endif /* CONFIG_DEBUG_FILE */
146}
147
148void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
149{
150	_wpa_hexdump(level, title, buf, len, 1);
151}
152
153
154void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
155{
156	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
157}
158
159
160static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
161			       size_t len, int show)
162{
163	size_t i, llen;
164	const u8 *pos = buf;
165	const size_t line_len = 16;
166
167	if (level < wpa_debug_level)
168		return;
169	wpa_debug_print_timestamp();
170#ifdef CONFIG_DEBUG_FILE
171	if (out_file) {
172		if (!show) {
173			fprintf(out_file,
174				"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
175				title, (unsigned long) len);
176			return;
177		}
178		if (buf == NULL) {
179			fprintf(out_file,
180				"%s - hexdump_ascii(len=%lu): [NULL]\n",
181				title, (unsigned long) len);
182			return;
183		}
184		fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
185			title, (unsigned long) len);
186		while (len) {
187			llen = len > line_len ? line_len : len;
188			fprintf(out_file, "    ");
189			for (i = 0; i < llen; i++)
190				fprintf(out_file, " %02x", pos[i]);
191			for (i = llen; i < line_len; i++)
192				fprintf(out_file, "   ");
193			fprintf(out_file, "   ");
194			for (i = 0; i < llen; i++) {
195				if (isprint(pos[i]))
196					fprintf(out_file, "%c", pos[i]);
197				else
198					fprintf(out_file, "_");
199			}
200			for (i = llen; i < line_len; i++)
201				fprintf(out_file, " ");
202			fprintf(out_file, "\n");
203			pos += llen;
204			len -= llen;
205		}
206	} else {
207#endif /* CONFIG_DEBUG_FILE */
208	if (!show) {
209		printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
210		       title, (unsigned long) len);
211		return;
212	}
213	if (buf == NULL) {
214		printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
215		       title, (unsigned long) len);
216		return;
217	}
218	printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
219	while (len) {
220		llen = len > line_len ? line_len : len;
221		printf("    ");
222		for (i = 0; i < llen; i++)
223			printf(" %02x", pos[i]);
224		for (i = llen; i < line_len; i++)
225			printf("   ");
226		printf("   ");
227		for (i = 0; i < llen; i++) {
228			if (isprint(pos[i]))
229				printf("%c", pos[i]);
230			else
231				printf("_");
232		}
233		for (i = llen; i < line_len; i++)
234			printf(" ");
235		printf("\n");
236		pos += llen;
237		len -= llen;
238	}
239#ifdef CONFIG_DEBUG_FILE
240	}
241#endif /* CONFIG_DEBUG_FILE */
242}
243
244
245void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
246{
247	_wpa_hexdump_ascii(level, title, buf, len, 1);
248}
249
250
251void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
252			   size_t len)
253{
254	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
255}
256
257
258int wpa_debug_open_file(const char *path)
259{
260#ifdef CONFIG_DEBUG_FILE
261	if (!path)
262		return 0;
263	out_file = fopen(path, "a");
264	if (out_file == NULL) {
265		wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
266			   "output file, using standard output");
267		return -1;
268	}
269#ifndef _WIN32
270	setvbuf(out_file, NULL, _IOLBF, 0);
271#endif /* _WIN32 */
272#endif /* CONFIG_DEBUG_FILE */
273	return 0;
274}
275
276
277void wpa_debug_close_file(void)
278{
279#ifdef CONFIG_DEBUG_FILE
280	if (!out_file)
281		return;
282	fclose(out_file);
283	out_file = NULL;
284#endif /* CONFIG_DEBUG_FILE */
285}
286
287#endif /* CONFIG_NO_STDOUT_DEBUG */
288
289#endif /* CONFIG_ANDROID_LOG */
290
291#ifndef CONFIG_NO_WPA_MSG
292static wpa_msg_cb_func wpa_msg_cb = NULL;
293
294void wpa_msg_register_cb(wpa_msg_cb_func func)
295{
296	wpa_msg_cb = func;
297}
298
299
300void wpa_msg(void *ctx, int level, const char *fmt, ...)
301{
302	va_list ap;
303	char *buf;
304	const int buflen = 2048;
305	int len;
306
307	buf = os_malloc(buflen);
308	if (buf == NULL) {
309		wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
310			   "buffer");
311		return;
312	}
313	va_start(ap, fmt);
314	len = vsnprintf(buf, buflen, fmt, ap);
315	va_end(ap);
316	wpa_printf(level, "%s", buf);
317	if (wpa_msg_cb)
318		wpa_msg_cb(ctx, level, buf, len);
319	os_free(buf);
320}
321
322
323void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
324{
325	va_list ap;
326	char *buf;
327	const int buflen = 2048;
328	int len;
329
330	if (!wpa_msg_cb)
331		return;
332
333	buf = os_malloc(buflen);
334	if (buf == NULL) {
335		wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
336			   "message buffer");
337		return;
338	}
339	va_start(ap, fmt);
340	len = vsnprintf(buf, buflen, fmt, ap);
341	va_end(ap);
342	wpa_msg_cb(ctx, level, buf, len);
343	os_free(buf);
344}
345#endif /* CONFIG_NO_WPA_MSG */
346
347
348#ifndef CONFIG_NO_HOSTAPD_LOGGER
349static hostapd_logger_cb_func hostapd_logger_cb = NULL;
350
351void hostapd_logger_register_cb(hostapd_logger_cb_func func)
352{
353	hostapd_logger_cb = func;
354}
355
356
357void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
358		    const char *fmt, ...)
359{
360	va_list ap;
361	char *buf;
362	const int buflen = 2048;
363	int len;
364
365	buf = os_malloc(buflen);
366	if (buf == NULL) {
367		wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
368			   "message buffer");
369		return;
370	}
371	va_start(ap, fmt);
372	len = vsnprintf(buf, buflen, fmt, ap);
373	va_end(ap);
374	if (hostapd_logger_cb)
375		hostapd_logger_cb(ctx, addr, module, level, buf, len);
376	else
377		wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
378	os_free(buf);
379}
380#endif /* CONFIG_NO_HOSTAPD_LOGGER */
381