xref: /freebsd/contrib/wpa/src/utils/wpa_debug.c (revision e28a4053)
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 #ifdef CONFIG_DEBUG_FILE
27 static FILE *out_file = NULL;
28 #endif /* CONFIG_DEBUG_FILE */
29 int wpa_debug_level = MSG_INFO;
30 int wpa_debug_show_keys = 0;
31 int wpa_debug_timestamp = 0;
32 
33 
34 #ifndef CONFIG_NO_STDOUT_DEBUG
35 
36 void 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
55 void wpa_debug_open_syslog(void)
56 {
57 	openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_DAEMON);
58 	wpa_debug_syslog++;
59 }
60 
61 
62 void wpa_debug_close_syslog(void)
63 {
64 	if (wpa_debug_syslog)
65 		closelog();
66 }
67 
68 
69 static 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  */
98 void 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 
129 static 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 
166 void 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 
172 void 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 
178 static 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 
263 void 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 
269 void 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 
276 int 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 
295 void 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
309 static wpa_msg_cb_func wpa_msg_cb = NULL;
310 
311 void wpa_msg_register_cb(wpa_msg_cb_func func)
312 {
313 	wpa_msg_cb = func;
314 }
315 
316 
317 void 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 
340 void 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
366 static hostapd_logger_cb_func hostapd_logger_cb = NULL;
367 
368 void hostapd_logger_register_cb(hostapd_logger_cb_func func)
369 {
370 	hostapd_logger_cb = func;
371 }
372 
373 
374 void 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