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