389 lines
7.7 KiB
C
389 lines
7.7 KiB
C
/*
|
|
* wpa_supplicant/hostapd / common helper functions, etc.
|
|
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* Alternatively, this software may be distributed under the terms of BSD
|
|
* license.
|
|
*
|
|
* See README and COPYING for more details.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#ifdef CONFIG_NATIVE_WINDOWS
|
|
#include <winsock2.h>
|
|
#include <wincrypt.h>
|
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
|
|
|
#include "common.h"
|
|
|
|
|
|
int wpa_debug_level = MSG_INFO;
|
|
int wpa_debug_show_keys = 0;
|
|
int wpa_debug_timestamp = 0;
|
|
|
|
|
|
int hostapd_get_rand(u8 *buf, size_t len)
|
|
{
|
|
#ifdef CONFIG_NATIVE_WINDOWS
|
|
HCRYPTPROV prov;
|
|
BOOL ret;
|
|
|
|
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT))
|
|
return -1;
|
|
|
|
ret = CryptGenRandom(prov, len, buf);
|
|
CryptReleaseContext(prov, 0);
|
|
|
|
return ret ? 0 : -1;
|
|
#else /* CONFIG_NATIVE_WINDOWS */
|
|
FILE *f;
|
|
size_t rc;
|
|
|
|
f = fopen("/dev/urandom", "r");
|
|
if (f == NULL) {
|
|
printf("Could not open /dev/urandom.\n");
|
|
return -1;
|
|
}
|
|
|
|
rc = fread(buf, 1, len, f);
|
|
fclose(f);
|
|
|
|
return rc != len ? -1 : 0;
|
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
|
}
|
|
|
|
|
|
void hostapd_hexdump(const char *title, const u8 *buf, size_t len)
|
|
{
|
|
size_t i;
|
|
printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
|
|
for (i = 0; i < len; i++)
|
|
printf(" %02x", buf[i]);
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
static int hex2num(char c)
|
|
{
|
|
if (c >= '0' && c <= '9')
|
|
return c - '0';
|
|
if (c >= 'a' && c <= 'f')
|
|
return c - 'a' + 10;
|
|
if (c >= 'A' && c <= 'F')
|
|
return c - 'A' + 10;
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int hex2byte(const char *hex)
|
|
{
|
|
int a, b;
|
|
a = hex2num(*hex++);
|
|
if (a < 0)
|
|
return -1;
|
|
b = hex2num(*hex++);
|
|
if (b < 0)
|
|
return -1;
|
|
return (a << 4) | b;
|
|
}
|
|
|
|
|
|
/**
|
|
* hwaddr_aton - Convert ASCII string to MAC address
|
|
* @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
|
|
* @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
|
|
* Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
|
|
*/
|
|
int hwaddr_aton(const char *txt, u8 *addr)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
int a, b;
|
|
|
|
a = hex2num(*txt++);
|
|
if (a < 0)
|
|
return -1;
|
|
b = hex2num(*txt++);
|
|
if (b < 0)
|
|
return -1;
|
|
*addr++ = (a << 4) | b;
|
|
if (i < 5 && *txt++ != ':')
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* hexstr2bin - Convert ASCII hex string into binary data
|
|
* @hex: ASCII hex string (e.g., "01ab")
|
|
* @buf: Buffer for the binary data
|
|
* @len: Length of the text to convert in bytes (of buf); hex will be double
|
|
* this size
|
|
* Returns: 0 on success, -1 on failure (invalid hex string)
|
|
*/
|
|
int hexstr2bin(const char *hex, u8 *buf, size_t len)
|
|
{
|
|
int i, a;
|
|
const char *ipos = hex;
|
|
u8 *opos = buf;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
a = hex2byte(ipos);
|
|
if (a < 0)
|
|
return -1;
|
|
*opos++ = a;
|
|
ipos += 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
char * rel2abs_path(const char *rel_path)
|
|
{
|
|
char *buf = NULL, *cwd, *ret;
|
|
size_t len = 128, cwd_len, rel_len, ret_len;
|
|
|
|
if (rel_path[0] == '/')
|
|
return strdup(rel_path);
|
|
|
|
for (;;) {
|
|
buf = malloc(len);
|
|
if (buf == NULL)
|
|
return NULL;
|
|
cwd = getcwd(buf, len);
|
|
if (cwd == NULL) {
|
|
free(buf);
|
|
if (errno != ERANGE) {
|
|
return NULL;
|
|
}
|
|
len *= 2;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
cwd_len = strlen(cwd);
|
|
rel_len = strlen(rel_path);
|
|
ret_len = cwd_len + 1 + rel_len + 1;
|
|
ret = malloc(ret_len);
|
|
if (ret) {
|
|
memcpy(ret, cwd, cwd_len);
|
|
ret[cwd_len] = '/';
|
|
memcpy(ret + cwd_len + 1, rel_path, rel_len);
|
|
ret[ret_len - 1] = '\0';
|
|
}
|
|
free(buf);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* inc_byte_array - Increment arbitrary length byte array by one
|
|
* @counter: Pointer to byte array
|
|
* @len: Length of the counter in bytes
|
|
*
|
|
* This function increments the last byte of the counter by one and continues
|
|
* rolling over to more significant bytes if the byte was incremented from
|
|
* 0xff to 0x00.
|
|
*/
|
|
void inc_byte_array(u8 *counter, size_t len)
|
|
{
|
|
int pos = len - 1;
|
|
while (pos >= 0) {
|
|
counter[pos]++;
|
|
if (counter[pos] != 0)
|
|
break;
|
|
pos--;
|
|
}
|
|
}
|
|
|
|
|
|
void print_char(char c)
|
|
{
|
|
if (c >= 32 && c < 127)
|
|
printf("%c", c);
|
|
else
|
|
printf("<%02x>", c);
|
|
}
|
|
|
|
|
|
void fprint_char(FILE *f, char c)
|
|
{
|
|
if (c >= 32 && c < 127)
|
|
fprintf(f, "%c", c);
|
|
else
|
|
fprintf(f, "<%02x>", c);
|
|
}
|
|
|
|
|
|
#ifndef CONFIG_NO_STDOUT_DEBUG
|
|
|
|
void wpa_debug_print_timestamp(void)
|
|
{
|
|
struct timeval tv;
|
|
char buf[16];
|
|
|
|
if (!wpa_debug_timestamp)
|
|
return;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S",
|
|
localtime((const time_t *) &tv.tv_sec)) <= 0) {
|
|
snprintf(buf, sizeof(buf), "%u", (int) tv.tv_sec);
|
|
}
|
|
printf("%s.%06u: ", buf, (unsigned int) tv.tv_usec);
|
|
}
|
|
|
|
|
|
/**
|
|
* wpa_printf - conditional printf
|
|
* @level: priority level (MSG_*) of the message
|
|
* @fmt: printf format string, followed by optional arguments
|
|
*
|
|
* This function is used to print conditional debugging and error messages. The
|
|
* output may be directed to stdout, stderr, and/or syslog based on
|
|
* configuration.
|
|
*
|
|
* Note: New line '\n' is added to the end of the text when printing to stdout.
|
|
*/
|
|
void wpa_printf(int level, char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
if (level >= wpa_debug_level) {
|
|
wpa_debug_print_timestamp();
|
|
vprintf(fmt, ap);
|
|
printf("\n");
|
|
}
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
static void _wpa_hexdump(int level, const char *title, const u8 *buf,
|
|
size_t len, int show)
|
|
{
|
|
size_t i;
|
|
if (level < wpa_debug_level)
|
|
return;
|
|
wpa_debug_print_timestamp();
|
|
printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
|
|
if (buf == NULL) {
|
|
printf(" [NULL]");
|
|
} else if (show) {
|
|
for (i = 0; i < len; i++)
|
|
printf(" %02x", buf[i]);
|
|
} else {
|
|
printf(" [REMOVED]");
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
|
|
{
|
|
_wpa_hexdump(level, title, buf, len, 1);
|
|
}
|
|
|
|
|
|
void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
|
|
{
|
|
_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
|
|
}
|
|
|
|
|
|
static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
|
|
size_t len, int show)
|
|
{
|
|
int i, llen;
|
|
const u8 *pos = buf;
|
|
const int line_len = 16;
|
|
|
|
if (level < wpa_debug_level)
|
|
return;
|
|
wpa_debug_print_timestamp();
|
|
if (!show) {
|
|
printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
|
|
title, (unsigned long) len);
|
|
return;
|
|
}
|
|
if (buf == NULL) {
|
|
printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
|
|
title, (unsigned long) len);
|
|
return;
|
|
}
|
|
printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
|
|
while (len) {
|
|
llen = len > line_len ? line_len : len;
|
|
printf(" ");
|
|
for (i = 0; i < llen; i++)
|
|
printf(" %02x", pos[i]);
|
|
for (i = llen; i < line_len; i++)
|
|
printf(" ");
|
|
printf(" ");
|
|
for (i = 0; i < llen; i++) {
|
|
if (isprint(pos[i]))
|
|
printf("%c", pos[i]);
|
|
else
|
|
printf("_");
|
|
}
|
|
for (i = llen; i < line_len; i++)
|
|
printf(" ");
|
|
printf("\n");
|
|
pos += llen;
|
|
len -= llen;
|
|
}
|
|
}
|
|
|
|
|
|
void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
|
|
{
|
|
_wpa_hexdump_ascii(level, title, buf, len, 1);
|
|
}
|
|
|
|
|
|
void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
|
|
size_t len)
|
|
{
|
|
_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
|
|
}
|
|
|
|
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
|
|
|
|
|
#ifdef CONFIG_NATIVE_WINDOWS
|
|
|
|
#define EPOCHFILETIME (116444736000000000ULL)
|
|
|
|
int gettimeofday(struct timeval *tv, struct timezone *tz)
|
|
{
|
|
FILETIME ft;
|
|
LARGE_INTEGER li;
|
|
ULONGLONG t;
|
|
|
|
GetSystemTimeAsFileTime(&ft);
|
|
li.LowPart = ft.dwLowDateTime;
|
|
li.HighPart = ft.dwHighDateTime;
|
|
t = (li.QuadPart - EPOCHFILETIME) / 10;
|
|
tv->tv_sec = (long) (t / 1000000);
|
|
tv->tv_usec = (long) (t % 1000000);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_NATIVE_WINDOWS */
|