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