Home | History | Annotate | Download | only in wpa_supplicant
      1 /*
      2  * wpa_supplicant/hostapd / common helper functions, etc.
      3  * Copyright (c) 2002-2006, Jouni Malinen <j (at) 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 static int hex2num(char c)
     29 {
     30 	if (c >= '0' && c <= '9')
     31 		return c - '0';
     32 	if (c >= 'a' && c <= 'f')
     33 		return c - 'a' + 10;
     34 	if (c >= 'A' && c <= 'F')
     35 		return c - 'A' + 10;
     36 	return -1;
     37 }
     38 
     39 
     40 static int hex2byte(const char *hex)
     41 {
     42 	int a, b;
     43 	a = hex2num(*hex++);
     44 	if (a < 0)
     45 		return -1;
     46 	b = hex2num(*hex++);
     47 	if (b < 0)
     48 		return -1;
     49 	return (a << 4) | b;
     50 }
     51 
     52 
     53 /**
     54  * hwaddr_aton - Convert ASCII string to MAC address
     55  * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
     56  * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
     57  * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
     58  */
     59 int hwaddr_aton(const char *txt, u8 *addr)
     60 {
     61 	int i;
     62 
     63 	for (i = 0; i < 6; i++) {
     64 		int a, b;
     65 
     66 		a = hex2num(*txt++);
     67 		if (a < 0)
     68 			return -1;
     69 		b = hex2num(*txt++);
     70 		if (b < 0)
     71 			return -1;
     72 		*addr++ = (a << 4) | b;
     73 		if (i < 5 && *txt++ != ':')
     74 			return -1;
     75 	}
     76 
     77 	return 0;
     78 }
     79 
     80 
     81 /**
     82  * hexstr2bin - Convert ASCII hex string into binary data
     83  * @hex: ASCII hex string (e.g., "01ab")
     84  * @buf: Buffer for the binary data
     85  * @len: Length of the text to convert in bytes (of buf); hex will be double
     86  * this size
     87  * Returns: 0 on success, -1 on failure (invalid hex string)
     88  */
     89 int hexstr2bin(const char *hex, u8 *buf, size_t len)
     90 {
     91 	size_t i;
     92 	int a;
     93 	const char *ipos = hex;
     94 	u8 *opos = buf;
     95 
     96 	for (i = 0; i < len; i++) {
     97 		a = hex2byte(ipos);
     98 		if (a < 0)
     99 			return -1;
    100 		*opos++ = a;
    101 		ipos += 2;
    102 	}
    103 	return 0;
    104 }
    105 
    106 
    107 /**
    108  * inc_byte_array - Increment arbitrary length byte array by one
    109  * @counter: Pointer to byte array
    110  * @len: Length of the counter in bytes
    111  *
    112  * This function increments the last byte of the counter by one and continues
    113  * rolling over to more significant bytes if the byte was incremented from
    114  * 0xff to 0x00.
    115  */
    116 void inc_byte_array(u8 *counter, size_t len)
    117 {
    118 	int pos = len - 1;
    119 	while (pos >= 0) {
    120 		counter[pos]++;
    121 		if (counter[pos] != 0)
    122 			break;
    123 		pos--;
    124 	}
    125 }
    126 
    127 
    128 void wpa_get_ntp_timestamp(u8 *buf)
    129 {
    130 	struct os_time now;
    131 	u32 sec, usec;
    132 
    133 	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
    134 	os_get_time(&now);
    135 	sec = host_to_be32(now.sec + 2208988800U); /* Epoch to 1900 */
    136 	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
    137 	usec = now.usec;
    138 	usec = host_to_be32(4295 * usec - (usec >> 5) - (usec >> 9));
    139 	os_memcpy(buf, (u8 *) &sec, 4);
    140 	os_memcpy(buf + 4, (u8 *) &usec, 4);
    141 }
    142 
    143 #ifdef ANDROID
    144 
    145 #include <android/log.h>
    146 
    147 void android_printf(int level, char *format, ...)
    148 {
    149 	if (level >= wpa_debug_level) {
    150 		va_list ap;
    151 		if (level == MSG_ERROR) {
    152 			level = ANDROID_LOG_ERROR;
    153 		} else if (level == MSG_WARNING) {
    154 			level = ANDROID_LOG_WARN;
    155 		} else if (level == MSG_INFO) {
    156 			level = ANDROID_LOG_INFO;
    157 		} else {
    158 			level = ANDROID_LOG_DEBUG;
    159 		}
    160 		va_start(ap, format);
    161 		__android_log_vprint(level, "wpa_supplicant", format, ap);
    162 		va_end(ap);
    163 	}
    164 }
    165 
    166 #else /* ANDROID */
    167 
    168 #ifndef CONFIG_NO_STDOUT_DEBUG
    169 
    170 void wpa_debug_print_timestamp(void)
    171 {
    172 	struct os_time tv;
    173 
    174 	if (!wpa_debug_timestamp)
    175 		return;
    176 
    177 	os_get_time(&tv);
    178 #ifdef CONFIG_DEBUG_FILE
    179 	if (out_file) {
    180 		fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
    181 			(unsigned int) tv.usec);
    182 	} else
    183 #endif /* CONFIG_DEBUG_FILE */
    184 	printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
    185 }
    186 
    187 
    188 /**
    189  * wpa_printf - conditional printf
    190  * @level: priority level (MSG_*) of the message
    191  * @fmt: printf format string, followed by optional arguments
    192  *
    193  * This function is used to print conditional debugging and error messages. The
    194  * output may be directed to stdout, stderr, and/or syslog based on
    195  * configuration.
    196  *
    197  * Note: New line '\n' is added to the end of the text when printing to stdout.
    198  */
    199 void wpa_printf(int level, char *fmt, ...)
    200 {
    201 	va_list ap;
    202 
    203 	va_start(ap, fmt);
    204 	if (level >= wpa_debug_level) {
    205 		wpa_debug_print_timestamp();
    206 #ifdef CONFIG_DEBUG_FILE
    207 		if (out_file) {
    208 			vfprintf(out_file, fmt, ap);
    209 			fprintf(out_file, "\n");
    210 		} else {
    211 #endif /* CONFIG_DEBUG_FILE */
    212 		vprintf(fmt, ap);
    213 		printf("\n");
    214 #ifdef CONFIG_DEBUG_FILE
    215 		}
    216 #endif /* CONFIG_DEBUG_FILE */
    217 	}
    218 	va_end(ap);
    219 }
    220 
    221 
    222 static void _wpa_hexdump(int level, const char *title, const u8 *buf,
    223 			 size_t len, int show)
    224 {
    225 	size_t i;
    226 	if (level < wpa_debug_level)
    227 		return;
    228 	wpa_debug_print_timestamp();
    229 #ifdef CONFIG_DEBUG_FILE
    230 	if (out_file) {
    231 		fprintf(out_file, "%s - hexdump(len=%lu):",
    232 			title, (unsigned long) len);
    233 		if (buf == NULL) {
    234 			fprintf(out_file, " [NULL]");
    235 		} else if (show) {
    236 			for (i = 0; i < len; i++)
    237 				fprintf(out_file, " %02x", buf[i]);
    238 		} else {
    239 			fprintf(out_file, " [REMOVED]");
    240 		}
    241 		fprintf(out_file, "\n");
    242 	} else {
    243 #endif /* CONFIG_DEBUG_FILE */
    244 	printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
    245 	if (buf == NULL) {
    246 		printf(" [NULL]");
    247 	} else if (show) {
    248 		for (i = 0; i < len; i++)
    249 			printf(" %02x", buf[i]);
    250 	} else {
    251 		printf(" [REMOVED]");
    252 	}
    253 	printf("\n");
    254 #ifdef CONFIG_DEBUG_FILE
    255 	}
    256 #endif /* CONFIG_DEBUG_FILE */
    257 }
    258 
    259 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
    260 {
    261 	_wpa_hexdump(level, title, buf, len, 1);
    262 }
    263 
    264 
    265 void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
    266 {
    267 	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
    268 }
    269 
    270 
    271 static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
    272 			       size_t len, int show)
    273 {
    274 	size_t i, llen;
    275 	const u8 *pos = buf;
    276 	const size_t line_len = 16;
    277 
    278 	if (level < wpa_debug_level)
    279 		return;
    280 	wpa_debug_print_timestamp();
    281 #ifdef CONFIG_DEBUG_FILE
    282 	if (out_file) {
    283 		if (!show) {
    284 			fprintf(out_file,
    285 				"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
    286 				title, (unsigned long) len);
    287 			return;
    288 		}
    289 		if (buf == NULL) {
    290 			fprintf(out_file,
    291 				"%s - hexdump_ascii(len=%lu): [NULL]\n",
    292 				title, (unsigned long) len);
    293 			return;
    294 		}
    295 		fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
    296 			title, (unsigned long) len);
    297 		while (len) {
    298 			llen = len > line_len ? line_len : len;
    299 			fprintf(out_file, "    ");
    300 			for (i = 0; i < llen; i++)
    301 				fprintf(out_file, " %02x", pos[i]);
    302 			for (i = llen; i < line_len; i++)
    303 				fprintf(out_file, "   ");
    304 			fprintf(out_file, "   ");
    305 			for (i = 0; i < llen; i++) {
    306 				if (isprint(pos[i]))
    307 					fprintf(out_file, "%c", pos[i]);
    308 				else
    309 					fprintf(out_file, "_");
    310 			}
    311 			for (i = llen; i < line_len; i++)
    312 				fprintf(out_file, " ");
    313 			fprintf(out_file, "\n");
    314 			pos += llen;
    315 			len -= llen;
    316 		}
    317 	} else {
    318 #endif /* CONFIG_DEBUG_FILE */
    319 	if (!show) {
    320 		printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
    321 		       title, (unsigned long) len);
    322 		return;
    323 	}
    324 	if (buf == NULL) {
    325 		printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
    326 		       title, (unsigned long) len);
    327 		return;
    328 	}
    329 	printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
    330 	while (len) {
    331 		llen = len > line_len ? line_len : len;
    332 		printf("    ");
    333 		for (i = 0; i < llen; i++)
    334 			printf(" %02x", pos[i]);
    335 		for (i = llen; i < line_len; i++)
    336 			printf("   ");
    337 		printf("   ");
    338 		for (i = 0; i < llen; i++) {
    339 			if (isprint(pos[i]))
    340 				printf("%c", pos[i]);
    341 			else
    342 				printf("_");
    343 		}
    344 		for (i = llen; i < line_len; i++)
    345 			printf(" ");
    346 		printf("\n");
    347 		pos += llen;
    348 		len -= llen;
    349 	}
    350 #ifdef CONFIG_DEBUG_FILE
    351 	}
    352 #endif /* CONFIG_DEBUG_FILE */
    353 }
    354 
    355 
    356 void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
    357 {
    358 	_wpa_hexdump_ascii(level, title, buf, len, 1);
    359 }
    360 
    361 
    362 void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
    363 			   size_t len)
    364 {
    365 	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
    366 }
    367 
    368 
    369 int wpa_debug_open_file(const char *path)
    370 {
    371 #ifdef CONFIG_DEBUG_FILE
    372 	if (!path)
    373 		return 0;
    374 	out_file = fopen(path, "a");
    375 	if (out_file == NULL) {
    376 		wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
    377 			   "output file, using standard output");
    378 		return -1;
    379 	}
    380 #ifndef _WIN32
    381 	setvbuf(out_file, NULL, _IOLBF, 0);
    382 #endif /* _WIN32 */
    383 #endif /* CONFIG_DEBUG_FILE */
    384 	return 0;
    385 }
    386 
    387 
    388 void wpa_debug_close_file(void)
    389 {
    390 #ifdef CONFIG_DEBUG_FILE
    391 	if (!out_file)
    392 		return;
    393 	fclose(out_file);
    394 	out_file = NULL;
    395 #endif /* CONFIG_DEBUG_FILE */
    396 }
    397 
    398 #endif /* CONFIG_NO_STDOUT_DEBUG */
    399 
    400 #endif /* ANDROID */
    401 
    402 #ifndef CONFIG_NO_WPA_MSG
    403 static wpa_msg_cb_func wpa_msg_cb = NULL;
    404 
    405 void wpa_msg_register_cb(wpa_msg_cb_func func)
    406 {
    407 	wpa_msg_cb = func;
    408 }
    409 
    410 
    411 void wpa_msg(void *ctx, int level, char *fmt, ...)
    412 {
    413 	va_list ap;
    414 	char *buf;
    415 	const int buflen = 2048;
    416 	int len;
    417 
    418 	buf = os_malloc(buflen);
    419 	if (buf == NULL) {
    420 		wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
    421 			   "buffer");
    422 		return;
    423 	}
    424 	va_start(ap, fmt);
    425 	len = vsnprintf(buf, buflen, fmt, ap);
    426 	va_end(ap);
    427 	wpa_printf(level, "%s", buf);
    428 	if (wpa_msg_cb)
    429 		wpa_msg_cb(ctx, level, buf, len);
    430 	os_free(buf);
    431 }
    432 #endif /* CONFIG_NO_WPA_MSG */
    433 
    434 
    435 static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
    436 				    size_t len, int uppercase)
    437 {
    438 	size_t i;
    439 	char *pos = buf, *end = buf + buf_size;
    440 	int ret;
    441 	if (buf_size == 0)
    442 		return 0;
    443 	for (i = 0; i < len; i++) {
    444 		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
    445 				  data[i]);
    446 		if (ret < 0 || ret >= end - pos) {
    447 			end[-1] = '\0';
    448 			return pos - buf;
    449 		}
    450 		pos += ret;
    451 	}
    452 	end[-1] = '\0';
    453 	return pos - buf;
    454 }
    455 
    456 /**
    457  * wpa_snprintf_hex - Print data as a hex string into a buffer
    458  * @buf: Memory area to use as the output buffer
    459  * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
    460  * @data: Data to be printed
    461  * @len: Length of data in bytes
    462  * Returns: Number of bytes written
    463  */
    464 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
    465 {
    466 	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
    467 }
    468 
    469 
    470 /**
    471  * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
    472  * @buf: Memory area to use as the output buffer
    473  * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
    474  * @data: Data to be printed
    475  * @len: Length of data in bytes
    476  * Returns: Number of bytes written
    477  */
    478 int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
    479 			       size_t len)
    480 {
    481 	return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
    482 }
    483 
    484 
    485 #ifdef CONFIG_ANSI_C_EXTRA
    486 
    487 #ifdef _WIN32_WCE
    488 void perror(const char *s)
    489 {
    490 	wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
    491 		   s, (int) GetLastError());
    492 }
    493 #endif /* _WIN32_WCE */
    494 
    495 
    496 int optind = 1;
    497 int optopt;
    498 char *optarg;
    499 
    500 int getopt(int argc, char *const argv[], const char *optstring)
    501 {
    502 	static int optchr = 1;
    503 	char *cp;
    504 
    505 	if (optchr == 1) {
    506 		if (optind >= argc) {
    507 			/* all arguments processed */
    508 			return EOF;
    509 		}
    510 
    511 		if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
    512 			/* no option characters */
    513 			return EOF;
    514 		}
    515 	}
    516 
    517 	if (os_strcmp(argv[optind], "--") == 0) {
    518 		/* no more options */
    519 		optind++;
    520 		return EOF;
    521 	}
    522 
    523 	optopt = argv[optind][optchr];
    524 	cp = os_strchr(optstring, optopt);
    525 	if (cp == NULL || optopt == ':') {
    526 		if (argv[optind][++optchr] == '\0') {
    527 			optchr = 1;
    528 			optind++;
    529 		}
    530 		return '?';
    531 	}
    532 
    533 	if (cp[1] == ':') {
    534 		/* Argument required */
    535 		optchr = 1;
    536 		if (argv[optind][optchr + 1]) {
    537 			/* No space between option and argument */
    538 			optarg = &argv[optind++][optchr + 1];
    539 		} else if (++optind >= argc) {
    540 			/* option requires an argument */
    541 			return '?';
    542 		} else {
    543 			/* Argument in the next argv */
    544 			optarg = argv[optind++];
    545 		}
    546 	} else {
    547 		/* No argument */
    548 		if (argv[optind][++optchr] == '\0') {
    549 			optchr = 1;
    550 			optind++;
    551 		}
    552 		optarg = NULL;
    553 	}
    554 	return *cp;
    555 }
    556 #endif /* CONFIG_ANSI_C_EXTRA */
    557 
    558 
    559 #ifdef CONFIG_NATIVE_WINDOWS
    560 /**
    561  * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
    562  * @str: Pointer to string to convert
    563  *
    564  * This function converts a unicode string to ASCII using the same
    565  * buffer for output. If UNICODE is not set, the buffer is not
    566  * modified.
    567  */
    568 void wpa_unicode2ascii_inplace(TCHAR *str)
    569 {
    570 #ifdef UNICODE
    571 	char *dst = (char *) str;
    572 	while (*str)
    573 		*dst++ = (char) *str++;
    574 	*dst = '\0';
    575 #endif /* UNICODE */
    576 }
    577 
    578 
    579 TCHAR * wpa_strdup_tchar(const char *str)
    580 {
    581 #ifdef UNICODE
    582 	TCHAR *buf;
    583 	buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
    584 	if (buf == NULL)
    585 		return NULL;
    586 	wsprintf(buf, L"%S", str);
    587 	return buf;
    588 #else /* UNICODE */
    589 	return os_strdup(str);
    590 #endif /* UNICODE */
    591 }
    592 #endif /* CONFIG_NATIVE_WINDOWS */
    593 
    594 
    595 /**
    596  * wpa_ssid_txt - Convert SSID to a printable string
    597  * @ssid: SSID (32-octet string)
    598  * @ssid_len: Length of ssid in octets
    599  * Returns: Pointer to a printable string
    600  *
    601  * This function can be used to convert SSIDs into printable form. In most
    602  * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
    603  * does not limit the used character set, so anything could be used in an SSID.
    604  *
    605  * This function uses a static buffer, so only one call can be used at the
    606  * time, i.e., this is not re-entrant and the returned buffer must be used
    607  * before calling this again.
    608  */
    609 const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
    610 {
    611 	static char ssid_txt[33];
    612 	char *pos;
    613 
    614 	if (ssid_len > 32)
    615 		ssid_len = 32;
    616 	os_memcpy(ssid_txt, ssid, ssid_len);
    617 	ssid_txt[ssid_len] = '\0';
    618 	for (pos = ssid_txt; *pos != '\0'; pos++) {
    619 #ifndef WPA_UNICODE_SSID
    620 		/* Don't do this, since it prevents us from using APs with non-ASCII SSIDs */
    621 		if ((u8) *pos < 32 || (u8) *pos >= 127)
    622 			*pos = '_';
    623 #endif
    624 	}
    625 	return ssid_txt;
    626 }
    627