NetBSD/dist/hostapd/common.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 */