wpa_supplicant: Initial Revision 0.8.X
Based on:
commit 0725cc7b7efc434910e89865c42eda7ce61bbf08
Author: Jouni Malinen <j@w1.fi>
Date: Thu Apr 21 20:41:01 2011 +0300
Enable CONFIG_DRIVER_NL80211=y in the default configuration
nl80211 should be preferred over WEXT with any recent Linux
kernel version.
Change-Id: I26aec5afbbd4f4a1f5fd900912545b6f5050de64
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/utils/.gitignore b/src/utils/.gitignore
new file mode 100644
index 0000000..833734f
--- /dev/null
+++ b/src/utils/.gitignore
@@ -0,0 +1 @@
+libutils.a
diff --git a/src/utils/Makefile b/src/utils/Makefile
new file mode 100644
index 0000000..0f1f191
--- /dev/null
+++ b/src/utils/Makefile
@@ -0,0 +1,39 @@
+all: libutils.a
+
+clean:
+ rm -f *~ *.o *.d libutils.a
+
+install:
+ @echo Nothing to be made.
+
+
+include ../lib.rules
+
+#CFLAGS += -DWPA_TRACE
+CFLAGS += -DCONFIG_IPV6
+
+LIB_OBJS= \
+ base64.o \
+ common.o \
+ ip_addr.o \
+ radiotap.o \
+ trace.o \
+ uuid.o \
+ wpa_debug.o \
+ wpabuf.o
+
+# Pick correct OS wrapper implementation
+LIB_OBJS += os_unix.o
+
+# Pick correct event loop implementation
+LIB_OBJS += eloop.o
+
+# Pick correct edit implementation
+LIB_OBJS += edit.o
+
+#LIB_OBJS += pcsc_funcs.o
+
+libutils.a: $(LIB_OBJS)
+ $(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/utils/base64.c b/src/utils/base64.c
new file mode 100644
index 0000000..155bfce
--- /dev/null
+++ b/src/utils/base64.c
@@ -0,0 +1,154 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "os.h"
+#include "base64.h"
+
+static const unsigned char base64_table[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode - Base64 encode
+ * @src: Data to be encoded
+ * @len: Length of the data to be encoded
+ * @out_len: Pointer to output length variable, or %NULL if not used
+ * Returns: Allocated buffer of out_len bytes of encoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer. Returned buffer is
+ * nul terminated to make it easier to use as a C string. The nul terminator is
+ * not included in out_len.
+ */
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+ size_t *out_len)
+{
+ unsigned char *out, *pos;
+ const unsigned char *end, *in;
+ size_t olen;
+ int line_len;
+
+ olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
+ olen += olen / 72; /* line feeds */
+ olen++; /* nul termination */
+ if (olen < len)
+ return NULL; /* integer overflow */
+ out = os_malloc(olen);
+ if (out == NULL)
+ return NULL;
+
+ end = src + len;
+ in = src;
+ pos = out;
+ line_len = 0;
+ while (end - in >= 3) {
+ *pos++ = base64_table[in[0] >> 2];
+ *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+ *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+ *pos++ = base64_table[in[2] & 0x3f];
+ in += 3;
+ line_len += 4;
+ if (line_len >= 72) {
+ *pos++ = '\n';
+ line_len = 0;
+ }
+ }
+
+ if (end - in) {
+ *pos++ = base64_table[in[0] >> 2];
+ if (end - in == 1) {
+ *pos++ = base64_table[(in[0] & 0x03) << 4];
+ *pos++ = '=';
+ } else {
+ *pos++ = base64_table[((in[0] & 0x03) << 4) |
+ (in[1] >> 4)];
+ *pos++ = base64_table[(in[1] & 0x0f) << 2];
+ }
+ *pos++ = '=';
+ line_len += 4;
+ }
+
+ if (line_len)
+ *pos++ = '\n';
+
+ *pos = '\0';
+ if (out_len)
+ *out_len = pos - out;
+ return out;
+}
+
+
+/**
+ * base64_decode - Base64 decode
+ * @src: Data to be decoded
+ * @len: Length of the data to be decoded
+ * @out_len: Pointer to output length variable
+ * Returns: Allocated buffer of out_len bytes of decoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+ size_t *out_len)
+{
+ unsigned char dtable[256], *out, *pos, in[4], block[4], tmp;
+ size_t i, count, olen;
+
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; i < sizeof(base64_table) - 1; i++)
+ dtable[base64_table[i]] = (unsigned char) i;
+ dtable['='] = 0;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ if (dtable[src[i]] != 0x80)
+ count++;
+ }
+
+ if (count == 0 || count % 4)
+ return NULL;
+
+ olen = count / 4 * 3;
+ pos = out = os_malloc(olen);
+ if (out == NULL)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ tmp = dtable[src[i]];
+ if (tmp == 0x80)
+ continue;
+
+ in[count] = src[i];
+ block[count] = tmp;
+ count++;
+ if (count == 4) {
+ *pos++ = (block[0] << 2) | (block[1] >> 4);
+ *pos++ = (block[1] << 4) | (block[2] >> 2);
+ *pos++ = (block[2] << 6) | block[3];
+ count = 0;
+ }
+ }
+
+ if (pos > out) {
+ if (in[2] == '=')
+ pos -= 2;
+ else if (in[3] == '=')
+ pos--;
+ }
+
+ *out_len = pos - out;
+ return out;
+}
diff --git a/src/utils/base64.h b/src/utils/base64.h
new file mode 100644
index 0000000..b87a168
--- /dev/null
+++ b/src/utils/base64.h
@@ -0,0 +1,23 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+ size_t *out_len);
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+ size_t *out_len);
+
+#endif /* BASE64_H */
diff --git a/src/utils/build_config.h b/src/utils/build_config.h
new file mode 100644
index 0000000..3666778
--- /dev/null
+++ b/src/utils/build_config.h
@@ -0,0 +1,105 @@
+/*
+ * wpa_supplicant/hostapd - Build time configuration defines
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.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.
+ *
+ * This header file can be used to define configuration defines that were
+ * originally defined in Makefile. This is mainly meant for IDE use or for
+ * systems that do not have suitable 'make' tool. In these cases, it may be
+ * easier to have a single place for defining all the needed C pre-processor
+ * defines.
+ */
+
+#ifndef BUILD_CONFIG_H
+#define BUILD_CONFIG_H
+
+/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */
+
+#ifdef CONFIG_WIN32_DEFAULTS
+#define CONFIG_NATIVE_WINDOWS
+#define CONFIG_ANSI_C_EXTRA
+#define CONFIG_WINPCAP
+#define IEEE8021X_EAPOL
+#define PKCS12_FUNCS
+#define PCSC_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_NAMED_PIPE
+#define CONFIG_DRIVER_NDIS
+#define CONFIG_NDIS_EVENTS_INTEGRATED
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define EAP_TNC
+#define _CRT_SECURE_NO_DEPRECATE
+
+#ifdef USE_INTERNAL_CRYPTO
+#define CONFIG_TLS_INTERNAL_CLIENT
+#define CONFIG_INTERNAL_LIBTOMMATH
+#define CONFIG_CRYPTO_INTERNAL
+#endif /* USE_INTERNAL_CRYPTO */
+#endif /* CONFIG_WIN32_DEFAULTS */
+
+#ifdef __SYMBIAN32__
+#define OS_NO_C_LIB_DEFINES
+#define CONFIG_ANSI_C_EXTRA
+#define CONFIG_NO_WPA_MSG
+#define CONFIG_NO_HOSTAPD_LOGGER
+#define CONFIG_NO_STDOUT_DEBUG
+#define CONFIG_BACKEND_FILE
+#define CONFIG_INTERNAL_LIBTOMMATH
+#define CONFIG_CRYPTO_INTERNAL
+#define IEEE8021X_EAPOL
+#define PKCS12_FUNCS
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define EAP_FAST
+#endif /* __SYMBIAN32__ */
+
+#ifdef CONFIG_XCODE_DEFAULTS
+#define CONFIG_DRIVER_OSX
+#define CONFIG_BACKEND_FILE
+#define IEEE8021X_EAPOL
+#define PKCS12_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_UNIX
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define EAP_TNC
+#define CONFIG_WPS
+#define EAP_WSC
+
+#ifdef USE_INTERNAL_CRYPTO
+#define CONFIG_TLS_INTERNAL_CLIENT
+#define CONFIG_INTERNAL_LIBTOMMATH
+#define CONFIG_CRYPTO_INTERNAL
+#endif /* USE_INTERNAL_CRYPTO */
+#endif /* CONFIG_XCODE_DEFAULTS */
+
+#endif /* BUILD_CONFIG_H */
diff --git a/src/utils/common.c b/src/utils/common.c
new file mode 100644
index 0000000..89eca1c
--- /dev/null
+++ b/src/utils/common.c
@@ -0,0 +1,387 @@
+/*
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+
+
+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;
+}
+
+
+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 (colon-delimited format)
+ * @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;
+}
+
+/**
+ * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
+ * @txt: MAC address as a string (e.g., "001122334455")
+ * @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_compact_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;
+ }
+
+ return 0;
+}
+
+/**
+ * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
+ * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: Characters used (> 0) on success, -1 on failure
+ */
+int hwaddr_aton2(const char *txt, u8 *addr)
+{
+ int i;
+ const char *pos = txt;
+
+ for (i = 0; i < 6; i++) {
+ int a, b;
+
+ while (*pos == ':' || *pos == '.' || *pos == '-')
+ pos++;
+
+ a = hex2num(*pos++);
+ if (a < 0)
+ return -1;
+ b = hex2num(*pos++);
+ if (b < 0)
+ return -1;
+ *addr++ = (a << 4) | b;
+ }
+
+ return pos - txt;
+}
+
+
+/**
+ * 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)
+{
+ size_t i;
+ int 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;
+}
+
+
+/**
+ * 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 wpa_get_ntp_timestamp(u8 *buf)
+{
+ struct os_time now;
+ u32 sec, usec;
+ be32 tmp;
+
+ /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
+ os_get_time(&now);
+ sec = now.sec + 2208988800U; /* Epoch to 1900 */
+ /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
+ usec = now.usec;
+ usec = 4295 * usec - (usec >> 5) - (usec >> 9);
+ tmp = host_to_be32(sec);
+ os_memcpy(buf, (u8 *) &tmp, 4);
+ tmp = host_to_be32(usec);
+ os_memcpy(buf + 4, (u8 *) &tmp, 4);
+}
+
+
+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
+ size_t len, int uppercase)
+{
+ size_t i;
+ char *pos = buf, *end = buf + buf_size;
+ int ret;
+ if (buf_size == 0)
+ return 0;
+ for (i = 0; i < len; i++) {
+ ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
+ data[i]);
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return pos - buf;
+ }
+ pos += ret;
+ }
+ end[-1] = '\0';
+ return pos - buf;
+}
+
+/**
+ * wpa_snprintf_hex - Print data as a hex string into a buffer
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
+{
+ return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
+}
+
+
+/**
+ * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+ size_t len)
+{
+ return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
+}
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#ifdef _WIN32_WCE
+void perror(const char *s)
+{
+ wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
+ s, (int) GetLastError());
+}
+#endif /* _WIN32_WCE */
+
+
+int optind = 1;
+int optopt;
+char *optarg;
+
+int getopt(int argc, char *const argv[], const char *optstring)
+{
+ static int optchr = 1;
+ char *cp;
+
+ if (optchr == 1) {
+ if (optind >= argc) {
+ /* all arguments processed */
+ return EOF;
+ }
+
+ if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
+ /* no option characters */
+ return EOF;
+ }
+ }
+
+ if (os_strcmp(argv[optind], "--") == 0) {
+ /* no more options */
+ optind++;
+ return EOF;
+ }
+
+ optopt = argv[optind][optchr];
+ cp = os_strchr(optstring, optopt);
+ if (cp == NULL || optopt == ':') {
+ if (argv[optind][++optchr] == '\0') {
+ optchr = 1;
+ optind++;
+ }
+ return '?';
+ }
+
+ if (cp[1] == ':') {
+ /* Argument required */
+ optchr = 1;
+ if (argv[optind][optchr + 1]) {
+ /* No space between option and argument */
+ optarg = &argv[optind++][optchr + 1];
+ } else if (++optind >= argc) {
+ /* option requires an argument */
+ return '?';
+ } else {
+ /* Argument in the next argv */
+ optarg = argv[optind++];
+ }
+ } else {
+ /* No argument */
+ if (argv[optind][++optchr] == '\0') {
+ optchr = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return *cp;
+}
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+/**
+ * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
+ * @str: Pointer to string to convert
+ *
+ * This function converts a unicode string to ASCII using the same
+ * buffer for output. If UNICODE is not set, the buffer is not
+ * modified.
+ */
+void wpa_unicode2ascii_inplace(TCHAR *str)
+{
+#ifdef UNICODE
+ char *dst = (char *) str;
+ while (*str)
+ *dst++ = (char) *str++;
+ *dst = '\0';
+#endif /* UNICODE */
+}
+
+
+TCHAR * wpa_strdup_tchar(const char *str)
+{
+#ifdef UNICODE
+ TCHAR *buf;
+ buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
+ if (buf == NULL)
+ return NULL;
+ wsprintf(buf, L"%S", str);
+ return buf;
+#else /* UNICODE */
+ return os_strdup(str);
+#endif /* UNICODE */
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+/**
+ * wpa_ssid_txt - Convert SSID to a printable string
+ * @ssid: SSID (32-octet string)
+ * @ssid_len: Length of ssid in octets
+ * Returns: Pointer to a printable string
+ *
+ * This function can be used to convert SSIDs into printable form. In most
+ * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
+ * does not limit the used character set, so anything could be used in an SSID.
+ *
+ * This function uses a static buffer, so only one call can be used at the
+ * time, i.e., this is not re-entrant and the returned buffer must be used
+ * before calling this again.
+ */
+const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
+{
+ static char ssid_txt[33];
+ char *pos;
+
+ if (ssid_len > 32)
+ ssid_len = 32;
+ os_memcpy(ssid_txt, ssid, ssid_len);
+ ssid_txt[ssid_len] = '\0';
+ for (pos = ssid_txt; *pos != '\0'; pos++) {
+ if ((u8) *pos < 32 || (u8) *pos >= 127)
+ *pos = '_';
+ }
+ return ssid_txt;
+}
+
+
+void * __hide_aliasing_typecast(void *foo)
+{
+ return foo;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
new file mode 100644
index 0000000..14ab297
--- /dev/null
+++ b/src/utils/common.h
@@ -0,0 +1,502 @@
+/*
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "os.h"
+
+#if defined(__linux__) || defined(__GLIBC__)
+#include <endian.h>
+#include <byteswap.h>
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
+ defined(__OpenBSD__)
+#include <sys/types.h>
+#include <sys/endian.h>
+#define __BYTE_ORDER _BYTE_ORDER
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#define __BIG_ENDIAN _BIG_ENDIAN
+#ifdef __OpenBSD__
+#define bswap_16 swap16
+#define bswap_32 swap32
+#define bswap_64 swap64
+#else /* __OpenBSD__ */
+#define bswap_16 bswap16
+#define bswap_32 bswap32
+#define bswap_64 bswap64
+#endif /* __OpenBSD__ */
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
+ * defined(__DragonFly__) || defined(__OpenBSD__) */
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <machine/endian.h>
+#define __BYTE_ORDER _BYTE_ORDER
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#define __BIG_ENDIAN _BIG_ENDIAN
+static inline unsigned short bswap_16(unsigned short v)
+{
+ return ((v & 0xff) << 8) | (v >> 8);
+}
+
+static inline unsigned int bswap_32(unsigned int v)
+{
+ return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
+ ((v & 0xff0000) >> 8) | (v >> 24);
+}
+#endif /* __APPLE__ */
+
+#ifdef CONFIG_TI_COMPILER
+#define __BIG_ENDIAN 4321
+#define __LITTLE_ENDIAN 1234
+#ifdef __big_endian__
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+#endif /* CONFIG_TI_COMPILER */
+
+#ifdef __SYMBIAN32__
+#define __BIG_ENDIAN 4321
+#define __LITTLE_ENDIAN 1234
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif /* __SYMBIAN32__ */
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+
+typedef int socklen_t;
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0 /* not supported */
+#endif
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#ifdef _MSC_VER
+#define inline __inline
+
+#undef vsnprintf
+#define vsnprintf _vsnprintf
+#undef close
+#define close closesocket
+#endif /* _MSC_VER */
+
+
+/* Define platform specific integer types */
+
+#ifdef _MSC_VER
+typedef UINT64 u64;
+typedef UINT32 u32;
+typedef UINT16 u16;
+typedef UINT8 u8;
+typedef INT64 s64;
+typedef INT32 s32;
+typedef INT16 s16;
+typedef INT8 s8;
+#define WPA_TYPES_DEFINED
+#endif /* _MSC_VER */
+
+#ifdef __vxworks
+typedef unsigned long long u64;
+typedef UINT32 u32;
+typedef UINT16 u16;
+typedef UINT8 u8;
+typedef long long s64;
+typedef INT32 s32;
+typedef INT16 s16;
+typedef INT8 s8;
+#define WPA_TYPES_DEFINED
+#endif /* __vxworks */
+
+#ifdef CONFIG_TI_COMPILER
+#ifdef _LLONG_AVAILABLE
+typedef unsigned long long u64;
+#else
+/*
+ * TODO: 64-bit variable not available. Using long as a workaround to test the
+ * build, but this will likely not work for all operations.
+ */
+typedef unsigned long u64;
+#endif
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+#define WPA_TYPES_DEFINED
+#endif /* CONFIG_TI_COMPILER */
+
+#ifdef __SYMBIAN32__
+#define __REMOVE_PLATSEC_DIAGNOSTICS__
+#include <e32def.h>
+typedef TUint64 u64;
+typedef TUint32 u32;
+typedef TUint16 u16;
+typedef TUint8 u8;
+#define WPA_TYPES_DEFINED
+#endif /* __SYMBIAN32__ */
+
+#ifndef WPA_TYPES_DEFINED
+#ifdef CONFIG_USE_INTTYPES_H
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t s8;
+#define WPA_TYPES_DEFINED
+#endif /* !WPA_TYPES_DEFINED */
+
+
+/* Define platform specific byte swapping macros */
+
+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+
+static inline unsigned short wpa_swap_16(unsigned short v)
+{
+ return ((v & 0xff) << 8) | (v >> 8);
+}
+
+static inline unsigned int wpa_swap_32(unsigned int v)
+{
+ return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
+ ((v & 0xff0000) >> 8) | (v >> 24);
+}
+
+#define le_to_host16(n) (n)
+#define host_to_le16(n) (n)
+#define be_to_host16(n) wpa_swap_16(n)
+#define host_to_be16(n) wpa_swap_16(n)
+#define le_to_host32(n) (n)
+#define be_to_host32(n) wpa_swap_32(n)
+#define host_to_be32(n) wpa_swap_32(n)
+
+#define WPA_BYTE_SWAP_DEFINED
+
+#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */
+
+
+#ifndef WPA_BYTE_SWAP_DEFINED
+
+#ifndef __BYTE_ORDER
+#ifndef __LITTLE_ENDIAN
+#ifndef __BIG_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#if defined(sparc)
+#define __BYTE_ORDER __BIG_ENDIAN
+#endif
+#endif /* __BIG_ENDIAN */
+#endif /* __LITTLE_ENDIAN */
+#endif /* __BYTE_ORDER */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define le_to_host16(n) ((__force u16) (le16) (n))
+#define host_to_le16(n) ((__force le16) (u16) (n))
+#define be_to_host16(n) bswap_16((__force u16) (be16) (n))
+#define host_to_be16(n) ((__force be16) bswap_16((n)))
+#define le_to_host32(n) ((__force u32) (le32) (n))
+#define host_to_le32(n) ((__force le32) (u32) (n))
+#define be_to_host32(n) bswap_32((__force u32) (be32) (n))
+#define host_to_be32(n) ((__force be32) bswap_32((n)))
+#define le_to_host64(n) ((__force u64) (le64) (n))
+#define host_to_le64(n) ((__force le64) (u64) (n))
+#define be_to_host64(n) bswap_64((__force u64) (be64) (n))
+#define host_to_be64(n) ((__force be64) bswap_64((n)))
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define le_to_host16(n) bswap_16(n)
+#define host_to_le16(n) bswap_16(n)
+#define be_to_host16(n) (n)
+#define host_to_be16(n) (n)
+#define le_to_host32(n) bswap_32(n)
+#define be_to_host32(n) (n)
+#define host_to_be32(n) (n)
+#define le_to_host64(n) bswap_64(n)
+#define host_to_le64(n) bswap_64(n)
+#define be_to_host64(n) (n)
+#define host_to_be64(n) (n)
+#ifndef WORDS_BIGENDIAN
+#define WORDS_BIGENDIAN
+#endif
+#else
+#error Could not determine CPU byte order
+#endif
+
+#define WPA_BYTE_SWAP_DEFINED
+#endif /* !WPA_BYTE_SWAP_DEFINED */
+
+
+/* Macros for handling unaligned memory accesses */
+
+#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
+#define WPA_PUT_BE16(a, val) \
+ do { \
+ (a)[0] = ((u16) (val)) >> 8; \
+ (a)[1] = ((u16) (val)) & 0xff; \
+ } while (0)
+
+#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
+#define WPA_PUT_LE16(a, val) \
+ do { \
+ (a)[1] = ((u16) (val)) >> 8; \
+ (a)[0] = ((u16) (val)) & 0xff; \
+ } while (0)
+
+#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
+ ((u32) (a)[2]))
+#define WPA_PUT_BE24(a, val) \
+ do { \
+ (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \
+ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
+ (a)[2] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
+ (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
+#define WPA_PUT_BE32(a, val) \
+ do { \
+ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \
+ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \
+ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \
+ (a)[3] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
+ (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
+#define WPA_PUT_LE32(a, val) \
+ do { \
+ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \
+ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \
+ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
+ (a)[0] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
+ (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
+ (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
+ (((u64) (a)[6]) << 8) | ((u64) (a)[7]))
+#define WPA_PUT_BE64(a, val) \
+ do { \
+ (a)[0] = (u8) (((u64) (val)) >> 56); \
+ (a)[1] = (u8) (((u64) (val)) >> 48); \
+ (a)[2] = (u8) (((u64) (val)) >> 40); \
+ (a)[3] = (u8) (((u64) (val)) >> 32); \
+ (a)[4] = (u8) (((u64) (val)) >> 24); \
+ (a)[5] = (u8) (((u64) (val)) >> 16); \
+ (a)[6] = (u8) (((u64) (val)) >> 8); \
+ (a)[7] = (u8) (((u64) (val)) & 0xff); \
+ } while (0)
+
+#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
+ (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
+ (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
+ (((u64) (a)[1]) << 8) | ((u64) (a)[0]))
+
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_P_ALL
+#define ETH_P_ALL 0x0003
+#endif
+#ifndef ETH_P_80211_ENCAP
+#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
+#endif
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+#ifndef ETH_P_EAPOL
+#define ETH_P_EAPOL ETH_P_PAE
+#endif /* ETH_P_EAPOL */
+#ifndef ETH_P_RSN_PREAUTH
+#define ETH_P_RSN_PREAUTH 0x88c7
+#endif /* ETH_P_RSN_PREAUTH */
+#ifndef ETH_P_RRB
+#define ETH_P_RRB 0x890D
+#endif /* ETH_P_RRB */
+
+
+#ifdef __GNUC__
+#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
+#define STRUCT_PACKED __attribute__ ((packed))
+#else
+#define PRINTF_FORMAT(a,b)
+#define STRUCT_PACKED
+#endif
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+/* snprintf - used in number of places; sprintf() is _not_ a good replacement
+ * due to possible buffer overflow; see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for portable implementation of
+ * snprintf. */
+int snprintf(char *str, size_t size, const char *format, ...);
+
+/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
+
+/* getopt - only used in main.c */
+int getopt(int argc, char *const argv[], const char *optstring);
+extern char *optarg;
+extern int optind;
+
+#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
+#ifndef __socklen_t_defined
+typedef int socklen_t;
+#endif
+#endif
+
+/* inline - define as __inline or just define it to be empty, if needed */
+#ifdef CONFIG_NO_INLINE
+#define inline
+#else
+#define inline __inline
+#endif
+
+#ifndef __func__
+#define __func__ "__func__ not defined"
+#endif
+
+#ifndef bswap_16
+#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff))
+#endif
+
+#ifndef bswap_32
+#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \
+ (((u32) (a) << 8) & 0xff0000) | \
+ (((u32) (a) >> 8) & 0xff00) | \
+ (((u32) (a) >> 24) & 0xff))
+#endif
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0
+#endif
+
+#ifdef _WIN32_WCE
+void perror(const char *s);
+#endif /* _WIN32_WCE */
+
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+#ifndef MAC2STR
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/*
+ * Compact form for string representation of MAC address
+ * To be used, e.g., for constructing dbus paths for P2P Devices
+ */
+#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x"
+#endif
+
+#ifndef BIT
+#define BIT(x) (1 << (x))
+#endif
+
+/*
+ * Definitions for sparse validation
+ * (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
+ */
+#ifdef __CHECKER__
+#define __force __attribute__((force))
+#define __bitwise __attribute__((bitwise))
+#else
+#define __force
+#define __bitwise
+#endif
+
+typedef u16 __bitwise be16;
+typedef u16 __bitwise le16;
+typedef u32 __bitwise be32;
+typedef u32 __bitwise le32;
+typedef u64 __bitwise be64;
+typedef u64 __bitwise le64;
+
+#ifndef __must_check
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define __must_check __attribute__((__warn_unused_result__))
+#else
+#define __must_check
+#endif /* __GNUC__ */
+#endif /* __must_check */
+
+int hwaddr_aton(const char *txt, u8 *addr);
+int hwaddr_compact_aton(const char *txt, u8 *addr);
+int hwaddr_aton2(const char *txt, u8 *addr);
+int hex2byte(const char *hex);
+int hexstr2bin(const char *hex, u8 *buf, size_t len);
+void inc_byte_array(u8 *counter, size_t len);
+void wpa_get_ntp_timestamp(u8 *buf);
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+ size_t len);
+
+#ifdef CONFIG_NATIVE_WINDOWS
+void wpa_unicode2ascii_inplace(TCHAR *str);
+TCHAR * wpa_strdup_tchar(const char *str);
+#else /* CONFIG_NATIVE_WINDOWS */
+#define wpa_unicode2ascii_inplace(s) do { } while (0)
+#define wpa_strdup_tchar(s) strdup((s))
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
+
+static inline int is_zero_ether_addr(const u8 *a)
+{
+ return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
+}
+
+static inline int is_broadcast_ether_addr(const u8 *a)
+{
+ return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
+}
+
+#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
+
+#include "wpa_debug.h"
+
+
+/*
+ * gcc 4.4 ends up generating strict-aliasing warnings about some very common
+ * networking socket uses that do not really result in a real problem and
+ * cannot be easily avoided with union-based type-punning due to struct
+ * definitions including another struct in system header files. To avoid having
+ * to fully disable strict-aliasing warnings, provide a mechanism to hide the
+ * typecast from aliasing for now. A cleaner solution will hopefully be found
+ * in the future to handle these cases.
+ */
+void * __hide_aliasing_typecast(void *foo);
+#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
+
+#ifdef CONFIG_VALGRIND
+#include <valgrind/memcheck.h>
+#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
+#else /* CONFIG_VALGRIND */
+#define WPA_MEM_DEFINED(ptr, len) do { } while (0)
+#endif /* CONFIG_VALGRIND */
+
+#endif /* COMMON_H */
diff --git a/src/utils/edit.c b/src/utils/edit.c
new file mode 100644
index 0000000..8f9e4ed
--- /dev/null
+++ b/src/utils/edit.c
@@ -0,0 +1,1161 @@
+/*
+ * Command line editing and history
+ * Copyright (c) 2010, Jouni Malinen <j@w1.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 "includes.h"
+#include <termios.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "list.h"
+#include "edit.h"
+
+#define CMD_BUF_LEN 256
+static char cmdbuf[CMD_BUF_LEN];
+static int cmdbuf_pos = 0;
+static int cmdbuf_len = 0;
+
+#define HISTORY_MAX 100
+
+struct edit_history {
+ struct dl_list list;
+ char str[1];
+};
+
+static struct dl_list history_list;
+static struct edit_history *history_curr;
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
+ NULL;
+
+static struct termios prevt, newt;
+
+
+#define CLEAR_END_LINE "\e[K"
+
+
+void edit_clear_line(void)
+{
+ int i;
+ putchar('\r');
+ for (i = 0; i < cmdbuf_len + 2; i++)
+ putchar(' ');
+}
+
+
+static void move_start(void)
+{
+ cmdbuf_pos = 0;
+ edit_redraw();
+}
+
+
+static void move_end(void)
+{
+ cmdbuf_pos = cmdbuf_len;
+ edit_redraw();
+}
+
+
+static void move_left(void)
+{
+ if (cmdbuf_pos > 0) {
+ cmdbuf_pos--;
+ edit_redraw();
+ }
+}
+
+
+static void move_right(void)
+{
+ if (cmdbuf_pos < cmdbuf_len) {
+ cmdbuf_pos++;
+ edit_redraw();
+ }
+}
+
+
+static void move_word_left(void)
+{
+ while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ')
+ cmdbuf_pos--;
+ while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ')
+ cmdbuf_pos--;
+ edit_redraw();
+}
+
+
+static void move_word_right(void)
+{
+ while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ')
+ cmdbuf_pos++;
+ while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ')
+ cmdbuf_pos++;
+ edit_redraw();
+}
+
+
+static void delete_left(void)
+{
+ if (cmdbuf_pos == 0)
+ return;
+
+ edit_clear_line();
+ os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos,
+ cmdbuf_len - cmdbuf_pos);
+ cmdbuf_pos--;
+ cmdbuf_len--;
+ edit_redraw();
+}
+
+
+static void delete_current(void)
+{
+ if (cmdbuf_pos == cmdbuf_len)
+ return;
+
+ edit_clear_line();
+ os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1,
+ cmdbuf_len - cmdbuf_pos);
+ cmdbuf_len--;
+ edit_redraw();
+}
+
+
+static void delete_word(void)
+{
+ int pos;
+
+ edit_clear_line();
+ pos = cmdbuf_pos;
+ while (pos > 0 && cmdbuf[pos - 1] == ' ')
+ pos--;
+ while (pos > 0 && cmdbuf[pos - 1] != ' ')
+ pos--;
+ os_memmove(cmdbuf + pos, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
+ cmdbuf_len -= cmdbuf_pos - pos;
+ cmdbuf_pos = pos;
+ edit_redraw();
+}
+
+
+static void clear_left(void)
+{
+ if (cmdbuf_pos == 0)
+ return;
+
+ edit_clear_line();
+ os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos);
+ cmdbuf_len -= cmdbuf_pos;
+ cmdbuf_pos = 0;
+ edit_redraw();
+}
+
+
+static void clear_right(void)
+{
+ if (cmdbuf_pos == cmdbuf_len)
+ return;
+
+ edit_clear_line();
+ cmdbuf_len = cmdbuf_pos;
+ edit_redraw();
+}
+
+
+static void history_add(const char *str)
+{
+ struct edit_history *h, *match = NULL, *last = NULL;
+ size_t len, count = 0;
+
+ if (str[0] == '\0')
+ return;
+
+ dl_list_for_each(h, &history_list, struct edit_history, list) {
+ if (os_strcmp(str, h->str) == 0) {
+ match = h;
+ break;
+ }
+ last = h;
+ count++;
+ }
+
+ if (match) {
+ dl_list_del(&h->list);
+ dl_list_add(&history_list, &h->list);
+ history_curr = h;
+ return;
+ }
+
+ if (count >= HISTORY_MAX && last) {
+ dl_list_del(&last->list);
+ os_free(last);
+ }
+
+ len = os_strlen(str);
+ h = os_zalloc(sizeof(*h) + len);
+ if (h == NULL)
+ return;
+ dl_list_add(&history_list, &h->list);
+ os_strlcpy(h->str, str, len + 1);
+ history_curr = h;
+}
+
+
+static void history_use(void)
+{
+ edit_clear_line();
+ cmdbuf_len = cmdbuf_pos = os_strlen(history_curr->str);
+ os_memcpy(cmdbuf, history_curr->str, cmdbuf_len);
+ edit_redraw();
+}
+
+
+static void history_prev(void)
+{
+ if (history_curr == NULL)
+ return;
+
+ if (history_curr ==
+ dl_list_first(&history_list, struct edit_history, list)) {
+ cmdbuf[cmdbuf_len] = '\0';
+ history_add(cmdbuf);
+ }
+
+ history_use();
+
+ if (history_curr ==
+ dl_list_last(&history_list, struct edit_history, list))
+ return;
+
+ history_curr = dl_list_entry(history_curr->list.next,
+ struct edit_history, list);
+}
+
+
+static void history_next(void)
+{
+ if (history_curr == NULL ||
+ history_curr ==
+ dl_list_first(&history_list, struct edit_history, list))
+ return;
+
+ history_curr = dl_list_entry(history_curr->list.prev,
+ struct edit_history, list);
+ history_use();
+}
+
+
+static void history_read(const char *fname)
+{
+ FILE *f;
+ char buf[CMD_BUF_LEN], *pos;
+
+ f = fopen(fname, "r");
+ if (f == NULL)
+ return;
+
+ while (fgets(buf, CMD_BUF_LEN, f)) {
+ for (pos = buf; *pos; pos++) {
+ if (*pos == '\r' || *pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ }
+ history_add(buf);
+ }
+
+ fclose(f);
+}
+
+
+static void history_write(const char *fname,
+ int (*filter_cb)(void *ctx, const char *cmd))
+{
+ FILE *f;
+ struct edit_history *h;
+
+ f = fopen(fname, "w");
+ if (f == NULL)
+ return;
+
+ dl_list_for_each_reverse(h, &history_list, struct edit_history, list) {
+ if (filter_cb && filter_cb(edit_cb_ctx, h->str))
+ continue;
+ fprintf(f, "%s\n", h->str);
+ }
+
+ fclose(f);
+}
+
+
+static void history_debug_dump(void)
+{
+ struct edit_history *h;
+ edit_clear_line();
+ printf("\r");
+ dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
+ printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
+ edit_redraw();
+}
+
+
+static void insert_char(int c)
+{
+ if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1)
+ return;
+ if (cmdbuf_len == cmdbuf_pos) {
+ cmdbuf[cmdbuf_pos++] = c;
+ cmdbuf_len++;
+ putchar(c);
+ fflush(stdout);
+ } else {
+ os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos,
+ cmdbuf_len - cmdbuf_pos);
+ cmdbuf[cmdbuf_pos++] = c;
+ cmdbuf_len++;
+ edit_redraw();
+ }
+}
+
+
+static void process_cmd(void)
+{
+
+ if (cmdbuf_len == 0) {
+ printf("\n> ");
+ fflush(stdout);
+ return;
+ }
+ printf("\n");
+ cmdbuf[cmdbuf_len] = '\0';
+ history_add(cmdbuf);
+ cmdbuf_pos = 0;
+ cmdbuf_len = 0;
+ edit_cmd_cb(edit_cb_ctx, cmdbuf);
+ printf("> ");
+ fflush(stdout);
+}
+
+
+static void free_completions(char **c)
+{
+ int i;
+ if (c == NULL)
+ return;
+ for (i = 0; c[i]; i++)
+ os_free(c[i]);
+ os_free(c);
+}
+
+
+static int filter_strings(char **c, char *str, size_t len)
+{
+ int i, j;
+
+ for (i = 0, j = 0; c[j]; j++) {
+ if (os_strncasecmp(c[j], str, len) == 0) {
+ if (i != j) {
+ c[i] = c[j];
+ c[j] = NULL;
+ }
+ i++;
+ } else {
+ os_free(c[j]);
+ c[j] = NULL;
+ }
+ }
+ c[i] = NULL;
+ return i;
+}
+
+
+static int common_len(const char *a, const char *b)
+{
+ int len = 0;
+ while (a[len] && a[len] == b[len])
+ len++;
+ return len;
+}
+
+
+static int max_common_length(char **c)
+{
+ int len, i;
+
+ len = os_strlen(c[0]);
+ for (i = 1; c[i]; i++) {
+ int same = common_len(c[0], c[i]);
+ if (same < len)
+ len = same;
+ }
+
+ return len;
+}
+
+
+static int cmp_str(const void *a, const void *b)
+{
+ return os_strcmp(* (const char **) a, * (const char **) b);
+}
+
+static void complete(int list)
+{
+ char **c;
+ int i, len, count;
+ int start, end;
+ int room, plen, add_space;
+
+ if (edit_completion_cb == NULL)
+ return;
+
+ cmdbuf[cmdbuf_len] = '\0';
+ c = edit_completion_cb(edit_cb_ctx, cmdbuf, cmdbuf_pos);
+ if (c == NULL)
+ return;
+
+ end = cmdbuf_pos;
+ start = end;
+ while (start > 0 && cmdbuf[start - 1] != ' ')
+ start--;
+ plen = end - start;
+
+ count = filter_strings(c, &cmdbuf[start], plen);
+ if (count == 0) {
+ free_completions(c);
+ return;
+ }
+
+ len = max_common_length(c);
+ if (len <= plen && count > 1) {
+ if (list) {
+ qsort(c, count, sizeof(char *), cmp_str);
+ edit_clear_line();
+ printf("\r");
+ for (i = 0; c[i]; i++)
+ printf("%s%s", i > 0 ? " " : "", c[i]);
+ printf("\n");
+ edit_redraw();
+ }
+ free_completions(c);
+ return;
+ }
+ len -= plen;
+
+ room = sizeof(cmdbuf) - 1 - cmdbuf_len;
+ if (room < len)
+ len = room;
+ add_space = count == 1 && len < room;
+
+ os_memmove(cmdbuf + cmdbuf_pos + len + add_space, cmdbuf + cmdbuf_pos,
+ cmdbuf_len - cmdbuf_pos);
+ os_memcpy(&cmdbuf[cmdbuf_pos - plen], c[0], plen + len);
+ if (add_space)
+ cmdbuf[cmdbuf_pos + len] = ' ';
+
+ cmdbuf_pos += len + add_space;
+ cmdbuf_len += len + add_space;
+
+ edit_redraw();
+
+ free_completions(c);
+}
+
+
+enum edit_key_code {
+ EDIT_KEY_NONE = 256,
+ EDIT_KEY_TAB,
+ EDIT_KEY_UP,
+ EDIT_KEY_DOWN,
+ EDIT_KEY_RIGHT,
+ EDIT_KEY_LEFT,
+ EDIT_KEY_ENTER,
+ EDIT_KEY_BACKSPACE,
+ EDIT_KEY_INSERT,
+ EDIT_KEY_DELETE,
+ EDIT_KEY_HOME,
+ EDIT_KEY_END,
+ EDIT_KEY_PAGE_UP,
+ EDIT_KEY_PAGE_DOWN,
+ EDIT_KEY_F1,
+ EDIT_KEY_F2,
+ EDIT_KEY_F3,
+ EDIT_KEY_F4,
+ EDIT_KEY_F5,
+ EDIT_KEY_F6,
+ EDIT_KEY_F7,
+ EDIT_KEY_F8,
+ EDIT_KEY_F9,
+ EDIT_KEY_F10,
+ EDIT_KEY_F11,
+ EDIT_KEY_F12,
+ EDIT_KEY_CTRL_UP,
+ EDIT_KEY_CTRL_DOWN,
+ EDIT_KEY_CTRL_RIGHT,
+ EDIT_KEY_CTRL_LEFT,
+ EDIT_KEY_CTRL_A,
+ EDIT_KEY_CTRL_B,
+ EDIT_KEY_CTRL_D,
+ EDIT_KEY_CTRL_E,
+ EDIT_KEY_CTRL_F,
+ EDIT_KEY_CTRL_G,
+ EDIT_KEY_CTRL_H,
+ EDIT_KEY_CTRL_J,
+ EDIT_KEY_CTRL_K,
+ EDIT_KEY_CTRL_L,
+ EDIT_KEY_CTRL_N,
+ EDIT_KEY_CTRL_O,
+ EDIT_KEY_CTRL_P,
+ EDIT_KEY_CTRL_R,
+ EDIT_KEY_CTRL_T,
+ EDIT_KEY_CTRL_U,
+ EDIT_KEY_CTRL_V,
+ EDIT_KEY_CTRL_W,
+ EDIT_KEY_ALT_UP,
+ EDIT_KEY_ALT_DOWN,
+ EDIT_KEY_ALT_RIGHT,
+ EDIT_KEY_ALT_LEFT,
+ EDIT_KEY_SHIFT_UP,
+ EDIT_KEY_SHIFT_DOWN,
+ EDIT_KEY_SHIFT_RIGHT,
+ EDIT_KEY_SHIFT_LEFT,
+ EDIT_KEY_ALT_SHIFT_UP,
+ EDIT_KEY_ALT_SHIFT_DOWN,
+ EDIT_KEY_ALT_SHIFT_RIGHT,
+ EDIT_KEY_ALT_SHIFT_LEFT,
+ EDIT_KEY_EOF
+};
+
+static void show_esc_buf(const char *esc_buf, char c, int i)
+{
+ edit_clear_line();
+ printf("\rESC buffer '%s' c='%c' [%d]\n", esc_buf, c, i);
+ edit_redraw();
+}
+
+
+static enum edit_key_code esc_seq_to_key1_no(char last)
+{
+ switch (last) {
+ case 'A':
+ return EDIT_KEY_UP;
+ case 'B':
+ return EDIT_KEY_DOWN;
+ case 'C':
+ return EDIT_KEY_RIGHT;
+ case 'D':
+ return EDIT_KEY_LEFT;
+ default:
+ return EDIT_KEY_NONE;
+ }
+}
+
+
+static enum edit_key_code esc_seq_to_key1_shift(char last)
+{
+ switch (last) {
+ case 'A':
+ return EDIT_KEY_SHIFT_UP;
+ case 'B':
+ return EDIT_KEY_SHIFT_DOWN;
+ case 'C':
+ return EDIT_KEY_SHIFT_RIGHT;
+ case 'D':
+ return EDIT_KEY_SHIFT_LEFT;
+ default:
+ return EDIT_KEY_NONE;
+ }
+}
+
+
+static enum edit_key_code esc_seq_to_key1_alt(char last)
+{
+ switch (last) {
+ case 'A':
+ return EDIT_KEY_ALT_UP;
+ case 'B':
+ return EDIT_KEY_ALT_DOWN;
+ case 'C':
+ return EDIT_KEY_ALT_RIGHT;
+ case 'D':
+ return EDIT_KEY_ALT_LEFT;
+ default:
+ return EDIT_KEY_NONE;
+ }
+}
+
+
+static enum edit_key_code esc_seq_to_key1_alt_shift(char last)
+{
+ switch (last) {
+ case 'A':
+ return EDIT_KEY_ALT_SHIFT_UP;
+ case 'B':
+ return EDIT_KEY_ALT_SHIFT_DOWN;
+ case 'C':
+ return EDIT_KEY_ALT_SHIFT_RIGHT;
+ case 'D':
+ return EDIT_KEY_ALT_SHIFT_LEFT;
+ default:
+ return EDIT_KEY_NONE;
+ }
+}
+
+
+static enum edit_key_code esc_seq_to_key1_ctrl(char last)
+{
+ switch (last) {
+ case 'A':
+ return EDIT_KEY_CTRL_UP;
+ case 'B':
+ return EDIT_KEY_CTRL_DOWN;
+ case 'C':
+ return EDIT_KEY_CTRL_RIGHT;
+ case 'D':
+ return EDIT_KEY_CTRL_LEFT;
+ default:
+ return EDIT_KEY_NONE;
+ }
+}
+
+
+static enum edit_key_code esc_seq_to_key1(int param1, int param2, char last)
+{
+ /* ESC-[<param1>;<param2><last> */
+
+ if (param1 < 0 && param2 < 0)
+ return esc_seq_to_key1_no(last);
+
+ if (param1 == 1 && param2 == 2)
+ return esc_seq_to_key1_shift(last);
+
+ if (param1 == 1 && param2 == 3)
+ return esc_seq_to_key1_alt(last);
+
+ if (param1 == 1 && param2 == 4)
+ return esc_seq_to_key1_alt_shift(last);
+
+ if (param1 == 1 && param2 == 5)
+ return esc_seq_to_key1_ctrl(last);
+
+ if (param2 < 0) {
+ if (last != '~')
+ return EDIT_KEY_NONE;
+ switch (param1) {
+ case 2:
+ return EDIT_KEY_INSERT;
+ case 3:
+ return EDIT_KEY_DELETE;
+ case 5:
+ return EDIT_KEY_PAGE_UP;
+ case 6:
+ return EDIT_KEY_PAGE_DOWN;
+ case 15:
+ return EDIT_KEY_F5;
+ case 17:
+ return EDIT_KEY_F6;
+ case 18:
+ return EDIT_KEY_F7;
+ case 19:
+ return EDIT_KEY_F8;
+ case 20:
+ return EDIT_KEY_F9;
+ case 21:
+ return EDIT_KEY_F10;
+ case 23:
+ return EDIT_KEY_F11;
+ case 24:
+ return EDIT_KEY_F12;
+ }
+ }
+
+ return EDIT_KEY_NONE;
+}
+
+
+static enum edit_key_code esc_seq_to_key2(int param1, int param2, char last)
+{
+ /* ESC-O<param1>;<param2><last> */
+
+ if (param1 >= 0 || param2 >= 0)
+ return EDIT_KEY_NONE;
+
+ switch (last) {
+ case 'F':
+ return EDIT_KEY_END;
+ case 'H':
+ return EDIT_KEY_HOME;
+ case 'P':
+ return EDIT_KEY_F1;
+ case 'Q':
+ return EDIT_KEY_F2;
+ case 'R':
+ return EDIT_KEY_F3;
+ case 'S':
+ return EDIT_KEY_F4;
+ default:
+ return EDIT_KEY_NONE;
+ }
+}
+
+
+static enum edit_key_code esc_seq_to_key(char *seq)
+{
+ char last, *pos;
+ int param1 = -1, param2 = -1;
+ enum edit_key_code ret = EDIT_KEY_NONE;
+
+ last = '\0';
+ for (pos = seq; *pos; pos++)
+ last = *pos;
+
+ if (seq[1] >= '0' && seq[1] <= '9') {
+ param1 = atoi(&seq[1]);
+ pos = os_strchr(seq, ';');
+ if (pos)
+ param2 = atoi(pos + 1);
+ }
+
+ if (seq[0] == '[')
+ ret = esc_seq_to_key1(param1, param2, last);
+ else if (seq[0] == 'O')
+ ret = esc_seq_to_key2(param1, param2, last);
+
+ if (ret != EDIT_KEY_NONE)
+ return ret;
+
+ edit_clear_line();
+ printf("\rUnknown escape sequence '%s'\n", seq);
+ edit_redraw();
+ return EDIT_KEY_NONE;
+}
+
+
+static enum edit_key_code edit_read_key(int sock)
+{
+ int c;
+ unsigned char buf[1];
+ int res;
+ static int esc = -1;
+ static char esc_buf[7];
+
+ res = read(sock, buf, 1);
+ if (res < 0)
+ perror("read");
+ if (res <= 0)
+ return EDIT_KEY_EOF;
+
+ c = buf[0];
+
+ if (esc >= 0) {
+ if (c == 27 /* ESC */) {
+ esc = 0;
+ return EDIT_KEY_NONE;
+ }
+
+ if (esc == 6) {
+ show_esc_buf(esc_buf, c, 0);
+ esc = -1;
+ } else {
+ esc_buf[esc++] = c;
+ esc_buf[esc] = '\0';
+ }
+ }
+
+ if (esc == 1) {
+ if (esc_buf[0] != '[' && esc_buf[0] != 'O') {
+ show_esc_buf(esc_buf, c, 1);
+ esc = -1;
+ return EDIT_KEY_NONE;
+ } else
+ return EDIT_KEY_NONE; /* Escape sequence continues */
+ }
+
+ if (esc > 1) {
+ if ((c >= '0' && c <= '9') || c == ';')
+ return EDIT_KEY_NONE; /* Escape sequence continues */
+
+ if (c == '~' || (c >= 'A' && c <= 'Z')) {
+ esc = -1;
+ return esc_seq_to_key(esc_buf);
+ }
+
+ show_esc_buf(esc_buf, c, 2);
+ esc = -1;
+ return EDIT_KEY_NONE;
+ }
+
+ switch (c) {
+ case 1:
+ return EDIT_KEY_CTRL_A;
+ case 2:
+ return EDIT_KEY_CTRL_B;
+ case 4:
+ return EDIT_KEY_CTRL_D;
+ case 5:
+ return EDIT_KEY_CTRL_E;
+ case 6:
+ return EDIT_KEY_CTRL_F;
+ case 7:
+ return EDIT_KEY_CTRL_G;
+ case 8:
+ return EDIT_KEY_CTRL_H;
+ case 9:
+ return EDIT_KEY_TAB;
+ case 10:
+ return EDIT_KEY_CTRL_J;
+ case 13: /* CR */
+ return EDIT_KEY_ENTER;
+ case 11:
+ return EDIT_KEY_CTRL_K;
+ case 12:
+ return EDIT_KEY_CTRL_L;
+ case 14:
+ return EDIT_KEY_CTRL_N;
+ case 15:
+ return EDIT_KEY_CTRL_O;
+ case 16:
+ return EDIT_KEY_CTRL_P;
+ case 18:
+ return EDIT_KEY_CTRL_R;
+ case 20:
+ return EDIT_KEY_CTRL_T;
+ case 21:
+ return EDIT_KEY_CTRL_U;
+ case 22:
+ return EDIT_KEY_CTRL_V;
+ case 23:
+ return EDIT_KEY_CTRL_W;
+ case 27: /* ESC */
+ esc = 0;
+ return EDIT_KEY_NONE;
+ case 127:
+ return EDIT_KEY_BACKSPACE;
+ default:
+ return c;
+ }
+}
+
+
+static char search_buf[21];
+static int search_skip;
+
+static char * search_find(void)
+{
+ struct edit_history *h;
+ size_t len = os_strlen(search_buf);
+ int skip = search_skip;
+
+ if (len == 0)
+ return NULL;
+
+ dl_list_for_each(h, &history_list, struct edit_history, list) {
+ if (os_strstr(h->str, search_buf)) {
+ if (skip == 0)
+ return h->str;
+ skip--;
+ }
+ }
+
+ search_skip = 0;
+ return NULL;
+}
+
+
+static void search_redraw(void)
+{
+ char *match = search_find();
+ printf("\rsearch '%s': %s" CLEAR_END_LINE,
+ search_buf, match ? match : "");
+ printf("\rsearch '%s", search_buf);
+ fflush(stdout);
+}
+
+
+static void search_start(void)
+{
+ edit_clear_line();
+ search_buf[0] = '\0';
+ search_skip = 0;
+ search_redraw();
+}
+
+
+static void search_clear(void)
+{
+ search_redraw();
+ printf("\r" CLEAR_END_LINE);
+}
+
+
+static void search_stop(void)
+{
+ char *match = search_find();
+ search_buf[0] = '\0';
+ search_clear();
+ if (match) {
+ os_strlcpy(cmdbuf, match, CMD_BUF_LEN);
+ cmdbuf_len = os_strlen(cmdbuf);
+ cmdbuf_pos = cmdbuf_len;
+ }
+ edit_redraw();
+}
+
+
+static void search_cancel(void)
+{
+ search_buf[0] = '\0';
+ search_clear();
+ edit_redraw();
+}
+
+
+static void search_backspace(void)
+{
+ size_t len;
+ len = os_strlen(search_buf);
+ if (len == 0)
+ return;
+ search_buf[len - 1] = '\0';
+ search_skip = 0;
+ search_redraw();
+}
+
+
+static void search_next(void)
+{
+ search_skip++;
+ search_find();
+ search_redraw();
+}
+
+
+static void search_char(char c)
+{
+ size_t len;
+ len = os_strlen(search_buf);
+ if (len == sizeof(search_buf) - 1)
+ return;
+ search_buf[len] = c;
+ search_buf[len + 1] = '\0';
+ search_skip = 0;
+ search_redraw();
+}
+
+
+static enum edit_key_code search_key(enum edit_key_code c)
+{
+ switch (c) {
+ case EDIT_KEY_ENTER:
+ case EDIT_KEY_CTRL_J:
+ case EDIT_KEY_LEFT:
+ case EDIT_KEY_RIGHT:
+ case EDIT_KEY_HOME:
+ case EDIT_KEY_END:
+ case EDIT_KEY_CTRL_A:
+ case EDIT_KEY_CTRL_E:
+ search_stop();
+ return c;
+ case EDIT_KEY_DOWN:
+ case EDIT_KEY_UP:
+ search_cancel();
+ return EDIT_KEY_EOF;
+ case EDIT_KEY_CTRL_H:
+ case EDIT_KEY_BACKSPACE:
+ search_backspace();
+ break;
+ case EDIT_KEY_CTRL_R:
+ search_next();
+ break;
+ default:
+ if (c >= 32 && c <= 255)
+ search_char(c);
+ break;
+ }
+
+ return EDIT_KEY_NONE;
+}
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ static int last_tab = 0;
+ static int search = 0;
+ enum edit_key_code c;
+
+ c = edit_read_key(sock);
+
+ if (search) {
+ c = search_key(c);
+ if (c == EDIT_KEY_NONE)
+ return;
+ search = 0;
+ if (c == EDIT_KEY_EOF)
+ return;
+ }
+
+ if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE)
+ last_tab = 0;
+
+ switch (c) {
+ case EDIT_KEY_NONE:
+ break;
+ case EDIT_KEY_EOF:
+ edit_eof_cb(edit_cb_ctx);
+ break;
+ case EDIT_KEY_TAB:
+ complete(last_tab);
+ last_tab = 1;
+ break;
+ case EDIT_KEY_UP:
+ case EDIT_KEY_CTRL_P:
+ history_prev();
+ break;
+ case EDIT_KEY_DOWN:
+ case EDIT_KEY_CTRL_N:
+ history_next();
+ break;
+ case EDIT_KEY_RIGHT:
+ case EDIT_KEY_CTRL_F:
+ move_right();
+ break;
+ case EDIT_KEY_LEFT:
+ case EDIT_KEY_CTRL_B:
+ move_left();
+ break;
+ case EDIT_KEY_CTRL_RIGHT:
+ move_word_right();
+ break;
+ case EDIT_KEY_CTRL_LEFT:
+ move_word_left();
+ break;
+ case EDIT_KEY_DELETE:
+ delete_current();
+ break;
+ case EDIT_KEY_END:
+ move_end();
+ break;
+ case EDIT_KEY_HOME:
+ case EDIT_KEY_CTRL_A:
+ move_start();
+ break;
+ case EDIT_KEY_F2:
+ history_debug_dump();
+ break;
+ case EDIT_KEY_CTRL_D:
+ if (cmdbuf_len > 0) {
+ delete_current();
+ return;
+ }
+ printf("\n");
+ edit_eof_cb(edit_cb_ctx);
+ break;
+ case EDIT_KEY_CTRL_E:
+ move_end();
+ break;
+ case EDIT_KEY_CTRL_H:
+ case EDIT_KEY_BACKSPACE:
+ delete_left();
+ break;
+ case EDIT_KEY_ENTER:
+ case EDIT_KEY_CTRL_J:
+ process_cmd();
+ break;
+ case EDIT_KEY_CTRL_K:
+ clear_right();
+ break;
+ case EDIT_KEY_CTRL_L:
+ edit_clear_line();
+ edit_redraw();
+ break;
+ case EDIT_KEY_CTRL_R:
+ search = 1;
+ search_start();
+ break;
+ case EDIT_KEY_CTRL_U:
+ clear_left();
+ break;
+ case EDIT_KEY_CTRL_W:
+ delete_word();
+ break;
+ default:
+ if (c >= 32 && c <= 255)
+ insert_char(c);
+ break;
+ }
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+ void (*eof_cb)(void *ctx),
+ char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+ void *ctx, const char *history_file)
+{
+ dl_list_init(&history_list);
+ history_curr = NULL;
+ if (history_file)
+ history_read(history_file);
+
+ edit_cb_ctx = ctx;
+ edit_cmd_cb = cmd_cb;
+ edit_eof_cb = eof_cb;
+ edit_completion_cb = completion_cb;
+
+ tcgetattr(STDIN_FILENO, &prevt);
+ newt = prevt;
+ newt.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+
+ eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+
+ printf("> ");
+ fflush(stdout);
+
+ return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+ int (*filter_cb)(void *ctx, const char *cmd))
+{
+ struct edit_history *h;
+ if (history_file)
+ history_write(history_file, filter_cb);
+ while ((h = dl_list_first(&history_list, struct edit_history, list))) {
+ dl_list_del(&h->list);
+ os_free(h);
+ }
+ edit_clear_line();
+ putchar('\r');
+ fflush(stdout);
+ eloop_unregister_read_sock(STDIN_FILENO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &prevt);
+}
+
+
+void edit_redraw(void)
+{
+ char tmp;
+ cmdbuf[cmdbuf_len] = '\0';
+ printf("\r> %s", cmdbuf);
+ if (cmdbuf_pos != cmdbuf_len) {
+ tmp = cmdbuf[cmdbuf_pos];
+ cmdbuf[cmdbuf_pos] = '\0';
+ printf("\r> %s", cmdbuf);
+ cmdbuf[cmdbuf_pos] = tmp;
+ }
+ fflush(stdout);
+}
diff --git a/src/utils/edit.h b/src/utils/edit.h
new file mode 100644
index 0000000..fc4474b
--- /dev/null
+++ b/src/utils/edit.h
@@ -0,0 +1,27 @@
+/*
+ * Command line editing and history
+ * Copyright (c) 2010, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef EDIT_H
+#define EDIT_H
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+ void (*eof_cb)(void *ctx),
+ char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+ void *ctx, const char *history_file);
+void edit_deinit(const char *history_file,
+ int (*filter_cb)(void *ctx, const char *cmd));
+void edit_clear_line(void);
+void edit_redraw(void);
+
+#endif /* EDIT_H */
diff --git a/src/utils/edit_readline.c b/src/utils/edit_readline.c
new file mode 100644
index 0000000..1fef7b9
--- /dev/null
+++ b/src/utils/edit_readline.c
@@ -0,0 +1,184 @@
+/*
+ * Command line editing and history wrapper for readline
+ * Copyright (c) 2010, Jouni Malinen <j@w1.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 "includes.h"
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "edit.h"
+
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) =
+ NULL;
+
+static char **pending_completions = NULL;
+
+
+static void readline_free_completions(void)
+{
+ int i;
+ if (pending_completions == NULL)
+ return;
+ for (i = 0; pending_completions[i]; i++)
+ os_free(pending_completions[i]);
+ os_free(pending_completions);
+ pending_completions = NULL;
+}
+
+
+static char * readline_completion_func(const char *text, int state)
+{
+ static int pos = 0;
+ static size_t len = 0;
+
+ if (pending_completions == NULL) {
+ rl_attempted_completion_over = 1;
+ return NULL;
+ }
+
+ if (state == 0) {
+ pos = 0;
+ len = os_strlen(text);
+ }
+ for (; pending_completions[pos]; pos++) {
+ if (strncmp(pending_completions[pos], text, len) == 0)
+ return strdup(pending_completions[pos++]);
+ }
+
+ rl_attempted_completion_over = 1;
+ return NULL;
+}
+
+
+static char ** readline_completion(const char *text, int start, int end)
+{
+ readline_free_completions();
+ if (edit_completion_cb)
+ pending_completions = edit_completion_cb(edit_cb_ctx,
+ rl_line_buffer, end);
+ return rl_completion_matches(text, readline_completion_func);
+}
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ rl_callback_read_char();
+}
+
+
+static void trunc_nl(char *str)
+{
+ char *pos = str;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+}
+
+
+static void readline_cmd_handler(char *cmd)
+{
+ if (cmd && *cmd) {
+ HIST_ENTRY *h;
+ while (next_history())
+ ;
+ h = previous_history();
+ if (h == NULL || os_strcmp(cmd, h->line) != 0)
+ add_history(cmd);
+ next_history();
+ }
+ if (cmd == NULL) {
+ edit_eof_cb(edit_cb_ctx);
+ return;
+ }
+ trunc_nl(cmd);
+ edit_cmd_cb(edit_cb_ctx, cmd);
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+ void (*eof_cb)(void *ctx),
+ char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+ void *ctx, const char *history_file)
+{
+ edit_cb_ctx = ctx;
+ edit_cmd_cb = cmd_cb;
+ edit_eof_cb = eof_cb;
+ edit_completion_cb = completion_cb;
+
+ rl_attempted_completion_function = readline_completion;
+ if (history_file) {
+ read_history(history_file);
+ stifle_history(100);
+ }
+
+ eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+
+ rl_callback_handler_install("> ", readline_cmd_handler);
+
+ return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+ int (*filter_cb)(void *ctx, const char *cmd))
+{
+ rl_callback_handler_remove();
+ readline_free_completions();
+
+ eloop_unregister_read_sock(STDIN_FILENO);
+
+ if (history_file) {
+ /* Save command history, excluding lines that may contain
+ * passwords. */
+ HIST_ENTRY *h;
+ history_set_pos(0);
+ while ((h = current_history())) {
+ char *p = h->line;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (filter_cb && filter_cb(edit_cb_ctx, p)) {
+ h = remove_history(where_history());
+ if (h) {
+ os_free(h->line);
+ free(h->data);
+ os_free(h);
+ } else
+ next_history();
+ } else
+ next_history();
+ }
+ write_history(history_file);
+ }
+}
+
+
+void edit_clear_line(void)
+{
+}
+
+
+void edit_redraw(void)
+{
+ rl_on_new_line();
+ rl_redisplay();
+}
diff --git a/src/utils/edit_simple.c b/src/utils/edit_simple.c
new file mode 100644
index 0000000..61fb24e
--- /dev/null
+++ b/src/utils/edit_simple.c
@@ -0,0 +1,96 @@
+/*
+ * Minimal command line editing
+ * Copyright (c) 2010, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "edit.h"
+
+
+#define CMD_BUF_LEN 256
+static char cmdbuf[CMD_BUF_LEN];
+static int cmdbuf_pos = 0;
+
+static void *edit_cb_ctx;
+static void (*edit_cmd_cb)(void *ctx, char *cmd);
+static void (*edit_eof_cb)(void *ctx);
+
+
+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ int c;
+ unsigned char buf[1];
+ int res;
+
+ res = read(sock, buf, 1);
+ if (res < 0)
+ perror("read");
+ if (res <= 0) {
+ edit_eof_cb(edit_cb_ctx);
+ return;
+ }
+ c = buf[0];
+
+ if (c == '\r' || c == '\n') {
+ cmdbuf[cmdbuf_pos] = '\0';
+ cmdbuf_pos = 0;
+ edit_cmd_cb(edit_cb_ctx, cmdbuf);
+ printf("> ");
+ fflush(stdout);
+ return;
+ }
+
+ if (c >= 32 && c <= 255) {
+ if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) {
+ cmdbuf[cmdbuf_pos++] = c;
+ }
+ }
+}
+
+
+int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
+ void (*eof_cb)(void *ctx),
+ char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
+ void *ctx, const char *history_file)
+{
+ edit_cb_ctx = ctx;
+ edit_cmd_cb = cmd_cb;
+ edit_eof_cb = eof_cb;
+ eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+
+ printf("> ");
+ fflush(stdout);
+
+ return 0;
+}
+
+
+void edit_deinit(const char *history_file,
+ int (*filter_cb)(void *ctx, const char *cmd))
+{
+ eloop_unregister_read_sock(STDIN_FILENO);
+}
+
+
+void edit_clear_line(void)
+{
+}
+
+
+void edit_redraw(void)
+{
+ cmdbuf[cmdbuf_pos] = '\0';
+ printf("\r> %s", cmdbuf);
+}
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
new file mode 100644
index 0000000..b550c63
--- /dev/null
+++ b/src/utils/eloop.c
@@ -0,0 +1,627 @@
+/*
+ * Event loop based on select() loop
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+#include "trace.h"
+#include "list.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+ int sock;
+ void *eloop_data;
+ void *user_data;
+ eloop_sock_handler handler;
+ WPA_TRACE_REF(eloop);
+ WPA_TRACE_REF(user);
+ WPA_TRACE_INFO
+};
+
+struct eloop_timeout {
+ struct dl_list list;
+ struct os_time time;
+ void *eloop_data;
+ void *user_data;
+ eloop_timeout_handler handler;
+ WPA_TRACE_REF(eloop);
+ WPA_TRACE_REF(user);
+ WPA_TRACE_INFO
+};
+
+struct eloop_signal {
+ int sig;
+ void *user_data;
+ eloop_signal_handler handler;
+ int signaled;
+};
+
+struct eloop_sock_table {
+ int count;
+ struct eloop_sock *table;
+ int changed;
+};
+
+struct eloop_data {
+ int max_sock;
+
+ struct eloop_sock_table readers;
+ struct eloop_sock_table writers;
+ struct eloop_sock_table exceptions;
+
+ struct dl_list timeout;
+
+ int signal_count;
+ struct eloop_signal *signals;
+ int signaled;
+ int pending_terminate;
+
+ int terminate;
+ int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+#ifdef WPA_TRACE
+
+static void eloop_sigsegv_handler(int sig)
+{
+ wpa_trace_show("eloop SIGSEGV");
+ abort();
+}
+
+static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
+{
+ int i;
+ if (table == NULL || table->table == NULL)
+ return;
+ for (i = 0; i < table->count; i++) {
+ wpa_trace_add_ref(&table->table[i], eloop,
+ table->table[i].eloop_data);
+ wpa_trace_add_ref(&table->table[i], user,
+ table->table[i].user_data);
+ }
+}
+
+
+static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
+{
+ int i;
+ if (table == NULL || table->table == NULL)
+ return;
+ for (i = 0; i < table->count; i++) {
+ wpa_trace_remove_ref(&table->table[i], eloop,
+ table->table[i].eloop_data);
+ wpa_trace_remove_ref(&table->table[i], user,
+ table->table[i].user_data);
+ }
+}
+
+#else /* WPA_TRACE */
+
+#define eloop_trace_sock_add_ref(table) do { } while (0)
+#define eloop_trace_sock_remove_ref(table) do { } while (0)
+
+#endif /* WPA_TRACE */
+
+
+int eloop_init(void)
+{
+ os_memset(&eloop, 0, sizeof(eloop));
+ dl_list_init(&eloop.timeout);
+#ifdef WPA_TRACE
+ signal(SIGSEGV, eloop_sigsegv_handler);
+#endif /* WPA_TRACE */
+ return 0;
+}
+
+
+static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
+ int sock, eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_sock *tmp;
+
+ if (table == NULL)
+ return -1;
+
+ eloop_trace_sock_remove_ref(table);
+ tmp = (struct eloop_sock *)
+ os_realloc(table->table,
+ (table->count + 1) * sizeof(struct eloop_sock));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[table->count].sock = sock;
+ tmp[table->count].eloop_data = eloop_data;
+ tmp[table->count].user_data = user_data;
+ tmp[table->count].handler = handler;
+ wpa_trace_record(&tmp[table->count]);
+ table->count++;
+ table->table = tmp;
+ if (sock > eloop.max_sock)
+ eloop.max_sock = sock;
+ table->changed = 1;
+ eloop_trace_sock_add_ref(table);
+
+ return 0;
+}
+
+
+static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
+ int sock)
+{
+ int i;
+
+ if (table == NULL || table->table == NULL || table->count == 0)
+ return;
+
+ for (i = 0; i < table->count; i++) {
+ if (table->table[i].sock == sock)
+ break;
+ }
+ if (i == table->count)
+ return;
+ eloop_trace_sock_remove_ref(table);
+ if (i != table->count - 1) {
+ os_memmove(&table->table[i], &table->table[i + 1],
+ (table->count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ table->count--;
+ table->changed = 1;
+ eloop_trace_sock_add_ref(table);
+}
+
+
+static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
+ fd_set *fds)
+{
+ int i;
+
+ FD_ZERO(fds);
+
+ if (table->table == NULL)
+ return;
+
+ for (i = 0; i < table->count; i++)
+ FD_SET(table->table[i].sock, fds);
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
+ fd_set *fds)
+{
+ int i;
+
+ if (table == NULL || table->table == NULL)
+ return;
+
+ table->changed = 0;
+ for (i = 0; i < table->count; i++) {
+ if (FD_ISSET(table->table[i].sock, fds)) {
+ table->table[i].handler(table->table[i].sock,
+ table->table[i].eloop_data,
+ table->table[i].user_data);
+ if (table->changed)
+ break;
+ }
+ }
+}
+
+
+static void eloop_sock_table_destroy(struct eloop_sock_table *table)
+{
+ if (table) {
+ int i;
+ for (i = 0; i < table->count && table->table; i++) {
+ wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
+ "sock=%d eloop_data=%p user_data=%p "
+ "handler=%p",
+ table->table[i].sock,
+ table->table[i].eloop_data,
+ table->table[i].user_data,
+ table->table[i].handler);
+ wpa_trace_dump_funcname("eloop unregistered socket "
+ "handler",
+ table->table[i].handler);
+ wpa_trace_dump("eloop sock", &table->table[i]);
+ }
+ os_free(table->table);
+ }
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
+{
+ return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
+ eloop_data, user_data);
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ eloop_unregister_sock(sock, EVENT_TYPE_READ);
+}
+
+
+static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
+{
+ switch (type) {
+ case EVENT_TYPE_READ:
+ return &eloop.readers;
+ case EVENT_TYPE_WRITE:
+ return &eloop.writers;
+ case EVENT_TYPE_EXCEPTION:
+ return &eloop.exceptions;
+ }
+
+ return NULL;
+}
+
+
+int eloop_register_sock(int sock, eloop_event_type type,
+ eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_sock_table *table;
+
+ table = eloop_get_sock_table(type);
+ return eloop_sock_table_add_sock(table, sock, handler,
+ eloop_data, user_data);
+}
+
+
+void eloop_unregister_sock(int sock, eloop_event_type type)
+{
+ struct eloop_sock_table *table;
+
+ table = eloop_get_sock_table(type);
+ eloop_sock_table_remove_sock(table, sock);
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *tmp;
+ os_time_t now_sec;
+
+ timeout = os_zalloc(sizeof(*timeout));
+ if (timeout == NULL)
+ return -1;
+ if (os_get_time(&timeout->time) < 0) {
+ os_free(timeout);
+ return -1;
+ }
+ now_sec = timeout->time.sec;
+ timeout->time.sec += secs;
+ if (timeout->time.sec < now_sec) {
+ /*
+ * Integer overflow - assume long enough timeout to be assumed
+ * to be infinite, i.e., the timeout would never happen.
+ */
+ wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
+ "ever happen - ignore it", secs);
+ os_free(timeout);
+ return 0;
+ }
+ timeout->time.usec += usecs;
+ while (timeout->time.usec >= 1000000) {
+ timeout->time.sec++;
+ timeout->time.usec -= 1000000;
+ }
+ timeout->eloop_data = eloop_data;
+ timeout->user_data = user_data;
+ timeout->handler = handler;
+ wpa_trace_add_ref(timeout, eloop, eloop_data);
+ wpa_trace_add_ref(timeout, user, user_data);
+ wpa_trace_record(timeout);
+
+ /* Maintain timeouts in order of increasing time */
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (os_time_before(&timeout->time, &tmp->time)) {
+ dl_list_add(tmp->list.prev, &timeout->list);
+ return 0;
+ }
+ }
+ dl_list_add_tail(&eloop.timeout, &timeout->list);
+
+ return 0;
+}
+
+
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+ dl_list_del(&timeout->list);
+ wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
+ wpa_trace_remove_ref(timeout, user, timeout->user_data);
+ os_free(timeout);
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *prev;
+ int removed = 0;
+
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data ||
+ eloop_data == ELOOP_ALL_CTX) &&
+ (timeout->user_data == user_data ||
+ user_data == ELOOP_ALL_CTX)) {
+ eloop_remove_timeout(timeout);
+ removed++;
+ }
+ }
+
+ return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *tmp;
+
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static void eloop_handle_alarm(int sig)
+{
+ wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
+ "two seconds. Looks like there\n"
+ "is a bug that ends up in a busy loop that "
+ "prevents clean shutdown.\n"
+ "Killing program forcefully.\n");
+ exit(1);
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static void eloop_handle_signal(int sig)
+{
+ int i;
+
+#ifndef CONFIG_NATIVE_WINDOWS
+ if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
+ /* Use SIGALRM to break out from potential busy loops that
+ * would not allow the program to be killed. */
+ eloop.pending_terminate = 1;
+ signal(SIGALRM, eloop_handle_alarm);
+ alarm(2);
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ eloop.signaled++;
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].sig == sig) {
+ eloop.signals[i].signaled++;
+ break;
+ }
+ }
+}
+
+
+static void eloop_process_pending_signals(void)
+{
+ int i;
+
+ if (eloop.signaled == 0)
+ return;
+ eloop.signaled = 0;
+
+ if (eloop.pending_terminate) {
+#ifndef CONFIG_NATIVE_WINDOWS
+ alarm(0);
+#endif /* CONFIG_NATIVE_WINDOWS */
+ eloop.pending_terminate = 0;
+ }
+
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].signaled) {
+ eloop.signals[i].signaled = 0;
+ eloop.signals[i].handler(eloop.signals[i].sig,
+ eloop.signals[i].user_data);
+ }
+ }
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+ void *user_data)
+{
+ struct eloop_signal *tmp;
+
+ tmp = (struct eloop_signal *)
+ os_realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.signal_count].sig = sig;
+ tmp[eloop.signal_count].user_data = user_data;
+ tmp[eloop.signal_count].handler = handler;
+ tmp[eloop.signal_count].signaled = 0;
+ eloop.signal_count++;
+ eloop.signals = tmp;
+ signal(sig, eloop_handle_signal);
+
+ return 0;
+}
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+ void *user_data)
+{
+ int ret = eloop_register_signal(SIGINT, handler, user_data);
+ if (ret == 0)
+ ret = eloop_register_signal(SIGTERM, handler, user_data);
+ return ret;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+ void *user_data)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+ return eloop_register_signal(SIGHUP, handler, user_data);
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void eloop_run(void)
+{
+ fd_set *rfds, *wfds, *efds;
+ int res;
+ struct timeval _tv;
+ struct os_time tv, now;
+
+ rfds = os_malloc(sizeof(*rfds));
+ wfds = os_malloc(sizeof(*wfds));
+ efds = os_malloc(sizeof(*efds));
+ if (rfds == NULL || wfds == NULL || efds == NULL)
+ goto out;
+
+ while (!eloop.terminate &&
+ (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
+ eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
+ struct eloop_timeout *timeout;
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+ list);
+ if (timeout) {
+ os_get_time(&now);
+ if (os_time_before(&now, &timeout->time))
+ os_time_sub(&timeout->time, &now, &tv);
+ else
+ tv.sec = tv.usec = 0;
+ _tv.tv_sec = tv.sec;
+ _tv.tv_usec = tv.usec;
+ }
+
+ eloop_sock_table_set_fds(&eloop.readers, rfds);
+ eloop_sock_table_set_fds(&eloop.writers, wfds);
+ eloop_sock_table_set_fds(&eloop.exceptions, efds);
+ res = select(eloop.max_sock + 1, rfds, wfds, efds,
+ timeout ? &_tv : NULL);
+ if (res < 0 && errno != EINTR && errno != 0) {
+ perror("select");
+ goto out;
+ }
+ eloop_process_pending_signals();
+
+ /* check if some registered timeouts have occurred */
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+ list);
+ if (timeout) {
+ os_get_time(&now);
+ if (!os_time_before(&now, &timeout->time)) {
+ void *eloop_data = timeout->eloop_data;
+ void *user_data = timeout->user_data;
+ eloop_timeout_handler handler =
+ timeout->handler;
+ eloop_remove_timeout(timeout);
+ handler(eloop_data, user_data);
+ }
+
+ }
+
+ if (res <= 0)
+ continue;
+
+ eloop_sock_table_dispatch(&eloop.readers, rfds);
+ eloop_sock_table_dispatch(&eloop.writers, wfds);
+ eloop_sock_table_dispatch(&eloop.exceptions, efds);
+ }
+
+out:
+ os_free(rfds);
+ os_free(wfds);
+ os_free(efds);
+}
+
+
+void eloop_terminate(void)
+{
+ eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+ struct eloop_timeout *timeout, *prev;
+ struct os_time now;
+
+ os_get_time(&now);
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ int sec, usec;
+ sec = timeout->time.sec - now.sec;
+ usec = timeout->time.usec - now.usec;
+ if (timeout->time.usec < now.usec) {
+ sec--;
+ usec += 1000000;
+ }
+ wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
+ "eloop_data=%p user_data=%p handler=%p",
+ sec, usec, timeout->eloop_data, timeout->user_data,
+ timeout->handler);
+ wpa_trace_dump_funcname("eloop unregistered timeout handler",
+ timeout->handler);
+ wpa_trace_dump("eloop timeout", timeout);
+ eloop_remove_timeout(timeout);
+ }
+ eloop_sock_table_destroy(&eloop.readers);
+ eloop_sock_table_destroy(&eloop.writers);
+ eloop_sock_table_destroy(&eloop.exceptions);
+ os_free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+ return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+ fd_set rfds;
+
+ if (sock < 0)
+ return;
+
+ FD_ZERO(&rfds);
+ FD_SET(sock, &rfds);
+ select(sock + 1, &rfds, NULL, NULL, NULL);
+}
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
new file mode 100644
index 0000000..1228f24
--- /dev/null
+++ b/src/utils/eloop.h
@@ -0,0 +1,316 @@
+/*
+ * Event loop
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.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.
+ *
+ * This file defines an event loop interface that supports processing events
+ * from registered timeouts (i.e., do something after N seconds), sockets
+ * (e.g., a new packet available for reading), and signals. eloop.c is an
+ * implementation of this interface using select() and sockets. This is
+ * suitable for most UNIX/POSIX systems. When porting to other operating
+ * systems, it may be necessary to replace that implementation with OS specific
+ * mechanisms.
+ */
+
+#ifndef ELOOP_H
+#define ELOOP_H
+
+/**
+ * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts
+ */
+#define ELOOP_ALL_CTX (void *) -1
+
+/**
+ * eloop_event_type - eloop socket event type for eloop_register_sock()
+ * @EVENT_TYPE_READ: Socket has data available for reading
+ * @EVENT_TYPE_WRITE: Socket has room for new data to be written
+ * @EVENT_TYPE_EXCEPTION: An exception has been reported
+ */
+typedef enum {
+ EVENT_TYPE_READ = 0,
+ EVENT_TYPE_WRITE,
+ EVENT_TYPE_EXCEPTION
+} eloop_event_type;
+
+/**
+ * eloop_sock_handler - eloop socket event callback type
+ * @sock: File descriptor number for the socket
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
+
+/**
+ * eloop_event_handler - eloop generic event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_timeout_handler - eloop timeout event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_signal_handler - eloop signal event callback type
+ * @sig: Signal number
+ * @signal_ctx: Registered callback context data (user_data from
+ * eloop_register_signal(), eloop_register_signal_terminate(), or
+ * eloop_register_signal_reconfig() call)
+ */
+typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
+
+/**
+ * eloop_init() - Initialize global event loop data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before any other eloop_* function.
+ */
+int eloop_init(void);
+
+/**
+ * eloop_register_read_sock - Register handler for read events
+ * @sock: File descriptor number for the socket
+ * @handler: Callback function to be called when data is available for reading
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a read socket notifier for the given file descriptor. The handler
+ * function will be called whenever data is available for reading from the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_read_sock - Unregister handler for read events
+ * @sock: File descriptor number for the socket
+ *
+ * Unregister a read socket notifier that was previously registered with
+ * eloop_register_read_sock().
+ */
+void eloop_unregister_read_sock(int sock);
+
+/**
+ * eloop_register_sock - Register handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event to wait for
+ * @handler: Callback function to be called when the event is triggered
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event notifier for the given socket's file descriptor. The
+ * handler function will be called whenever the that event is triggered for the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_sock(int sock, eloop_event_type type,
+ eloop_sock_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_sock - Unregister handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event for which sock was registered
+ *
+ * Unregister a socket event notifier that was previously registered with
+ * eloop_register_sock().
+ */
+void eloop_unregister_sock(int sock, eloop_event_type type);
+
+/**
+ * eloop_register_event - Register handler for generic events
+ * @event: Event to wait (eloop implementation specific)
+ * @event_size: Size of event data
+ * @handler: Callback function to be called when event is triggered
+ * @eloop_data: Callback context data (eloop_data)
+ * @user_data: Callback context data (user_data)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event handler for the given event. This function is used to
+ * register eloop implementation specific events which are mainly targetted for
+ * operating system specific code (driver interface and l2_packet) since the
+ * portable code will not be able to use such an OS-specific call. The handler
+ * function will be called whenever the event is triggered. The handler
+ * function is responsible for clearing the event after having processed it in
+ * order to avoid eloop from calling the handler again for the same event.
+ *
+ * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE
+ * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable,
+ * and they would call this function with eloop_register_event(h, sizeof(h),
+ * ...).
+ */
+int eloop_register_event(void *event, size_t event_size,
+ eloop_event_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_event - Unregister handler for a generic event
+ * @event: Event to cancel (eloop implementation specific)
+ * @event_size: Size of event data
+ *
+ * Unregister a generic event notifier that was previously registered with
+ * eloop_register_event().
+ */
+void eloop_unregister_event(void *event, size_t event_size);
+
+/**
+ * eloop_register_timeout - Register timeout
+ * @secs: Number of seconds to the timeout
+ * @usecs: Number of microseconds to the timeout
+ * @handler: Callback function to be called when timeout occurs
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a timeout that will cause the handler function to be called after
+ * given time.
+ */
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ eloop_timeout_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
+ * eloop_cancel_timeout - Cancel timeouts
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all
+ * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeouts registered with
+ * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
+ * cancelling all timeouts regardless of eloop_data/user_data.
+ */
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
+ * eloop_is_timeout_registered - Check if a timeout is already registered
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is registered, 0 if the timeout is not registered
+ *
+ * Determine if a matching <handler,eloop_data,user_data> timeout is registered
+ * with eloop_register_timeout().
+ */
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
+ * eloop_register_signal - Register handler for signals
+ * @sig: Signal number (e.g., SIGHUP)
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a signal is received.
+ * The callback function is actually called only after the system signal
+ * handler has returned. This means that the normal limits for sighandlers
+ * (i.e., only "safe functions" allowed) do not apply for the registered
+ * callback.
+ */
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+ void *user_data);
+
+/**
+ * eloop_register_signal_terminate - Register handler for terminate signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a process termination
+ * signal is received. The callback function is actually called only after the
+ * system signal handler has returned. This means that the normal limits for
+ * sighandlers (i.e., only "safe functions" allowed) do not apply for the
+ * registered callback.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers handlers for SIGINT and SIGTERM.
+ */
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+ void *user_data);
+
+/**
+ * eloop_register_signal_reconfig - Register handler for reconfig signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a reconfiguration /
+ * hangup signal is received. The callback function is actually called only
+ * after the system signal handler has returned. This means that the normal
+ * limits for sighandlers (i.e., only "safe functions" allowed) do not apply
+ * for the registered callback.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers a handler for SIGHUP.
+ */
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+ void *user_data);
+
+/**
+ * eloop_run - Start the event loop
+ *
+ * Start the event loop and continue running as long as there are any
+ * registered event handlers. This function is run after event loop has been
+ * initialized with event_init() and one or more events have been registered.
+ */
+void eloop_run(void);
+
+/**
+ * eloop_terminate - Terminate event loop
+ *
+ * Terminate event loop even if there are registered events. This can be used
+ * to request the program to be terminated cleanly.
+ */
+void eloop_terminate(void);
+
+/**
+ * eloop_destroy - Free any resources allocated for the event loop
+ *
+ * After calling eloop_destroy(), other eloop_* functions must not be called
+ * before re-running eloop_init().
+ */
+void eloop_destroy(void);
+
+/**
+ * eloop_terminated - Check whether event loop has been terminated
+ * Returns: 1 = event loop terminate, 0 = event loop still running
+ *
+ * This function can be used to check whether eloop_terminate() has been called
+ * to request termination of the event loop. This is normally used to abort
+ * operations that may still be queued to be run when eloop_terminate() was
+ * called.
+ */
+int eloop_terminated(void);
+
+/**
+ * eloop_wait_for_read_sock - Wait for a single reader
+ * @sock: File descriptor number for the socket
+ *
+ * Do a blocking wait for a single read socket.
+ */
+void eloop_wait_for_read_sock(int sock);
+
+#endif /* ELOOP_H */
diff --git a/src/utils/eloop_none.c b/src/utils/eloop_none.c
new file mode 100644
index 0000000..18eae4e
--- /dev/null
+++ b/src/utils/eloop_none.c
@@ -0,0 +1,401 @@
+/*
+ * Event loop - empty template (basic structure, but no OS specific operations)
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+ int sock;
+ void *eloop_data;
+ void *user_data;
+ void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+};
+
+struct eloop_timeout {
+ struct os_time time;
+ void *eloop_data;
+ void *user_data;
+ void (*handler)(void *eloop_ctx, void *sock_ctx);
+ struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+ int sig;
+ void *user_data;
+ void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+ int signaled;
+};
+
+struct eloop_data {
+ int max_sock, reader_count;
+ struct eloop_sock *readers;
+
+ struct eloop_timeout *timeout;
+
+ int signal_count;
+ struct eloop_signal *signals;
+ int signaled;
+ int pending_terminate;
+
+ int terminate;
+ int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void)
+{
+ memset(&eloop, 0, sizeof(eloop));
+ return 0;
+}
+
+
+int eloop_register_read_sock(int sock,
+ void (*handler)(int sock, void *eloop_ctx,
+ void *sock_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_sock *tmp;
+
+ tmp = (struct eloop_sock *)
+ realloc(eloop.readers,
+ (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.reader_count].sock = sock;
+ tmp[eloop.reader_count].eloop_data = eloop_data;
+ tmp[eloop.reader_count].user_data = user_data;
+ tmp[eloop.reader_count].handler = handler;
+ eloop.reader_count++;
+ eloop.readers = tmp;
+ if (sock > eloop.max_sock)
+ eloop.max_sock = sock;
+ eloop.reader_table_changed = 1;
+
+ return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ int i;
+
+ if (eloop.readers == NULL || eloop.reader_count == 0)
+ return;
+
+ for (i = 0; i < eloop.reader_count; i++) {
+ if (eloop.readers[i].sock == sock)
+ break;
+ }
+ if (i == eloop.reader_count)
+ return;
+ if (i != eloop.reader_count - 1) {
+ memmove(&eloop.readers[i], &eloop.readers[i + 1],
+ (eloop.reader_count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ eloop.reader_count--;
+ eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ void (*handler)(void *eloop_ctx, void *timeout_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *tmp, *prev;
+
+ timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+ if (timeout == NULL)
+ return -1;
+ os_get_time(&timeout->time);
+ timeout->time.sec += secs;
+ timeout->time.usec += usecs;
+ while (timeout->time.usec >= 1000000) {
+ timeout->time.sec++;
+ timeout->time.usec -= 1000000;
+ }
+ timeout->eloop_data = eloop_data;
+ timeout->user_data = user_data;
+ timeout->handler = handler;
+ timeout->next = NULL;
+
+ if (eloop.timeout == NULL) {
+ eloop.timeout = timeout;
+ return 0;
+ }
+
+ prev = NULL;
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (os_time_before(&timeout->time, &tmp->time))
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (prev == NULL) {
+ timeout->next = eloop.timeout;
+ eloop.timeout = timeout;
+ } else {
+ timeout->next = prev->next;
+ prev->next = timeout;
+ }
+
+ return 0;
+}
+
+
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *prev, *next;
+ int removed = 0;
+
+ prev = NULL;
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ next = timeout->next;
+
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data ||
+ eloop_data == ELOOP_ALL_CTX) &&
+ (timeout->user_data == user_data ||
+ user_data == ELOOP_ALL_CTX)) {
+ if (prev == NULL)
+ eloop.timeout = next;
+ else
+ prev->next = next;
+ free(timeout);
+ removed++;
+ } else
+ prev = timeout;
+
+ timeout = next;
+ }
+
+ return removed;
+}
+
+
+int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
+ void *timeout_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *tmp;
+
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data)
+ return 1;
+
+ tmp = tmp->next;
+ }
+
+ return 0;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+ int i;
+
+ eloop.signaled++;
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].sig == sig) {
+ eloop.signals[i].signaled++;
+ break;
+ }
+ }
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+ int i;
+
+ if (eloop.signaled == 0)
+ return;
+ eloop.signaled = 0;
+
+ if (eloop.pending_terminate) {
+ eloop.pending_terminate = 0;
+ }
+
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].signaled) {
+ eloop.signals[i].signaled = 0;
+ eloop.signals[i].handler(eloop.signals[i].sig,
+ eloop.user_data,
+ eloop.signals[i].user_data);
+ }
+ }
+}
+
+
+int eloop_register_signal(int sig,
+ void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+ struct eloop_signal *tmp;
+
+ tmp = (struct eloop_signal *)
+ realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.signal_count].sig = sig;
+ tmp[eloop.signal_count].user_data = user_data;
+ tmp[eloop.signal_count].handler = handler;
+ tmp[eloop.signal_count].signaled = 0;
+ eloop.signal_count++;
+ eloop.signals = tmp;
+
+ /* TODO: register signal handler */
+
+ return 0;
+}
+
+
+int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+#if 0
+ /* TODO: for example */
+ int ret = eloop_register_signal(SIGINT, handler, user_data);
+ if (ret == 0)
+ ret = eloop_register_signal(SIGTERM, handler, user_data);
+ return ret;
+#endif
+ return 0;
+}
+
+
+int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+#if 0
+ /* TODO: for example */
+ return eloop_register_signal(SIGHUP, handler, user_data);
+#endif
+ return 0;
+}
+
+
+void eloop_run(void)
+{
+ int i;
+ struct os_time tv, now;
+
+ while (!eloop.terminate &&
+ (eloop.timeout || eloop.reader_count > 0)) {
+ if (eloop.timeout) {
+ os_get_time(&now);
+ if (os_time_before(&now, &eloop.timeout->time))
+ os_time_sub(&eloop.timeout->time, &now, &tv);
+ else
+ tv.sec = tv.usec = 0;
+ }
+
+ /*
+ * TODO: wait for any event (read socket ready, timeout (tv),
+ * signal
+ */
+ os_sleep(1, 0); /* just a dummy wait for testing */
+
+ eloop_process_pending_signals();
+
+ /* check if some registered timeouts have occurred */
+ if (eloop.timeout) {
+ struct eloop_timeout *tmp;
+
+ os_get_time(&now);
+ if (!os_time_before(&now, &eloop.timeout->time)) {
+ tmp = eloop.timeout;
+ eloop.timeout = eloop.timeout->next;
+ tmp->handler(tmp->eloop_data,
+ tmp->user_data);
+ free(tmp);
+ }
+
+ }
+
+ eloop.reader_table_changed = 0;
+ for (i = 0; i < eloop.reader_count; i++) {
+ /*
+ * TODO: call each handler that has pending data to
+ * read
+ */
+ if (0 /* TODO: eloop.readers[i].sock ready */) {
+ eloop.readers[i].handler(
+ eloop.readers[i].sock,
+ eloop.readers[i].eloop_data,
+ eloop.readers[i].user_data);
+ if (eloop.reader_table_changed)
+ break;
+ }
+ }
+ }
+}
+
+
+void eloop_terminate(void)
+{
+ eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+ struct eloop_timeout *timeout, *prev;
+
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ prev = timeout;
+ timeout = timeout->next;
+ free(prev);
+ }
+ free(eloop.readers);
+ free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+ return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+ /*
+ * TODO: wait for the file descriptor to have something available for
+ * reading
+ */
+}
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
new file mode 100644
index 0000000..c726ece
--- /dev/null
+++ b/src/utils/eloop_win.c
@@ -0,0 +1,623 @@
+/*
+ * Event loop based on Windows events and WaitForMultipleObjects
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.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 "includes.h"
+#include <winsock2.h>
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+ int sock;
+ void *eloop_data;
+ void *user_data;
+ eloop_sock_handler handler;
+ WSAEVENT event;
+};
+
+struct eloop_event {
+ void *eloop_data;
+ void *user_data;
+ eloop_event_handler handler;
+ HANDLE event;
+};
+
+struct eloop_timeout {
+ struct os_time time;
+ void *eloop_data;
+ void *user_data;
+ eloop_timeout_handler handler;
+ struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+ int sig;
+ void *user_data;
+ eloop_signal_handler handler;
+ int signaled;
+};
+
+struct eloop_data {
+ int max_sock;
+ size_t reader_count;
+ struct eloop_sock *readers;
+
+ size_t event_count;
+ struct eloop_event *events;
+
+ struct eloop_timeout *timeout;
+
+ int signal_count;
+ struct eloop_signal *signals;
+ int signaled;
+ int pending_terminate;
+
+ int terminate;
+ int reader_table_changed;
+
+ struct eloop_signal term_signal;
+ HANDLE term_event;
+
+ HANDLE *handles;
+ size_t num_handles;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void)
+{
+ os_memset(&eloop, 0, sizeof(eloop));
+ eloop.num_handles = 1;
+ eloop.handles = os_malloc(eloop.num_handles *
+ sizeof(eloop.handles[0]));
+ if (eloop.handles == NULL)
+ return -1;
+
+ eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (eloop.term_event == NULL) {
+ printf("CreateEvent() failed: %d\n",
+ (int) GetLastError());
+ os_free(eloop.handles);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eloop_prepare_handles(void)
+{
+ HANDLE *n;
+
+ if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
+ return 0;
+ n = os_realloc(eloop.handles,
+ eloop.num_handles * 2 * sizeof(eloop.handles[0]));
+ if (n == NULL)
+ return -1;
+ eloop.handles = n;
+ eloop.num_handles *= 2;
+ return 0;
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
+{
+ WSAEVENT event;
+ struct eloop_sock *tmp;
+
+ if (eloop_prepare_handles())
+ return -1;
+
+ event = WSACreateEvent();
+ if (event == WSA_INVALID_EVENT) {
+ printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+ return -1;
+ }
+
+ if (WSAEventSelect(sock, event, FD_READ)) {
+ printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+ WSACloseEvent(event);
+ return -1;
+ }
+ tmp = os_realloc(eloop.readers,
+ (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ if (tmp == NULL) {
+ WSAEventSelect(sock, event, 0);
+ WSACloseEvent(event);
+ return -1;
+ }
+
+ tmp[eloop.reader_count].sock = sock;
+ tmp[eloop.reader_count].eloop_data = eloop_data;
+ tmp[eloop.reader_count].user_data = user_data;
+ tmp[eloop.reader_count].handler = handler;
+ tmp[eloop.reader_count].event = event;
+ eloop.reader_count++;
+ eloop.readers = tmp;
+ if (sock > eloop.max_sock)
+ eloop.max_sock = sock;
+ eloop.reader_table_changed = 1;
+
+ return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ size_t i;
+
+ if (eloop.readers == NULL || eloop.reader_count == 0)
+ return;
+
+ for (i = 0; i < eloop.reader_count; i++) {
+ if (eloop.readers[i].sock == sock)
+ break;
+ }
+ if (i == eloop.reader_count)
+ return;
+
+ WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
+ WSACloseEvent(eloop.readers[i].event);
+
+ if (i != eloop.reader_count - 1) {
+ os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
+ (eloop.reader_count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ eloop.reader_count--;
+ eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_event(void *event, size_t event_size,
+ eloop_event_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_event *tmp;
+ HANDLE h = event;
+
+ if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
+ return -1;
+
+ if (eloop_prepare_handles())
+ return -1;
+
+ tmp = os_realloc(eloop.events,
+ (eloop.event_count + 1) * sizeof(struct eloop_event));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.event_count].eloop_data = eloop_data;
+ tmp[eloop.event_count].user_data = user_data;
+ tmp[eloop.event_count].handler = handler;
+ tmp[eloop.event_count].event = h;
+ eloop.event_count++;
+ eloop.events = tmp;
+
+ return 0;
+}
+
+
+void eloop_unregister_event(void *event, size_t event_size)
+{
+ size_t i;
+ HANDLE h = event;
+
+ if (eloop.events == NULL || eloop.event_count == 0 ||
+ event_size != sizeof(HANDLE))
+ return;
+
+ for (i = 0; i < eloop.event_count; i++) {
+ if (eloop.events[i].event == h)
+ break;
+ }
+ if (i == eloop.event_count)
+ return;
+
+ if (i != eloop.event_count - 1) {
+ os_memmove(&eloop.events[i], &eloop.events[i + 1],
+ (eloop.event_count - i - 1) *
+ sizeof(struct eloop_event));
+ }
+ eloop.event_count--;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *tmp, *prev;
+ os_time_t now_sec;
+
+ timeout = os_malloc(sizeof(*timeout));
+ if (timeout == NULL)
+ return -1;
+ os_get_time(&timeout->time);
+ now_sec = timeout->time.sec;
+ timeout->time.sec += secs;
+ if (timeout->time.sec < now_sec) {
+ /*
+ * Integer overflow - assume long enough timeout to be assumed
+ * to be infinite, i.e., the timeout would never happen.
+ */
+ wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
+ "ever happen - ignore it", secs);
+ os_free(timeout);
+ return 0;
+ }
+ timeout->time.usec += usecs;
+ while (timeout->time.usec >= 1000000) {
+ timeout->time.sec++;
+ timeout->time.usec -= 1000000;
+ }
+ timeout->eloop_data = eloop_data;
+ timeout->user_data = user_data;
+ timeout->handler = handler;
+ timeout->next = NULL;
+
+ if (eloop.timeout == NULL) {
+ eloop.timeout = timeout;
+ return 0;
+ }
+
+ prev = NULL;
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (os_time_before(&timeout->time, &tmp->time))
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (prev == NULL) {
+ timeout->next = eloop.timeout;
+ eloop.timeout = timeout;
+ } else {
+ timeout->next = prev->next;
+ prev->next = timeout;
+ }
+
+ return 0;
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *prev, *next;
+ int removed = 0;
+
+ prev = NULL;
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ next = timeout->next;
+
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data ||
+ eloop_data == ELOOP_ALL_CTX) &&
+ (timeout->user_data == user_data ||
+ user_data == ELOOP_ALL_CTX)) {
+ if (prev == NULL)
+ eloop.timeout = next;
+ else
+ prev->next = next;
+ os_free(timeout);
+ removed++;
+ } else
+ prev = timeout;
+
+ timeout = next;
+ }
+
+ return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *tmp;
+
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data)
+ return 1;
+
+ tmp = tmp->next;
+ }
+
+ return 0;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+ int i;
+
+ eloop.signaled++;
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].sig == sig) {
+ eloop.signals[i].signaled++;
+ break;
+ }
+ }
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+ int i;
+
+ if (eloop.signaled == 0)
+ return;
+ eloop.signaled = 0;
+
+ if (eloop.pending_terminate) {
+ eloop.pending_terminate = 0;
+ }
+
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].signaled) {
+ eloop.signals[i].signaled = 0;
+ eloop.signals[i].handler(eloop.signals[i].sig,
+ eloop.signals[i].user_data);
+ }
+ }
+
+ if (eloop.term_signal.signaled) {
+ eloop.term_signal.signaled = 0;
+ eloop.term_signal.handler(eloop.term_signal.sig,
+ eloop.term_signal.user_data);
+ }
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+ void *user_data)
+{
+ struct eloop_signal *tmp;
+
+ tmp = os_realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.signal_count].sig = sig;
+ tmp[eloop.signal_count].user_data = user_data;
+ tmp[eloop.signal_count].handler = handler;
+ tmp[eloop.signal_count].signaled = 0;
+ eloop.signal_count++;
+ eloop.signals = tmp;
+
+ /* TODO: register signal handler */
+
+ return 0;
+}
+
+
+#ifndef _WIN32_WCE
+static BOOL eloop_handle_console_ctrl(DWORD type)
+{
+ switch (type) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ eloop.signaled++;
+ eloop.term_signal.signaled++;
+ SetEvent(eloop.term_event);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+#endif /* _WIN32_WCE */
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+ void *user_data)
+{
+#ifndef _WIN32_WCE
+ if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
+ TRUE) == 0) {
+ printf("SetConsoleCtrlHandler() failed: %d\n",
+ (int) GetLastError());
+ return -1;
+ }
+#endif /* _WIN32_WCE */
+
+ eloop.term_signal.handler = handler;
+ eloop.term_signal.user_data = user_data;
+
+ return 0;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+ void *user_data)
+{
+ /* TODO */
+ return 0;
+}
+
+
+void eloop_run(void)
+{
+ struct os_time tv, now;
+ DWORD count, ret, timeout, err;
+ size_t i;
+
+ while (!eloop.terminate &&
+ (eloop.timeout || eloop.reader_count > 0 ||
+ eloop.event_count > 0)) {
+ tv.sec = tv.usec = 0;
+ if (eloop.timeout) {
+ os_get_time(&now);
+ if (os_time_before(&now, &eloop.timeout->time))
+ os_time_sub(&eloop.timeout->time, &now, &tv);
+ }
+
+ count = 0;
+ for (i = 0; i < eloop.event_count; i++)
+ eloop.handles[count++] = eloop.events[i].event;
+
+ for (i = 0; i < eloop.reader_count; i++)
+ eloop.handles[count++] = eloop.readers[i].event;
+
+ if (eloop.term_event)
+ eloop.handles[count++] = eloop.term_event;
+
+ if (eloop.timeout)
+ timeout = tv.sec * 1000 + tv.usec / 1000;
+ else
+ timeout = INFINITE;
+
+ if (count > MAXIMUM_WAIT_OBJECTS) {
+ printf("WaitForMultipleObjects: Too many events: "
+ "%d > %d (ignoring extra events)\n",
+ (int) count, MAXIMUM_WAIT_OBJECTS);
+ count = MAXIMUM_WAIT_OBJECTS;
+ }
+#ifdef _WIN32_WCE
+ ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
+ timeout);
+#else /* _WIN32_WCE */
+ ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
+ timeout, TRUE);
+#endif /* _WIN32_WCE */
+ err = GetLastError();
+
+ eloop_process_pending_signals();
+
+ /* check if some registered timeouts have occurred */
+ if (eloop.timeout) {
+ struct eloop_timeout *tmp;
+
+ os_get_time(&now);
+ if (!os_time_before(&now, &eloop.timeout->time)) {
+ tmp = eloop.timeout;
+ eloop.timeout = eloop.timeout->next;
+ tmp->handler(tmp->eloop_data,
+ tmp->user_data);
+ os_free(tmp);
+ }
+
+ }
+
+ if (ret == WAIT_FAILED) {
+ printf("WaitForMultipleObjects(count=%d) failed: %d\n",
+ (int) count, (int) err);
+ os_sleep(1, 0);
+ continue;
+ }
+
+#ifndef _WIN32_WCE
+ if (ret == WAIT_IO_COMPLETION)
+ continue;
+#endif /* _WIN32_WCE */
+
+ if (ret == WAIT_TIMEOUT)
+ continue;
+
+ while (ret >= WAIT_OBJECT_0 &&
+ ret < WAIT_OBJECT_0 + eloop.event_count) {
+ eloop.events[ret].handler(
+ eloop.events[ret].eloop_data,
+ eloop.events[ret].user_data);
+ ret = WaitForMultipleObjects(eloop.event_count,
+ eloop.handles, FALSE, 0);
+ }
+
+ eloop.reader_table_changed = 0;
+ for (i = 0; i < eloop.reader_count; i++) {
+ WSANETWORKEVENTS events;
+ if (WSAEnumNetworkEvents(eloop.readers[i].sock,
+ eloop.readers[i].event,
+ &events) == 0 &&
+ (events.lNetworkEvents & FD_READ)) {
+ eloop.readers[i].handler(
+ eloop.readers[i].sock,
+ eloop.readers[i].eloop_data,
+ eloop.readers[i].user_data);
+ if (eloop.reader_table_changed)
+ break;
+ }
+ }
+ }
+}
+
+
+void eloop_terminate(void)
+{
+ eloop.terminate = 1;
+ SetEvent(eloop.term_event);
+}
+
+
+void eloop_destroy(void)
+{
+ struct eloop_timeout *timeout, *prev;
+
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ prev = timeout;
+ timeout = timeout->next;
+ os_free(prev);
+ }
+ os_free(eloop.readers);
+ os_free(eloop.signals);
+ if (eloop.term_event)
+ CloseHandle(eloop.term_event);
+ os_free(eloop.handles);
+ eloop.handles = NULL;
+ os_free(eloop.events);
+ eloop.events = NULL;
+}
+
+
+int eloop_terminated(void)
+{
+ return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+ WSAEVENT event;
+
+ event = WSACreateEvent();
+ if (event == WSA_INVALID_EVENT) {
+ printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+ return;
+ }
+
+ if (WSAEventSelect(sock, event, FD_READ)) {
+ printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+ WSACloseEvent(event);
+ return ;
+ }
+
+ WaitForSingleObject(event, INFINITE);
+ WSAEventSelect(sock, event, 0);
+ WSACloseEvent(event);
+}
diff --git a/src/utils/includes.h b/src/utils/includes.h
new file mode 100644
index 0000000..63b5c23
--- /dev/null
+++ b/src/utils/includes.h
@@ -0,0 +1,59 @@
+/*
+ * wpa_supplicant/hostapd - Default include files
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.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.
+ *
+ * This header file is included into all C files so that commonly used header
+ * files can be selected with OS specific ifdef blocks in one place instead of
+ * having to have OS/C library specific selection in many files.
+ */
+
+#ifndef INCLUDES_H
+#define INCLUDES_H
+
+/* Include possible build time configuration before including anything else */
+#include "build_config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+#ifndef CONFIG_TI_COMPILER
+#include <signal.h>
+#include <sys/types.h>
+#endif /* CONFIG_TI_COMPILER */
+#include <errno.h>
+#endif /* _WIN32_WCE */
+#include <ctype.h>
+#include <time.h>
+
+#ifndef CONFIG_TI_COMPILER
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif /* _MSC_VER */
+#endif /* CONFIG_TI_COMPILER */
+
+#ifndef CONFIG_NATIVE_WINDOWS
+#ifndef CONFIG_TI_COMPILER
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifndef __vxworks
+#ifndef __SYMBIAN32__
+#include <sys/uio.h>
+#endif /* __SYMBIAN32__ */
+#include <sys/time.h>
+#endif /* __vxworks */
+#endif /* CONFIG_TI_COMPILER */
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#endif /* INCLUDES_H */
diff --git a/src/utils/ip_addr.c b/src/utils/ip_addr.c
new file mode 100644
index 0000000..158fd57
--- /dev/null
+++ b/src/utils/ip_addr.c
@@ -0,0 +1,83 @@
+/*
+ * IP address processing
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+#include "ip_addr.h"
+
+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
+ size_t buflen)
+{
+ if (buflen == 0 || addr == NULL)
+ return NULL;
+
+ if (addr->af == AF_INET) {
+ os_strlcpy(buf, inet_ntoa(addr->u.v4), buflen);
+ } else {
+ buf[0] = '\0';
+ }
+#ifdef CONFIG_IPV6
+ if (addr->af == AF_INET6) {
+ if (inet_ntop(AF_INET6, &addr->u.v6, buf, buflen) == NULL)
+ buf[0] = '\0';
+ }
+#endif /* CONFIG_IPV6 */
+
+ return buf;
+}
+
+
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b)
+{
+ if (a == NULL && b == NULL)
+ return 0;
+ if (a == NULL || b == NULL)
+ return 1;
+
+ switch (a->af) {
+ case AF_INET:
+ if (a->u.v4.s_addr != b->u.v4.s_addr)
+ return 1;
+ break;
+#ifdef CONFIG_IPV6
+ case AF_INET6:
+ if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0)
+ return 1;
+ break;
+#endif /* CONFIG_IPV6 */
+ }
+
+ return 0;
+}
+
+
+int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+ if (inet_aton(txt, &addr->u.v4)) {
+ addr->af = AF_INET;
+ return 0;
+ }
+
+#ifdef CONFIG_IPV6
+ if (inet_pton(AF_INET6, txt, &addr->u.v6) > 0) {
+ addr->af = AF_INET6;
+ return 0;
+ }
+#endif /* CONFIG_IPV6 */
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ return -1;
+}
diff --git a/src/utils/ip_addr.h b/src/utils/ip_addr.h
new file mode 100644
index 0000000..28ccaef
--- /dev/null
+++ b/src/utils/ip_addr.h
@@ -0,0 +1,34 @@
+/*
+ * IP address processing
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef IP_ADDR_H
+#define IP_ADDR_H
+
+struct hostapd_ip_addr {
+ int af; /* AF_INET / AF_INET6 */
+ union {
+ struct in_addr v4;
+#ifdef CONFIG_IPV6
+ struct in6_addr v6;
+#endif /* CONFIG_IPV6 */
+ u8 max_len[16];
+ } u;
+};
+
+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
+ size_t buflen);
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b);
+int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr);
+
+#endif /* IP_ADDR_H */
diff --git a/src/utils/list.h b/src/utils/list.h
new file mode 100644
index 0000000..ded7846
--- /dev/null
+++ b/src/utils/list.h
@@ -0,0 +1,98 @@
+/*
+ * Doubly-linked list
+ * Copyright (c) 2009, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+/**
+ * struct dl_list - Doubly-linked list
+ */
+struct dl_list {
+ struct dl_list *next;
+ struct dl_list *prev;
+};
+
+static inline void dl_list_init(struct dl_list *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+static inline void dl_list_add(struct dl_list *list, struct dl_list *item)
+{
+ item->next = list->next;
+ item->prev = list;
+ list->next->prev = item;
+ list->next = item;
+}
+
+static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item)
+{
+ dl_list_add(list->prev, item);
+}
+
+static inline void dl_list_del(struct dl_list *item)
+{
+ item->next->prev = item->prev;
+ item->prev->next = item->next;
+ item->next = NULL;
+ item->prev = NULL;
+}
+
+static inline int dl_list_empty(struct dl_list *list)
+{
+ return list->next == list;
+}
+
+static inline unsigned int dl_list_len(struct dl_list *list)
+{
+ struct dl_list *item;
+ int count = 0;
+ for (item = list->next; item != list; item = item->next)
+ count++;
+ return count;
+}
+
+#ifndef offsetof
+#define offsetof(type, member) ((long) &((type *) 0)->member)
+#endif
+
+#define dl_list_entry(item, type, member) \
+ ((type *) ((char *) item - offsetof(type, member)))
+
+#define dl_list_first(list, type, member) \
+ (dl_list_empty((list)) ? NULL : \
+ dl_list_entry((list)->next, type, member))
+
+#define dl_list_last(list, type, member) \
+ (dl_list_empty((list)) ? NULL : \
+ dl_list_entry((list)->prev, type, member))
+
+#define dl_list_for_each(item, list, type, member) \
+ for (item = dl_list_entry((list)->next, type, member); \
+ &item->member != (list); \
+ item = dl_list_entry(item->member.next, type, member))
+
+#define dl_list_for_each_safe(item, n, list, type, member) \
+ for (item = dl_list_entry((list)->next, type, member), \
+ n = dl_list_entry(item->member.next, type, member); \
+ &item->member != (list); \
+ item = n, n = dl_list_entry(n->member.next, type, member))
+
+#define dl_list_for_each_reverse(item, list, type, member) \
+ for (item = dl_list_entry((list)->prev, type, member); \
+ &item->member != (list); \
+ item = dl_list_entry(item->member.prev, type, member))
+
+#endif /* LIST_H */
diff --git a/src/utils/os.h b/src/utils/os.h
new file mode 100644
index 0000000..f4723d8
--- /dev/null
+++ b/src/utils/os.h
@@ -0,0 +1,508 @@
+/*
+ * OS specific functions
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef OS_H
+#define OS_H
+
+typedef long os_time_t;
+
+/**
+ * os_sleep - Sleep (sec, usec)
+ * @sec: Number of seconds to sleep
+ * @usec: Number of microseconds to sleep
+ */
+void os_sleep(os_time_t sec, os_time_t usec);
+
+struct os_time {
+ os_time_t sec;
+ os_time_t usec;
+};
+
+/**
+ * os_get_time - Get current time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_time(struct os_time *t);
+
+
+/* Helper macros for handling struct os_time */
+
+#define os_time_before(a, b) \
+ ((a)->sec < (b)->sec || \
+ ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+
+#define os_time_sub(a, b, res) do { \
+ (res)->sec = (a)->sec - (b)->sec; \
+ (res)->usec = (a)->usec - (b)->usec; \
+ if ((res)->usec < 0) { \
+ (res)->sec--; \
+ (res)->usec += 1000000; \
+ } \
+} while (0)
+
+/**
+ * os_mktime - Convert broken-down time into seconds since 1970-01-01
+ * @year: Four digit year
+ * @month: Month (1 .. 12)
+ * @day: Day of month (1 .. 31)
+ * @hour: Hour (0 .. 23)
+ * @min: Minute (0 .. 59)
+ * @sec: Second (0 .. 60)
+ * @t: Buffer for returning calendar time representation (seconds since
+ * 1970-01-01 00:00:00)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time
+ * which is used by POSIX mktime().
+ */
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t);
+
+
+/**
+ * os_daemonize - Run in the background (detach from the controlling terminal)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ * Returns: 0 on success, -1 on failure
+ */
+int os_daemonize(const char *pid_file);
+
+/**
+ * os_daemonize_terminate - Stop running in the background (remove pid file)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ */
+void os_daemonize_terminate(const char *pid_file);
+
+/**
+ * os_get_random - Get cryptographically strong pseudo random data
+ * @buf: Buffer for pseudo random data
+ * @len: Length of the buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_random(unsigned char *buf, size_t len);
+
+/**
+ * os_random - Get pseudo random value (not necessarily very strong)
+ * Returns: Pseudo random value
+ */
+unsigned long os_random(void);
+
+/**
+ * os_rel2abs_path - Get an absolute path for a file
+ * @rel_path: Relative path to a file
+ * Returns: Absolute path for the file or %NULL on failure
+ *
+ * This function tries to convert a relative path of a file to an absolute path
+ * in order for the file to be found even if current working directory has
+ * changed. The returned value is allocated and caller is responsible for
+ * freeing it. It is acceptable to just return the same path in an allocated
+ * buffer, e.g., return strdup(rel_path). This function is only used to find
+ * configuration files when os_daemonize() may have changed the current working
+ * directory and relative path would be pointing to a different location.
+ */
+char * os_rel2abs_path(const char *rel_path);
+
+/**
+ * os_program_init - Program initialization (called at start)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when a programs starts. If there are any OS specific
+ * processing that is needed, it can be placed here. It is also acceptable to
+ * just return 0 if not special processing is needed.
+ */
+int os_program_init(void);
+
+/**
+ * os_program_deinit - Program deinitialization (called just before exit)
+ *
+ * This function is called just before a program exists. If there are any OS
+ * specific processing, e.g., freeing resourced allocated in os_program_init(),
+ * it should be done here. It is also acceptable for this function to do
+ * nothing.
+ */
+void os_program_deinit(void);
+
+/**
+ * os_setenv - Set environment variable
+ * @name: Name of the variable
+ * @value: Value to set to the variable
+ * @overwrite: Whether existing variable should be overwritten
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_setenv(const char *name, const char *value, int overwrite);
+
+/**
+ * os_unsetenv - Delete environent variable
+ * @name: Name of the variable
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_unsetenv(const char *name);
+
+/**
+ * os_readfile - Read a file to an allocated memory buffer
+ * @name: Name of the file to read
+ * @len: For returning the length of the allocated buffer
+ * Returns: Pointer to the allocated buffer or %NULL on failure
+ *
+ * This function allocates memory and reads the given file to this buffer. Both
+ * binary and text files can be read with this function. The caller is
+ * responsible for freeing the returned buffer with os_free().
+ */
+char * os_readfile(const char *name, size_t *len);
+
+/**
+ * os_zalloc - Allocate and zero memory
+ * @size: Number of bytes to allocate
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_zalloc(size_t size);
+
+
+/*
+ * The following functions are wrapper for standard ANSI C or POSIX functions.
+ * By default, they are just defined to use the standard function name and no
+ * os_*.c implementation is needed for them. This avoids extra function calls
+ * by allowing the C pre-processor take care of the function name mapping.
+ *
+ * If the target system uses a C library that does not provide these functions,
+ * build_config.h can be used to define the wrappers to use a different
+ * function name. This can be done on function-by-function basis since the
+ * defines here are only used if build_config.h does not define the os_* name.
+ * If needed, os_*.c file can be used to implement the functions that are not
+ * included in the C library on the target system. Alternatively,
+ * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case
+ * these functions need to be implemented in os_*.c file for the target system.
+ */
+
+#ifdef OS_NO_C_LIB_DEFINES
+
+/**
+ * os_malloc - Allocate dynamic memory
+ * @size: Size of the buffer to allocate
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_malloc(size_t size);
+
+/**
+ * os_realloc - Re-allocate dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc()
+ * @size: Size of the new buffer
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ * If re-allocation fails, %NULL is returned and the original buffer (ptr) is
+ * not freed and caller is still responsible for freeing it.
+ */
+void * os_realloc(void *ptr, size_t size);
+
+/**
+ * os_free - Free dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL
+ */
+void os_free(void *ptr);
+
+/**
+ * os_memcpy - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst must not overlap. os_memmove() can be used with
+ * overlapping memory.
+ */
+void * os_memcpy(void *dest, const void *src, size_t n);
+
+/**
+ * os_memmove - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst may overlap.
+ */
+void * os_memmove(void *dest, const void *src, size_t n);
+
+/**
+ * os_memset - Fill memory with a constant byte
+ * @s: Memory area to be filled
+ * @c: Constant byte
+ * @n: Number of bytes started from s to fill with c
+ * Returns: s
+ */
+void * os_memset(void *s, int c, size_t n);
+
+/**
+ * os_memcmp - Compare memory areas
+ * @s1: First buffer
+ * @s2: Second buffer
+ * @n: Maximum numbers of octets to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_memcmp(const void *s1, const void *s2, size_t n);
+
+/**
+ * os_strdup - Duplicate a string
+ * @s: Source string
+ * Returns: Allocated buffer with the string copied into it or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * os_strdup(const char *s);
+
+/**
+ * os_strlen - Calculate the length of a string
+ * @s: '\0' terminated string
+ * Returns: Number of characters in s (not counting the '\0' terminator)
+ */
+size_t os_strlen(const char *s);
+
+/**
+ * os_strcasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcasecmp(const char *s1, const char *s2);
+
+/**
+ * os_strncasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncasecmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strchr - Locate the first occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strchr(const char *s, int c);
+
+/**
+ * os_strrchr - Locate the last occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strrchr(const char *s, int c);
+
+/**
+ * os_strcmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcmp(const char *s1, const char *s2);
+
+/**
+ * os_strncmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strncpy - Copy a string
+ * @dest: Destination
+ * @src: Source
+ * @n: Maximum number of characters to copy
+ * Returns: dest
+ */
+char * os_strncpy(char *dest, const char *src, size_t n);
+
+/**
+ * os_strstr - Locate a substring
+ * @haystack: String (haystack) to search from
+ * @needle: Needle to search from haystack
+ * Returns: Pointer to the beginning of the substring or %NULL if not found
+ */
+char * os_strstr(const char *haystack, const char *needle);
+
+/**
+ * os_snprintf - Print to a memory buffer
+ * @str: Memory buffer to print into
+ * @size: Maximum length of the str buffer
+ * @format: printf format
+ * Returns: Number of characters printed (not including trailing '\0').
+ *
+ * If the output buffer is truncated, number of characters which would have
+ * been written is returned. Since some C libraries return -1 in such a case,
+ * the caller must be prepared on that value, too, to indicate truncation.
+ *
+ * Note: Some C library implementations of snprintf() may not guarantee null
+ * termination in case the output is truncated. The OS wrapper function of
+ * os_snprintf() should provide this guarantee, i.e., to null terminate the
+ * output buffer if a C library version of the function is used and if that
+ * function does not guarantee null termination.
+ *
+ * If the target system does not include snprintf(), see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for an example of a portable
+ * implementation of snprintf.
+ */
+int os_snprintf(char *str, size_t size, const char *format, ...);
+
+#else /* OS_NO_C_LIB_DEFINES */
+
+#ifdef WPA_TRACE
+void * os_malloc(size_t size);
+void * os_realloc(void *ptr, size_t size);
+void os_free(void *ptr);
+char * os_strdup(const char *s);
+#else /* WPA_TRACE */
+#ifndef os_malloc
+#define os_malloc(s) malloc((s))
+#endif
+#ifndef os_realloc
+#define os_realloc(p, s) realloc((p), (s))
+#endif
+#ifndef os_free
+#define os_free(p) free((p))
+#endif
+#ifndef os_strdup
+#ifdef _MSC_VER
+#define os_strdup(s) _strdup(s)
+#else
+#define os_strdup(s) strdup(s)
+#endif
+#endif
+#endif /* WPA_TRACE */
+
+#ifndef os_memcpy
+#define os_memcpy(d, s, n) memcpy((d), (s), (n))
+#endif
+#ifndef os_memmove
+#define os_memmove(d, s, n) memmove((d), (s), (n))
+#endif
+#ifndef os_memset
+#define os_memset(s, c, n) memset(s, c, n)
+#endif
+#ifndef os_memcmp
+#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+
+#ifndef os_strlen
+#define os_strlen(s) strlen(s)
+#endif
+#ifndef os_strcasecmp
+#ifdef _MSC_VER
+#define os_strcasecmp(s1, s2) _stricmp((s1), (s2))
+#else
+#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
+#endif
+#endif
+#ifndef os_strncasecmp
+#ifdef _MSC_VER
+#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
+#else
+#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
+#endif
+#endif
+#ifndef os_strchr
+#define os_strchr(s, c) strchr((s), (c))
+#endif
+#ifndef os_strcmp
+#define os_strcmp(s1, s2) strcmp((s1), (s2))
+#endif
+#ifndef os_strncmp
+#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
+#endif
+#ifndef os_strncpy
+#define os_strncpy(d, s, n) strncpy((d), (s), (n))
+#endif
+#ifndef os_strrchr
+#define os_strrchr(s, c) strrchr((s), (c))
+#endif
+#ifndef os_strstr
+#define os_strstr(h, n) strstr((h), (n))
+#endif
+
+#ifndef os_snprintf
+#ifdef _MSC_VER
+#define os_snprintf _snprintf
+#else
+#define os_snprintf snprintf
+#endif
+#endif
+
+#endif /* OS_NO_C_LIB_DEFINES */
+
+
+/**
+ * os_strlcpy - Copy a string with size bound and NUL-termination
+ * @dest: Destination
+ * @src: Source
+ * @siz: Size of the target buffer
+ * Returns: Total length of the target string (length of src) (not including
+ * NUL-termination)
+ *
+ * This function matches in behavior with the strlcpy(3) function in OpenBSD.
+ */
+size_t os_strlcpy(char *dest, const char *src, size_t siz);
+
+
+#ifdef OS_REJECT_C_LIB_FUNCTIONS
+#define malloc OS_DO_NOT_USE_malloc
+#define realloc OS_DO_NOT_USE_realloc
+#define free OS_DO_NOT_USE_free
+#define memcpy OS_DO_NOT_USE_memcpy
+#define memmove OS_DO_NOT_USE_memmove
+#define memset OS_DO_NOT_USE_memset
+#define memcmp OS_DO_NOT_USE_memcmp
+#undef strdup
+#define strdup OS_DO_NOT_USE_strdup
+#define strlen OS_DO_NOT_USE_strlen
+#define strcasecmp OS_DO_NOT_USE_strcasecmp
+#define strncasecmp OS_DO_NOT_USE_strncasecmp
+#undef strchr
+#define strchr OS_DO_NOT_USE_strchr
+#undef strcmp
+#define strcmp OS_DO_NOT_USE_strcmp
+#undef strncmp
+#define strncmp OS_DO_NOT_USE_strncmp
+#undef strncpy
+#define strncpy OS_DO_NOT_USE_strncpy
+#define strrchr OS_DO_NOT_USE_strrchr
+#define strstr OS_DO_NOT_USE_strstr
+#undef snprintf
+#define snprintf OS_DO_NOT_USE_snprintf
+
+#define strcpy OS_DO_NOT_USE_strcpy
+#endif /* OS_REJECT_C_LIB_FUNCTIONS */
+
+#endif /* OS_H */
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
new file mode 100644
index 0000000..5260e23
--- /dev/null
+++ b/src/utils/os_internal.c
@@ -0,0 +1,471 @@
+/*
+ * wpa_supplicant/hostapd / Internal implementation of OS specific functions
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.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.
+ *
+ * This file is an example of operating system specific wrapper functions.
+ * This version implements many of the functions internally, so it can be used
+ * to fill in missing functions from the target system C libraries.
+ *
+ * Some of the functions are using standard C library calls in order to keep
+ * this file in working condition to allow the functions to be tested on a
+ * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for
+ * this file to work correctly. Note that these implementations are only
+ * examples and are not optimized for speed.
+ */
+
+#include "includes.h"
+
+#undef OS_REJECT_C_LIB_FUNCTIONS
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+ if (sec)
+ sleep(sec);
+ if (usec)
+ usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+ int res;
+ struct timeval tv;
+ res = gettimeofday(&tv, NULL);
+ t->sec = tv.tv_sec;
+ t->usec = tv.tv_usec;
+ return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ struct tm tm;
+
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+ sec > 60)
+ return -1;
+
+ os_memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ *t = (os_time_t) mktime(&tm);
+ return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+ if (daemon(0, 0)) {
+ perror("daemon");
+ return -1;
+ }
+
+ if (pid_file) {
+ FILE *f = fopen(pid_file, "w");
+ if (f) {
+ fprintf(f, "%u\n", getpid());
+ fclose(f);
+ }
+ }
+
+ return -0;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+ if (pid_file)
+ unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ FILE *f;
+ size_t rc;
+
+ f = fopen("/dev/urandom", "rb");
+ 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;
+}
+
+
+unsigned long os_random(void)
+{
+ return random();
+}
+
+
+char * os_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 os_strdup(rel_path);
+
+ for (;;) {
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+ cwd = getcwd(buf, len);
+ if (cwd == NULL) {
+ os_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 = os_malloc(ret_len);
+ if (ret) {
+ os_memcpy(ret, cwd, cwd_len);
+ ret[cwd_len] = '/';
+ os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+ ret[ret_len - 1] = '\0';
+ }
+ os_free(buf);
+ return ret;
+}
+
+
+int os_program_init(void)
+{
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+ unsetenv(name);
+ return 0;
+#else
+ return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ FILE *f;
+ char *buf;
+
+ f = fopen(name, "rb");
+ if (f == NULL)
+ return NULL;
+
+ fseek(f, 0, SEEK_END);
+ *len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ buf = os_malloc(*len);
+ if (buf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ if (fread(buf, 1, *len, f) != *len) {
+ fclose(f);
+ os_free(buf);
+ return NULL;
+ }
+
+ fclose(f);
+
+ return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+ void *n = os_malloc(size);
+ if (n)
+ os_memset(n, 0, size);
+ return n;
+}
+
+
+void * os_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+ return realloc(ptr, size);
+}
+
+
+void os_free(void *ptr)
+{
+ free(ptr);
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+ char *d = dest;
+ const char *s = src;
+ while (n--)
+ *d++ = *s++;
+ return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+ if (dest < src)
+ os_memcpy(dest, src, n);
+ else {
+ /* overlapping areas */
+ char *d = (char *) dest + n;
+ const char *s = (const char *) src + n;
+ while (n--)
+ *--d = *--s;
+ }
+ return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+ char *p = s;
+ while (n--)
+ *p++ = c;
+ return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *p1 = s1, *p2 = s2;
+
+ if (n == 0)
+ return 0;
+
+ while (*p1 == *p2) {
+ p1++;
+ p2++;
+ n--;
+ if (n == 0)
+ return 0;
+ }
+
+ return *p1 - *p2;
+}
+
+
+char * os_strdup(const char *s)
+{
+ char *res;
+ size_t len;
+ if (s == NULL)
+ return NULL;
+ len = os_strlen(s);
+ res = os_malloc(len + 1);
+ if (res)
+ os_memcpy(res, s, len + 1);
+ return res;
+}
+
+
+size_t os_strlen(const char *s)
+{
+ const char *p = s;
+ while (*p)
+ p++;
+ return p - s;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+ while (*s) {
+ if (*s == c)
+ return (char *) s;
+ s++;
+ }
+ return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+ const char *p = s;
+ while (*p)
+ p++;
+ p--;
+ while (p >= s) {
+ if (*p == c)
+ return (char *) p;
+ p--;
+ }
+ return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+ while (*s1 == *s2) {
+ if (*s1 == '\0')
+ break;
+ s1++;
+ s2++;
+ }
+
+ return *s1 - *s2;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+ if (n == 0)
+ return 0;
+
+ while (*s1 == *s2) {
+ if (*s1 == '\0')
+ break;
+ s1++;
+ s2++;
+ n--;
+ if (n == 0)
+ return 0;
+ }
+
+ return *s1 - *s2;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+ char *d = dest;
+
+ while (n--) {
+ *d = *src;
+ if (*src == '\0')
+ break;
+ d++;
+ src++;
+ }
+
+ return dest;
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+ const char *s = src;
+ size_t left = siz;
+
+ if (left) {
+ /* Copy string up to the maximum size of the dest buffer */
+ while (--left != 0) {
+ if ((*dest++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ if (left == 0) {
+ /* Not enough room for the string; force NUL-termination */
+ if (siz != 0)
+ *dest = '\0';
+ while (*s++)
+ ; /* determine total src string length */
+ }
+
+ return s - src - 1;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+ size_t len = os_strlen(needle);
+ while (*haystack) {
+ if (os_strncmp(haystack, needle, len) == 0)
+ return (char *) haystack;
+ haystack++;
+ }
+
+ return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ /* See http://www.ijs.si/software/snprintf/ for portable
+ * implementation of snprintf.
+ */
+
+ va_start(ap, format);
+ ret = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ if (size > 0)
+ str[size - 1] = '\0';
+ return ret;
+}
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
new file mode 100644
index 0000000..bab8f17
--- /dev/null
+++ b/src/utils/os_none.c
@@ -0,0 +1,226 @@
+/*
+ * wpa_supplicant/hostapd / Empty OS specific functions
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.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.
+ *
+ * This file can be used as a starting point when adding a new OS target. The
+ * functions here do not really work as-is since they are just empty or only
+ * return an error value. os_internal.c can be used as another starting point
+ * or reference since it has example implementation of many of these functions.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+}
+
+
+int os_get_time(struct os_time *t)
+{
+ return -1;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ return -1;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+ return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ return -1;
+}
+
+
+unsigned long os_random(void)
+{
+ return 0;
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ return NULL; /* strdup(rel_path) can be used here */
+}
+
+
+int os_program_init(void)
+{
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return -1;
+}
+
+
+int os_unsetenv(const char *name)
+{
+ return -1;
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ return NULL;
+}
+
+
+void * os_zalloc(size_t size)
+{
+ return NULL;
+}
+
+
+#ifdef OS_NO_C_LIB_DEFINES
+void * os_malloc(size_t size)
+{
+ return NULL;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+ return NULL;
+}
+
+
+void os_free(void *ptr)
+{
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+ return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+ return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+ return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+ return 0;
+}
+
+
+char * os_strdup(const char *s)
+{
+ return NULL;
+}
+
+
+size_t os_strlen(const char *s)
+{
+ return 0;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+ return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+ return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+ return 0;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+ return 0;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+ return dest;
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t size)
+{
+ return 0;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+ return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+ return 0;
+}
+#endif /* OS_NO_C_LIB_DEFINES */
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
new file mode 100644
index 0000000..4e11758
--- /dev/null
+++ b/src/utils/os_unix.c
@@ -0,0 +1,474 @@
+/*
+ * OS specific functions for UNIX/POSIX systems
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.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 "includes.h"
+
+#ifdef ANDROID
+#include <linux/capability.h>
+#include <linux/prctl.h>
+#include <private/android_filesystem_config.h>
+#endif /* ANDROID */
+
+#include "os.h"
+
+#ifdef WPA_TRACE
+
+#include "common.h"
+#include "list.h"
+#include "wpa_debug.h"
+#include "trace.h"
+
+static struct dl_list alloc_list;
+
+#define ALLOC_MAGIC 0xa84ef1b2
+#define FREED_MAGIC 0x67fd487a
+
+struct os_alloc_trace {
+ unsigned int magic;
+ struct dl_list list;
+ size_t len;
+ WPA_TRACE_INFO
+};
+
+#endif /* WPA_TRACE */
+
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+ if (sec)
+ sleep(sec);
+ if (usec)
+ usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+ int res;
+ struct timeval tv;
+ res = gettimeofday(&tv, NULL);
+ t->sec = tv.tv_sec;
+ t->usec = tv.tv_usec;
+ return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ struct tm tm, *tm1;
+ time_t t_local, t1, t2;
+ os_time_t tz_offset;
+
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+ sec > 60)
+ return -1;
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ t_local = mktime(&tm);
+
+ /* figure out offset to UTC */
+ tm1 = localtime(&t_local);
+ if (tm1) {
+ t1 = mktime(tm1);
+ tm1 = gmtime(&t_local);
+ if (tm1) {
+ t2 = mktime(tm1);
+ tz_offset = t2 - t1;
+ } else
+ tz_offset = 0;
+ } else
+ tz_offset = 0;
+
+ *t = (os_time_t) t_local - tz_offset;
+ return 0;
+}
+
+
+#ifdef __APPLE__
+#include <fcntl.h>
+static int os_daemon(int nochdir, int noclose)
+{
+ int devnull;
+
+ if (chdir("/") < 0)
+ return -1;
+
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0)
+ return -1;
+
+ if (dup2(devnull, STDIN_FILENO) < 0) {
+ close(devnull);
+ return -1;
+ }
+
+ if (dup2(devnull, STDOUT_FILENO) < 0) {
+ close(devnull);
+ return -1;
+ }
+
+ if (dup2(devnull, STDERR_FILENO) < 0) {
+ close(devnull);
+ return -1;
+ }
+
+ return 0;
+}
+#else /* __APPLE__ */
+#define os_daemon daemon
+#endif /* __APPLE__ */
+
+
+int os_daemonize(const char *pid_file)
+{
+#if defined(__uClinux__) || defined(__sun__)
+ return -1;
+#else /* defined(__uClinux__) || defined(__sun__) */
+ if (os_daemon(0, 0)) {
+ perror("daemon");
+ return -1;
+ }
+
+ if (pid_file) {
+ FILE *f = fopen(pid_file, "w");
+ if (f) {
+ fprintf(f, "%u\n", getpid());
+ fclose(f);
+ }
+ }
+
+ return -0;
+#endif /* defined(__uClinux__) || defined(__sun__) */
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+ if (pid_file)
+ unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ FILE *f;
+ size_t rc;
+
+ f = fopen("/dev/urandom", "rb");
+ 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;
+}
+
+
+unsigned long os_random(void)
+{
+ return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ char *buf = NULL, *cwd, *ret;
+ size_t len = 128, cwd_len, rel_len, ret_len;
+ int last_errno;
+
+ if (rel_path[0] == '/')
+ return os_strdup(rel_path);
+
+ for (;;) {
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+ cwd = getcwd(buf, len);
+ if (cwd == NULL) {
+ last_errno = errno;
+ os_free(buf);
+ if (last_errno != ERANGE)
+ return NULL;
+ len *= 2;
+ if (len > 2000)
+ return NULL;
+ } else {
+ buf[len - 1] = '\0';
+ break;
+ }
+ }
+
+ cwd_len = os_strlen(cwd);
+ rel_len = os_strlen(rel_path);
+ ret_len = cwd_len + 1 + rel_len + 1;
+ ret = os_malloc(ret_len);
+ if (ret) {
+ os_memcpy(ret, cwd, cwd_len);
+ ret[cwd_len] = '/';
+ os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+ ret[ret_len - 1] = '\0';
+ }
+ os_free(buf);
+ return ret;
+}
+
+
+int os_program_init(void)
+{
+#ifdef ANDROID
+ /*
+ * We ignore errors here since errors are normal if we
+ * are already running as non-root.
+ */
+ gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap;
+
+ setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+ setgid(AID_WIFI);
+ setuid(AID_WIFI);
+
+ header.version = _LINUX_CAPABILITY_VERSION;
+ header.pid = 0;
+ cap.effective = cap.permitted =
+ (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
+ cap.inheritable = 0;
+ capset(&header, &cap);
+#endif /* ANDROID */
+
+#ifdef WPA_TRACE
+ dl_list_init(&alloc_list);
+#endif /* WPA_TRACE */
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+#ifdef WPA_TRACE
+ struct os_alloc_trace *a;
+ unsigned long total = 0;
+ dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
+ total += a->len;
+ if (a->magic != ALLOC_MAGIC) {
+ wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
+ "len %lu",
+ a, a->magic, (unsigned long) a->len);
+ continue;
+ }
+ wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
+ a, (unsigned long) a->len);
+ wpa_trace_dump("memleak", a);
+ }
+ if (total)
+ wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
+ (unsigned long) total);
+#endif /* WPA_TRACE */
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
+ defined(__OpenBSD__)
+ unsetenv(name);
+ return 0;
+#else
+ return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ FILE *f;
+ char *buf;
+ long pos;
+
+ f = fopen(name, "rb");
+ if (f == NULL)
+ return NULL;
+
+ if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
+ fclose(f);
+ return NULL;
+ }
+ *len = pos;
+ if (fseek(f, 0, SEEK_SET) < 0) {
+ fclose(f);
+ return NULL;
+ }
+
+ buf = os_malloc(*len);
+ if (buf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ if (fread(buf, 1, *len, f) != *len) {
+ fclose(f);
+ os_free(buf);
+ return NULL;
+ }
+
+ fclose(f);
+
+ return buf;
+}
+
+
+#ifndef WPA_TRACE
+void * os_zalloc(size_t size)
+{
+ return calloc(1, size);
+}
+#endif /* WPA_TRACE */
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+ const char *s = src;
+ size_t left = siz;
+
+ if (left) {
+ /* Copy string up to the maximum size of the dest buffer */
+ while (--left != 0) {
+ if ((*dest++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ if (left == 0) {
+ /* Not enough room for the string; force NUL-termination */
+ if (siz != 0)
+ *dest = '\0';
+ while (*s++)
+ ; /* determine total src string length */
+ }
+
+ return s - src - 1;
+}
+
+
+#ifdef WPA_TRACE
+
+void * os_malloc(size_t size)
+{
+ struct os_alloc_trace *a;
+ a = malloc(sizeof(*a) + size);
+ if (a == NULL)
+ return NULL;
+ a->magic = ALLOC_MAGIC;
+ dl_list_add(&alloc_list, &a->list);
+ a->len = size;
+ wpa_trace_record(a);
+ return a + 1;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+ struct os_alloc_trace *a;
+ size_t copy_len;
+ void *n;
+
+ if (ptr == NULL)
+ return os_malloc(size);
+
+ a = (struct os_alloc_trace *) ptr - 1;
+ if (a->magic != ALLOC_MAGIC) {
+ wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
+ a, a->magic,
+ a->magic == FREED_MAGIC ? " (already freed)" : "");
+ wpa_trace_show("Invalid os_realloc() call");
+ abort();
+ }
+ n = os_malloc(size);
+ if (n == NULL)
+ return NULL;
+ copy_len = a->len;
+ if (copy_len > size)
+ copy_len = size;
+ os_memcpy(n, a + 1, copy_len);
+ os_free(ptr);
+ return n;
+}
+
+
+void os_free(void *ptr)
+{
+ struct os_alloc_trace *a;
+
+ if (ptr == NULL)
+ return;
+ a = (struct os_alloc_trace *) ptr - 1;
+ if (a->magic != ALLOC_MAGIC) {
+ wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
+ a, a->magic,
+ a->magic == FREED_MAGIC ? " (already freed)" : "");
+ wpa_trace_show("Invalid os_free() call");
+ abort();
+ }
+ dl_list_del(&a->list);
+ a->magic = FREED_MAGIC;
+
+ wpa_trace_check_ref(ptr);
+ free(a);
+}
+
+
+void * os_zalloc(size_t size)
+{
+ void *ptr = os_malloc(size);
+ if (ptr)
+ os_memset(ptr, 0, size);
+ return ptr;
+}
+
+
+char * os_strdup(const char *s)
+{
+ size_t len;
+ char *d;
+ len = os_strlen(s);
+ d = os_malloc(len + 1);
+ if (d == NULL)
+ return NULL;
+ os_memcpy(d, s, len);
+ d[len] = '\0';
+ return d;
+}
+
+#endif /* WPA_TRACE */
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
new file mode 100644
index 0000000..0740964
--- /dev/null
+++ b/src/utils/os_win32.c
@@ -0,0 +1,222 @@
+/*
+ * wpa_supplicant/hostapd / OS specific functions for Win32 systems
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.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 "includes.h"
+#include <winsock2.h>
+#include <wincrypt.h>
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+ if (sec)
+ Sleep(sec * 1000);
+ if (usec)
+ Sleep(usec / 1000);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+#define EPOCHFILETIME (116444736000000000ULL)
+ FILETIME ft;
+ LARGE_INTEGER li;
+ ULONGLONG tt;
+
+#ifdef _WIN32_WCE
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+#else /* _WIN32_WCE */
+ GetSystemTimeAsFileTime(&ft);
+#endif /* _WIN32_WCE */
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ tt = (li.QuadPart - EPOCHFILETIME) / 10;
+ t->sec = (os_time_t) (tt / 1000000);
+ t->usec = (os_time_t) (tt % 1000000);
+
+ return 0;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ struct tm tm, *tm1;
+ time_t t_local, t1, t2;
+ os_time_t tz_offset;
+
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+ sec > 60)
+ return -1;
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ t_local = mktime(&tm);
+
+ /* figure out offset to UTC */
+ tm1 = localtime(&t_local);
+ if (tm1) {
+ t1 = mktime(tm1);
+ tm1 = gmtime(&t_local);
+ if (tm1) {
+ t2 = mktime(tm1);
+ tz_offset = t2 - t1;
+ } else
+ tz_offset = 0;
+ } else
+ tz_offset = 0;
+
+ *t = (os_time_t) t_local - tz_offset;
+ return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+ /* TODO */
+ return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ 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;
+}
+
+
+unsigned long os_random(void)
+{
+ return rand();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ return _strdup(rel_path);
+}
+
+
+int os_program_init(void)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+ printf("Could not find a usable WinSock.dll\n");
+ return -1;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return -1;
+}
+
+
+int os_unsetenv(const char *name)
+{
+ return -1;
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ FILE *f;
+ char *buf;
+
+ f = fopen(name, "rb");
+ if (f == NULL)
+ return NULL;
+
+ fseek(f, 0, SEEK_END);
+ *len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ buf = malloc(*len);
+ if (buf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ fread(buf, 1, *len, f);
+ fclose(f);
+
+ return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+ return calloc(1, size);
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+ const char *s = src;
+ size_t left = siz;
+
+ if (left) {
+ /* Copy string up to the maximum size of the dest buffer */
+ while (--left != 0) {
+ if ((*dest++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ if (left == 0) {
+ /* Not enough room for the string; force NUL-termination */
+ if (siz != 0)
+ *dest = '\0';
+ while (*s++)
+ ; /* determine total src string length */
+ }
+
+ return s - src - 1;
+}
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
new file mode 100644
index 0000000..bf9f04a
--- /dev/null
+++ b/src/utils/pcsc_funcs.c
@@ -0,0 +1,1238 @@
+/*
+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.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.
+ *
+ * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM
+ * cards through PC/SC smartcard library. These functions are used to implement
+ * authentication routines for EAP-SIM and EAP-AKA.
+ */
+
+#include "includes.h"
+#include <winscard.h>
+
+#include "common.h"
+#include "pcsc_funcs.h"
+
+
+/* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
+ * SIM commands:
+ * Command APDU: CLA INS P1 P2 P3 Data
+ * CLA (class of instruction): A0 for GSM, 00 for USIM
+ * INS (instruction)
+ * P1 P2 P3 (parameters, P3 = length of Data)
+ * Response APDU: Data SW1 SW2
+ * SW1 SW2 (Status words)
+ * Commands (INS P1 P2 P3):
+ * SELECT: A4 00 00 02 <file_id, 2 bytes>
+ * GET RESPONSE: C0 00 00 <len>
+ * RUN GSM ALG: 88 00 00 00 <RAND len = 10>
+ * RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
+ * P1 = ID of alg in card
+ * P2 = ID of secret key
+ * READ BINARY: B0 <offset high> <offset low> <len>
+ * READ RECORD: B2 <record number> <mode> <len>
+ * P2 (mode) = '02' (next record), '03' (previous record),
+ * '04' (absolute mode)
+ * VERIFY CHV: 20 00 <CHV number> 08
+ * CHANGE CHV: 24 00 <CHV number> 10
+ * DISABLE CHV: 26 00 01 08
+ * ENABLE CHV: 28 00 01 08
+ * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10
+ * SLEEP: FA 00 00 00
+ */
+
+/* GSM SIM commands */
+#define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02
+#define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10
+#define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00
+#define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00
+#define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00
+#define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08
+
+/* USIM commands */
+#define USIM_CLA 0x00
+#define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22
+#define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00
+
+#define SIM_RECORD_MODE_ABSOLUTE 0x04
+
+#define USIM_FSP_TEMPL_TAG 0x62
+
+#define USIM_TLV_FILE_DESC 0x82
+#define USIM_TLV_FILE_ID 0x83
+#define USIM_TLV_DF_NAME 0x84
+#define USIM_TLV_PROPR_INFO 0xA5
+#define USIM_TLV_LIFE_CYCLE_STATUS 0x8A
+#define USIM_TLV_FILE_SIZE 0x80
+#define USIM_TLV_TOTAL_FILE_SIZE 0x81
+#define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6
+#define USIM_TLV_SHORT_FILE_ID 0x88
+
+#define USIM_PS_DO_TAG 0x90
+
+#define AKA_RAND_LEN 16
+#define AKA_AUTN_LEN 16
+#define AKA_AUTS_LEN 14
+#define RES_MAX_LEN 16
+#define IK_LEN 16
+#define CK_LEN 16
+
+
+typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
+
+struct scard_data {
+ SCARDCONTEXT ctx;
+ SCARDHANDLE card;
+ DWORD protocol;
+ sim_types sim_type;
+ int pin1_required;
+};
+
+#ifdef __MINGW32_VERSION
+/* MinGW does not yet support WinScard, so load the needed functions
+ * dynamically from winscard.dll for now. */
+
+static HINSTANCE dll = NULL; /* winscard.dll */
+
+static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci;
+#undef SCARD_PCI_T0
+#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
+#undef SCARD_PCI_T1
+#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
+
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardEstablishContext)(IN DWORD dwScope,
+ IN LPCVOID pvReserved1,
+ IN LPCVOID pvReserved2,
+ OUT LPSCARDCONTEXT phContext);
+#define SCardEstablishContext dll_SCardEstablishContext
+
+static long (*dll_SCardReleaseContext)(long hContext);
+#define SCardReleaseContext dll_SCardReleaseContext
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext,
+ IN LPCSTR mszGroups,
+ OUT LPSTR mszReaders,
+ IN OUT LPDWORD pcchReaders);
+#undef SCardListReaders
+#define SCardListReaders dll_SCardListReadersA
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardConnectA)(IN SCARDCONTEXT hContext,
+ IN LPCSTR szReader,
+ IN DWORD dwShareMode,
+ IN DWORD dwPreferredProtocols,
+ OUT LPSCARDHANDLE phCard,
+ OUT LPDWORD pdwActiveProtocol);
+#undef SCardConnect
+#define SCardConnect dll_SCardConnectA
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardDisconnect)(IN SCARDHANDLE hCard,
+ IN DWORD dwDisposition);
+#define SCardDisconnect dll_SCardDisconnect
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardTransmit)(IN SCARDHANDLE hCard,
+ IN LPCSCARD_IO_REQUEST pioSendPci,
+ IN LPCBYTE pbSendBuffer,
+ IN DWORD cbSendLength,
+ IN OUT LPSCARD_IO_REQUEST pioRecvPci,
+ OUT LPBYTE pbRecvBuffer,
+ IN OUT LPDWORD pcbRecvLength);
+#define SCardTransmit dll_SCardTransmit
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard);
+#define SCardBeginTransaction dll_SCardBeginTransaction
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition);
+#define SCardEndTransaction dll_SCardEndTransaction
+
+
+static int mingw_load_symbols(void)
+{
+ char *sym;
+
+ if (dll)
+ return 0;
+
+ dll = LoadLibrary("winscard");
+ if (dll == NULL) {
+ wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll "
+ "library");
+ return -1;
+ }
+
+#define LOADSYM(s) \
+ sym = #s; \
+ dll_ ## s = (void *) GetProcAddress(dll, sym); \
+ if (dll_ ## s == NULL) \
+ goto fail;
+
+ LOADSYM(SCardEstablishContext);
+ LOADSYM(SCardReleaseContext);
+ LOADSYM(SCardListReadersA);
+ LOADSYM(SCardConnectA);
+ LOADSYM(SCardDisconnect);
+ LOADSYM(SCardTransmit);
+ LOADSYM(SCardBeginTransaction);
+ LOADSYM(SCardEndTransaction);
+ LOADSYM(g_rgSCardT0Pci);
+ LOADSYM(g_rgSCardT1Pci);
+
+#undef LOADSYM
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from "
+ "winscard.dll", sym);
+ FreeLibrary(dll);
+ dll = NULL;
+ return -1;
+}
+
+
+static void mingw_unload_symbols(void)
+{
+ if (dll == NULL)
+ return;
+
+ FreeLibrary(dll);
+ dll = NULL;
+}
+
+#else /* __MINGW32_VERSION */
+
+#define mingw_load_symbols() 0
+#define mingw_unload_symbols() do { } while (0)
+
+#endif /* __MINGW32_VERSION */
+
+
+static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
+ unsigned char *buf, size_t *buf_len,
+ sim_types sim_type, unsigned char *aid,
+ size_t aidlen);
+static int scard_select_file(struct scard_data *scard, unsigned short file_id,
+ unsigned char *buf, size_t *buf_len);
+static int scard_verify_pin(struct scard_data *scard, const char *pin);
+static int scard_get_record_len(struct scard_data *scard,
+ unsigned char recnum, unsigned char mode);
+static int scard_read_record(struct scard_data *scard,
+ unsigned char *data, size_t len,
+ unsigned char recnum, unsigned char mode);
+
+
+static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
+ int *ps_do, int *file_len)
+{
+ unsigned char *pos, *end;
+
+ if (ps_do)
+ *ps_do = -1;
+ if (file_len)
+ *file_len = -1;
+
+ pos = buf;
+ end = pos + buf_len;
+ if (*pos != USIM_FSP_TEMPL_TAG) {
+ wpa_printf(MSG_DEBUG, "SCARD: file header did not "
+ "start with FSP template tag");
+ return -1;
+ }
+ pos++;
+ if (pos >= end)
+ return -1;
+ if ((pos + pos[0]) < end)
+ end = pos + 1 + pos[0];
+ pos++;
+ wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
+ pos, end - pos);
+
+ while (pos + 1 < end) {
+ wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV "
+ "0x%02x len=%d", pos[0], pos[1]);
+ if (pos + 2 + pos[1] > end)
+ break;
+
+ if (pos[0] == USIM_TLV_FILE_SIZE &&
+ (pos[1] == 1 || pos[1] == 2) && file_len) {
+ if (pos[1] == 1)
+ *file_len = (int) pos[2];
+ else
+ *file_len = ((int) pos[2] << 8) |
+ (int) pos[3];
+ wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
+ *file_len);
+ }
+
+ if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE &&
+ pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
+ pos[3] >= 1 && ps_do) {
+ wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
+ pos[4]);
+ *ps_do = (int) pos[4];
+ }
+
+ pos += 2 + pos[1];
+
+ if (pos == end)
+ return 0;
+ }
+ return -1;
+}
+
+
+static int scard_pin_needed(struct scard_data *scard,
+ unsigned char *hdr, size_t hlen)
+{
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ if (hlen > SCARD_CHV1_OFFSET &&
+ !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
+ return 1;
+ return 0;
+ }
+
+ if (scard->sim_type == SCARD_USIM) {
+ int ps_do;
+ if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL))
+ return -1;
+ /* TODO: there could be more than one PS_DO entry because of
+ * multiple PINs in key reference.. */
+ if (ps_do > 0 && (ps_do & 0x80))
+ return 1;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
+ size_t maxlen)
+{
+ int rlen, rec;
+ struct efdir {
+ unsigned char appl_template_tag; /* 0x61 */
+ unsigned char appl_template_len;
+ unsigned char appl_id_tag; /* 0x4f */
+ unsigned char aid_len;
+ unsigned char rid[5];
+ unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
+ } *efdir;
+ unsigned char buf[100];
+ size_t blen;
+
+ efdir = (struct efdir *) buf;
+ blen = sizeof(buf);
+ if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen);
+
+ for (rec = 1; rec < 10; rec++) {
+ rlen = scard_get_record_len(scard, rec,
+ SIM_RECORD_MODE_ABSOLUTE);
+ if (rlen < 0) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR "
+ "record length");
+ return -1;
+ }
+ blen = sizeof(buf);
+ if (rlen > (int) blen) {
+ wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record");
+ return -1;
+ }
+ if (scard_read_record(scard, buf, rlen, rec,
+ SIM_RECORD_MODE_ABSOLUTE) < 0) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read "
+ "EF_DIR record %d", rec);
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen);
+
+ if (efdir->appl_template_tag != 0x61) {
+ wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
+ "template tag 0x%x",
+ efdir->appl_template_tag);
+ continue;
+ }
+
+ if (efdir->appl_template_len > rlen - 2) {
+ wpa_printf(MSG_DEBUG, "SCARD: Too long application "
+ "template (len=%d rlen=%d)",
+ efdir->appl_template_len, rlen);
+ continue;
+ }
+
+ if (efdir->appl_id_tag != 0x4f) {
+ wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
+ "identifier tag 0x%x", efdir->appl_id_tag);
+ continue;
+ }
+
+ if (efdir->aid_len < 1 || efdir->aid_len > 16) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
+ efdir->aid_len);
+ continue;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
+ efdir->rid, efdir->aid_len);
+
+ if (efdir->appl_code[0] == 0x10 &&
+ efdir->appl_code[1] == 0x02) {
+ wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from "
+ "EF_DIR record %d", rec);
+ break;
+ }
+ }
+
+ if (rec >= 10) {
+ wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found "
+ "from EF_DIR records");
+ return -1;
+ }
+
+ if (efdir->aid_len > maxlen) {
+ wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
+ return -1;
+ }
+
+ os_memcpy(aid, efdir->rid, efdir->aid_len);
+
+ return efdir->aid_len;
+}
+
+
+/**
+ * scard_init - Initialize SIM/USIM connection using PC/SC
+ * @sim_type: Allowed SIM types (SIM, USIM, or both)
+ * Returns: Pointer to private data structure, or %NULL on failure
+ *
+ * This function is used to initialize SIM/USIM connection. PC/SC is used to
+ * open connection to the SIM/USIM card and the card is verified to support the
+ * selected sim_type. In addition, local flag is set if a PIN is needed to
+ * access some of the card functions. Once the connection is not needed
+ * anymore, scard_deinit() can be used to close it.
+ */
+struct scard_data * scard_init(scard_sim_type sim_type)
+{
+ long ret;
+ unsigned long len;
+ struct scard_data *scard;
+#ifdef CONFIG_NATIVE_WINDOWS
+ TCHAR *readers = NULL;
+#else /* CONFIG_NATIVE_WINDOWS */
+ char *readers = NULL;
+#endif /* CONFIG_NATIVE_WINDOWS */
+ unsigned char buf[100];
+ size_t blen;
+ int transaction = 0;
+ int pin_needed;
+
+ wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
+ if (mingw_load_symbols())
+ return NULL;
+ scard = os_zalloc(sizeof(*scard));
+ if (scard == NULL)
+ return NULL;
+
+ ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
+ &scard->ctx);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card "
+ "context (err=%ld)", ret);
+ goto failed;
+ }
+
+ ret = SCardListReaders(scard->ctx, NULL, NULL, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed "
+ "(err=%ld)", ret);
+ goto failed;
+ }
+
+#ifdef UNICODE
+ len *= 2;
+#endif /* UNICODE */
+ readers = os_malloc(len);
+ if (readers == NULL) {
+ wpa_printf(MSG_INFO, "SCARD: malloc failed\n");
+ goto failed;
+ }
+
+ ret = SCardListReaders(scard->ctx, NULL, readers, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) "
+ "(err=%ld)", ret);
+ goto failed;
+ }
+ if (len < 3) {
+ wpa_printf(MSG_WARNING, "SCARD: No smart card readers "
+ "available.");
+ goto failed;
+ }
+ /* readers is a list of available reader. Last entry is terminated with
+ * double NUL.
+ * TODO: add support for selecting the reader; now just use the first
+ * one.. */
+#ifdef UNICODE
+ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
+#else /* UNICODE */
+ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
+#endif /* UNICODE */
+
+ ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
+ SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
+ if (ret != SCARD_S_SUCCESS) {
+ if (ret == (long) SCARD_E_NO_SMARTCARD)
+ wpa_printf(MSG_INFO, "No smart card inserted.");
+ else
+ wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
+ goto failed;
+ }
+
+ os_free(readers);
+ readers = NULL;
+
+ wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
+ (unsigned int) scard->card, scard->protocol,
+ scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
+
+ ret = SCardBeginTransaction(scard->card);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: "
+ "0x%x", (unsigned int) ret);
+ goto failed;
+ }
+ transaction = 1;
+
+ blen = sizeof(buf);
+
+ scard->sim_type = SCARD_GSM_SIM;
+ if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
+ wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
+ if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
+ SCARD_USIM, NULL, 0)) {
+ wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
+ if (sim_type == SCARD_USIM_ONLY)
+ goto failed;
+ wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
+ scard->sim_type = SCARD_GSM_SIM;
+ } else {
+ wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
+ scard->sim_type = SCARD_USIM;
+ }
+ }
+
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ blen = sizeof(buf);
+ if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF");
+ goto failed;
+ }
+
+ blen = sizeof(buf);
+ if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF");
+ goto failed;
+ }
+ } else {
+ unsigned char aid[32];
+ int aid_len;
+
+ aid_len = scard_get_aid(scard, aid, sizeof(aid));
+ if (aid_len < 0) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for "
+ "3G USIM app - try to use standard 3G RID");
+ os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
+ aid_len = 5;
+ }
+ wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len);
+
+ /* Select based on AID = 3G RID from EF_DIR. This is usually
+ * starting with A0 00 00 00 87. */
+ blen = sizeof(buf);
+ if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type,
+ aid, aid_len)) {
+ wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM "
+ "app");
+ wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID",
+ aid, aid_len);
+ goto failed;
+ }
+ }
+
+ /* Verify whether CHV1 (PIN1) is needed to access the card. */
+ pin_needed = scard_pin_needed(scard, buf, blen);
+ if (pin_needed < 0) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN "
+ "is needed");
+ goto failed;
+ }
+ if (pin_needed) {
+ scard->pin1_required = 1;
+ wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
+ }
+
+ ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: "
+ "0x%x", (unsigned int) ret);
+ }
+
+ return scard;
+
+failed:
+ if (transaction)
+ SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
+ os_free(readers);
+ scard_deinit(scard);
+ return NULL;
+}
+
+
+/**
+ * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands
+ * @scard: Pointer to private data from scard_init()
+ * @pin: PIN code as an ASCII string (e.g., "1234")
+ * Returns: 0 on success, -1 on failure
+ */
+int scard_set_pin(struct scard_data *scard, const char *pin)
+{
+ if (scard == NULL)
+ return -1;
+
+ /* Verify whether CHV1 (PIN1) is needed to access the card. */
+ if (scard->pin1_required) {
+ if (pin == NULL) {
+ wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
+ "access");
+ return -1;
+ }
+ if (scard_verify_pin(scard, pin)) {
+ wpa_printf(MSG_INFO, "PIN verification failed for "
+ "SIM access");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * scard_deinit - Deinitialize SIM/USIM connection
+ * @scard: Pointer to private data from scard_init()
+ *
+ * This function closes the SIM/USIM connect opened with scard_init().
+ */
+void scard_deinit(struct scard_data *scard)
+{
+ long ret;
+
+ if (scard == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface");
+ if (scard->card) {
+ ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect "
+ "smart card (err=%ld)", ret);
+ }
+ }
+
+ if (scard->ctx) {
+ ret = SCardReleaseContext(scard->ctx);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "Failed to release smart card "
+ "context (err=%ld)", ret);
+ }
+ }
+ os_free(scard);
+ mingw_unload_symbols();
+}
+
+
+static long scard_transmit(struct scard_data *scard,
+ unsigned char *_send, size_t send_len,
+ unsigned char *_recv, size_t *recv_len)
+{
+ long ret;
+ unsigned long rlen;
+
+ wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
+ _send, send_len);
+ rlen = *recv_len;
+ ret = SCardTransmit(scard->card,
+ scard->protocol == SCARD_PROTOCOL_T1 ?
+ SCARD_PCI_T1 : SCARD_PCI_T0,
+ _send, (unsigned long) send_len,
+ NULL, _recv, &rlen);
+ *recv_len = rlen;
+ if (ret == SCARD_S_SUCCESS) {
+ wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
+ _recv, rlen);
+ } else {
+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
+ "(err=0x%lx)", ret);
+ }
+ return ret;
+}
+
+
+static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
+ unsigned char *buf, size_t *buf_len,
+ sim_types sim_type, unsigned char *aid,
+ size_t aidlen)
+{
+ long ret;
+ unsigned char resp[3];
+ unsigned char cmd[50] = { SIM_CMD_SELECT };
+ int cmdlen;
+ unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
+ size_t len, rlen;
+
+ if (sim_type == SCARD_USIM) {
+ cmd[0] = USIM_CLA;
+ cmd[3] = 0x04;
+ get_resp[0] = USIM_CLA;
+ }
+
+ wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
+ if (aid) {
+ wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID",
+ aid, aidlen);
+ if (5 + aidlen > sizeof(cmd))
+ return -1;
+ cmd[2] = 0x04; /* Select by AID */
+ cmd[4] = aidlen; /* len */
+ os_memcpy(cmd + 5, aid, aidlen);
+ cmdlen = 5 + aidlen;
+ } else {
+ cmd[5] = file_id >> 8;
+ cmd[6] = file_id & 0xff;
+ cmdlen = 7;
+ }
+ len = sizeof(resp);
+ ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
+ "(err=0x%lx)", ret);
+ return -1;
+ }
+
+ if (len != 2) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected resp len "
+ "%d (expected 2)", (int) len);
+ return -1;
+ }
+
+ if (resp[0] == 0x98 && resp[1] == 0x04) {
+ /* Security status not satisfied (PIN_WLAN) */
+ wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied "
+ "(PIN_WLAN)");
+ return -1;
+ }
+
+ if (resp[0] == 0x6e) {
+ wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported");
+ return -1;
+ }
+
+ if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x "
+ "(expected 0x61, 0x6c, or 0x9f)", resp[0]);
+ return -1;
+ }
+ /* Normal ending of command; resp[1] bytes available */
+ get_resp[4] = resp[1];
+ wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)",
+ resp[1]);
+
+ rlen = *buf_len;
+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen);
+ if (ret == SCARD_S_SUCCESS) {
+ *buf_len = resp[1] < rlen ? resp[1] : rlen;
+ return 0;
+ }
+
+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret);
+ return -1;
+}
+
+
+static int scard_select_file(struct scard_data *scard, unsigned short file_id,
+ unsigned char *buf, size_t *buf_len)
+{
+ return _scard_select_file(scard, file_id, buf, buf_len,
+ scard->sim_type, NULL, 0);
+}
+
+
+static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
+ unsigned char mode)
+{
+ unsigned char buf[255];
+ unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
+ size_t blen;
+ long ret;
+
+ if (scard->sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ cmd[2] = recnum;
+ cmd[3] = mode;
+ cmd[4] = sizeof(buf);
+
+ blen = sizeof(buf);
+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: failed to determine file "
+ "length for record %d", recnum);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
+ buf, blen);
+
+ if (blen < 2 || buf[0] != 0x6c) {
+ wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
+ "length determination");
+ return -1;
+ }
+
+ return buf[1];
+}
+
+
+static int scard_read_record(struct scard_data *scard,
+ unsigned char *data, size_t len,
+ unsigned char recnum, unsigned char mode)
+{
+ unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
+ size_t blen = len + 3;
+ unsigned char *buf;
+ long ret;
+
+ if (scard->sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ cmd[2] = recnum;
+ cmd[3] = mode;
+ cmd[4] = len;
+
+ buf = os_malloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ os_free(buf);
+ return -2;
+ }
+ if (blen != len + 2) {
+ wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
+ "length %ld (expected %ld)",
+ (long) blen, (long) len + 2);
+ os_free(buf);
+ return -3;
+ }
+
+ if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
+ wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
+ "status %02x %02x (expected 90 00)",
+ buf[len], buf[len + 1]);
+ os_free(buf);
+ return -4;
+ }
+
+ os_memcpy(data, buf, len);
+ os_free(buf);
+
+ return 0;
+}
+
+
+static int scard_read_file(struct scard_data *scard,
+ unsigned char *data, size_t len)
+{
+ unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ };
+ size_t blen = len + 3;
+ unsigned char *buf;
+ long ret;
+
+ cmd[4] = len;
+
+ buf = os_malloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ if (scard->sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ os_free(buf);
+ return -2;
+ }
+ if (blen != len + 2) {
+ wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
+ "length %ld (expected %ld)",
+ (long) blen, (long) len + 2);
+ os_free(buf);
+ return -3;
+ }
+
+ if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
+ wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
+ "status %02x %02x (expected 90 00)",
+ buf[len], buf[len + 1]);
+ os_free(buf);
+ return -4;
+ }
+
+ os_memcpy(data, buf, len);
+ os_free(buf);
+
+ return 0;
+}
+
+
+static int scard_verify_pin(struct scard_data *scard, const char *pin)
+{
+ long ret;
+ unsigned char resp[3];
+ unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
+ size_t len;
+
+ wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
+
+ if (pin == NULL || os_strlen(pin) > 8)
+ return -1;
+
+ if (scard->sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ os_memcpy(cmd + 5, pin, os_strlen(pin));
+ os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin));
+
+ len = sizeof(resp);
+ ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -2;
+
+ if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
+ wpa_printf(MSG_WARNING, "SCARD: PIN verification failed");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully");
+ return 0;
+}
+
+
+/**
+ * scard_get_imsi - Read IMSI from SIM/USIM card
+ * @scard: Pointer to private data from scard_init()
+ * @imsi: Buffer for IMSI
+ * @len: Length of imsi buffer; set to IMSI length on success
+ * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
+ * selection returns invalid result code, -3 if parsing FSP template file fails
+ * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
+ * to needed length), -5 if reading IMSI file fails.
+ *
+ * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
+ * file is PIN protected, scard_set_pin() must have been used to set the
+ * correct PIN code before calling scard_get_imsi().
+ */
+int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
+{
+ unsigned char buf[100];
+ size_t blen, imsilen, i;
+ char *pos;
+
+ wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
+ blen = sizeof(buf);
+ if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen))
+ return -1;
+ if (blen < 4) {
+ wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI "
+ "header (len=%ld)", (long) blen);
+ return -2;
+ }
+
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ blen = (buf[2] << 8) | buf[3];
+ } else {
+ int file_size;
+ if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
+ return -3;
+ blen = file_size;
+ }
+ if (blen < 2 || blen > sizeof(buf)) {
+ wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld",
+ (long) blen);
+ return -3;
+ }
+
+ imsilen = (blen - 2) * 2 + 1;
+ wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld",
+ (long) blen, (long) imsilen);
+ if (blen < 2 || imsilen > *len) {
+ *len = imsilen;
+ return -4;
+ }
+
+ if (scard_read_file(scard, buf, blen))
+ return -5;
+
+ pos = imsi;
+ *pos++ = '0' + (buf[1] >> 4 & 0x0f);
+ for (i = 2; i < blen; i++) {
+ unsigned char digit;
+
+ digit = buf[i] & 0x0f;
+ if (digit < 10)
+ *pos++ = '0' + digit;
+ else
+ imsilen--;
+
+ digit = buf[i] >> 4 & 0x0f;
+ if (digit < 10)
+ *pos++ = '0' + digit;
+ else
+ imsilen--;
+ }
+ *len = imsilen;
+
+ return 0;
+}
+
+
+/**
+ * scard_gsm_auth - Run GSM authentication command on SIM card
+ * @scard: Pointer to private data from scard_init()
+ * @_rand: 16-byte RAND value from HLR/AuC
+ * @sres: 4-byte buffer for SRES
+ * @kc: 8-byte buffer for Kc
+ * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized,
+ * -2 if authentication command execution fails, -3 if unknown response code
+ * for authentication command is received, -4 if reading of response fails,
+ * -5 if if response data is of unexpected length
+ *
+ * This function performs GSM authentication using SIM/USIM card and the
+ * provided RAND value from HLR/AuC. If authentication command can be completed
+ * successfully, SRES and Kc values will be written into sres and kc buffers.
+ */
+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
+ unsigned char *sres, unsigned char *kc)
+{
+ unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
+ int cmdlen;
+ unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
+ unsigned char resp[3], buf[12 + 3 + 2];
+ size_t len;
+ long ret;
+
+ if (scard == NULL)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16);
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ cmdlen = 5 + 16;
+ os_memcpy(cmd + 5, _rand, 16);
+ } else {
+ cmdlen = 5 + 1 + 16;
+ cmd[0] = USIM_CLA;
+ cmd[3] = 0x80;
+ cmd[4] = 17;
+ cmd[5] = 16;
+ os_memcpy(cmd + 6, _rand, 16);
+ }
+ len = sizeof(resp);
+ ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -2;
+
+ if ((scard->sim_type == SCARD_GSM_SIM &&
+ (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) ||
+ (scard->sim_type == SCARD_USIM &&
+ (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM "
+ "auth request (len=%ld resp=%02x %02x)",
+ (long) len, resp[0], resp[1]);
+ return -3;
+ }
+ get_resp[4] = resp[1];
+
+ len = sizeof(buf);
+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -4;
+
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ if (len != 4 + 8 + 2) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected data "
+ "length for GSM auth (len=%ld, expected 14)",
+ (long) len);
+ return -5;
+ }
+ os_memcpy(sres, buf, 4);
+ os_memcpy(kc, buf + 4, 8);
+ } else {
+ if (len != 1 + 4 + 1 + 8 + 2) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected data "
+ "length for USIM auth (len=%ld, "
+ "expected 16)", (long) len);
+ return -5;
+ }
+ if (buf[0] != 4 || buf[5] != 8) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc "
+ "length (%d %d, expected 4 8)",
+ buf[0], buf[5]);
+ }
+ os_memcpy(sres, buf + 1, 4);
+ os_memcpy(kc, buf + 6, 8);
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8);
+
+ return 0;
+}
+
+
+/**
+ * scard_umts_auth - Run UMTS authentication command on USIM card
+ * @scard: Pointer to private data from scard_init()
+ * @_rand: 16-byte RAND value from HLR/AuC
+ * @autn: 16-byte AUTN value from HLR/AuC
+ * @res: 16-byte buffer for RES
+ * @res_len: Variable that will be set to RES length
+ * @ik: 16-byte buffer for IK
+ * @ck: 16-byte buffer for CK
+ * @auts: 14-byte buffer for AUTS
+ * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
+ * failure
+ *
+ * This function performs AKA authentication using USIM card and the provided
+ * RAND and AUTN values from HLR/AuC. If authentication command can be
+ * completed successfully, RES, IK, and CK values will be written into provided
+ * buffers and res_len is set to length of received RES value. If USIM reports
+ * synchronization failure, the received AUTS value will be written into auts
+ * buffer. In this case, RES, IK, and CK are not valid.
+ */
+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
+ const unsigned char *autn,
+ unsigned char *res, size_t *res_len,
+ unsigned char *ik, unsigned char *ck, unsigned char *auts)
+{
+ unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] =
+ { USIM_CMD_RUN_UMTS_ALG };
+ unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
+ unsigned char resp[3], buf[64], *pos, *end;
+ size_t len;
+ long ret;
+
+ if (scard == NULL)
+ return -1;
+
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS "
+ "auth");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN);
+ cmd[5] = AKA_RAND_LEN;
+ os_memcpy(cmd + 6, _rand, AKA_RAND_LEN);
+ cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
+ os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
+
+ len = sizeof(resp);
+ ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -1;
+
+ if (len <= sizeof(resp))
+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
+
+ if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
+ wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - "
+ "MAC != XMAC");
+ return -1;
+ } else if (len != 2 || resp[0] != 0x61) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS "
+ "auth request (len=%ld resp=%02x %02x)",
+ (long) len, resp[0], resp[1]);
+ return -1;
+ }
+ get_resp[4] = resp[1];
+
+ len = sizeof(buf);
+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
+ if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len);
+ if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc &&
+ buf[1] == AKA_AUTS_LEN) {
+ wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure");
+ os_memcpy(auts, buf + 2, AKA_AUTS_LEN);
+ wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
+ return -2;
+ } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
+ pos = buf + 1;
+ end = buf + len;
+
+ /* RES */
+ if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
+ return -1;
+ }
+ *res_len = *pos++;
+ os_memcpy(res, pos, *res_len);
+ pos += *res_len;
+ wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
+
+ /* CK */
+ if (pos[0] != CK_LEN || pos + CK_LEN > end) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
+ return -1;
+ }
+ pos++;
+ os_memcpy(ck, pos, CK_LEN);
+ pos += CK_LEN;
+ wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
+
+ /* IK */
+ if (pos[0] != IK_LEN || pos + IK_LEN > end) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
+ return -1;
+ }
+ pos++;
+ os_memcpy(ik, pos, IK_LEN);
+ pos += IK_LEN;
+ wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
+
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
+ return -1;
+}
diff --git a/src/utils/pcsc_funcs.h b/src/utils/pcsc_funcs.h
new file mode 100644
index 0000000..543f7c5
--- /dev/null
+++ b/src/utils/pcsc_funcs.h
@@ -0,0 +1,68 @@
+/*
+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef PCSC_FUNCS_H
+#define PCSC_FUNCS_H
+
+/* GSM files
+ * File type in first octet:
+ * 3F = Master File
+ * 7F = Dedicated File
+ * 2F = Elementary File under the Master File
+ * 6F = Elementary File under a Dedicated File
+ */
+#define SCARD_FILE_MF 0x3F00
+#define SCARD_FILE_GSM_DF 0x7F20
+#define SCARD_FILE_UMTS_DF 0x7F50
+#define SCARD_FILE_GSM_EF_IMSI 0x6F07
+#define SCARD_FILE_EF_DIR 0x2F00
+#define SCARD_FILE_EF_ICCID 0x2FE2
+#define SCARD_FILE_EF_CK 0x6FE1
+#define SCARD_FILE_EF_IK 0x6FE2
+
+#define SCARD_CHV1_OFFSET 13
+#define SCARD_CHV1_FLAG 0x80
+
+typedef enum {
+ SCARD_GSM_SIM_ONLY,
+ SCARD_USIM_ONLY,
+ SCARD_TRY_BOTH
+} scard_sim_type;
+
+
+#ifdef PCSC_FUNCS
+struct scard_data * scard_init(scard_sim_type sim_type);
+void scard_deinit(struct scard_data *scard);
+
+int scard_set_pin(struct scard_data *scard, const char *pin);
+int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len);
+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
+ unsigned char *sres, unsigned char *kc);
+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
+ const unsigned char *autn,
+ unsigned char *res, size_t *res_len,
+ unsigned char *ik, unsigned char *ck, unsigned char *auts);
+
+#else /* PCSC_FUNCS */
+
+#define scard_init(s) NULL
+#define scard_deinit(s) do { } while (0)
+#define scard_set_pin(s, p) -1
+#define scard_get_imsi(s, i, l) -1
+#define scard_gsm_auth(s, r, s2, k) -1
+#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1
+
+#endif /* PCSC_FUNCS */
+
+#endif /* PCSC_FUNCS_H */
diff --git a/src/utils/radiotap.c b/src/utils/radiotap.c
new file mode 100644
index 0000000..804473f
--- /dev/null
+++ b/src/utils/radiotap.c
@@ -0,0 +1,287 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007 Andy Green <andy@warmcat.com>
+ *
+ * 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.
+ *
+ *
+ * Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
+ * I only modified some things on top to ease syncing should bugs be found.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "radiotap_iter.h"
+
+#define le16_to_cpu le_to_host16
+#define le32_to_cpu le_to_host32
+#define __le32 uint32_t
+#define ulong unsigned long
+#define unlikely(cond) (cond)
+#define get_unaligned(p) \
+({ \
+ struct packed_dummy_struct { \
+ typeof(*(p)) __val; \
+ } __attribute__((packed)) *__ptr = (void *) (p); \
+ \
+ __ptr->__val; \
+})
+
+/* function prototypes and related defs are in radiotap_iter.h */
+
+/**
+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
+ * @iterator: radiotap_iterator to initialize
+ * @radiotap_header: radiotap header to parse
+ * @max_length: total length we can parse into (eg, whole packet length)
+ *
+ * Returns: 0 or a negative error code if there is a problem.
+ *
+ * This function initializes an opaque iterator struct which can then
+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
+ * argument which is present in the header. It knows about extended
+ * present headers and handles them.
+ *
+ * How to use:
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * checking for a good 0 return code. Then loop calling
+ * __ieee80211_radiotap_iterator_next()... it returns either 0,
+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
+ * The iterator's @this_arg member points to the start of the argument
+ * associated with the current argument index that is present, which can be
+ * found in the iterator's @this_arg_index member. This arg index corresponds
+ * to the IEEE80211_RADIOTAP_... defines.
+ *
+ * Radiotap header length:
+ * You can find the CPU-endian total radiotap header length in
+ * iterator->max_length after executing ieee80211_radiotap_iterator_init()
+ * successfully.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ *
+ * Example code:
+ * See Documentation/networking/radiotap-headers.txt
+ */
+
+int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length)
+{
+ /* Linux only supports version 0 radiotap format */
+ if (radiotap_header->it_version)
+ return -EINVAL;
+
+ /* sanity check for allowed length and radiotap length field */
+ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ return -EINVAL;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = le16_to_cpu(get_unaligned(
+ &radiotap_header->it_len));
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
+ &radiotap_header->it_present));
+ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
+ iterator->this_arg = NULL;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
+ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
+ (1<<IEEE80211_RADIOTAP_EXT)) {
+ iterator->arg += sizeof(u32);
+
+ /*
+ * check for insanity where the present bitmaps
+ * keep claiming to extend up to or even beyond the
+ * stated radiotap header length
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader)
+ > (ulong)iterator->max_length)
+ return -EINVAL;
+ }
+
+ iterator->arg += sizeof(u32);
+
+ /*
+ * no need to check again for blowing past stated radiotap
+ * header length, because ieee80211_radiotap_iterator_next
+ * checks it before it is dereferenced
+ */
+ }
+
+ /* we are all initialized happily */
+
+ return 0;
+}
+
+
+/**
+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ * @iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * Returns: 0 if there is an argument to handle,
+ * -ENOENT if there are no more args or -EINVAL
+ * if there is something else wrong.
+ *
+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * in @this_arg_index and sets @this_arg to point to the
+ * payload for the field. It takes care of alignment handling and extended
+ * present fields. @this_arg can be changed by the caller (eg,
+ * incremented to move inside a compound argument like
+ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
+ * little-endian format whatever the endianess of your CPU.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+
+int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator)
+{
+
+ /*
+ * small length lookup table for all radiotap types we heard of
+ * starting from b0 in the bitmap, so we can walk the payload
+ * area of the radiotap header
+ *
+ * There is a requirement to pad args, so that args
+ * of a given length must begin at a boundary of that length
+ * -- but note that compound args are allowed (eg, 2 x u16
+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+ * a reliable indicator of alignment requirement.
+ *
+ * upper nybble: content alignment for arg
+ * lower nybble: content length for arg
+ */
+
+ static const u8 rt_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = 0x88,
+ [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+ [IEEE80211_RADIOTAP_RATE] = 0x11,
+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+ [IEEE80211_RADIOTAP_FHSS] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
+ [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
+ /*
+ * add more here as they are defined in
+ * include/net/ieee80211_radiotap.h
+ */
+ };
+
+ /*
+ * for every radiotap entry we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (iterator->arg_index < (int) sizeof(rt_sizes)) {
+ int hit = 0;
+ int pad;
+
+ if (!(iterator->bitmap_shifter & 1))
+ goto next_entry; /* arg not present */
+
+ /*
+ * arg is present, account for alignment padding
+ * 8-bit args can be at any alignment
+ * 16-bit args must start on 16-bit boundary
+ * 32-bit args must start on 32-bit boundary
+ * 64-bit args must start on 64-bit boundary
+ *
+ * note that total arg size can differ from alignment of
+ * elements inside arg, so we use upper nybble of length
+ * table to base alignment on
+ *
+ * also note: these alignments are ** relative to the
+ * start of the radiotap header **. There is no guarantee
+ * that the radiotap header itself is aligned on any
+ * kind of boundary.
+ *
+ * the above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area
+ */
+
+ pad = (((ulong)iterator->arg) -
+ ((ulong)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1);
+
+ if (pad)
+ iterator->arg +=
+ (rt_sizes[iterator->arg_index] >> 4) - pad;
+
+ /*
+ * this is what we will return to user, but we need to
+ * move on first so next call has something fresh to test
+ */
+ iterator->this_arg_index = iterator->arg_index;
+ iterator->this_arg = iterator->arg;
+ hit = 1;
+
+ /* internally move on the size of this arg */
+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+ /*
+ * check for insanity where we are given a bitmap that
+ * claims to have more arg content than the length of the
+ * radiotap section. We will normally end up equalling this
+ * max_length on the last arg, never exceeding it.
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
+ (ulong) iterator->max_length)
+ return -EINVAL;
+
+ next_entry:
+ iterator->arg_index++;
+ if (unlikely((iterator->arg_index & 31) == 0)) {
+ /* completed current u32 bitmap */
+ if (iterator->bitmap_shifter & 1) {
+ /* b31 was set, there is more */
+ /* move to next u32 bitmap */
+ iterator->bitmap_shifter = le32_to_cpu(
+ get_unaligned(iterator->next_bitmap));
+ iterator->next_bitmap++;
+ } else
+ /* no more bitmaps: end */
+ iterator->arg_index = sizeof(rt_sizes);
+ } else /* just try the next bit */
+ iterator->bitmap_shifter >>= 1;
+
+ /* if we found a valid arg earlier, return it now */
+ if (hit)
+ return 0;
+ }
+
+ /* we don't know how to handle any more args, we're done */
+ return -ENOENT;
+}
diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h
new file mode 100644
index 0000000..508264c
--- /dev/null
+++ b/src/utils/radiotap.h
@@ -0,0 +1,242 @@
+/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
+/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2003, 2004 David Young. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of David Young may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications to fit into the linux IEEE 802.11 stack,
+ * Mike Kershaw (dragorn@kismetwireless.net)
+ */
+
+#ifndef IEEE80211RADIOTAP_H
+#define IEEE80211RADIOTAP_H
+
+#include <stdint.h>
+
+/* Base version of the radiotap packet header data */
+#define PKTHDR_RADIOTAP_VERSION 0
+
+/* A generic radio capture format is desirable. There is one for
+ * Linux, but it is neither rigidly defined (there were not even
+ * units given for some fields) nor easily extensible.
+ *
+ * I suggest the following extensible radio capture format. It is
+ * based on a bitmap indicating which fields are present.
+ *
+ * I am trying to describe precisely what the application programmer
+ * should expect in the following, and for that reason I tell the
+ * units and origin of each measurement (where it applies), or else I
+ * use sufficiently weaselly language ("is a monotonically nondecreasing
+ * function of...") that I cannot set false expectations for lawyerly
+ * readers.
+ */
+
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
+struct ieee80211_radiotap_header {
+ uint8_t it_version; /* Version 0. Only increases
+ * for drastic changes,
+ * introduction of compatible
+ * new fields does not count.
+ */
+ uint8_t it_pad;
+ uint16_t it_len; /* length of the whole
+ * header in bytes, including
+ * it_version, it_pad,
+ * it_len, and data fields.
+ */
+ uint32_t it_present; /* A bitmap telling which
+ * fields are present. Set bit 31
+ * (0x80000000) to extend the
+ * bitmap by another 32 bits.
+ * Additional extensions are made
+ * by setting bit 31.
+ */
+};
+
+/* Name Data type Units
+ * ---- --------- -----
+ *
+ * IEEE80211_RADIOTAP_TSFT __le64 microseconds
+ *
+ * Value in microseconds of the MAC's 64-bit 802.11 Time
+ * Synchronization Function timer when the first bit of the
+ * MPDU arrived at the MAC. For received frames, only.
+ *
+ * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
+ *
+ * Tx/Rx frequency in MHz, followed by flags (see below).
+ *
+ * IEEE80211_RADIOTAP_FHSS uint16_t see below
+ *
+ * For frequency-hopping radios, the hop set (first byte)
+ * and pattern (second byte).
+ *
+ * IEEE80211_RADIOTAP_RATE u8 500kb/s
+ *
+ * Tx/Rx data rate
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF signal power at the antenna, decibel difference from
+ * one milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF noise power at the antenna, decibel difference from one
+ * milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
+ *
+ * RF signal power at the antenna, decibel difference from an
+ * arbitrary, fixed reference.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
+ *
+ * RF noise power at the antenna, decibel difference from an
+ * arbitrary, fixed reference point.
+ *
+ * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
+ *
+ * Quality of Barker code lock. Unitless. Monotonically
+ * nondecreasing with "better" lock strength. Called "Signal
+ * Quality" in datasheets. (Is there a standard way to measure
+ * this?)
+ *
+ * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
+ *
+ * Transmit power expressed as unitless distance from max
+ * power set at factory calibration. 0 is max power.
+ * Monotonically nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
+ *
+ * Transmit power expressed as decibel distance from max power
+ * set at factory calibration. 0 is max power. Monotonically
+ * nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * Transmit power expressed as dBm (decibels from a 1 milliwatt
+ * reference). This is the absolute power level measured at
+ * the antenna port.
+ *
+ * IEEE80211_RADIOTAP_FLAGS u8 bitmap
+ *
+ * Properties of transmitted and received frames. See flags
+ * defined below.
+ *
+ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
+ *
+ * Unitless indication of the Rx/Tx antenna for this packet.
+ * The first antenna is antenna 0.
+ *
+ * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
+ *
+ * Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
+ *
+ * Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
+ *
+ * Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
+ *
+ * Number of unicast retries a transmitted frame used.
+ *
+ */
+enum ieee80211_radiotap_type {
+ IEEE80211_RADIOTAP_TSFT = 0,
+ IEEE80211_RADIOTAP_FLAGS = 1,
+ IEEE80211_RADIOTAP_RATE = 2,
+ IEEE80211_RADIOTAP_CHANNEL = 3,
+ IEEE80211_RADIOTAP_FHSS = 4,
+ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
+ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
+ IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
+ IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
+ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
+ IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
+ IEEE80211_RADIOTAP_ANTENNA = 11,
+ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
+ IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
+ IEEE80211_RADIOTAP_RX_FLAGS = 14,
+ IEEE80211_RADIOTAP_TX_FLAGS = 15,
+ IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+ IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+ IEEE80211_RADIOTAP_EXT = 31
+};
+
+/* Channel flags. */
+#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
+#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
+#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
+#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
+#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
+#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
+#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
+#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+
+/* For IEEE80211_RADIOTAP_FLAGS */
+#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
+ * during CFP
+ */
+#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
+ * with short
+ * preamble
+ */
+#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
+ * with WEP encryption
+ */
+#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
+ * with fragmentation
+ */
+#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
+#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
+ * 802.11 header and payload
+ * (to 32-bit boundary)
+ */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
+ * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
+
+#endif /* IEEE80211_RADIOTAP_H */
diff --git a/src/utils/radiotap_iter.h b/src/utils/radiotap_iter.h
new file mode 100644
index 0000000..92a798a
--- /dev/null
+++ b/src/utils/radiotap_iter.h
@@ -0,0 +1,41 @@
+#ifndef __RADIOTAP_ITER_H
+#define __RADIOTAP_ITER_H
+
+#include "radiotap.h"
+
+/* Radiotap header iteration
+ * implemented in radiotap.c
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+ struct ieee80211_radiotap_header *rtheader;
+ int max_length;
+ int this_arg_index;
+ unsigned char *this_arg;
+
+ int arg_index;
+ unsigned char *arg;
+ uint32_t *next_bitmap;
+ uint32_t bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator);
+
+#endif /* __RADIOTAP_ITER_H */
diff --git a/src/utils/state_machine.h b/src/utils/state_machine.h
new file mode 100644
index 0000000..31f6672
--- /dev/null
+++ b/src/utils/state_machine.h
@@ -0,0 +1,144 @@
+/*
+ * wpa_supplicant/hostapd - State machine definitions
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.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.
+ *
+ * This file includes a set of pre-processor macros that can be used to
+ * implement a state machine. In addition to including this header file, each
+ * file implementing a state machine must define STATE_MACHINE_DATA to be the
+ * data structure including state variables (enum machine_state,
+ * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
+ * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define
+ * a group of state machines with shared data structure, STATE_MACHINE_ADDR
+ * needs to be defined to point to the MAC address used in debug output.
+ * SM_ENTRY_M macro can be used to define similar group of state machines
+ * without this additional debug info.
+ */
+
+#ifndef STATE_MACHINE_H
+#define STATE_MACHINE_H
+
+/**
+ * SM_STATE - Declaration of a state machine function
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used to declare a state machine function. It is used in place
+ * of a C function definition to declare functions to be run when the state is
+ * entered by calling SM_ENTER or SM_ENTER_GLOBAL.
+ */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \
+ int global)
+
+/**
+ * SM_ENTRY - State machine function entry point
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used inside each state machine function declared with
+ * SM_STATE. SM_ENTRY should be in the beginning of the function body, but
+ * after declaration of possible local variables. This macro prints debug
+ * information about state transition and update the state machine state.
+ */
+#define SM_ENTRY(machine, state) \
+if (!global || sm->machine ## _state != machine ## _ ## state) { \
+ sm->changed = TRUE; \
+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \
+ " entering state " #state); \
+} \
+sm->machine ## _state = machine ## _ ## state;
+
+/**
+ * SM_ENTRY_M - State machine function entry point for state machine group
+ * @machine: State machine name
+ * @_state: State machine state
+ * @data: State variable prefix (full variable: prefix_state)
+ *
+ * This macro is like SM_ENTRY, but for state machine groups that use a shared
+ * data structure for more than one state machine. Both machine and prefix
+ * parameters are set to "sub-state machine" name. prefix is used to allow more
+ * than one state variable to be stored in the same data structure.
+ */
+#define SM_ENTRY_M(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+ sm->changed = TRUE; \
+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \
+ #machine " entering state " #_state); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTRY_MA - State machine function entry point for state machine group
+ * @machine: State machine name
+ * @_state: State machine state
+ * @data: State variable prefix (full variable: prefix_state)
+ *
+ * This macro is like SM_ENTRY_M, but a MAC address is included in debug
+ * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to
+ * be included in debug.
+ */
+#define SM_ENTRY_MA(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+ sm->changed = TRUE; \
+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \
+ #machine " entering state " #_state, \
+ MAC2STR(STATE_MACHINE_ADDR)); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTER - Enter a new state machine state
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro expands to a function call to a state machine function defined
+ * with SM_STATE macro. SM_ENTER is used in a state machine step function to
+ * move the state machine to a new state.
+ */
+#define SM_ENTER(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 0)
+
+/**
+ * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is like SM_ENTER, but this is used when entering a new state
+ * based on a global (not specific to any particular state) rule. A separate
+ * macro is used to avoid unwanted debug message floods when the same global
+ * rule is forcing a state machine to remain in on state.
+ */
+#define SM_ENTER_GLOBAL(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 1)
+
+/**
+ * SM_STEP - Declaration of a state machine step function
+ * @machine: State machine name
+ *
+ * This macro is used to declare a state machine step function. It is used in
+ * place of a C function definition to declare a function that is used to move
+ * state machine to a new state based on state variables. This function uses
+ * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state.
+ */
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm)
+
+/**
+ * SM_STEP_RUN - Call the state machine step function
+ * @machine: State machine name
+ *
+ * This macro expands to a function call to a state machine step function
+ * defined with SM_STEP macro.
+ */
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+#endif /* STATE_MACHINE_H */
diff --git a/src/utils/trace.c b/src/utils/trace.c
new file mode 100644
index 0000000..bb3eb24
--- /dev/null
+++ b/src/utils/trace.c
@@ -0,0 +1,329 @@
+/*
+ * Backtrace debugging
+ * Copyright (c) 2009, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+#include "trace.h"
+
+#ifdef WPA_TRACE
+
+static struct dl_list active_references =
+{ &active_references, &active_references };
+
+#ifdef WPA_TRACE_BFD
+#include <bfd.h>
+#ifdef __linux__
+#include <demangle.h>
+#else /* __linux__ */
+#include <libiberty/demangle.h>
+#endif /* __linux__ */
+
+static char *prg_fname = NULL;
+static bfd *cached_abfd = NULL;
+static asymbol **syms = NULL;
+
+static void get_prg_fname(void)
+{
+ char exe[50], fname[512];
+ int len;
+ os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
+ len = readlink(exe, fname, sizeof(fname) - 1);
+ if (len < 0 || len >= (int) sizeof(fname)) {
+ perror("readlink");
+ return;
+ }
+ fname[len] = '\0';
+ prg_fname = strdup(fname);
+}
+
+
+static bfd * open_bfd(const char *fname)
+{
+ bfd *abfd;
+ char **matching;
+
+ abfd = bfd_openr(prg_fname, NULL);
+ if (abfd == NULL) {
+ wpa_printf(MSG_INFO, "bfd_openr failed");
+ return NULL;
+ }
+
+ if (bfd_check_format(abfd, bfd_archive)) {
+ wpa_printf(MSG_INFO, "bfd_check_format failed");
+ bfd_close(abfd);
+ return NULL;
+ }
+
+ if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
+ wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
+ free(matching);
+ bfd_close(abfd);
+ return NULL;
+ }
+
+ return abfd;
+}
+
+
+static void read_syms(bfd *abfd)
+{
+ long storage, symcount;
+ bfd_boolean dynamic = FALSE;
+
+ if (syms)
+ return;
+
+ if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
+ wpa_printf(MSG_INFO, "No symbols");
+ return;
+ }
+
+ storage = bfd_get_symtab_upper_bound(abfd);
+ if (storage == 0) {
+ storage = bfd_get_dynamic_symtab_upper_bound(abfd);
+ dynamic = TRUE;
+ }
+ if (storage < 0) {
+ wpa_printf(MSG_INFO, "Unknown symtab upper bound");
+ return;
+ }
+
+ syms = malloc(storage);
+ if (syms == NULL) {
+ wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
+ "(%ld bytes)", storage);
+ return;
+ }
+ if (dynamic)
+ symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
+ else
+ symcount = bfd_canonicalize_symtab(abfd, syms);
+ if (symcount < 0) {
+ wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
+ dynamic ? "dynamic " : "");
+ free(syms);
+ syms = NULL;
+ return;
+ }
+}
+
+
+struct bfd_data {
+ bfd_vma pc;
+ bfd_boolean found;
+ const char *filename;
+ const char *function;
+ unsigned int line;
+};
+
+
+static void find_addr_sect(bfd *abfd, asection *section, void *obj)
+{
+ struct bfd_data *data = obj;
+ bfd_vma vma;
+ bfd_size_type size;
+
+ if (data->found)
+ return;
+
+ if (!(bfd_get_section_vma(abfd, section)))
+ return;
+
+ vma = bfd_get_section_vma(abfd, section);
+ if (data->pc < vma)
+ return;
+
+ size = bfd_get_section_size(section);
+ if (data->pc >= vma + size)
+ return;
+
+ data->found = bfd_find_nearest_line(abfd, section, syms,
+ data->pc - vma,
+ &data->filename,
+ &data->function,
+ &data->line);
+}
+
+
+static void wpa_trace_bfd_addr(void *pc)
+{
+ bfd *abfd = cached_abfd;
+ struct bfd_data data;
+ const char *name;
+ char *aname = NULL;
+ const char *filename;
+
+ if (abfd == NULL)
+ return;
+
+ data.pc = (bfd_vma) pc;
+ data.found = FALSE;
+ bfd_map_over_sections(abfd, find_addr_sect, &data);
+
+ if (!data.found)
+ return;
+
+ do {
+ if (data.function)
+ aname = bfd_demangle(abfd, data.function,
+ DMGL_ANSI | DMGL_PARAMS);
+ name = aname ? aname : data.function;
+ filename = data.filename;
+ if (filename) {
+ char *end = os_strrchr(filename, '/');
+ int i = 0;
+ while (*filename && *filename == prg_fname[i] &&
+ filename <= end) {
+ filename++;
+ i++;
+ }
+ }
+ wpa_printf(MSG_INFO, " %s() %s:%u",
+ name, filename, data.line);
+ free(aname);
+
+ data.found = bfd_find_inliner_info(abfd, &data.filename,
+ &data.function, &data.line);
+ } while (data.found);
+}
+
+
+static const char * wpa_trace_bfd_addr2func(void *pc)
+{
+ bfd *abfd = cached_abfd;
+ struct bfd_data data;
+
+ if (abfd == NULL)
+ return NULL;
+
+ data.pc = (bfd_vma) pc;
+ data.found = FALSE;
+ bfd_map_over_sections(abfd, find_addr_sect, &data);
+
+ if (!data.found)
+ return NULL;
+
+ return data.function;
+}
+
+
+static void wpa_trace_bfd_init(void)
+{
+ if (!prg_fname) {
+ get_prg_fname();
+ if (!prg_fname)
+ return;
+ }
+
+ if (!cached_abfd) {
+ cached_abfd = open_bfd(prg_fname);
+ if (!cached_abfd) {
+ wpa_printf(MSG_INFO, "Failed to open bfd");
+ return;
+ }
+ }
+
+ read_syms(cached_abfd);
+ if (!syms) {
+ wpa_printf(MSG_INFO, "Failed to read symbols");
+ return;
+ }
+}
+
+
+void wpa_trace_dump_funcname(const char *title, void *pc)
+{
+ wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
+ wpa_trace_bfd_init();
+ wpa_trace_bfd_addr(pc);
+}
+
+#else /* WPA_TRACE_BFD */
+
+#define wpa_trace_bfd_init() do { } while (0)
+#define wpa_trace_bfd_addr(pc) do { } while (0)
+#define wpa_trace_bfd_addr2func(pc) NULL
+
+#endif /* WPA_TRACE_BFD */
+
+void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
+{
+ char **sym;
+ int i;
+ enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
+
+ wpa_trace_bfd_init();
+ wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
+ sym = backtrace_symbols(btrace, btrace_num);
+ state = TRACE_HEAD;
+ for (i = 0; i < btrace_num; i++) {
+ const char *func = wpa_trace_bfd_addr2func(btrace[i]);
+ if (state == TRACE_HEAD && func &&
+ (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
+ os_strcmp(func, "wpa_trace_check_ref") == 0 ||
+ os_strcmp(func, "wpa_trace_show") == 0))
+ continue;
+ if (state == TRACE_TAIL && sym && sym[i] &&
+ os_strstr(sym[i], "__libc_start_main"))
+ break;
+ if (state == TRACE_HEAD)
+ state = TRACE_RELEVANT;
+ if (sym)
+ wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
+ else
+ wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
+ wpa_trace_bfd_addr(btrace[i]);
+ if (state == TRACE_RELEVANT && func &&
+ os_strcmp(func, "main") == 0)
+ state = TRACE_TAIL;
+ }
+ free(sym);
+ wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
+}
+
+
+void wpa_trace_show(const char *title)
+{
+ struct info {
+ WPA_TRACE_INFO
+ } info;
+ wpa_trace_record(&info);
+ wpa_trace_dump(title, &info);
+}
+
+
+void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
+{
+ if (addr == NULL)
+ return;
+ ref->addr = addr;
+ wpa_trace_record(ref);
+ dl_list_add(&active_references, &ref->list);
+}
+
+
+void wpa_trace_check_ref(const void *addr)
+{
+ struct wpa_trace_ref *ref;
+ dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
+ if (addr != ref->addr)
+ continue;
+ wpa_trace_show("Freeing referenced memory");
+ wpa_trace_dump("Reference registration", ref);
+ abort();
+ }
+}
+
+#endif /* WPA_TRACE */
diff --git a/src/utils/trace.h b/src/utils/trace.h
new file mode 100644
index 0000000..22d3de0
--- /dev/null
+++ b/src/utils/trace.h
@@ -0,0 +1,74 @@
+/*
+ * Backtrace debugging
+ * Copyright (c) 2009, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef TRACE_H
+#define TRACE_H
+
+#define WPA_TRACE_LEN 16
+
+#ifdef WPA_TRACE
+#include <execinfo.h>
+
+#include "list.h"
+
+#define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num;
+
+struct wpa_trace_ref {
+ struct dl_list list;
+ const void *addr;
+ WPA_TRACE_INFO
+};
+#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name
+
+#define wpa_trace_dump(title, ptr) \
+ wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num)
+void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num);
+#define wpa_trace_record(ptr) \
+ (ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN)
+void wpa_trace_show(const char *title);
+#define wpa_trace_add_ref(ptr, name, addr) \
+ wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr))
+void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr);
+#define wpa_trace_remove_ref(ptr, name, addr) \
+ do { \
+ if ((addr)) \
+ dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \
+ } while (0)
+void wpa_trace_check_ref(const void *addr);
+
+#else /* WPA_TRACE */
+
+#define WPA_TRACE_INFO
+#define WPA_TRACE_REF(n)
+#define wpa_trace_dump(title, ptr) do { } while (0)
+#define wpa_trace_record(ptr) do { } while (0)
+#define wpa_trace_show(title) do { } while (0)
+#define wpa_trace_add_ref(ptr, name, addr) do { } while (0)
+#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0)
+#define wpa_trace_check_ref(addr) do { } while (0)
+
+#endif /* WPA_TRACE */
+
+
+#ifdef WPA_TRACE_BFD
+
+void wpa_trace_dump_funcname(const char *title, void *pc);
+
+#else /* WPA_TRACE_BFD */
+
+#define wpa_trace_dump_funcname(title, pc) do { } while (0)
+
+#endif /* WPA_TRACE_BFD */
+
+#endif /* TRACE_H */
diff --git a/src/utils/uuid.c b/src/utils/uuid.c
new file mode 100644
index 0000000..d8cc267
--- /dev/null
+++ b/src/utils/uuid.c
@@ -0,0 +1,77 @@
+/*
+ * Universally Unique IDentifier (UUID)
+ * Copyright (c) 2008, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+#include "uuid.h"
+
+int uuid_str2bin(const char *str, u8 *bin)
+{
+ const char *pos;
+ u8 *opos;
+
+ pos = str;
+ opos = bin;
+
+ if (hexstr2bin(pos, opos, 4))
+ return -1;
+ pos += 8;
+ opos += 4;
+
+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+ return -1;
+ pos += 4;
+ opos += 2;
+
+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+ return -1;
+ pos += 4;
+ opos += 2;
+
+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+ return -1;
+ pos += 4;
+ opos += 2;
+
+ if (*pos++ != '-' || hexstr2bin(pos, opos, 6))
+ return -1;
+
+ return 0;
+}
+
+
+int uuid_bin2str(const u8 *bin, char *str, size_t max_len)
+{
+ int len;
+ len = os_snprintf(str, max_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x-%02x%02x%02x%02x%02x%02x",
+ bin[0], bin[1], bin[2], bin[3],
+ bin[4], bin[5], bin[6], bin[7],
+ bin[8], bin[9], bin[10], bin[11],
+ bin[12], bin[13], bin[14], bin[15]);
+ if (len < 0 || (size_t) len >= max_len)
+ return -1;
+ return 0;
+}
+
+
+int is_nil_uuid(const u8 *uuid)
+{
+ int i;
+ for (i = 0; i < UUID_LEN; i++)
+ if (uuid[i])
+ return 0;
+ return 1;
+}
diff --git a/src/utils/uuid.h b/src/utils/uuid.h
new file mode 100644
index 0000000..0759165
--- /dev/null
+++ b/src/utils/uuid.h
@@ -0,0 +1,24 @@
+/*
+ * Universally Unique IDentifier (UUID)
+ * Copyright (c) 2008, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef UUID_H
+#define UUID_H
+
+#define UUID_LEN 16
+
+int uuid_str2bin(const char *str, u8 *bin);
+int uuid_bin2str(const u8 *bin, char *str, size_t max_len);
+int is_nil_uuid(const u8 *uuid);
+
+#endif /* UUID_H */
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
new file mode 100644
index 0000000..b8c5e2f
--- /dev/null
+++ b/src/utils/wpa_debug.c
@@ -0,0 +1,484 @@
+/*
+ * wpa_supplicant/hostapd / Debug prints
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+
+#ifdef CONFIG_DEBUG_SYSLOG
+#include <syslog.h>
+
+static int wpa_debug_syslog = 0;
+#endif /* CONFIG_DEBUG_SYSLOG */
+
+
+int wpa_debug_level = MSG_INFO;
+int wpa_debug_show_keys = 0;
+int wpa_debug_timestamp = 0;
+
+
+#ifdef CONFIG_ANDROID_LOG
+
+#include <android/log.h>
+
+void android_printf(int level, char *format, ...)
+{
+ if (level >= wpa_debug_level) {
+ va_list ap;
+ if (level == MSG_ERROR)
+ level = ANDROID_LOG_ERROR;
+ else if (level == MSG_WARNING)
+ level = ANDROID_LOG_WARN;
+ else if (level == MSG_INFO)
+ level = ANDROID_LOG_INFO;
+ else
+ level = ANDROID_LOG_DEBUG;
+ va_start(ap, format);
+ __android_log_vprint(level, "wpa_supplicant", format, ap);
+ va_end(ap);
+ }
+}
+
+#else /* CONFIG_ANDROID_LOG */
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+
+#ifdef CONFIG_DEBUG_FILE
+static FILE *out_file = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+
+
+void wpa_debug_print_timestamp(void)
+{
+ struct os_time tv;
+
+ if (!wpa_debug_timestamp)
+ return;
+
+ os_get_time(&tv);
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
+ (unsigned int) tv.usec);
+ } else
+#endif /* CONFIG_DEBUG_FILE */
+ printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+}
+
+
+#ifdef CONFIG_DEBUG_SYSLOG
+#ifndef LOG_HOSTAPD
+#define LOG_HOSTAPD LOG_DAEMON
+#endif /* LOG_HOSTAPD */
+
+void wpa_debug_open_syslog(void)
+{
+ openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD);
+ wpa_debug_syslog++;
+}
+
+
+void wpa_debug_close_syslog(void)
+{
+ if (wpa_debug_syslog)
+ closelog();
+}
+
+
+static int syslog_priority(int level)
+{
+ switch (level) {
+ case MSG_MSGDUMP:
+ case MSG_DEBUG:
+ return LOG_DEBUG;
+ case MSG_INFO:
+ return LOG_NOTICE;
+ case MSG_WARNING:
+ return LOG_WARNING;
+ case MSG_ERROR:
+ return LOG_ERR;
+ }
+ return LOG_INFO;
+}
+#endif /* CONFIG_DEBUG_SYSLOG */
+
+
+/**
+ * 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, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (level >= wpa_debug_level) {
+#ifdef CONFIG_DEBUG_SYSLOG
+ if (wpa_debug_syslog) {
+ vsyslog(syslog_priority(level), fmt, ap);
+ } else {
+#endif /* CONFIG_DEBUG_SYSLOG */
+ wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ vfprintf(out_file, fmt, ap);
+ fprintf(out_file, "\n");
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
+ vprintf(fmt, ap);
+ printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
+#ifdef CONFIG_DEBUG_SYSLOG
+ }
+#endif /* CONFIG_DEBUG_SYSLOG */
+ }
+ 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();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ fprintf(out_file, "%s - hexdump(len=%lu):",
+ title, (unsigned long) len);
+ if (buf == NULL) {
+ fprintf(out_file, " [NULL]");
+ } else if (show) {
+ for (i = 0; i < len; i++)
+ fprintf(out_file, " %02x", buf[i]);
+ } else {
+ fprintf(out_file, " [REMOVED]");
+ }
+ fprintf(out_file, "\n");
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
+ 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");
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+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)
+{
+ size_t i, llen;
+ const u8 *pos = buf;
+ const size_t line_len = 16;
+
+ if (level < wpa_debug_level)
+ return;
+ wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ if (!show) {
+ fprintf(out_file,
+ "%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ if (buf == NULL) {
+ fprintf(out_file,
+ "%s - hexdump_ascii(len=%lu): [NULL]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
+ title, (unsigned long) len);
+ while (len) {
+ llen = len > line_len ? line_len : len;
+ fprintf(out_file, " ");
+ for (i = 0; i < llen; i++)
+ fprintf(out_file, " %02x", pos[i]);
+ for (i = llen; i < line_len; i++)
+ fprintf(out_file, " ");
+ fprintf(out_file, " ");
+ for (i = 0; i < llen; i++) {
+ if (isprint(pos[i]))
+ fprintf(out_file, "%c", pos[i]);
+ else
+ fprintf(out_file, "_");
+ }
+ for (i = llen; i < line_len; i++)
+ fprintf(out_file, " ");
+ fprintf(out_file, "\n");
+ pos += llen;
+ len -= llen;
+ }
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
+ 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;
+ }
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+
+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);
+}
+
+
+#ifdef CONFIG_DEBUG_FILE
+static char *last_path = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+
+int wpa_debug_reopen_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+ int rv;
+ if (last_path) {
+ char *tmp = os_strdup(last_path);
+ wpa_debug_close_file();
+ rv = wpa_debug_open_file(tmp);
+ os_free(tmp);
+ } else {
+ wpa_printf(MSG_ERROR, "Last-path was not set, cannot "
+ "re-open log file.");
+ rv = -1;
+ }
+ return rv;
+#else /* CONFIG_DEBUG_FILE */
+ return 0;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+
+int wpa_debug_open_file(const char *path)
+{
+#ifdef CONFIG_DEBUG_FILE
+ if (!path)
+ return 0;
+
+ if (last_path == NULL || os_strcmp(last_path, path) != 0) {
+ /* Save our path to enable re-open */
+ os_free(last_path);
+ last_path = os_strdup(path);
+ }
+
+ out_file = fopen(path, "a");
+ if (out_file == NULL) {
+ wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
+ "output file, using standard output");
+ return -1;
+ }
+#ifndef _WIN32
+ setvbuf(out_file, NULL, _IOLBF, 0);
+#endif /* _WIN32 */
+#endif /* CONFIG_DEBUG_FILE */
+ return 0;
+}
+
+
+void wpa_debug_close_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+ if (!out_file)
+ return;
+ fclose(out_file);
+ out_file = NULL;
+ os_free(last_path);
+ last_path = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+#endif /* CONFIG_ANDROID_LOG */
+
+#ifndef CONFIG_NO_WPA_MSG
+static wpa_msg_cb_func wpa_msg_cb = NULL;
+
+void wpa_msg_register_cb(wpa_msg_cb_func func)
+{
+ wpa_msg_cb = func;
+}
+
+
+static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
+
+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
+{
+ wpa_msg_ifname_cb = func;
+}
+
+
+void wpa_msg(void *ctx, int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ const int buflen = 2048;
+ int len;
+ char prefix[130];
+
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
+ "buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ prefix[0] = '\0';
+ if (wpa_msg_ifname_cb) {
+ const char *ifname = wpa_msg_ifname_cb(ctx);
+ if (ifname) {
+ int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
+ ifname);
+ if (res < 0 || res >= (int) sizeof(prefix))
+ prefix[0] = '\0';
+ }
+ }
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ wpa_printf(level, "%s%s", prefix, buf);
+ if (wpa_msg_cb)
+ wpa_msg_cb(ctx, level, buf, len);
+ os_free(buf);
+}
+
+
+void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ const int buflen = 2048;
+ int len;
+
+ if (!wpa_msg_cb)
+ return;
+
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
+ "message buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ wpa_msg_cb(ctx, level, buf, len);
+ os_free(buf);
+}
+#endif /* CONFIG_NO_WPA_MSG */
+
+
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+static hostapd_logger_cb_func hostapd_logger_cb = NULL;
+
+void hostapd_logger_register_cb(hostapd_logger_cb_func func)
+{
+ hostapd_logger_cb = func;
+}
+
+
+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ const int buflen = 2048;
+ int len;
+
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
+ "message buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ if (hostapd_logger_cb)
+ hostapd_logger_cb(ctx, addr, module, level, buf, len);
+ else if (addr)
+ wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s",
+ MAC2STR(addr), buf);
+ else
+ wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
+ os_free(buf);
+}
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
new file mode 100644
index 0000000..ae36afe
--- /dev/null
+++ b/src/utils/wpa_debug.h
@@ -0,0 +1,307 @@
+/*
+ * wpa_supplicant/hostapd / Debug prints
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef WPA_DEBUG_H
+#define WPA_DEBUG_H
+
+#include "wpabuf.h"
+
+/* Debugging function - conditional printf and hex dump. Driver wrappers can
+ * use these for debugging purposes. */
+
+enum {
+ MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
+};
+
+#ifdef CONFIG_ANDROID_LOG
+
+#define wpa_debug_print_timestamp() do {} while (0)
+#define wpa_hexdump(...) do {} while (0)
+#define wpa_hexdump_key(...) do {} while (0)
+#define wpa_hexdump_buf(l,t,b) do {} while (0)
+#define wpa_hexdump_buf_key(l,t,b) do {} while (0)
+#define wpa_hexdump_ascii(...) do {} while (0)
+#define wpa_hexdump_ascii_key(...) do {} while (0)
+#define wpa_debug_open_file(...) do {} while (0)
+#define wpa_debug_close_file() do {} while (0)
+#define wpa_dbg(...) do {} while (0)
+
+static inline int wpa_debug_reopen_file(void)
+{
+ return 0;
+}
+
+
+void android_printf(int level, char *format, ...)
+PRINTF_FORMAT(2, 3);
+
+#define wpa_printf android_printf
+
+#else /* CONFIG_ANDROID_LOG */
+
+#ifdef CONFIG_NO_STDOUT_DEBUG
+
+#define wpa_debug_print_timestamp() do { } while (0)
+#define wpa_printf(args...) do { } while (0)
+#define wpa_hexdump(l,t,b,le) do { } while (0)
+#define wpa_hexdump_buf(l,t,b) do { } while (0)
+#define wpa_hexdump_key(l,t,b,le) do { } while (0)
+#define wpa_hexdump_buf_key(l,t,b) do { } while (0)
+#define wpa_hexdump_ascii(l,t,b,le) do { } while (0)
+#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
+#define wpa_debug_open_file(p) do { } while (0)
+#define wpa_debug_close_file() do { } while (0)
+#define wpa_dbg(args...) do { } while (0)
+
+static inline int wpa_debug_reopen_file(void)
+{
+ return 0;
+}
+
+#else /* CONFIG_NO_STDOUT_DEBUG */
+
+int wpa_debug_open_file(const char *path);
+int wpa_debug_reopen_file(void);
+void wpa_debug_close_file(void);
+
+/**
+ * wpa_debug_printf_timestamp - Print timestamp for debug output
+ *
+ * This function prints a timestamp in seconds_from_1970.microsoconds
+ * format if debug output has been configured to include timestamps in debug
+ * messages.
+ */
+void wpa_debug_print_timestamp(void);
+
+/**
+ * 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, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
+/**
+ * wpa_hexdump - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * 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. The contents of buf is printed out has hex dump.
+ */
+void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
+
+static inline void wpa_hexdump_buf(int level, const char *title,
+ const struct wpabuf *buf)
+{
+ wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL,
+ buf ? wpabuf_len(buf) : 0);
+}
+
+/**
+ * wpa_hexdump_key - conditional hex dump, hide keys
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * 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. The contents of buf is printed out has hex dump. This works
+ * like wpa_hexdump(), but by default, does not include secret keys (passwords,
+ * etc.) in debug output.
+ */
+void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
+
+static inline void wpa_hexdump_buf_key(int level, const char *title,
+ const struct wpabuf *buf)
+{
+ wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : 0,
+ buf ? wpabuf_len(buf) : 0);
+}
+
+/**
+ * wpa_hexdump_ascii - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * 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. The contents of buf is printed out has hex dump with both
+ * the hex numbers and ASCII characters (for printable range) are shown. 16
+ * bytes per line will be shown.
+ */
+void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+ size_t len);
+
+/**
+ * wpa_hexdump_ascii_key - conditional hex dump, hide keys
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * 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. The contents of buf is printed out has hex dump with both
+ * the hex numbers and ASCII characters (for printable range) are shown. 16
+ * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
+ * default, does not include secret keys (passwords, etc.) in debug output.
+ */
+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+ size_t len);
+
+/*
+ * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce
+ * binary size. As such, it should be used with debugging messages that are not
+ * needed in the control interface while wpa_msg() has to be used for anything
+ * that needs to shown to control interface monitors.
+ */
+#define wpa_dbg(args...) wpa_msg(args)
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+#endif /* CONFIG_ANDROID_LOG */
+
+
+#ifdef CONFIG_NO_WPA_MSG
+#define wpa_msg(args...) do { } while (0)
+#define wpa_msg_ctrl(args...) do { } while (0)
+#define wpa_msg_register_cb(f) do { } while (0)
+#define wpa_msg_register_ifname_cb(f) do { } while (0)
+#else /* CONFIG_NO_WPA_MSG */
+/**
+ * wpa_msg - Conditional printf for default target and ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @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. This function is like wpa_printf(), but it also sends the
+ * same message to all attached ctrl_iface monitors.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
+void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
+
+/**
+ * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @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.
+ * This function is like wpa_msg(), but it sends the output only to the
+ * attached ctrl_iface monitors. In other words, it can be used for frequent
+ * events that do not need to be sent to syslog.
+ */
+void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
+ size_t len);
+
+/**
+ * wpa_msg_register_cb - Register callback function for wpa_msg() messages
+ * @func: Callback function (%NULL to unregister)
+ */
+void wpa_msg_register_cb(wpa_msg_cb_func func);
+
+typedef const char * (*wpa_msg_get_ifname_func)(void *ctx);
+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func);
+
+#endif /* CONFIG_NO_WPA_MSG */
+
+#ifdef CONFIG_NO_HOSTAPD_LOGGER
+#define hostapd_logger(args...) do { } while (0)
+#define hostapd_logger_register_cb(f) do { } while (0)
+#else /* CONFIG_NO_HOSTAPD_LOGGER */
+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
+ const char *fmt, ...) PRINTF_FORMAT(5, 6);
+
+typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr,
+ unsigned int module, int level,
+ const char *txt, size_t len);
+
+/**
+ * hostapd_logger_register_cb - Register callback function for hostapd_logger()
+ * @func: Callback function (%NULL to unregister)
+ */
+void hostapd_logger_register_cb(hostapd_logger_cb_func func);
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+
+#define HOSTAPD_MODULE_IEEE80211 0x00000001
+#define HOSTAPD_MODULE_IEEE8021X 0x00000002
+#define HOSTAPD_MODULE_RADIUS 0x00000004
+#define HOSTAPD_MODULE_WPA 0x00000008
+#define HOSTAPD_MODULE_DRIVER 0x00000010
+#define HOSTAPD_MODULE_IAPP 0x00000020
+#define HOSTAPD_MODULE_MLME 0x00000040
+
+enum hostapd_logger_level {
+ HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
+ HOSTAPD_LEVEL_DEBUG = 1,
+ HOSTAPD_LEVEL_INFO = 2,
+ HOSTAPD_LEVEL_NOTICE = 3,
+ HOSTAPD_LEVEL_WARNING = 4
+};
+
+
+#ifdef CONFIG_DEBUG_SYSLOG
+
+void wpa_debug_open_syslog(void);
+void wpa_debug_close_syslog(void);
+
+#else /* CONFIG_DEBUG_SYSLOG */
+
+static inline void wpa_debug_open_syslog(void)
+{
+}
+
+static inline void wpa_debug_close_syslog(void)
+{
+}
+
+#endif /* CONFIG_DEBUG_SYSLOG */
+
+
+#ifdef EAPOL_TEST
+#define WPA_ASSERT(a) \
+ do { \
+ if (!(a)) { \
+ printf("WPA_ASSERT FAILED '" #a "' " \
+ "%s %s:%d\n", \
+ __FUNCTION__, __FILE__, __LINE__); \
+ exit(1); \
+ } \
+ } while (0)
+#else
+#define WPA_ASSERT(a) do { } while (0)
+#endif
+
+#endif /* WPA_DEBUG_H */
diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c
new file mode 100644
index 0000000..eda779e
--- /dev/null
+++ b/src/utils/wpabuf.c
@@ -0,0 +1,304 @@
+/*
+ * Dynamic data buffer
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.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 "includes.h"
+
+#include "common.h"
+#include "trace.h"
+#include "wpabuf.h"
+
+#ifdef WPA_TRACE
+#define WPABUF_MAGIC 0x51a974e3
+
+struct wpabuf_trace {
+ unsigned int magic;
+};
+
+static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf)
+{
+ return (struct wpabuf_trace *)
+ ((const u8 *) buf - sizeof(struct wpabuf_trace));
+}
+#endif /* WPA_TRACE */
+
+
+static void wpabuf_overflow(const struct wpabuf *buf, size_t len)
+{
+#ifdef WPA_TRACE
+ struct wpabuf_trace *trace = wpabuf_get_trace(buf);
+ if (trace->magic != WPABUF_MAGIC) {
+ wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
+ trace->magic);
+ }
+#endif /* WPA_TRACE */
+ wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
+ buf, (unsigned long) buf->size, (unsigned long) buf->used,
+ (unsigned long) len);
+ wpa_trace_show("wpabuf overflow");
+ abort();
+}
+
+
+int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
+{
+ struct wpabuf *buf = *_buf;
+#ifdef WPA_TRACE
+ struct wpabuf_trace *trace;
+#endif /* WPA_TRACE */
+
+ if (buf == NULL) {
+ *_buf = wpabuf_alloc(add_len);
+ return *_buf == NULL ? -1 : 0;
+ }
+
+#ifdef WPA_TRACE
+ trace = wpabuf_get_trace(buf);
+ if (trace->magic != WPABUF_MAGIC) {
+ wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
+ trace->magic);
+ wpa_trace_show("wpabuf_resize invalid magic");
+ abort();
+ }
+#endif /* WPA_TRACE */
+
+ if (buf->used + add_len > buf->size) {
+ unsigned char *nbuf;
+ if (buf->ext_data) {
+ nbuf = os_realloc(buf->ext_data, buf->used + add_len);
+ if (nbuf == NULL)
+ return -1;
+ os_memset(nbuf + buf->used, 0, add_len);
+ buf->ext_data = nbuf;
+ } else {
+#ifdef WPA_TRACE
+ nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
+ sizeof(struct wpabuf) +
+ buf->used + add_len);
+ if (nbuf == NULL)
+ return -1;
+ trace = (struct wpabuf_trace *) nbuf;
+ buf = (struct wpabuf *) (trace + 1);
+ os_memset(nbuf + sizeof(struct wpabuf_trace) +
+ sizeof(struct wpabuf) + buf->used, 0,
+ add_len);
+#else /* WPA_TRACE */
+ nbuf = os_realloc(buf, sizeof(struct wpabuf) +
+ buf->used + add_len);
+ if (nbuf == NULL)
+ return -1;
+ buf = (struct wpabuf *) nbuf;
+ os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
+ add_len);
+#endif /* WPA_TRACE */
+ *_buf = buf;
+ }
+ buf->size = buf->used + add_len;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpabuf_alloc - Allocate a wpabuf of the given size
+ * @len: Length for the allocated buffer
+ * Returns: Buffer to the allocated wpabuf or %NULL on failure
+ */
+struct wpabuf * wpabuf_alloc(size_t len)
+{
+#ifdef WPA_TRACE
+ struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
+ sizeof(struct wpabuf) + len);
+ struct wpabuf *buf;
+ if (trace == NULL)
+ return NULL;
+ trace->magic = WPABUF_MAGIC;
+ buf = (struct wpabuf *) (trace + 1);
+#else /* WPA_TRACE */
+ struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len);
+ if (buf == NULL)
+ return NULL;
+#endif /* WPA_TRACE */
+
+ buf->size = len;
+ return buf;
+}
+
+
+struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
+{
+#ifdef WPA_TRACE
+ struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
+ sizeof(struct wpabuf));
+ struct wpabuf *buf;
+ if (trace == NULL)
+ return NULL;
+ trace->magic = WPABUF_MAGIC;
+ buf = (struct wpabuf *) (trace + 1);
+#else /* WPA_TRACE */
+ struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf));
+ if (buf == NULL)
+ return NULL;
+#endif /* WPA_TRACE */
+
+ buf->size = len;
+ buf->used = len;
+ buf->ext_data = data;
+
+ return buf;
+}
+
+
+struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)
+{
+ struct wpabuf *buf = wpabuf_alloc(len);
+ if (buf)
+ wpabuf_put_data(buf, data, len);
+ return buf;
+}
+
+
+struct wpabuf * wpabuf_dup(const struct wpabuf *src)
+{
+ struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src));
+ if (buf)
+ wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
+ return buf;
+}
+
+
+/**
+ * wpabuf_free - Free a wpabuf
+ * @buf: wpabuf buffer
+ */
+void wpabuf_free(struct wpabuf *buf)
+{
+#ifdef WPA_TRACE
+ struct wpabuf_trace *trace;
+ if (buf == NULL)
+ return;
+ trace = wpabuf_get_trace(buf);
+ if (trace->magic != WPABUF_MAGIC) {
+ wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x",
+ trace->magic);
+ wpa_trace_show("wpabuf_free magic mismatch");
+ abort();
+ }
+ os_free(buf->ext_data);
+ os_free(trace);
+#else /* WPA_TRACE */
+ if (buf == NULL)
+ return;
+ os_free(buf->ext_data);
+ os_free(buf);
+#endif /* WPA_TRACE */
+}
+
+
+void * wpabuf_put(struct wpabuf *buf, size_t len)
+{
+ void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
+ buf->used += len;
+ if (buf->used > buf->size) {
+ wpabuf_overflow(buf, len);
+ }
+ return tmp;
+}
+
+
+/**
+ * wpabuf_concat - Concatenate two buffers into a newly allocated one
+ * @a: First buffer
+ * @b: Second buffer
+ * Returns: wpabuf with concatenated a + b data or %NULL on failure
+ *
+ * Both buffers a and b will be freed regardless of the return value. Input
+ * buffers can be %NULL which is interpreted as an empty buffer.
+ */
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
+{
+ struct wpabuf *n = NULL;
+ size_t len = 0;
+
+ if (b == NULL)
+ return a;
+
+ if (a)
+ len += wpabuf_len(a);
+ if (b)
+ len += wpabuf_len(b);
+
+ n = wpabuf_alloc(len);
+ if (n) {
+ if (a)
+ wpabuf_put_buf(n, a);
+ if (b)
+ wpabuf_put_buf(n, b);
+ }
+
+ wpabuf_free(a);
+ wpabuf_free(b);
+
+ return n;
+}
+
+
+/**
+ * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
+ * @buf: Buffer to be padded
+ * @len: Length for the padded buffer
+ * Returns: wpabuf padded to len octets or %NULL on failure
+ *
+ * If buf is longer than len octets or of same size, it will be returned as-is.
+ * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
+ * by the source data. The source buffer will be freed on error, i.e., caller
+ * will only be responsible on freeing the returned buffer. If buf is %NULL,
+ * %NULL will be returned.
+ */
+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
+{
+ struct wpabuf *ret;
+ size_t blen;
+
+ if (buf == NULL)
+ return NULL;
+
+ blen = wpabuf_len(buf);
+ if (blen >= len)
+ return buf;
+
+ ret = wpabuf_alloc(len);
+ if (ret) {
+ os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
+ wpabuf_put_buf(ret, buf);
+ }
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
+{
+ va_list ap;
+ void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
+ int res;
+
+ va_start(ap, fmt);
+ res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
+ va_end(ap);
+ if (res < 0 || (size_t) res >= buf->size - buf->used)
+ wpabuf_overflow(buf, res);
+ buf->used += res;
+}
diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h
new file mode 100644
index 0000000..cccfcc8
--- /dev/null
+++ b/src/utils/wpabuf.h
@@ -0,0 +1,168 @@
+/*
+ * Dynamic data buffer
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.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.
+ */
+
+#ifndef WPABUF_H
+#define WPABUF_H
+
+/*
+ * Internal data structure for wpabuf. Please do not touch this directly from
+ * elsewhere. This is only defined in header file to allow inline functions
+ * from this file to access data.
+ */
+struct wpabuf {
+ size_t size; /* total size of the allocated buffer */
+ size_t used; /* length of data in the buffer */
+ u8 *ext_data; /* pointer to external data; NULL if data follows
+ * struct wpabuf */
+ /* optionally followed by the allocated buffer */
+};
+
+
+int wpabuf_resize(struct wpabuf **buf, size_t add_len);
+struct wpabuf * wpabuf_alloc(size_t len);
+struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len);
+struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
+struct wpabuf * wpabuf_dup(const struct wpabuf *src);
+void wpabuf_free(struct wpabuf *buf);
+void * wpabuf_put(struct wpabuf *buf, size_t len);
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
+
+
+/**
+ * wpabuf_size - Get the currently allocated size of a wpabuf buffer
+ * @buf: wpabuf buffer
+ * Returns: Currently allocated size of the buffer
+ */
+static inline size_t wpabuf_size(const struct wpabuf *buf)
+{
+ return buf->size;
+}
+
+/**
+ * wpabuf_len - Get the current length of a wpabuf buffer data
+ * @buf: wpabuf buffer
+ * Returns: Currently used length of the buffer
+ */
+static inline size_t wpabuf_len(const struct wpabuf *buf)
+{
+ return buf->used;
+}
+
+/**
+ * wpabuf_tailroom - Get size of available tail room in the end of the buffer
+ * @buf: wpabuf buffer
+ * Returns: Tail room (in bytes) of available space in the end of the buffer
+ */
+static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
+{
+ return buf->size - buf->used;
+}
+
+/**
+ * wpabuf_head - Get pointer to the head of the buffer data
+ * @buf: wpabuf buffer
+ * Returns: Pointer to the head of the buffer data
+ */
+static inline const void * wpabuf_head(const struct wpabuf *buf)
+{
+ if (buf->ext_data)
+ return buf->ext_data;
+ return buf + 1;
+}
+
+static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
+{
+ return wpabuf_head(buf);
+}
+
+/**
+ * wpabuf_mhead - Get modifiable pointer to the head of the buffer data
+ * @buf: wpabuf buffer
+ * Returns: Pointer to the head of the buffer data
+ */
+static inline void * wpabuf_mhead(struct wpabuf *buf)
+{
+ if (buf->ext_data)
+ return buf->ext_data;
+ return buf + 1;
+}
+
+static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
+{
+ return wpabuf_mhead(buf);
+}
+
+static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
+{
+ u8 *pos = wpabuf_put(buf, 1);
+ *pos = data;
+}
+
+static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
+{
+ u8 *pos = wpabuf_put(buf, 2);
+ WPA_PUT_LE16(pos, data);
+}
+
+static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
+{
+ u8 *pos = wpabuf_put(buf, 4);
+ WPA_PUT_LE32(pos, data);
+}
+
+static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
+{
+ u8 *pos = wpabuf_put(buf, 2);
+ WPA_PUT_BE16(pos, data);
+}
+
+static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
+{
+ u8 *pos = wpabuf_put(buf, 3);
+ WPA_PUT_BE24(pos, data);
+}
+
+static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
+{
+ u8 *pos = wpabuf_put(buf, 4);
+ WPA_PUT_BE32(pos, data);
+}
+
+static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,
+ size_t len)
+{
+ if (data)
+ os_memcpy(wpabuf_put(buf, len), data, len);
+}
+
+static inline void wpabuf_put_buf(struct wpabuf *dst,
+ const struct wpabuf *src)
+{
+ wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src));
+}
+
+static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
+{
+ buf->ext_data = (u8 *) data;
+ buf->size = buf->used = len;
+}
+
+static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)
+{
+ wpabuf_put_data(dst, str, os_strlen(str));
+}
+
+#endif /* WPABUF_H */